Revision
14390
Author
cseket
Date
2009-07-27 15:18:20 -0500 (Mon, 27 Jul 2009)

Log Message

merge from trunk r14389

Modified Paths

Added Paths

Removed Paths

Property Changed

Diff

Property changes: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia


Name: svn:ignore
   - Release
Debug
*.user
*.so
*.pdb
*.dylib
   + mod_sofia.log
Release
Debug
*.user
*.so
*.pdb
*.dylib
*.o
.libs
Makefile.in
.deps
Makefile
debug
cisco
Win32
x64
sofia.diff
diff.txt

Deleted: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/Makefile

Copied: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/Makefile.am (from rev 14389, freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile.am) (0 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/Makefile.am	                        (rev 0)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/Makefile.am	2009-07-27 20:18:20 UTC (rev 14390)
@@ -0,0 +1,51 @@
+AM_CFLAGS   = $(SWITCH_AM_CFLAGS)
+AM_CPPFLAGS = $(SWITCH_AM_CXXFLAGS)
+#AM_LDFLAGS  = $(SWITCH_AM_LDFLAGS)
+#we should set all these vars from configure, no reason to have these in each Makefile.am
+LIBTOOL = echo "`link=\`echo $@|grep .la;echo $@|grep .so;echo $@|grep .dll\`;if test -n "$$link"; then echo Creating $@;fi`";`if test -z "$(VERBOSE)" ; \
+then echo $(SHELL) $(switch_builddir)/quiet_libtool ;else echo $(SHELL) $(switch_builddir)/libtool;  fi`
+AM_MAKEFLAGS=`test -n "$(VERBOSE)" || echo -s`
+# Dirty trick to override the link output
+LIBS+=> $(MODNAME).log || error="yes";if test -n "$(VERBOSE)" -o "$$error" = "yes";then cat $(MODNAME).log;fi;if test "$$error" = "yes";then exit 1;fi
+
+moddir=@modinstdir@
+
+MODNAME=mod_sofia
+
+SOFIA_DIR=$(switch_builddir)/libs/sofia-sip
+SOFIAUA_DIR=$(SOFIA_DIR)/libsofia-sip-ua
+SOFIALA=$(SOFIAUA_DIR)/libsofia-sip-ua.la
+
+mod_LTLIBRARIES = mod_sofia.la
+mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c  mod_sofia.h
+mod_sofia_la_CFLAGS  = $(AM_CFLAGS) 
+mod_sofia_la_CFLAGS += -I. -I$(SOFIAUA_DIR)/bnf  -I$(SOFIAUA_DIR)/features
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_DIR)/ipt
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/iptsec -I$(SOFIAUA_DIR)/msg
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/nea -I$(SOFIAUA_DIR)/nta
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/nth -I$(SOFIAUA_DIR)/nua
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/sdp -I$(SOFIAUA_DIR)/sip
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/soa -I$(SOFIAUA_DIR)/sresolv
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/stun -I$(SOFIAUA_DIR)/su
+mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/tport -I$(SOFIAUA_DIR)/url
+mod_sofia_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SOFIALA)
+mod_sofia_la_LDFLAGS = -avoid-version -module -no-undefined
+
+if ADD_ODBC
+mod_sofia_la_CFLAGS += -DSWITCH_HAVE_ODBC
+endif
+
+if ISMAC
+mod_sofia_la_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration
+endif
+
+BUILT_SOURCES = $(SOFIALA)
+
+$(mod_sofia_la_SOURCES) : $(BUILT_SOURCES)
+
+$(SOFIALA): $(SOFIA_DIR) $(SOFIA_DIR)/.update
+	cd $(SOFIA_DIR) && $(MAKE) SOFIA_CFLAGS="$(AM_CFLAGS)"
+	$(TOUCH_TARGET)
+
+../../../../libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h: $(SOFIALA)
+

Copied: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj (from rev 14389, freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj) (0 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj	                        (rev 0)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj	2009-07-27 20:18:20 UTC (rev 14390)
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="mod_sofia"
+	ProjectGUID="{0DF3ABD0-DDC0-4265-B778-07C66780979B}"
+	RootNamespace="mod_sofia"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&quot;"
+				PreprocessorDefinitions="LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
+				UsePrecompiledHeader="0"
+				DisableSpecificWarnings="4201"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib advapi32.lib iphlpapi.lib"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			ConfigurationType="2"
+			InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&quot;"
+				PreprocessorDefinitions="LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
+				UsePrecompiledHeader="0"
+				DisableSpecificWarnings="4201"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib advapi32.lib iphlpapi.lib"
+				OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&quot;"
+				PreprocessorDefinitions="LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
+				UsePrecompiledHeader="0"
+				DisableSpecificWarnings="4201"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib advapi32.lib iphlpapi.lib"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			ConfigurationType="2"
+			InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&quot;"
+				PreprocessorDefinitions="LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
+				UsePrecompiledHeader="0"
+				DisableSpecificWarnings="4201"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib advapi32.lib iphlpapi.lib"
+				OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\mod_sofia.c"
+			>
+		</File>
+		<File
+			RelativePath=".\mod_sofia.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia.c"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia_glue.c"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia_presence.c"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia_reg.c"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia_sla.c"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c (14389 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c	2009-07-27 19:05:59 UTC (rev 14389)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c	2009-07-27 20:18:20 UTC (rev 14390)
@@ -1,6 +1,6 @@
 /* 
  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
  *
  * Version: MPL 1.1
  *
@@ -17,14 +17,14 @@
  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
  *
  * The Initial Developer of the Original Code is
- * Anthony Minessale II <anthmct@yahoo.com>
+ * Anthony Minessale II <anthm@freeswitch.org>
  * Portions created by the Initial Developer are Copyright (C)
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  * 
- * Anthony Minessale II <anthmct@yahoo.com>
- * Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Ken Rice <krice at cometsig.com>
  * Paul D. Tinsley <pdt at jackhammer.org>
  * Bret McDanel <trixter AT 0xdecafbad.com>
  *
@@ -35,1255 +35,166 @@
 
 /* Best viewed in a 160 x 60 VT100 Terminal or so the line below at least fits across your screen*/
 /*************************************************************************************************************************************************************/
+#include "mod_sofia.h"
+#include "sofia-sip/sip_extra.h"
+SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown);
+SWITCH_MODULE_DEFINITION(mod_sofia, mod_sofia_load, mod_sofia_shutdown, NULL);
 
-
-/*Defines etc..*/
-/*************************************************************************************************************************************************************/
-#define HAVE_APR
-#include <switch.h>
-static const switch_state_handler_table_t noop_state_handler = {0};
-struct outbound_reg;
-typedef struct outbound_reg outbound_reg_t;
-
-struct sofia_profile;
-typedef struct sofia_profile sofia_profile_t;
-#define NUA_MAGIC_T sofia_profile_t
-
-struct sofia_private {
-    char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
-	outbound_reg_t *oreg;
-};
-
-typedef struct sofia_private sofia_private_t;
-
-struct private_object;
-typedef struct private_object private_object_t;
-#define NUA_HMAGIC_T sofia_private_t
-
-#define MY_EVENT_REGISTER "sofia::register"
-#define MY_EVENT_EXPIRE "sofia::expire"
-#define MULTICAST_EVENT "multicast::event"
-#define SOFIA_REPLACES_HEADER "_sofia_replaces_"
-#define SOFIA_USER_AGENT "FreeSWITCH(mod_sofia)"
-#define SOFIA_CHAT_PROTO "sip"
-#define SOFIA_SIP_HEADER_PREFIX "sip_h_"
-#define SOFIA_SIP_HEADER_PREFIX_T "~sip_h_"
-
-#include <sofia-sip/nua.h>
-#include <sofia-sip/sip_status.h>
-#include <sofia-sip/sdp.h>
-#include <sofia-sip/sip_protos.h>
-#include <sofia-sip/auth_module.h>
-#include <sofia-sip/su_md5.h>
-#include <sofia-sip/su_log.h>
-#include <sofia-sip/nea.h>
-#include <sofia-sip/msg_addr.h>
-
-extern su_log_t tport_log[];
-
+struct mod_sofia_globals mod_sofia_globals;
+switch_endpoint_interface_t *sofia_endpoint_interface;
 static switch_frame_t silence_frame = { 0 };
 static char silence_data[13] = "";
 
-
-static char reg_sql[] =
-"CREATE TABLE sip_registrations (\n"
-"   user            VARCHAR(255),\n"
-"   host            VARCHAR(255),\n"
-"   contact         VARCHAR(1024),\n"
-"   status          VARCHAR(255),\n"
-"   rpid            VARCHAR(255),\n"
-"   expires         INTEGER(8)"
-");\n";
-
-
-static char sub_sql[] =
-"CREATE TABLE sip_subscriptions (\n"
-"   proto           VARCHAR(255),\n"
-"   user            VARCHAR(255),\n"
-"   host            VARCHAR(255),\n"
-"   sub_to_user     VARCHAR(255),\n"
-"   sub_to_host     VARCHAR(255),\n"
-"   event           VARCHAR(255),\n"
-"   contact         VARCHAR(1024),\n"
-"   call_id         VARCHAR(255),\n"
-"   full_from       VARCHAR(255),\n"
-"   full_via        VARCHAR(255),\n"
-"   expires         INTEGER(8)"
-");\n";
-
-
-static char auth_sql[] =
-"CREATE TABLE sip_authentication (\n"
-"   user            VARCHAR(255),\n"
-"   host            VARCHAR(255),\n"
-"   passwd            VARCHAR(255),\n"
-"   nonce           VARCHAR(255),\n"
-"   expires         INTEGER(8)"
-");\n";
-
-static const char modname[] = "mod_sofia";
 #define STRLEN 15
 
-static switch_memory_pool_t *module_pool = NULL;
-
-#define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);}
-#define set_anchor(t,m) if (t->Anchor) {delete t->Anchor;} t->Anchor = new SipMessage(m);
-
-
-/* Local Structures */
-/*************************************************************************************************************************************************************/
-struct sip_alias_node {
-	char *url;
-	nua_t *nua;
-	struct sip_alias_node *next;
-};
-
-typedef struct sip_alias_node sip_alias_node_t;
-
-typedef enum {
-	PFLAG_AUTH_CALLS = (1 << 0),
-	PFLAG_BLIND_REG = (1 << 1),
-	PFLAG_AUTH_ALL = (1 << 2),
-	PFLAG_FULL_ID = (1 << 3),
-	PFLAG_PRESENCE = (1 << 4),
-	PFLAG_PASS_RFC2833 = (1 << 5),
-    PFLAG_DISABLE_TRANSCODING = (1 << 6)
-} PFLAGS;
-
-typedef enum {
-	TFLAG_IO = (1 << 0),
-	TFLAG_CHANGE_MEDIA = (1 << 1),
-	TFLAG_OUTBOUND = (1 << 2),
-	TFLAG_READING = (1 << 3),
-	TFLAG_WRITING = (1 << 4),
-	TFLAG_HUP = (1 << 5),
-	TFLAG_RTP = (1 << 6),
-	TFLAG_BYE = (1 << 7),
-	TFLAG_ANS = (1 << 8),
-	TFLAG_EARLY_MEDIA = (1 << 9),
-	TFLAG_SECURE = (1 << 10),
-	TFLAG_VAD_IN = ( 1 << 11),
-	TFLAG_VAD_OUT = ( 1 << 12),
-	TFLAG_VAD = ( 1 << 13),
-	TFLAG_TIMER = (1 << 14),
-	TFLAG_READY = (1 << 15),
-	TFLAG_REINVITE = (1 << 16),
-	TFLAG_REFER = (1 << 17),
-	TFLAG_NOHUP = (1 << 18),
-	TFLAG_XFER = (1 << 19),
-	TFLAG_NOMEDIA = (1 << 20),
-	TFLAG_BUGGY_2833 = (1 << 21),
-	TFLAG_SIP_HOLD = (1 << 22),
-	TFLAG_INB_NOMEDIA = (1 << 23),
-	TFLAG_LATE_NEGOTIATION = (1 << 24)
-} TFLAGS;
-
-static struct {
-	switch_hash_t *profile_hash;
-	switch_mutex_t *hash_mutex;
-	uint32_t callid;
-	int32_t running;
-	switch_mutex_t *mutex;
-    char guess_ip[80];
-} globals;
-
-typedef enum {
-	REG_FLAG_AUTHED = (1 << 0),
-} reg_flags_t;
-
-typedef enum {
-	REG_STATE_UNREGED,
-	REG_STATE_TRYING,
-	REG_STATE_REGISTER,
-	REG_STATE_REGED,
-	REG_STATE_FAILED,
-	REG_STATE_EXPIRED
-} reg_state_t;
-
-struct outbound_reg {
-	sofia_private_t *sofia_private;
-	nua_handle_t *nh;
-	sofia_profile_t *profile;
-	char *name;
-	char *register_scheme;
-	char *register_realm;
-	char *register_username;
-	char *register_password;
-	char *register_from;
-	char *register_to;
-	char *register_proxy;
-	char *expires_str;
-	uint32_t freq;
-	time_t expires;
-	time_t retry;
-	uint32_t flags;
-	reg_state_t state;
-	switch_memory_pool_t *pool;
-	struct outbound_reg *next;
-};
-
-
-struct sofia_profile {
-	int debug;
-	char *name;
-	char *dbname;
-	char *dialplan;
-	char *context;
-	char *extrtpip;
-	char *rtpip;
-	char *sipip;
-	char *extsipip;
-	char *username;
-	char *url;
-	char *bindurl;
-	char *sipdomain;
-	char *timer_name;
-	int sip_port;
-	char *codec_string;
-	int running;
-	int codec_ms;
-	int dtmf_duration;
-	unsigned int flags;
-	unsigned int pflags;
-	uint32_t max_calls;
-    uint32_t nonce_ttl;
-	nua_t *nua;
-	switch_memory_pool_t *pool;
-	su_root_t *s_root;
-	sip_alias_node_t *aliases;
-	switch_payload_t te;
-	uint32_t codec_flags;
-	switch_mutex_t *ireg_mutex;
-	switch_mutex_t *oreg_mutex;
-	outbound_reg_t *registrations;
-	su_home_t *home;
-	switch_hash_t *profile_hash;
-	switch_hash_t *chat_hash;
-};
-
-
-struct private_object {
-	sofia_private_t *sofia_private;
-	uint32_t flags;
-	switch_payload_t agreed_pt;
-	switch_core_session_t *session;
-	switch_frame_t read_frame;
-	char *codec_order[SWITCH_MAX_CODECS];
-	int codec_order_last;
-	const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
-	int num_codecs;
-	switch_codec_t read_codec;
-	switch_codec_t write_codec;
-	uint32_t codec_ms;
-	switch_caller_profile_t *caller_profile;
-	uint32_t timestamp_send;
-	//int32_t timestamp_recv;
-	switch_rtp_t *rtp_session;
-	int ssrc;
-	//switch_time_t last_read;
-	sofia_profile_t *profile;
-	char *local_sdp_audio_ip;
-	switch_port_t local_sdp_audio_port;
-	char *remote_sdp_audio_ip;
-	switch_port_t remote_sdp_audio_port;
-	char *adv_sdp_audio_ip;
-	switch_port_t adv_sdp_audio_port;
-	char *proxy_sdp_audio_ip;
-	switch_port_t proxy_sdp_audio_port;
-	char *from_uri;
-	char *to_uri;
-	char *from_address;
-	char *to_address;
-	char *callid;
-	char *far_end_contact;
-	char *contact_url;
-	char *from_str;
-	char *rm_encoding;
-	char *rm_fmtp;
-	char *fmtp_out;
-	char *remote_sdp_str;
-	char *local_sdp_str;
-	char *dest;
-	char *dest_to;
-	char *key;
-	char *xferto;
-	char *kick;
-	char *origin;
-	char *hash_key;
-	char *chat_from;
-	char *chat_to;
-	char *e_dest;
-    char *call_id;
-	unsigned long rm_rate;
-	switch_payload_t pt;
-	switch_mutex_t *flag_mutex;
-	switch_payload_t te;
-	switch_payload_t bte;
-	nua_handle_t *nh;
-	nua_handle_t *nh2;
-	su_home_t *home;
-	sip_contact_t *contact;
-};
-
-/* Function Prototypes */
-/*************************************************************************************************************************************************************/
 static switch_status_t sofia_on_init(switch_core_session_t *session);
 
-static switch_status_t sofia_on_hangup(switch_core_session_t *session);
-
-static switch_status_t sofia_on_loopback(switch_core_session_t *session);
-
-static switch_status_t sofia_on_transmit(switch_core_session_t *session);
-
-static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_caller_profile_t *outbound_profile,
-												  switch_core_session_t **new_session, switch_memory_pool_t **pool);
-
-static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout,
-										switch_io_flag_t flags, int stream_id);
-
-static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout,
-										 switch_io_flag_t flags, int stream_id);
-
-static switch_status_t config_sofia(int reload);
-
+static switch_status_t sofia_on_exchange_media(switch_core_session_t *session);
+static switch_status_t sofia_on_soft_execute(switch_core_session_t *session);
+static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+												  switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
+												  switch_memory_pool_t **pool, switch_originate_flag_t flags);
+static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t sofia_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t sofia_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
 static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig);
 
-static switch_status_t activate_rtp(private_object_t *tech_pvt);
-
-static void deactivate_rtp(private_object_t *tech_pvt);
-
-static void set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, char *sr, int force);
-
-static void tech_set_codecs(private_object_t *tech_pvt);
-
-static void attach_private(switch_core_session_t *session,
-                           sofia_profile_t *profile,
-                           private_object_t *tech_pvt,
-                           const char *channame);
-
-static void terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line);
-
-static switch_status_t tech_choose_port(private_object_t *tech_pvt);
-
-static switch_status_t do_invite(switch_core_session_t *session);
-
-static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp);
-
-static char *get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t *mutex);
-
-static void establish_presence(sofia_profile_t *profile);
-
-static void sip_i_state(int status,
-                        char const *phrase,
-                        nua_t *nua,
-                        sofia_profile_t *profile,
-                        nua_handle_t *nh,
-						sofia_private_t *sofia_private,
-                        sip_t const *sip,
-                        tagi_t tags[]);
-
-
-static void sip_i_refer(nua_t *nua,
-						sofia_profile_t *profile,
-						nua_handle_t *nh,
-                        switch_core_session_t *session,
-						sip_t const *sip,
-						tagi_t tags[]);
-
-static void sip_i_info(nua_t *nua,
-                       sofia_profile_t *profile,
-                       nua_handle_t *nh,
-                       switch_core_session_t *session,
-                       sip_t const *sip,
-                       tagi_t tags[]);
-
-static void sip_i_invite(nua_t *nua,
-                         sofia_profile_t *profile,
-                         nua_handle_t *nh,
-						 sofia_private_t *sofia_private,
-                         sip_t const *sip,
-                         tagi_t tags[]);
-
-static void sip_i_register(nua_t *nua,
-						   sofia_profile_t *profile,
-						   nua_handle_t *nh,
-						   sofia_private_t *sofia_private,
-						   sip_t const *sip,
-						   tagi_t tags[]);
-
-static void event_callback(nua_event_t   event,
-                           int           status,
-                           char const   *phrase,
-                           nua_t        *nua,
-                           sofia_profile_t  *profile,
-                           nua_handle_t *nh,
-						   sofia_private_t *sofia_private,
-                           sip_t const  *sip,
-                           tagi_t        tags[]);
-
-
-static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void *obj);
-
-static void launch_profile_thread(sofia_profile_t *profile);
-
-static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint);
-
 /* BODY OF THE MODULE */
 /*************************************************************************************************************************************************************/
 
-typedef enum {
-	AUTH_OK,
-	AUTH_FORBIDDEN,
-	AUTH_STALE,
-} auth_res_t;
-
-
-static char *get_url_from_contact(char *buf, uint8_t to_dup)
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status_t sofia_on_init(switch_core_session_t *session)
 {
-	char *url = NULL, *e;
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
 
-	if ((url = strchr(buf, '<')) && (e = strchr(url, '>'))) {
-		url++;
-		if (to_dup) {
-			url = strdup(url);
-			e = strchr(url, '>');
-		}
+	switch_assert(tech_pvt != NULL);
 
-		*e = '\0';
+	tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
+	switch_mutex_lock(tech_pvt->sofia_mutex);
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA INIT\n", switch_channel_get_name(channel));
+	if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+		sofia_glue_tech_absorb_sdp(tech_pvt);
 	}
-	
-	return url;
-}
 
+	if (sofia_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+		const char *var;
 
-static auth_res_t parse_auth(sofia_profile_t *profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen)
-{
-	int indexnum;
-	const char *cur;
-	su_md5_t ctx;
-	char uridigest[2 * SU_MD5_DIGEST_SIZE + 1];
-	char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1];
-	char *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL;
-	auth_res_t ret = AUTH_FORBIDDEN;
-	char *npassword = NULL;
-	int cnt = 0;
-	nonce = uri = qop = cnonce = nc = response = NULL;
-
-	if (authorization->au_params) {
-		for(indexnum = 0; (cur=authorization->au_params[indexnum]); indexnum++) {
-			char *var, *val, *p, *work; 
-			var = val = work = NULL;
-			if ((work = strdup(cur))) {
-				var = work;
-				if ((val = strchr(var, '='))) {
-					*val++ = '\0';
-					while(*val == '"') {
-						*val++ = '\0';
-					}
-					if ((p = strchr(val, '"'))) {
-						*p = '\0';
-					}
-
-					if (!strcasecmp(var, "nonce")) {
-						nonce = strdup(val);
-						cnt++;
-					} else if (!strcasecmp(var, "uri")) {
-						uri = strdup(val);
-						cnt++;
-					} else if (!strcasecmp(var, "qop")) {
-						qop = strdup(val);
-						cnt++;
-					} else if (!strcasecmp(var, "cnonce")) {
-						cnonce = strdup(val);
-						cnt++;
-					} else if (!strcasecmp(var, "response")) {
-						response = strdup(val);
-						cnt++;
-					} else if (!strcasecmp(var, "nc")) {
-						nc = strdup(val);
-						cnt++;
-					}
-				}
-				
-				free(work);
+		if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && !switch_strlen_zero(var)) {
+			if (switch_true(var) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_32)) {
+				sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
+				sofia_glue_build_crypto(tech_pvt, 1, AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
+			} else if (!strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_80)) {
+				sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
+				sofia_glue_build_crypto(tech_pvt, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
 			}
 		}
-	}
 
-	if (cnt != 6) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Authorization header!\n");
-		goto end;
-	}
 
-	if (switch_strlen_zero(np)) {
-		if (!get_auth_data(profile->dbname, nonce, np, nplen, profile->ireg_mutex)) {
-			ret = AUTH_STALE;
+		if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) {
+			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+			assert(switch_channel_get_state(channel) != CS_INIT);
+			status = SWITCH_STATUS_FALSE;
 			goto end;
-		} 
-	}
-
-	npassword = np;
-
-	if ((input = switch_mprintf("%s:%q", regstr, uri))) {
-		su_md5_init(&ctx);
-		su_md5_strupdate(&ctx, input);
-		su_md5_hexdigest(&ctx, uridigest);
-		su_md5_deinit(&ctx);
-	}
-
-	if ((input2 = switch_mprintf("%q:%q:%q:%q:%q:%q", npassword, nonce, nc, cnonce, qop, uridigest))) {
-		memset(&ctx, 0, sizeof(ctx));
-		su_md5_init(&ctx);
-		su_md5_strupdate(&ctx, input2);
-		su_md5_hexdigest(&ctx, bigdigest);
-		su_md5_deinit(&ctx);
-
-		if (!strcasecmp(bigdigest, response)) {
-			ret = AUTH_OK;
-		} else {
-			ret = AUTH_FORBIDDEN;
 		}
 	}
 
- end:
-    switch_safe_free(input);
-    switch_safe_free(input2);
-	switch_safe_free(nonce);
-	switch_safe_free(uri);
-	switch_safe_free(qop);
-	switch_safe_free(cnonce);
-	switch_safe_free(nc);
-	switch_safe_free(response);
+	/* Move channel's state machine to ROUTING */
+	switch_channel_set_state(channel, CS_ROUTING);
+	assert(switch_channel_get_state(channel) != CS_INIT);
 
-	return ret;
-
-}
-
-
-static void execute_sql(char *dbname, char *sql, switch_mutex_t *mutex)
-{
-	switch_core_db_t *db;
-
-	if (mutex) {
-		switch_mutex_lock(mutex);
-	}
-
-	if (!(db = switch_core_db_open_file(dbname))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname);
-		goto end;
-	}
-	switch_core_db_persistant_execute(db, sql, 25);
-	switch_core_db_close(db);
-
  end:
-	if (mutex) {
-		switch_mutex_unlock(mutex);
-	}
-}
 
+	switch_mutex_unlock(tech_pvt->sofia_mutex);
 
-struct callback_t {
-	char *val;
-	switch_size_t len;
-	int matches;
-};
-
-static int find_callback(void *pArg, int argc, char **argv, char **columnNames){
-	struct callback_t *cbt = (struct callback_t *) pArg;
-
-	switch_copy_string(cbt->val, argv[0], cbt->len);
-	cbt->matches++;
-	return 0;
+	return status;
 }
 
-static int del_callback(void *pArg, int argc, char **argv, char **columnNames){
-	switch_event_t *s_event;
-
-	if (argc >=3 ) {
-		if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) {
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", argv[0]);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "user", "%s", argv[1]);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "host", "%s", argv[2]);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", argv[3]);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%d", argv[4]);
-			switch_event_fire(&s_event);
-		}
-	}
-	return 0;
-}
-
-static void check_expire(switch_core_db_t *db, sofia_profile_t *profile, time_t now)
+static switch_status_t sofia_on_routing(switch_core_session_t *session)
 {
-	char sql[1024];
-	char *errmsg;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
 
-	if (!db) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-		return;
+	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
 	}
 
-	switch_mutex_lock(profile->ireg_mutex);
-	snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires < %ld", profile->name, (long) now);	
-	switch_core_db_exec(db, sql, del_callback, NULL, &errmsg);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA ROUTING\n", switch_channel_get_name(switch_core_session_get_channel(session)));
 
-	if (errmsg) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", sql, errmsg);
-		switch_safe_free(errmsg);
-		errmsg = NULL;
-	}
-	
-	snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires < %ld", (long) now);
-	switch_core_db_persistant_execute(db, sql, 1000);
-	snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires < %ld", (long) now);
-	switch_core_db_persistant_execute(db, sql, 1000);
-	snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires < %ld", (long) now);
-	switch_core_db_persistant_execute(db, sql, 1000);
-
-	switch_mutex_unlock(profile->ireg_mutex);
-
+	return SWITCH_STATUS_SUCCESS;
 }
 
-static char *find_reg_url(sofia_profile_t *profile, const char *user, const char *host, char *val, switch_size_t len)
-{
-	char *errmsg;
-	struct callback_t cbt = {0};
-	switch_core_db_t *db;
 
-	if (!user) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n");
-        return NULL;
-	}
-
-	if (!(db = switch_core_db_open_file(profile->dbname))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-		return NULL;
-	}
-
-	cbt.val = val;
-	cbt.len = len;
-	switch_mutex_lock(profile->ireg_mutex);
-	if (host) {
-		snprintf(val, len, "select contact from sip_registrations where user='%s' and host='%s'", user, host);	
-	} else {
-		snprintf(val, len, "select contact from sip_registrations where user='%s'", user);	
-	}
-
-	switch_core_db_exec(db, val, find_callback, &cbt, &errmsg);
-
-	if (errmsg) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", val, errmsg);
-		switch_safe_free(errmsg);
-		errmsg = NULL;
-	}
-
-	switch_mutex_unlock(profile->ireg_mutex);
-
-	switch_core_db_close(db);
-    if (cbt.matches) {
-        return val;
-    } else {
-        return NULL;
-    }
-}
-
-
-static void set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, char *sr, int force)
+static switch_status_t sofia_on_reset(switch_core_session_t *session)
 {
-	char buf[2048];
-	switch_time_t now = switch_time_now();
-    int ptime = 0;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
 
-	if (!force && !ip && !sr && switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-		return;
+	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
 	}
 
-	if (!ip) {
-		if (!(ip = tech_pvt->adv_sdp_audio_ip)) {
-			ip = tech_pvt->proxy_sdp_audio_ip;
-		}
-	}
-	if (!port) {
-		if (!(port = tech_pvt->adv_sdp_audio_port)) {
-			port = tech_pvt->proxy_sdp_audio_port;
-		}
-	}
-	if (!sr) {
-		sr = "sendrecv";
-	}
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA RESET\n", switch_channel_get_name(switch_core_session_get_channel(session)));
 
-	snprintf(buf, sizeof(buf), 
-			 "v=0\n"
-			 "o=FreeSWITCH %d%"APR_TIME_T_FMT" %d%"APR_TIME_T_FMT" IN IP4 %s\n"
-			 "s=FreeSWITCH\n"
-			 "c=IN IP4 %s\n"
-			 "t=0 0\n"
-			 "a=%s\n"
-			 "m=audio %d RTP/AVP",
-			 port,
-			 now,
-			 port,
-			 now,
-			 ip,
-			 ip,
-			 sr,
-			 port
-			 );
-
-	if (tech_pvt->rm_encoding) {
-		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
-	} else if (tech_pvt->num_codecs) {
-		int i;
-		for (i = 0; i < tech_pvt->num_codecs; i++) {
-			const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
-
-			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
-            if (!ptime) {
-                ptime = imp->microseconds_per_frame / 1000;
-            }
-		}
-	}
-
-	if (tech_pvt->te > 95) {
-		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->te);
-	}
-
-	snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
-
-	if (tech_pvt->rm_encoding) {
-		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->pt, tech_pvt->rm_encoding, tech_pvt->rm_rate);
-		if (tech_pvt->fmtp_out) {
-			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->pt, tech_pvt->fmtp_out);
-		}
-		if (tech_pvt->read_codec.implementation && ! ptime) {
-            ptime = tech_pvt->read_codec.implementation->microseconds_per_frame / 1000;
-		}
-
-	} else if (tech_pvt->num_codecs) {
-		int i;
-		for (i = 0; i < tech_pvt->num_codecs; i++) {
-			const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
-            if (ptime && ptime != imp->microseconds_per_frame / 1000) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "ptime %u != advertised ptime %u\n", imp->microseconds_per_frame / 1000, ptime);
-            }
-			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, imp->samples_per_second);
-			if (imp->fmtp) {
-				snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
-			}
-		}
-	}
-	
-	if (tech_pvt->te > 95) {
-		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te);
-	}
-
-    if (ptime) {
-        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
-    }
-
-	tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf);
+	return SWITCH_STATUS_SUCCESS;
 }
 
-static void tech_set_codecs(private_object_t *tech_pvt)
-{
-    switch_channel_t *channel;
-    char *abs, *codec_string = NULL;
-    char *csdyn = NULL;
-    char *ocodec = NULL;
 
-	if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-		return;
-	}
-
-	if (tech_pvt->num_codecs) {
-		return;
-	}
-
-    assert(tech_pvt->session != NULL);
-
-    channel = switch_core_session_get_channel(tech_pvt->session);
-    assert (channel != NULL);
-
-
-    if ((abs = switch_channel_get_variable(channel, "absolute_codec_string"))) {
-        codec_string = abs;
-    } else {
-        if (!(codec_string = switch_channel_get_variable(channel, "codec_string"))) {
-			if (tech_pvt->profile->codec_string) {
-				codec_string = tech_pvt->profile->codec_string;
-			}
-        }
-        
-        if ((ocodec = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
-            if (!codec_string || (tech_pvt->profile->pflags & PFLAG_DISABLE_TRANSCODING)) {
-                codec_string = ocodec;
-            } else {
-                if ((csdyn = switch_mprintf("%s,%s", ocodec, codec_string))) {
-                    codec_string = csdyn;
-                } else {
-                    codec_string = ocodec;
-                }
-            }
-        }
-    }
-
-	if (codec_string) {
-		char *tmp_codec_string;
-		if ((tmp_codec_string = strdup(codec_string))) {
-			tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS);
-			tech_pvt->num_codecs = switch_loadable_module_get_codecs_sorted(tech_pvt->codecs,
-																			SWITCH_MAX_CODECS,
-																			tech_pvt->codec_order,
-																			tech_pvt->codec_order_last);
-			free(tmp_codec_string);
-		}
-	} else {
-		tech_pvt->num_codecs = switch_loadable_module_get_codecs(switch_core_session_get_pool(tech_pvt->session), tech_pvt->codecs,
-																 sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0]));
-	}
-
-    switch_safe_free(csdyn);
-}
-
-
-static void attach_private(switch_core_session_t *session,
-						   sofia_profile_t *profile,
-						   private_object_t *tech_pvt,
-						   const char *channame)
+static switch_status_t sofia_on_hibernate(switch_core_session_t *session)
 {
-	switch_channel_t *channel;
-	char name[256];
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
 
-	assert(session != NULL);
-	assert(profile != NULL);
-	assert(tech_pvt != NULL);
-
-	switch_core_session_add_stream(session, NULL);
-	channel = switch_core_session_get_channel(session);
-	
-	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
-	switch_mutex_lock(tech_pvt->flag_mutex);
-	tech_pvt->flags = profile->flags;
-	switch_mutex_unlock(tech_pvt->flag_mutex);
-	tech_pvt->profile = profile;
-	if (tech_pvt->bte) {
-		tech_pvt->te = tech_pvt->bte;
-	} else {
-		tech_pvt->te = profile->te;
+	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
 	}
-	tech_pvt->session = session;
-	tech_pvt->home = su_home_new(sizeof(*tech_pvt->home));
 
-	switch_core_session_set_private(session, tech_pvt);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA HIBERNATE\n", switch_channel_get_name(switch_core_session_get_channel(session)));
 
-
-	snprintf(name, sizeof(name), "sofia/%s/%s", profile->name, channame);
-    switch_channel_set_name(channel, name);
-	//tech_set_codecs(tech_pvt);
-
+	return SWITCH_STATUS_SUCCESS;
 }
 
-static void terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line)
+static switch_status_t sofia_on_execute(switch_core_session_t *session)
 {
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Term called from line: %d\n", line);
-	if (*session) {
-		switch_channel_t *channel = switch_core_session_get_channel(*session);
-		switch_channel_state_t state = switch_channel_get_state(channel);
-		struct private_object *tech_pvt = NULL;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
 
-		tech_pvt = switch_core_session_get_private(*session);
-
-		if (tech_pvt) {
-			if (state < CS_HANGUP) {
-				switch_channel_hangup(channel, cause);
-			}
-			
-			if (!switch_test_flag(tech_pvt, TFLAG_READY)) {
-				if (state > CS_INIT && state < CS_HANGUP) {
-					sofia_on_hangup(*session);
-				}
-				switch_core_session_destroy(session);
-			} 
-		} else {
-			switch_core_session_destroy(session);
-		}
+	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
 	}
-}
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA EXECUTE\n", switch_channel_get_name(switch_core_session_get_channel(session)));
 
-
-static switch_status_t tech_choose_port(private_object_t *tech_pvt)
-{
-	char *ip = tech_pvt->profile->rtpip;
-	switch_channel_t *channel;
-	switch_port_t sdp_port;
-	char *err;
-	char tmp[50];
-
-	channel = switch_core_session_get_channel(tech_pvt->session);
-	
-	if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA) || tech_pvt->adv_sdp_audio_port) {
-		return SWITCH_STATUS_SUCCESS;
-	}
-	
-	tech_pvt->local_sdp_audio_ip = ip;
-	tech_pvt->local_sdp_audio_port = switch_rtp_request_port();
-	sdp_port = tech_pvt->local_sdp_audio_port;
-
-
-	if (tech_pvt->profile->extrtpip) {
-		if (!strncasecmp(tech_pvt->profile->extrtpip, "stun:", 5)) {
-			char *stun_ip = tech_pvt->profile->extrtpip + 5;
-			if (!stun_ip) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! NO STUN SERVER\n");
-				terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-				return SWITCH_STATUS_FALSE;
-			}
-			if (switch_stun_lookup(&ip,
-								   &sdp_port,
-								   stun_ip,
-								   SWITCH_STUN_DEFAULT_PORT,
-								   &err,
-								   switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! %s:%d [%s]\n", stun_ip, SWITCH_STUN_DEFAULT_PORT, err);
-				terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-				return SWITCH_STATUS_FALSE;
-			}
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stun Success [%s]:[%d]\n", ip, sdp_port);
-		} else {
-			ip = tech_pvt->profile->extrtpip;
-		}
-	}
-
-	tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip);
-	tech_pvt->adv_sdp_audio_port = sdp_port;
-
-	snprintf(tmp, sizeof(tmp), "%d", sdp_port);
-	switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
-	switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
-	
-
 	return SWITCH_STATUS_SUCCESS;
 }
 
-static switch_status_t do_invite(switch_core_session_t *session)
+char * generate_pai_str(switch_core_session_t *session) 
 {
-	char rpid[1024] = { 0 };
-	char alert_info[1024] = { 0 };
-	char max_forwards[8] = { 0 };
-	char *alertbuf;
-	char *forwardbuf;
-	int forwardval;
-	private_object_t *tech_pvt;
-    switch_channel_t *channel = NULL;
-	switch_caller_profile_t *caller_profile;
-	char *cid_name, *cid_num;
-	char *e_dest = NULL;
-	const char *holdstr = "";
-	switch_stream_handle_t stream = {0};
-	switch_hash_index_t *hi;
-	void *vval;
-	char *extra_headers = NULL;
-	const void *vvar;
-	switch_status_t status = SWITCH_STATUS_FALSE;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	const char *callee_name = NULL, *callee_number = NULL;
+	char *pai = NULL;
 
-    channel = switch_core_session_get_channel(session);
-    assert(channel != NULL);
-
-    tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-    assert(tech_pvt != NULL);
-
-	caller_profile = switch_channel_get_caller_profile(channel);
-
-	cid_name = (char *) caller_profile->caller_id_name;
-	cid_num = (char *) caller_profile->caller_id_number;
-    tech_set_codecs(tech_pvt);
-
-	if ((tech_pvt->from_str = switch_mprintf("\"%s\" <sip:%s@%s>", 
-													 cid_name,
-													 cid_num,
-													 tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip
-													 ))) {
-
-		char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
-
-		if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) {
-			snprintf(alert_info, sizeof(alert_info) - 1, "Alert-Info: %s", alertbuf);
+	if ((callee_name = switch_channel_get_variable(tech_pvt->channel, "sip_callee_id_name"))) {
+		if (!(callee_number = switch_channel_get_variable(tech_pvt->channel, "sip_callee_id_number"))) {
+			callee_number = tech_pvt->caller_profile->destination_number;
 		}
-
-		if ((forwardbuf = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE))) {
-			forwardval = atoi(forwardbuf) - 1;
-			snprintf(max_forwards, sizeof(max_forwards) - 1, "%d", forwardval);
-		}
-
-		if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
-            return status;
-        }
-        
-		set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
-
-		switch_set_flag_locked(tech_pvt, TFLAG_READY);
-
-		// forge a RPID for now KHR  -- Should wrap this in an if statement so it can be turned on and off
-		if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
-			const char *priv = "off";
-			const char *screen = "no";
-			if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) {
-				priv = "name";
-				if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
-					priv = "yes";
-				}
-			} else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
-				priv = "yes";
-			}
-			if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
-				screen = "yes";
-			}
-
-			snprintf(rpid, sizeof(rpid) - 1, "Remote-Party-ID: %s;party=calling;screen=%s;privacy=%s", tech_pvt->from_str, screen, priv);
-								
-		}
-
-		if (!tech_pvt->nh) {
-			char *url =  get_url_from_contact(tech_pvt->dest, 1);
-			tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
-									  NUTAG_URL(url),
-									  SIPTAG_TO_STR(tech_pvt->dest_to),
-									  SIPTAG_FROM_STR(tech_pvt->from_str),
-									  SIPTAG_CONTACT_STR(tech_pvt->profile->url),
-									  TAG_END());
-			switch_safe_free(url);
-
-            if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) {
-                abort();
-            }
-            memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private));
-			switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
-			nua_handle_bind(tech_pvt->nh, tech_pvt->sofia_private);
-
-		}
-
-
-		if (tech_pvt->e_dest && (e_dest = strdup(tech_pvt->e_dest))) {
-			char *user = e_dest, *host = NULL;
-			char hash_key[256] = "";
-
-			if ((host = strchr(user, '@'))) {
-				*host++ = '\0';
-			}
-			snprintf(hash_key, sizeof(hash_key), "%s%s%s", user, host, cid_num);
-
-			tech_pvt->chat_from = tech_pvt->from_str;
-			tech_pvt->chat_to = tech_pvt->dest;
-			tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
-			switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
-			free(e_dest);			
-		}
-
-		holdstr = switch_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? "*" : "";
-
-
-		SWITCH_STANDARD_STREAM(stream);
-		for (hi = switch_channel_variable_first(channel, switch_core_session_get_pool(tech_pvt->session)); hi; hi = switch_hash_next(hi)) {
-            switch_hash_this(hi, &vvar, NULL, &vval);
-            if (vvar && vval) {
-				const char *name = vvar;
-				char *value = (char *) vval;
-
-				if (!strncasecmp(name, SOFIA_SIP_HEADER_PREFIX, strlen(SOFIA_SIP_HEADER_PREFIX))) {
-					const char *hname = name + strlen(SOFIA_SIP_HEADER_PREFIX);
-					stream.write_function(&stream, "%s: %s\r\n", hname, value);
-				}
-			}
-		}
-		
-		if (stream.data) {
-			extra_headers = stream.data;
-		}
-
-		nua_invite(tech_pvt->nh,
-				   TAG_IF(!switch_strlen_zero(rpid), SIPTAG_HEADER_STR(rpid)),
-				   TAG_IF(!switch_strlen_zero(alert_info), SIPTAG_HEADER_STR(alert_info)),
-				   TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
-				   TAG_IF(!switch_strlen_zero(max_forwards),SIPTAG_MAX_FORWARDS_STR(max_forwards)),
-				   //SIPTAG_CONTACT_STR(tech_pvt->profile->url),
-				   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-				   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
-				   SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
-				   TAG_IF(rep, SIPTAG_REPLACES_STR(rep)),
-				   SOATAG_HOLD(holdstr),
-				   TAG_END());
-		
-		switch_safe_free(stream.data);
-		status = SWITCH_STATUS_SUCCESS;
-	} else {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+		pai = switch_core_session_sprintf(tech_pvt->session, "P-Asserted-Identity: \"%s\" <%s>", callee_name, callee_number);
 	}
-
-	return status;
-	
+	return pai;
 }
 
-
-
-static void do_xfer_invite(switch_core_session_t *session)
+/* map QSIG cause codes to SIP from RFC4497 section 8.4.1 */
+static int hangup_cause_to_sip(switch_call_cause_t cause)
 {
-	char rpid[1024];
-	private_object_t *tech_pvt;
-    switch_channel_t *channel = NULL;
-	switch_caller_profile_t *caller_profile;
-
-    channel = switch_core_session_get_channel(session);
-    assert(channel != NULL);
-
-    tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-    assert(tech_pvt != NULL);
-
-	caller_profile = switch_channel_get_caller_profile(channel);
-
-	
-
-	if ((tech_pvt->from_str = switch_mprintf("\"%s\" <sip:%s@%s>", 
-													 (char *) caller_profile->caller_id_name, 
-													 (char *) caller_profile->caller_id_number,
-													 tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip
-													 ))) {
-
-		char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
-
-		tech_pvt->nh2 = nua_handle(tech_pvt->profile->nua, NULL,
-								  SIPTAG_TO_STR(tech_pvt->dest),
-								  SIPTAG_FROM_STR(tech_pvt->from_str),
-								  SIPTAG_CONTACT_STR(tech_pvt->profile->url),
-								  TAG_END());
-			
-        
-		nua_handle_bind(tech_pvt->nh2, tech_pvt->sofia_private);
-
-		nua_invite(tech_pvt->nh2,
-				   TAG_IF(rpid, SIPTAG_HEADER_STR(rpid)),
-				   SIPTAG_CONTACT_STR(tech_pvt->profile->url),
-				   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-				   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
-				   SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
-				   TAG_IF(rep, SIPTAG_REPLACES_STR(rep)),
-				   TAG_END());
-	} else {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
-	}
-	
-}
-
-static void tech_absorb_sdp(private_object_t *tech_pvt)
-{
-	switch_channel_t *channel;
-	char *sdp_str;
-
-	channel = switch_core_session_get_channel(tech_pvt->session);
-	assert(channel != NULL);
-	
-	if ((sdp_str = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
-		sdp_parser_t *parser;
-		sdp_session_t *sdp;
-		sdp_media_t *m;
-		sdp_connection_t *connection;
-
-		if ((parser = sdp_parse(tech_pvt->home, sdp_str, (int)strlen(sdp_str), 0))) {
-			if ((sdp = sdp_session(parser))) {
-				for (m = sdp->sdp_media; m ; m = m->m_next) {
-					if (m->m_type != sdp_media_audio) {
-						continue;
-					}
-
-					connection = sdp->sdp_connection;
-					if (m->m_connections) {
-						connection = m->m_connections;
-					}
-
-					if (connection) {
-						tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address);
-					}
-					tech_pvt->proxy_sdp_audio_port = (switch_port_t)m->m_port;
-					if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) {
-						break;
-					}
-				}
-			}
-			sdp_parser_free(parser);
-		}	
-		tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, sdp_str);
-	}
-}
-
-/* 
-   State methods they get called when the state changes to the specific state 
-   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
-   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
-*/
-static switch_status_t sofia_on_init(switch_core_session_t *session)
-{
-	private_object_t *tech_pvt;
-	switch_channel_t *channel = NULL;
-	
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
-
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
-
-	tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
-
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA INIT\n");
-	if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
-		switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-		tech_absorb_sdp(tech_pvt);
-	}
-
-	if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
-		if (do_invite(session) != SWITCH_STATUS_SUCCESS) {
-			return SWITCH_STATUS_FALSE;
-		}
-	}
-	
-	/* Move Channel's State Machine to RING */
-	switch_channel_set_state(channel, CS_RING);
-	return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t sofia_on_ring(switch_core_session_t *session)
-{
-	switch_channel_t *channel = NULL;
-	private_object_t *tech_pvt = NULL;
-
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
-
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
-
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA RING\n");
-
-	return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t sofia_on_execute(switch_core_session_t *session)
-{
-	switch_channel_t *channel = NULL;
-	private_object_t *tech_pvt = NULL;
-
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
-
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
-
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA EXECUTE\n");
-
-	return SWITCH_STATUS_SUCCESS;
-}
-
-// map QSIG cause codes to SIP from RFC4497 section 8.4.1
-static int hangup_cause_to_sip(switch_call_cause_t cause) {
 	switch (cause) {
+	case SWITCH_CAUSE_UNALLOCATED_NUMBER:
 	case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
 	case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
 		return 404;
@@ -1292,7 +203,6 @@
 	case SWITCH_CAUSE_NO_USER_RESPONSE:
 		return 408;
 	case SWITCH_CAUSE_NO_ANSWER:
-		return 480;
 	case SWITCH_CAUSE_SUBSCRIBER_ABSENT:
 		return 480;
 	case SWITCH_CAUSE_CALL_REJECTED:
@@ -1316,421 +226,378 @@
 		return 503;
 	case SWITCH_CAUSE_OUTGOING_CALL_BARRED:
 	case SWITCH_CAUSE_INCOMING_CALL_BARRED:
-	case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH: 
+	case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH:
 		return 403;
 	case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL:
 		return 503;
 	case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL:
+	case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
 		return 488;
 	case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
 	case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED:
 		return 501;
-	case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
-		return 503;
 	case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
 		return 504;
 	case SWITCH_CAUSE_ORIGINATOR_CANCEL:
 		return 487;
+	case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR:
+		return 483;
 	default:
 		return 480;
 	}
+}
 
+switch_status_t sofia_on_destroy(switch_core_session_t *session)
+{
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SOFIA DESTROY\n", switch_channel_get_name(channel));
+
+	if (tech_pvt) {
+		if (switch_core_codec_ready(&tech_pvt->read_codec)) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+		
+		if (switch_core_codec_ready(&tech_pvt->write_codec)) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+
+		switch_core_session_unset_read_codec(session);
+		switch_core_session_unset_write_codec(session);
+
+		switch_mutex_lock(tech_pvt->profile->flag_mutex);
+		tech_pvt->profile->inuse--;
+		switch_mutex_unlock(tech_pvt->profile->flag_mutex);
+
+		sofia_glue_deactivate_rtp(tech_pvt);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+
 }
 
-static switch_status_t sofia_on_hangup(switch_core_session_t *session)
+switch_status_t sofia_on_hangup(switch_core_session_t *session)
 {
 	switch_core_session_t *a_session;
-	private_object_t *tech_pvt;
-	switch_channel_t *channel = NULL;
-	switch_call_cause_t cause;
-	int sip_cause;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	switch_call_cause_t cause = switch_channel_get_cause(channel);
+	int sip_cause = hangup_cause_to_sip(cause);
+	const char *ps_cause = NULL, *use_my_cause;
 
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
+	switch_mutex_lock(tech_pvt->sofia_mutex);
 
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
+	if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+			tech_pvt->profile->ob_failed_calls++;
+		} else {
+			tech_pvt->profile->ib_failed_calls++;
+		}
+	}
 
-	cause = switch_channel_get_cause(channel);
-	sip_cause = hangup_cause_to_sip(cause);
+	if (!((use_my_cause = switch_channel_get_variable(channel, "sip_ignore_remote_cause")) && switch_true(use_my_cause))) {
+		ps_cause = switch_channel_get_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE);
+	}
 
-	deactivate_rtp(tech_pvt);
+	if (!switch_strlen_zero(ps_cause) && (!strncasecmp(ps_cause, "sip:", 4) || !strncasecmp(ps_cause, "sips:", 5))) {
+		int new_cause = atoi(sofia_glue_strip_proto(ps_cause));
+		if (new_cause) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Overriding SIP cause %d with %d from the other leg\n",
+							  switch_channel_get_name(channel), sip_cause, new_cause);
+			sip_cause = new_cause;
+		}
+	}
 
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s\n", 
+	if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD) && cause != SWITCH_CAUSE_ATTENDED_TRANSFER) {
+		const char *buuid;
+		switch_core_session_t *bsession;
+		switch_channel_t *bchannel;
+		const char *lost_ext;
+
+		if (tech_pvt->max_missed_packets) {
+			switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
+		}
+		switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL);
+
+		if ((buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
+			if ((bsession = switch_core_session_locate(buuid))) {
+				bchannel = switch_core_session_get_channel(bsession);
+				if (switch_channel_test_flag(bchannel, CF_BROADCAST)) {
+					if ((lost_ext = switch_channel_get_variable(bchannel, "left_hanging_extension"))) {
+						switch_ivr_session_transfer(bsession, lost_ext, NULL, NULL);
+					}
+					switch_channel_stop_broadcast(bchannel);
+				}
+				switch_core_session_rwunlock(bsession);
+			}
+		}
+		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s\n",
 					  switch_channel_get_name(channel), switch_channel_cause2str(cause));
 
 	if (tech_pvt->hash_key) {
 		switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key);
 	}
 
+	if (session && tech_pvt->profile->pres_type) {
+		char *sql = switch_mprintf("delete from sip_dialogs where call_id='%q'", tech_pvt->call_id);
+		switch_assert(sql);
+		sofia_glue_execute_sql(tech_pvt->profile, &sql, SWITCH_TRUE);
+	}
+
 	if (tech_pvt->kick && (a_session = switch_core_session_locate(tech_pvt->kick))) {
 		switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
 		switch_channel_hangup(a_channel, switch_channel_get_cause(channel));
 		switch_core_session_rwunlock(a_session);
 	}
 
-	if (tech_pvt->nh) {
-		if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
-			if (switch_test_flag(tech_pvt, TFLAG_ANS)) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel));
-				nua_bye(tech_pvt->nh, TAG_END());
+	if (tech_pvt->nh && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		char reason[128] = "";
+		switch_stream_handle_t stream = { 0 };
+		switch_event_header_t *hi;
+		char *bye_headers = NULL;
+
+		SWITCH_STANDARD_STREAM(stream);
+		if ((hi = switch_channel_variable_first(channel))) {
+			for (; hi; hi = hi->next) {
+				const char *name = (char *) hi->name;
+				char *value = (char *) hi->value;
+				
+				if (!strncasecmp(name, SOFIA_SIP_BYE_HEADER_PREFIX, strlen(SOFIA_SIP_BYE_HEADER_PREFIX))) {
+					const char *hname = name + strlen(SOFIA_SIP_BYE_HEADER_PREFIX);
+					stream.write_function(&stream, "%s: %s\r\n", hname, value);
+				}
+			}
+			switch_channel_variable_last(channel);
+		}
+
+		if (stream.data) {
+			bye_headers = stream.data;
+		}
+		
+		if (cause > 0 && cause < 128) {
+			switch_snprintf(reason, sizeof(reason), "Q.850;cause=%d;text=\"%s\"", cause, switch_channel_cause2str(cause));
+		} else if (cause == SWITCH_CAUSE_PICKED_OFF || cause == SWITCH_CAUSE_LOSE_RACE) {
+			switch_snprintf(reason, sizeof(reason), "SIP;cause=200;text=\"Call completed elsewhere\"");
+		} else {
+			switch_snprintf(reason, sizeof(reason), "%s;cause=%d;text=\"%s\"",
+					tech_pvt->profile->username, 
+					cause,
+					switch_channel_cause2str(cause));
+		}
+
+		if (switch_channel_test_flag(channel, CF_ANSWERED)) {
+			if (!tech_pvt->got_bye) {
+				switch_channel_set_variable(channel, "sip_hangup_disposition", "send_bye");
+			}
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel));
+			if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+				nua_bye(tech_pvt->nh, 
+						SIPTAG_REASON_STR(reason),
+						TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
+						TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)),
+						TAG_END());
+			}
+		} else {
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel));
+				if (!tech_pvt->got_bye) {
+					switch_channel_set_variable(channel, "sip_hangup_disposition", "send_cancel");
+				}
+				if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+					nua_cancel(tech_pvt->nh, 
+							   SIPTAG_REASON_STR(reason), 
+							   TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)),
+							   TAG_END());
+				}
 			} else {
-				if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause);
-					nua_respond(tech_pvt->nh, sip_cause, NULL, TAG_END());
-				} else {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel));
-					nua_cancel(tech_pvt->nh, TAG_END());
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause);
+				if (!tech_pvt->got_bye) {
+					switch_channel_set_variable(channel, "sip_hangup_disposition", "send_refuse");
 				}
+				if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+					nua_respond(tech_pvt->nh, sip_cause, sip_status_phrase(sip_cause), 
+								SIPTAG_REASON_STR(reason), 
+								TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)),
+								TAG_END());
+				}
 			}
-			switch_set_flag_locked(tech_pvt, TFLAG_BYE);
 		}
-	}
 
-	if (tech_pvt->from_str) {
-		switch_safe_free(tech_pvt->from_str);
+		sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+		switch_safe_free(stream.data);
 	}
 
-	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+	sofia_clear_flag(tech_pvt, TFLAG_IO);
 
-	if (tech_pvt->home) {
-		su_home_unref(tech_pvt->home);
-		tech_pvt->home = NULL;
+	if (tech_pvt->sofia_private) {
+		*tech_pvt->sofia_private->uuid = '\0';
 	}
+	
 
-    if (tech_pvt->sofia_private) {
-        *tech_pvt->sofia_private->uuid = '\0';
-    }
+	sofia_glue_set_rtp_stats(tech_pvt);
 
+	switch_mutex_unlock(tech_pvt->sofia_mutex);
+
 	return SWITCH_STATUS_SUCCESS;
 }
 
-static switch_status_t sofia_on_loopback(switch_core_session_t *session)
+static switch_status_t sofia_on_exchange_media(switch_core_session_t *session)
 {
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA LOOPBACK\n");
 	return SWITCH_STATUS_SUCCESS;
 }
 
-static switch_status_t sofia_on_transmit(switch_core_session_t *session)
+static switch_status_t sofia_on_soft_execute(switch_core_session_t *session)
 {
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA TRANSMIT\n");
 	return SWITCH_STATUS_SUCCESS;
 }
 
-static void deactivate_rtp(private_object_t *tech_pvt)
+static switch_status_t sofia_answer_channel(switch_core_session_t *session)
 {
-	int loops = 0;//, sock = -1;
-	if (switch_rtp_ready(tech_pvt->rtp_session)) {
-		while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
-			switch_yield(10000);
-			loops++;
-		}
-		switch_rtp_destroy(&tech_pvt->rtp_session);
-	}
-}
-
-static switch_status_t tech_set_codec(private_object_t *tech_pvt, int force)
-{
-	switch_channel_t *channel;
-
-	if (tech_pvt->read_codec.implementation) {
-		if (!force) {
-			return SWITCH_STATUS_SUCCESS;
-		}
-		if (strcasecmp(tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding) ||
-			tech_pvt->read_codec.implementation->samples_per_second != tech_pvt->rm_rate) {
-
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n",
-							  tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding);
-		switch_core_codec_destroy(&tech_pvt->read_codec);
-		switch_core_codec_destroy(&tech_pvt->write_codec);
-		switch_core_session_reset(tech_pvt->session);
-		} else {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already using %s\n",
-							  tech_pvt->read_codec.implementation->iananame);
-			return SWITCH_STATUS_SUCCESS;
-		}
-	}
-
-	channel = switch_core_session_get_channel(tech_pvt->session);
-	assert(channel != NULL);
-
-	if (!tech_pvt->rm_encoding) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec with no name?\n");
-		terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-		return SWITCH_STATUS_FALSE;
-	}
-
-	if (switch_core_codec_init(&tech_pvt->read_codec,  
-							   tech_pvt->rm_encoding,
-							   tech_pvt->rm_fmtp,
-							   tech_pvt->rm_rate,
-							   tech_pvt->codec_ms,
-							   1,
-							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
-							   NULL,
-							   switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
-		terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-		return SWITCH_STATUS_FALSE;
-	} else {
-		if (switch_core_codec_init(&tech_pvt->write_codec,
-								   tech_pvt->rm_encoding,
-								   tech_pvt->rm_fmtp,
-								   tech_pvt->rm_rate,
-								   tech_pvt->codec_ms,
-								   1,
-								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
-								   NULL,
-								   switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
-			terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-			return SWITCH_STATUS_FALSE;
-		} else {
-			int ms;
-			tech_pvt->read_frame.rate = tech_pvt->rm_rate;
-			ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set Codec %s %s/%d %d ms\n",
-							  switch_channel_get_name(channel),
-							  tech_pvt->rm_encoding, tech_pvt->rm_rate, tech_pvt->codec_ms);
-			tech_pvt->read_frame.codec = &tech_pvt->read_codec;
-				
-			switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
-			switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
-			tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out);
-		}
-	}
-	return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t activate_rtp(private_object_t *tech_pvt)
-{
-	int bw, ms;
-	switch_channel_t *channel;
-	const char *err = NULL;
-    char *val = NULL;
-	switch_rtp_flag_t flags;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
 	switch_status_t status;
-	char tmp[50];
-	assert(tech_pvt != NULL);
+	uint32_t session_timeout = tech_pvt->profile->session_timeout;
+	const char *val;
+	const char *b_sdp = NULL;
+	int is_proxy = 0;
+	char *sticky = NULL;
 
-	channel = switch_core_session_get_channel(tech_pvt->session);
-	assert(channel != NULL);
-
-	if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+	if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_test_flag(channel, CF_OUTBOUND)) {
 		return SWITCH_STATUS_SUCCESS;
 	}
 
-	if (switch_rtp_ready(tech_pvt->rtp_session) && !switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
-		return SWITCH_STATUS_SUCCESS;
-	}
 
-	if ((status = tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
-		return status;
-	}
-	
-	bw = tech_pvt->read_codec.implementation->bits_per_second;
-	ms = tech_pvt->read_codec.implementation->microseconds_per_frame;
+	b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE);
+	is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA));
 
-	flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+	if (b_sdp && is_proxy) {
+		sofia_glue_tech_set_local_sdp(tech_pvt, b_sdp, SWITCH_TRUE);
 
-	if (switch_test_flag(tech_pvt, TFLAG_BUGGY_2833)) {
-		flags |= SWITCH_RTP_FLAG_BUGGY_2833;
-	}
-
-    if ((tech_pvt->profile->pflags & PFLAG_PASS_RFC2833) || ((val = switch_channel_get_variable(channel, "pass_rfc2833")) && switch_true(val))) {
-        flags |= SWITCH_RTP_FLAG_PASS_RFC2833;
-    }
-
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
-					  switch_channel_get_name(channel),
-					  tech_pvt->local_sdp_audio_ip,
-					  tech_pvt->local_sdp_audio_port,
-					  tech_pvt->remote_sdp_audio_ip,
-					  tech_pvt->remote_sdp_audio_port,
-					  tech_pvt->agreed_pt,
-					  tech_pvt->read_codec.implementation->microseconds_per_frame / 1000);
-
-	snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
-	switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
-	switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
-	
-	if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
-		switch_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
-		
-		if (switch_rtp_set_remote_address(tech_pvt->rtp_session,
-										  tech_pvt->remote_sdp_audio_ip,
-										  tech_pvt->remote_sdp_audio_port,
-										  &err) != SWITCH_STATUS_SUCCESS) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
-		} else {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP CHANGING DEST TO: [%s:%d]\n", 
-							  tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
-            /* Reactivate the NAT buster flag. */
-            switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+		if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+			sofia_glue_tech_patch_sdp(tech_pvt);
+			if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+				return SWITCH_STATUS_FALSE;
+			}
 		}
-		return SWITCH_STATUS_SUCCESS;
-	}
+	} else {
+		/* This if statement check and handles the 3pcc proxy mode */
+		if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)) {
+			/* Send the 200 OK */
+			if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+				nua_respond(tech_pvt->nh, SIP_200_OK,
+							SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+							SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+							SOATAG_REUSE_REJECTED(1),
+							SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
 
-	tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
-										   tech_pvt->local_sdp_audio_port,
-										   tech_pvt->remote_sdp_audio_ip,
-										   tech_pvt->remote_sdp_audio_port,
-										   tech_pvt->agreed_pt,
-										   tech_pvt->read_codec.implementation->encoded_bytes_per_frame,
-										   tech_pvt->codec_ms * 1000,
-										   (switch_rtp_flag_t) flags,
-										   NULL,
-										   tech_pvt->profile->timer_name,
-										   &err,
-										   switch_core_session_get_pool(tech_pvt->session));
-	
-	if (switch_rtp_ready(tech_pvt->rtp_session)) {
-		uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
-		uint8_t vad_out = switch_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
-		uint8_t inb = switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1;
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "3PCC-PROXY, Sent a 200 OK, waiting for ACK\n");
+			}
 
-		tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
-		switch_set_flag_locked(tech_pvt, TFLAG_RTP);
-		switch_set_flag_locked(tech_pvt, TFLAG_IO);
-		
-		if ((vad_in && inb) || (vad_out && !inb)) {
-			switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING);
-			switch_set_flag_locked(tech_pvt, TFLAG_VAD);
-            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP Engage VAD for %s ( %s %s )\n", 
-                              switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)),
-                              vad_in ? "in" : "", vad_out ? "out" : "");
+			/* Unlock the session signal to allow the ack to make it in */
+			// Maybe we should timeout?
+			switch_mutex_unlock(tech_pvt->sofia_mutex);
+			
+			while(switch_channel_ready(channel) && !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) {
+				switch_cond_next();
+			}
+			
+			/*  Regain lock on sofia */
+			switch_mutex_lock(tech_pvt->sofia_mutex);
+			
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for ACK\n");
 		}
-	} else {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
-		terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-		switch_clear_flag_locked(tech_pvt, TFLAG_IO);
-		return SWITCH_STATUS_FALSE;
-	}
-		
-	switch_set_flag_locked(tech_pvt, TFLAG_IO);
-	return SWITCH_STATUS_SUCCESS;
-}
 
-static switch_status_t tech_media(private_object_t *tech_pvt, char *r_sdp)
-{
-    sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-    sdp_session_t *sdp;
-    uint8_t match = 0;
-    switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session);
+		if ((is_proxy && !b_sdp) || sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || !tech_pvt->iananame) {
+			sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
 
-    assert(tech_pvt != NULL);
+			if (is_proxy) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disabling proxy mode due to call answer with no bridge\n");
+				switch_channel_clear_flag(channel, CF_PROXY_MEDIA);
+				switch_channel_clear_flag(channel, CF_PROXY_MODE);
+			}
 
-    if (switch_strlen_zero(r_sdp)) {
-        return SWITCH_STATUS_FALSE;
-    }
+			if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
+				const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
+				tech_pvt->num_codecs = 0;
+				sofia_glue_tech_prepare_codecs(tech_pvt);
 
-    if (tech_pvt->num_codecs) {
-        if ((sdp = sdp_session(parser))) {
-            match = negotiate_sdp(tech_pvt->session, sdp);
-        }
-    }
-
-    if (parser) {
-        sdp_parser_free(parser);
-    }
-
-    if (match) {
-        if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
-            return SWITCH_STATUS_FALSE;
-        }
-        activate_rtp(tech_pvt);
-        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA");
-        switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
-        switch_channel_mark_pre_answered(channel);
-        return SWITCH_STATUS_SUCCESS;
-    }
-    
-    return SWITCH_STATUS_FALSE;
-}
-
-
-
-static switch_status_t sofia_answer_channel(switch_core_session_t *session)
-{
-	private_object_t *tech_pvt;
-	switch_channel_t *channel = NULL;
-	switch_status_t status;
-
-	assert(session != NULL);
-
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
-
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
-    
-	if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) {
-		switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-
-		if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
-			char *sdp = NULL;
-			switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-			if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
-				tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
-			}
-		} else {
-			if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
-				char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
-				if (tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
+				if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
 					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
-					nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+					//switch_mutex_lock(tech_pvt->sofia_mutex);
+					//nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+					//switch_mutex_unlock(tech_pvt->sofia_mutex);
 					return SWITCH_STATUS_FALSE;
 				}
-				switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
 			}
+		}
 
-			if ((status = tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
-				return status;
-			}
-
-			set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
-			activate_rtp(tech_pvt);
+		if ((status = sofia_glue_tech_choose_port(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+			return status;
+		}
 		
-			if (tech_pvt->nh) {
-				if (tech_pvt->local_sdp_str) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n",
-									  switch_channel_get_name(channel),
-								  tech_pvt->local_sdp_str);
-				}
+		sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+		if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+		}
+
+		if (tech_pvt->nh) {
+			if (tech_pvt->local_sdp_str) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", switch_channel_get_name(channel), tech_pvt->local_sdp_str);
 			}
 		}
-		nua_respond(tech_pvt->nh, SIP_200_OK, 
-					SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+	}
+
+	if ((val = switch_channel_get_variable(channel, SOFIA_SESSION_TIMEOUT))) {
+		int v_session_timeout = atoi(val);
+		if (v_session_timeout >= 0) {
+			session_timeout = v_session_timeout;
+		}
+	}
+
+	if (sofia_test_flag(tech_pvt, TFLAG_NAT) ||
+		(val = switch_channel_get_variable(channel, "sip-force-contact")) ||
+		((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val))) {
+		sticky = tech_pvt->record_route;
+		session_timeout = SOFIA_NAT_SESSION_TIMEOUT;
+		switch_channel_set_variable(channel, "sip_nat_detected", "true");
+	}
+
+	if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		nua_respond(tech_pvt->nh, SIP_200_OK,
+					NUTAG_AUTOANSWER(0),
+					TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
+					SIPTAG_HEADER_STR(generate_pai_str(session)),
+					NUTAG_SESSION_TIMER(session_timeout),
+					SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+					SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
 					SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-					SOATAG_AUDIO_AUX("cn telephone-event"),
-					NUTAG_INCLUDE_EXTRA_SDP(1),
-					TAG_END());
-	} 
+					SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
+		sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
+	}
 
 	return SWITCH_STATUS_SUCCESS;
 }
 
-
-static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout,
-										switch_io_flag_t flags, int stream_id)
+static switch_status_t sofia_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
 {
-	private_object_t *tech_pvt = NULL;
-	switch_channel_t *channel = NULL;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
 	int payload = 0;
-	
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
 
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
+	switch_assert(tech_pvt != NULL);
 
-	if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
+	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
 		return SWITCH_STATUS_FALSE;
 	}
 
-	while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+	while (!(tech_pvt->video_read_codec.implementation && switch_rtp_ready(tech_pvt->video_rtp_session))) {
 		if (switch_channel_ready(channel)) {
 			switch_yield(10000);
 		} else {
@@ -1738,107 +605,60 @@
 		}
 	}
 
+	tech_pvt->video_read_frame.datalen = 0;
 
-	tech_pvt->read_frame.datalen = 0;
-	switch_set_flag_locked(tech_pvt, TFLAG_READING);
-
-#if 0	
-	if (tech_pvt->last_read) {
-		elapsed = (unsigned int)((switch_time_now() - tech_pvt->last_read) / 1000);
-		if (elapsed > 60000) {
-			return SWITCH_STATUS_TIMEOUT;
-		}
-	}
-#endif
-
-
-	if (switch_test_flag(tech_pvt, TFLAG_IO)) {
+	if (sofia_test_flag(tech_pvt, TFLAG_IO)) {
 		switch_status_t status;
 
-		if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+		if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
 			return SWITCH_STATUS_GENERR;
 		}
 
-		assert(tech_pvt->rtp_session != NULL);
-		tech_pvt->read_frame.datalen = 0;
+		switch_assert(tech_pvt->rtp_session != NULL);
+		tech_pvt->video_read_frame.datalen = 0;
 
+		while (sofia_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->video_read_frame.datalen == 0) {
+			tech_pvt->video_read_frame.flags = SFF_NONE;
 
-		while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
-			tech_pvt->read_frame.flags = SFF_NONE;
-
-			status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame);
+			status = switch_rtp_zerocopy_read_frame(tech_pvt->video_rtp_session, &tech_pvt->video_read_frame, flags);
 			if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
-				return SWITCH_STATUS_FALSE;
-			}
-
-			
-			
-			payload = tech_pvt->read_frame.payload;
-
-#if 0
-			elapsed = (unsigned int)((switch_time_now() - started) / 1000);
-
-			if (timeout > -1) {
-				if (elapsed >= (unsigned int)timeout) {
-					return SWITCH_STATUS_BREAK;
+				if (status == SWITCH_STATUS_TIMEOUT) {
+					if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+						sofia_glue_toggle_hold(tech_pvt, 0);
+						sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+					}
+					switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_MEDIA_TIMEOUT);
 				}
+				return status;
 			}
-			
-			elapsed = (unsigned int)((switch_time_now() - last_act) / 1000);
-			if (elapsed >= hard_timeout) {
-				return SWITCH_STATUS_BREAK;
-			}
-#endif
-			if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
-				char dtmf[128];
-				switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf));
-				switch_channel_queue_dtmf(channel, dtmf);
-			}
 
+			payload = tech_pvt->video_read_frame.payload;
 
-			if (tech_pvt->read_frame.datalen > 0) {
-                size_t bytes = 0;
-                int frames = 1;
-				//tech_pvt->last_read = switch_time_now();
-                if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) {
-                    if ((bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame)) {
-                        frames = (tech_pvt->read_frame.datalen / bytes);
-                    }
-                    tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_codec.implementation->samples_per_frame);
-                }
+			if (tech_pvt->video_read_frame.datalen > 0) {
 				break;
 			}
 		}
 	}
-	
-	switch_clear_flag_locked(tech_pvt, TFLAG_READING);
 
-	if (tech_pvt->read_frame.datalen == 0) {
+	if (tech_pvt->video_read_frame.datalen == 0) {
 		*frame = NULL;
 		return SWITCH_STATUS_GENERR;
 	}
 
-	*frame = &tech_pvt->read_frame;
+	*frame = &tech_pvt->video_read_frame;
 
 	return SWITCH_STATUS_SUCCESS;
 }
 
-
-static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout,
-										 switch_io_flag_t flags, int stream_id)
+static switch_status_t sofia_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
 {
-	private_object_t *tech_pvt;
-	switch_channel_t *channel = NULL;
+	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
 	switch_status_t status = SWITCH_STATUS_SUCCESS;
-	int bytes = 0, samples = 0, frames = 0;
 
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
+	switch_assert(tech_pvt != NULL);
 
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
-
-	while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+	while (!(tech_pvt->video_read_codec.implementation && switch_rtp_ready(tech_pvt->video_rtp_session))) {
 		if (switch_channel_ready(channel)) {
 			switch_yield(10000);
 		} else {
@@ -1846,4046 +666,2723 @@
 		}
 	}
 
-	if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
+	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
 		return SWITCH_STATUS_FALSE;
 	}
 
-	if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+	if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
 		return SWITCH_STATUS_GENERR;
 	}
 
-	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+	if (!sofia_test_flag(tech_pvt, TFLAG_IO)) {
 		return SWITCH_STATUS_SUCCESS;
 	}
 
-	switch_set_flag_locked(tech_pvt, TFLAG_WRITING);
+	if (!switch_test_flag(frame, SFF_CNG)) {
+		switch_rtp_write_frame(tech_pvt->video_rtp_session, frame);
+	}
 
-
-	if (tech_pvt->read_codec.implementation->encoded_bytes_per_frame) {
-		bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
-		frames = ((int) frame->datalen / bytes);
-	} else
-		frames = 1;
-
-	samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
-
-#if 0
-	printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n",
-		   switch_channel_get_name(channel),
-		   tech_pvt->local_sdp_audio_ip,
-		   tech_pvt->remote_sdp_audio_ip,
-		   frame->datalen,
-		   samples,
-		   frames,
-		   tech_pvt->timestamp_send);
-#endif
-
-	tech_pvt->timestamp_send += samples;
-	switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send);
-
-	switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
 	return status;
 }
 
-
-
-static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig)
+static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
 {
-	private_object_t *tech_pvt;
-	switch_channel_t *channel = NULL;
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	int payload = 0;
 
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
+	switch_assert(tech_pvt != NULL);
 
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
+	if (!sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) {
+		switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING);
+		return SWITCH_STATUS_FALSE;
+	}
 
+	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
+		return SWITCH_STATUS_FALSE;
+	}
 
-    switch(sig) {
-    case SWITCH_SIG_BREAK:
-        if (switch_rtp_ready(tech_pvt->rtp_session)) {
-			switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK);
+	while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session) && !switch_channel_test_flag(channel, CF_REQ_MEDIA))) {
+		if (switch_channel_ready(channel)) {
+			switch_yield(10000);
+		} else {
+			return SWITCH_STATUS_GENERR;
 		}
-        break;
-    case SWITCH_SIG_KILL:
-    default:
-        switch_clear_flag_locked(tech_pvt, TFLAG_IO);
-        switch_set_flag_locked(tech_pvt, TFLAG_HUP);
+	}
 
-        if (switch_rtp_ready(tech_pvt->rtp_session)) {
-            switch_rtp_kill_socket(tech_pvt->rtp_session);
-        }
-        break;
-    }
+	tech_pvt->read_frame.datalen = 0;
+	sofia_set_flag_locked(tech_pvt, TFLAG_READING);
 
-	return SWITCH_STATUS_SUCCESS;
+	if (sofia_test_flag(tech_pvt, TFLAG_HUP) || sofia_test_flag(tech_pvt, TFLAG_BYE) || !tech_pvt->read_codec.implementation || 
+		!switch_core_codec_ready(&tech_pvt->read_codec)) {
+		return SWITCH_STATUS_FALSE;
+	}
 
-}
+	if (sofia_test_flag(tech_pvt, TFLAG_IO)) {
+		switch_status_t status;
 
-static switch_status_t sofia_waitfor_read(switch_core_session_t *session, int ms, int stream_id)
-{
-	private_object_t *tech_pvt;
-	switch_channel_t *channel = NULL;
+		if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
+			return SWITCH_STATUS_GENERR;
+		}
 
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
+		switch_assert(tech_pvt->rtp_session != NULL);
+		tech_pvt->read_frame.datalen = 0;
+		
+		while (sofia_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
+			tech_pvt->read_frame.flags = SFF_NONE;
 
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
+			status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags);
 
-	return SWITCH_STATUS_SUCCESS;
-}
+			if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+				if (status == SWITCH_STATUS_TIMEOUT) {
+					
+					if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+						sofia_glue_toggle_hold(tech_pvt, 0);
+						sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+					}
+					
+					switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_MEDIA_TIMEOUT);
+				}
+				return status;
+			}
 
+			/* Fast PASS! */
+			if (switch_test_flag((&tech_pvt->read_frame), SFF_PROXY_PACKET)) {
+				sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
+				*frame = &tech_pvt->read_frame;
+				return SWITCH_STATUS_SUCCESS;
+			}
 
-static switch_status_t sofia_waitfor_write(switch_core_session_t *session, int ms, int stream_id)
-{
-	private_object_t *tech_pvt;
-	switch_channel_t *channel = NULL;
+			payload = tech_pvt->read_frame.payload;
 
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
+			if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
+				switch_dtmf_t dtmf = { 0 };
+				switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf);
+				switch_channel_queue_dtmf(channel, &dtmf);
+			}
 
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
+			if (tech_pvt->read_frame.datalen > 0) {
+				size_t bytes = 0;
+				int frames = 1;
+				
+				if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) {
+					if (!tech_pvt->read_codec.implementation || !switch_core_codec_ready(&tech_pvt->read_codec)) {
+						*frame = NULL;
+						return SWITCH_STATUS_GENERR;
+					}
+					
+					if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING) && tech_pvt->check_frames++ < MAX_CODEC_CHECK_FRAMES) {
+						if (!tech_pvt->read_impl.encoded_bytes_per_packet) {
+							tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES;
+							goto skip;
+						}
 
-	return SWITCH_STATUS_SUCCESS;
+						if (tech_pvt->last_ts && tech_pvt->read_frame.datalen != tech_pvt->read_impl.encoded_bytes_per_packet) {
+							switch_size_t codec_ms = (int)(tech_pvt->read_frame.timestamp - 
+														   tech_pvt->last_ts) / (tech_pvt->read_impl.samples_per_second / 1000);
 
-}
+							if ((codec_ms % 10) != 0) {
+								tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES;
+								goto skip;
+							}
+							
+							if (tech_pvt->last_codec_ms && tech_pvt->last_codec_ms == codec_ms) {
+								tech_pvt->mismatch_count++;
+							}
 
-static switch_status_t sofia_send_dtmf(switch_core_session_t *session, char *digits)
-{
-	private_object_t *tech_pvt;
+							tech_pvt->last_codec_ms = codec_ms;
 
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-    assert(tech_pvt != NULL);
+							if (tech_pvt->mismatch_count > MAX_MISMATCH_FRAMES) {
+								if (switch_rtp_ready(tech_pvt->rtp_session) && codec_ms != tech_pvt->codec_ms) {
+									const char *val;
+									int rtp_timeout_sec = 0;
+									int rtp_hold_timeout_sec = 0;
+								
+									if (codec_ms > 120) { /* yeah right */
+										switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+														  "Your phone is trying to send timestamps that suggest an increment of %dms per packet\n"
+														  "That seems hard to believe so I am going to go on ahead and um ignore that, mmkay?", (int)codec_ms);
+										tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES;
+										goto skip;
+									}
 
-	return switch_rtp_queue_rfc2833(tech_pvt->rtp_session,
-									digits,
-									tech_pvt->profile->dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000));
-	
-}
+									tech_pvt->read_frame.datalen = 0;
+									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+													  "We were told to use ptime %d but what they meant to say was %d\n"
+													  "This issue has so far been identified to happen on the following broken platforms/devices:\n" 
+													  "Linksys/Sipura aka Cisco\n"
+													  "ShoreTel\n"
+													  "Sonus/L3\n"
+													  "We will try to fix it but some of the devices on this list are so broken who knows what will happen..\n"
+													  , 
+													  (int)tech_pvt->codec_ms, (int)codec_ms);
+									tech_pvt->codec_ms = codec_ms;
+									switch_core_session_lock_codec_write(session);
+									switch_core_session_lock_codec_read(session);
 
-static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
-{
-	switch_channel_t *channel;
-	private_object_t *tech_pvt;
-    switch_status_t status;
+									switch_core_codec_destroy(&tech_pvt->read_codec);									
+									switch_core_codec_destroy(&tech_pvt->write_codec);
+									
+									if (sofia_glue_tech_set_codec(tech_pvt, 2) != SWITCH_STATUS_SUCCESS) {
+										*frame = NULL;
+										switch_core_session_unlock_codec_write(session);
+										switch_core_session_unlock_codec_read(session);
+										return SWITCH_STATUS_GENERR;
+									}
+									
+									if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_timeout_sec"))) {
+										int v = atoi(val);
+										if (v >= 0) {
+											rtp_timeout_sec = v;
+										}
+									}
+									
+									if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_hold_timeout_sec"))) {
+										int v = atoi(val);
+										if (v >= 0) {
+											rtp_hold_timeout_sec = v;
+										}
+									}
+									
+									if (rtp_timeout_sec) {
+										tech_pvt->max_missed_packets = (tech_pvt->read_impl.samples_per_second * rtp_timeout_sec) /
+											tech_pvt->read_impl.samples_per_packet;
+										
+										switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
+										if (!rtp_hold_timeout_sec) {
+											rtp_hold_timeout_sec = rtp_timeout_sec * 10;
+										}
+									}
+									
+									if (rtp_hold_timeout_sec) {
+										tech_pvt->max_missed_hold_packets = (tech_pvt->read_impl.samples_per_second * rtp_hold_timeout_sec) /
+											tech_pvt->read_impl.samples_per_packet;
+									}
+									
+									if (switch_rtp_change_interval(tech_pvt->rtp_session, 
+																   tech_pvt->codec_ms * 1000,
+																   tech_pvt->read_impl.samples_per_packet
+																   ) != SWITCH_STATUS_SUCCESS) {
+										switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+										
+									}
 
-	channel = switch_core_session_get_channel(session);
-	assert(channel != NULL);
-			
-	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
+									tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES;
+									/* inform them of the codec they are actually sending */
+									sofia_glue_do_invite(session);
+									switch_core_session_unlock_codec_write(session);
+									switch_core_session_unlock_codec_read(session);
 
+								}
+							
+							}
+							
+						} else {
+							tech_pvt->mismatch_count = 0;
+						}
+						tech_pvt->last_ts = tech_pvt->read_frame.timestamp;
+					}
+				skip:
+					
+					if ((bytes = tech_pvt->read_impl.encoded_bytes_per_packet)) {
+						frames = (tech_pvt->read_frame.datalen / bytes);
+					}
+					tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_impl.samples_per_packet);
 
-	switch (msg->message_id) {
-	case SWITCH_MESSAGE_INDICATE_NOMEDIA: {
-		char *uuid;
-		switch_core_session_t *other_session;
-		switch_channel_t *other_channel;
-		char *ip = NULL, *port = NULL;
-
-		switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-		tech_pvt->local_sdp_str = NULL;
-		if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
-			other_channel = switch_core_session_get_channel(other_session);
-			ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
-			port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
-			switch_core_session_rwunlock(other_session);
-			if (ip && port) {
-				set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1);
+					if (tech_pvt->read_frame.datalen == 0) {
+						continue;
+					}
+				}
+				break;
 			}
 		}
-		if (!tech_pvt->local_sdp_str) {
-			tech_absorb_sdp(tech_pvt);
-		}
-		do_invite(session);
 	}
-		break;
-	case SWITCH_MESSAGE_INDICATE_MEDIA: {
-		switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-		tech_pvt->local_sdp_str = NULL;
-		if (!switch_rtp_ready(tech_pvt->rtp_session)) {
-			tech_set_codecs(tech_pvt);
-			if ((status=tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
-                return status;
-            }
-		}
-		set_local_sdp(tech_pvt, NULL, 0, NULL, 1);
-		do_invite(session);
-		while (!switch_rtp_ready(tech_pvt->rtp_session) && switch_channel_get_state(channel) < CS_HANGUP) {
-			switch_yield(1000);
-		}
-	}
-		break;
 
-	case SWITCH_MESSAGE_INDICATE_HOLD: {
-		switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-		do_invite(session);
-	}
-		break;
+	sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
 
-	case SWITCH_MESSAGE_INDICATE_UNHOLD: {
-		switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-		do_invite(session);
+	if (tech_pvt->read_frame.datalen == 0) {
+		*frame = NULL;
+		return SWITCH_STATUS_GENERR;
 	}
-		break;
-	case SWITCH_MESSAGE_INDICATE_BRIDGE:
 
-		if (switch_test_flag(tech_pvt, TFLAG_XFER)) {
-			switch_clear_flag_locked(tech_pvt, TFLAG_XFER);
-			if (msg->pointer_arg) {
-				switch_core_session_t *a_session, *b_session = msg->pointer_arg;
+	*frame = &tech_pvt->read_frame;
 
-				if ((a_session = switch_core_session_locate(tech_pvt->xferto))) {
-					private_object_t *a_tech_pvt = switch_core_session_get_private(a_session);
-					private_object_t *b_tech_pvt = switch_core_session_get_private(b_session);
-
-					switch_set_flag_locked(a_tech_pvt, TFLAG_REINVITE);
-					a_tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt->remote_sdp_audio_ip);
-					a_tech_pvt->remote_sdp_audio_port = b_tech_pvt->remote_sdp_audio_port;
-					a_tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt->local_sdp_audio_ip);
-					a_tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port;
-					activate_rtp(a_tech_pvt);
-					
-					b_tech_pvt->kick = switch_core_session_strdup(b_session, tech_pvt->xferto);
-                    switch_core_session_rwunlock(a_session);
-				}
-
-				
-				msg->pointer_arg = NULL;
-				return SWITCH_STATUS_FALSE;
-			}
-		}
-		if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) {
-			switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "De-activate timed RTP!\n");
-		}
-		break;
-	case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
-		if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) {
-			switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-activate timed RTP!\n");
-		}
-		break;
-	case SWITCH_MESSAGE_INDICATE_REDIRECT:
-		if(msg->string_arg) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-directing to %s\n", msg->string_arg);
-			nua_respond(tech_pvt->nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg->string_arg), TAG_END());
-		}
-		break;
-	case SWITCH_MESSAGE_INDICATE_RINGING:
-		nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END());
-		break;
-	case SWITCH_MESSAGE_INDICATE_PROGRESS: {
-		if (!switch_test_flag(tech_pvt, TFLAG_ANS)) {
-			switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Asked to send early media by %s\n", msg->from);
-
-			/* Transmit 183 Progress with SDP */
-			if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
-				char *sdp = NULL;
-				switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-				if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
-					tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
-				}
-			} else {
-				if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
-					char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
-					if (tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
-						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
-						nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
-						return SWITCH_STATUS_FALSE;
-					}
-					switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
-				}
-
-				if ((status=tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
-					return status;
-				}
-				set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
-				activate_rtp(tech_pvt);
-				if (tech_pvt->local_sdp_str) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Ring SDP:\n%s\n", tech_pvt->local_sdp_str);
-				}
-			}
-			
-			nua_respond(tech_pvt->nh,
-						SIP_183_SESSION_PROGRESS,
-						SIPTAG_CONTACT_STR(tech_pvt->profile->url),
-						SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-						SOATAG_AUDIO_AUX("cn telephone-event"),
-						TAG_END());
-	    }
-	}
-		break;
-	default:
-		break;
-	}
-
 	return SWITCH_STATUS_SUCCESS;
 }
 
-static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event)
+static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
 {
-	switch_channel_t *channel;
-    struct private_object *tech_pvt;
-	char *body;
-	nua_handle_t *msg_nh;
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	int bytes = 0, samples = 0, frames = 0;
 
-    channel = switch_core_session_get_channel(session);
-    assert(channel != NULL);
+	switch_assert(tech_pvt != NULL);
 
-    tech_pvt = switch_core_session_get_private(session);
-    assert(tech_pvt != NULL);
+	while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session) && !switch_channel_test_flag(channel, CF_REQ_MEDIA))) {
+		if (switch_channel_ready(channel)) {
+			switch_yield(10000);
+		} else {
+			return SWITCH_STATUS_GENERR;
+		}
+	}
 
+	if (!tech_pvt->read_codec.implementation || !switch_core_codec_ready(&tech_pvt->read_codec)) {
+		return SWITCH_STATUS_GENERR;
+	}
 
-	if (!(body = switch_event_get_body(event))) {
-		body = "";
+	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
+		return SWITCH_STATUS_FALSE;
 	}
 
-	if (tech_pvt->hash_key) {
-		msg_nh = nua_handle(tech_pvt->profile->nua, NULL,
-							SIPTAG_FROM_STR(tech_pvt->chat_from),
-							NUTAG_URL(tech_pvt->chat_to),
-							SIPTAG_TO_STR(tech_pvt->chat_to),
-							SIPTAG_CONTACT_STR(tech_pvt->profile->url),
-							TAG_END());
+	if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
+		return SWITCH_STATUS_GENERR;
+	}
 
-		nua_message(msg_nh,
-					SIPTAG_CONTENT_TYPE_STR("text/html"),
-					SIPTAG_PAYLOAD_STR(body),
-					TAG_END());
+	if (!sofia_test_flag(tech_pvt, TFLAG_IO)) {
+		return SWITCH_STATUS_SUCCESS;
 	}
 
-	return SWITCH_STATUS_SUCCESS;
-}
+	if (sofia_test_flag(tech_pvt, TFLAG_BYE) || !tech_pvt->read_codec.implementation || !switch_core_codec_ready(&tech_pvt->read_codec)) {
+		return SWITCH_STATUS_FALSE;
+	}
 
-static const switch_io_routines_t sofia_io_routines = {
-	/*.outgoing_channel */ sofia_outgoing_channel,
-	/*.answer_channel */ sofia_answer_channel,
-	/*.read_frame */ sofia_read_frame,
-	/*.write_frame */ sofia_write_frame,
-	/*.kill_channel */ sofia_kill_channel,
-	/*.waitfor_read */ sofia_waitfor_read,
-	/*.waitfor_read */ sofia_waitfor_write,
-	/*.send_dtmf*/ sofia_send_dtmf,
-	/*.receive_message*/ sofia_receive_message,
-	/*.receive_event*/ sofia_receive_event
-};
+	sofia_set_flag_locked(tech_pvt, TFLAG_WRITING);
 
-static const switch_state_handler_table_t sofia_event_handlers = {
-	/*.on_init */ sofia_on_init,
-	/*.on_ring */ sofia_on_ring,
-	/*.on_execute */ sofia_on_execute,
-	/*.on_hangup */ sofia_on_hangup,
-	/*.on_loopback */ sofia_on_loopback,
-	/*.on_transmit */ sofia_on_transmit
-};
+	if (!switch_test_flag(frame, SFF_CNG) && !switch_test_flag(frame, SFF_PROXY_PACKET)) {
+		if (tech_pvt->read_impl.encoded_bytes_per_packet) {
+			bytes = tech_pvt->read_impl.encoded_bytes_per_packet;
+			frames = ((int) frame->datalen / bytes);
+		} else
+			frames = 1;
 
-static const switch_endpoint_interface_t sofia_endpoint_interface = {
-	/*.interface_name */ "sofia",
-	/*.io_routines */ &sofia_io_routines,
-	/*.event_handlers */ &sofia_event_handlers,
-	/*.private */ NULL,
-	/*.next */ NULL
-};
+		samples = frames * tech_pvt->read_impl.samples_per_packet;
+	}
 
-static const switch_chat_interface_t sofia_chat_interface = {
-	/*.name */ SOFIA_CHAT_PROTO,
-	/*.chat_send */ chat_send,
-	
-};
+	tech_pvt->timestamp_send += samples;
+	switch_rtp_write_frame(tech_pvt->rtp_session, frame);
 
-static const switch_loadable_module_interface_t sofia_module_interface = {
-	/*.module_name */ modname,
-	/*.endpoint_interface */ &sofia_endpoint_interface,
-	/*.timer_interface */ NULL,
-	/*.dialplan_interface */ NULL,
-	/*.codec_interface */ NULL,
-	/*.application_interface */ NULL,
-	/*.api_interface */ NULL,
-	/*.file_interface */ NULL,
-	/*.speech_interface */ NULL,
-	/*.directory_interface */ NULL,
-	/*.chat_interface */ &sofia_chat_interface
-};
+	sofia_clear_flag_locked(tech_pvt, TFLAG_WRITING);
+	return status;
+}
 
-
-static void logger(void *logarg, char const *fmt, va_list ap)
+static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig)
 {
-	char *data = NULL;
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
 
-	if (fmt) {
-#ifdef HAVE_VASPRINTF
-		int ret;
-		ret = vasprintf(&data, fmt, ap);
-		if ((ret == -1) || !data) {
-			return;
+	if (!tech_pvt) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	switch (sig) {
+	case SWITCH_SIG_BREAK:
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			switch_rtp_break(tech_pvt->rtp_session);
 		}
-#else
-		data = (char *) malloc(2048);
-		if (data) {
-			vsnprintf(data, 2048, fmt, ap);
-		} else { 
-			return;
+		if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+			switch_rtp_break(tech_pvt->video_rtp_session);
 		}
-#endif
+		break;
+	case SWITCH_SIG_KILL:
+	default:
+		sofia_clear_flag_locked(tech_pvt, TFLAG_IO);
+		sofia_set_flag_locked(tech_pvt, TFLAG_HUP);
+
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			switch_rtp_kill_socket(tech_pvt->rtp_session);
+		}
+		if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+			switch_rtp_kill_socket(tech_pvt->video_rtp_session);
+		}
+		break;
 	}
-	if (data) {
-		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, (char*) "%s", data);
-		free(data);
-	}
+	return SWITCH_STATUS_SUCCESS;
 }
 
-
-static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_caller_profile_t *outbound_profile,
-												  switch_core_session_t **new_session, switch_memory_pool_t **pool)
+static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
 {
-	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
-	switch_core_session_t *nsession;
-	char *data, *profile_name, *dest;
-	sofia_profile_t *profile;
-	switch_caller_profile_t *caller_profile = NULL;
-	private_object_t *tech_pvt = NULL;
-	switch_channel_t *nchannel;
-	char *host, *dest_to;
+	private_object_t *tech_pvt;
+	char message[128] = "";
+	sofia_dtmf_t dtmf_type;
 
-	*new_session = NULL;
+	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
 
-	if (!(nsession = switch_core_session_request(&sofia_endpoint_interface, pool))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
-		goto done;
-	}
+	dtmf_type = tech_pvt->dtmf_type;
 
-	if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
-		terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-		goto done;
+	/* We only can send INFO when we have no media */
+	if (!tech_pvt->rtp_session || !switch_channel_media_ready(tech_pvt->channel) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
+		dtmf_type = DTMF_INFO;
 	}
 
-	data = switch_core_session_strdup(nsession, outbound_profile->destination_number);
-	profile_name = data;
-	
-	if (!(dest = strchr(profile_name, '/'))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
-        terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-		cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
-        goto done;
-	}
-
-	*dest++ = '\0';
-	
-	if (!(profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, profile_name))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
-        terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-		cause =  SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
-        goto done;
-	}
-
-	if ((dest_to = strchr(dest, '^'))) {
-		*dest_to++ = '\0';
-		tech_pvt->dest_to = switch_core_session_alloc(nsession, strlen(dest_to) + 5);
-		snprintf(tech_pvt->dest_to, strlen(dest_to) + 5, "sip:%s", dest_to);
-	}
-
-	if ((host = strchr(dest, '%'))) {
-		char buf[128];
-		*host = '@';
-		tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
-		*host++ = '\0';
-		if (find_reg_url(profile, dest, host, buf, sizeof(buf))) {
-			tech_pvt->dest = switch_core_session_strdup(nsession, buf);
-			
-		} else {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, host);
-			cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
-			terminate_session(&nsession, cause, __LINE__);
-			goto done;
+	switch (dtmf_type) {
+	case DTMF_2833:
+		{
+			return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, dtmf);
 		}
-	} else if (!strchr(dest, '@')) {
-		char buf[128];
-		tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
-		if (find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) {
-            tech_pvt->dest = switch_core_session_strdup(nsession, buf);
-
-        } else {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, profile_name);
-			cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
-            terminate_session(&nsession, cause, __LINE__);
-            goto done;
-        }
-	} else {
-		tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
-		snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest);
-	}
-
-	if (!tech_pvt->dest_to) {
-		tech_pvt->dest_to = tech_pvt->dest;
-	}
-
-	attach_private(nsession, profile, tech_pvt, dest);
-
-	nchannel = switch_core_session_get_channel(nsession);
-	caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
-	switch_channel_set_caller_profile(nchannel, caller_profile);
-	switch_channel_set_flag(nchannel, CF_OUTBOUND);
-	switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
-	switch_channel_set_state(nchannel, CS_INIT);
-	*new_session = nsession;
-	cause = SWITCH_CAUSE_SUCCESS;
-	if (session) {
-		//char *val;
-		//switch_channel_t *channel = switch_core_session_get_channel(session);
-		switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
-		switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T);
-		if (switch_core_session_compare(session, nsession)) {
-			/* It's another sofia channel! so lets cache what they use as a pt for telephone event so 
-			   we can keep it the same
-			*/
-			private_object_t *ctech_pvt;
-			ctech_pvt = switch_core_session_get_private(session);
-			assert(ctech_pvt != NULL);
-			tech_pvt->bte = ctech_pvt->te;
+	case DTMF_INFO:
+		{
+			snprintf(message, sizeof(message), "Signal=%c\r\nDuration=%d\r\n", dtmf->digit, dtmf->duration / 8);
+			switch_mutex_lock(tech_pvt->sofia_mutex);
+			nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/dtmf-relay"), SIPTAG_PAYLOAD_STR(message), TAG_END());
+			switch_mutex_unlock(tech_pvt->sofia_mutex);
 		}
+		break;
+	case DTMF_NONE:
+		break;
+	default:
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled DTMF type!\n");
+		break;
 	}
 
- done:
-	return cause;
+	return SWITCH_STATUS_SUCCESS;
 }
 
-
-static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
+static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
 {
-	uint8_t match = 0;
-	switch_payload_t te = 0;
-	private_object_t *tech_pvt;
-	sdp_media_t *m;
-	sdp_attribute_t *a;
-	switch_channel_t *channel;
-    int ptime = 0, dptime = 0;
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
 
-	tech_pvt = switch_core_session_get_private(session);
-	assert(tech_pvt != NULL);
-
-	channel = switch_core_session_get_channel(session);
-	
-	if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
-		if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
-			switch_set_flag_locked(tech_pvt, TFLAG_BUGGY_2833);
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
-		}
+	if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		status = SWITCH_STATUS_FALSE;
+		goto end;
 	}
 
-	for (a = sdp->sdp_attributes; a; a = a->a_next) {
-		if (!strcasecmp(a->a_name, "sendonly")) {
-			switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-		} else if (!strcasecmp(a->a_name, "sendrecv")) {
-			switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-		} else if (!strcasecmp(a->a_name, "ptime")) {
-            dptime = atoi(a->a_value);
+	/* ones that do not need to lock sofia mutex */
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY:
+		if (tech_pvt->rtp_session && switch_rtp_test_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Pass 2833 mode may not work on a transcoded call.\n");
 		}
-	}
+		goto end;
 
-	for (m = sdp->sdp_media; m ; m = m->m_next) {
-        sdp_connection_t *connection;
+	case SWITCH_MESSAGE_INDICATE_BRIDGE:
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			const char *val;
+			int ok = 0;
 
-        ptime = dptime;
-        for (a = m->m_attributes; a; a = a->a_next) {
-            if (!strcasecmp(a->a_name, "ptime") && a->a_value) {
-                ptime = atoi(a->a_value);
-            }
-        }
+			if (sofia_test_flag(tech_pvt, TFLAG_PASS_RFC2833) && switch_channel_test_flag_partner(channel, CF_FS_RTP)) {
+				switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s activate passthru 2833 mode.\n", switch_channel_get_name(channel));
+			}
 
-		if (m->m_type == sdp_media_audio) {
-			sdp_rtpmap_t *map;
+			if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) {
+				ok = switch_true(val);
+			} else {
+				ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
+			}
+			
+			if (ok) {
+				rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_STICK);
+			} else {
+				rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE);
+			}
+		}
+		goto end;
+	case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			const char *val;
+			int ok = 0;
 
-			connection = sdp->sdp_connection;
-			if (m->m_connections) {
-				connection = m->m_connections;
+			if (switch_rtp_test_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s deactivate passthru 2833 mode.\n", switch_channel_get_name(channel));
+				switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
 			}
 
-			if (!connection) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
-				match = 0;
-				break;
+			if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) {
+				ok = switch_true(val);
+			} else {
+				ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
 			}
+			
+			if (ok) {
+				rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_UNSTICK);
+			} else {
+				rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE);
+			}
 
-			for (map = m->m_rtpmaps; map; map = map->rm_next) {
-				int32_t i;
-                const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
+		}
+		goto end;
+	case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE);
+		}
+		goto end;
 
-				if (!te && !strcasecmp(map->rm_encoding, "telephone-event")) {
-					te = tech_pvt->te = (switch_payload_t)map->rm_pt;
-				}
-
-				if (match) {
-					if (te) {
-						break;
-					}
-					continue;
-				}
-
-				for (i = 0; i < tech_pvt->num_codecs; i++) {
-					const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Codec Compare [%s:%d]/[%s:%d]\n", 
-									  map->rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
-					if (map->rm_pt < 96) {
-						match = (map->rm_pt == imp->ianacode) ? 1 : 0;
-					} else {
-						match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
-					}
-
-					if (match && (map->rm_rate == imp->samples_per_second)) {
-                        if (ptime && ptime * 1000 != imp->microseconds_per_frame) {
-                            near_match = imp;
-                            match = 0;
-                            continue;
-                        }
-                        mimp = imp;
-						break;
-					} else {
-						match = 0;
-					}
-                }
-                
-                if (!match && near_match) {
-                    const switch_codec_implementation_t *search[1];
-                    char *prefs[1];
-                    char tmp[80];
-                    int num;
-                    
-                    snprintf(tmp, sizeof(tmp), "%s@%uk@%ui",
-                             near_match->iananame,
-                             near_match->samples_per_second,
-                             ptime);
-
-                    prefs[0] = tmp;
-                    num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
-
-                    if (num) {
-                        mimp = search[0];
-                    } else {
-                        mimp = near_match;
-                    }
-
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Substituting codec %s@%ums\n", 
-                                      mimp->iananame, mimp->microseconds_per_frame / 1000 );
-                    match = 1;
-                }
-
-                if (mimp) {
-                    if ((tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *)map->rm_encoding))) {
-                        char tmp[50];
-                        tech_pvt->pt = (switch_payload_t)map->rm_pt;
-                        tech_pvt->rm_rate = map->rm_rate;
-                        tech_pvt->codec_ms = mimp->microseconds_per_frame / 1000;
-                        tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *)connection->c_address);
-                        tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *)map->rm_fmtp);
-                        tech_pvt->remote_sdp_audio_port = (switch_port_t)m->m_port;
-                        tech_pvt->agreed_pt = (switch_payload_t)map->rm_pt;
-                        snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
-                        switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
-                        switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
-                    } else {
-                        match = 0;
-                    }
-                }
-                
-				if (match) {
-					if (tech_set_codec(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) {
-						match = 0;
-					}
-				}
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+		{
+			const char *var;
+			if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) {
+				sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
 			}
 		}
+		break;
+	default:
+		break;
 	}
 
-	return match;
-}
+	/* ones that do need to lock sofia mutex */
+	switch_mutex_lock(tech_pvt->sofia_mutex);
 
-// map sip responses to QSIG cause codes ala RFC4497 section 8.4.4
-static switch_call_cause_t sip_cause_to_freeswitch(int status) {
-	switch (status) {
-	case 200:
-		return SWITCH_CAUSE_NORMAL_CLEARING;
-	case 401:
-	case 402: 
-	case 403:
-	case 407:
-	case 603:
-		return SWITCH_CAUSE_CALL_REJECTED;
-	case 404:
-	case 485:
-	case 604:	
-		return SWITCH_CAUSE_NO_ROUTE_DESTINATION;
-	case 408: 
-	case 504:
-		return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
-	case 410: 
-		return SWITCH_CAUSE_NUMBER_CHANGED;
-	case 413: 
-	case 414:
-	case 416:
-	case 420:
-	case 421:
-	case 423:
-	case 505:
-	case 513:
-		return SWITCH_CAUSE_INTERWORKING;
-	case 480:
-		return SWITCH_CAUSE_NO_USER_RESPONSE;
-	case 400:
-	case 481:
-	case 500:
-	case 503:
-		return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE;
-	case 486:
-	case 600:
-		return SWITCH_CAUSE_USER_BUSY;
-	case 484:
-		return SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
-	case 488:
-	case 606:
-		return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL;
-	case 502:
-		return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
-	case 405:
-		return SWITCH_CAUSE_SERVICE_UNAVAILABLE;
-	case 406:
-	case 415:
-	case 501:
-		return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED;
-	case 482:
-	case 483:
-		return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR;
-	case 487:
-		return SWITCH_CAUSE_ORIGINATOR_CANCEL;
-
-	default: 
-		return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
-
+	if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		status = SWITCH_STATUS_FALSE;
+		goto end_lock;
 	}
-}
 
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
+		{
+			const char *pl =
+				"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
+				" <media_control>\r\n"
+				"  <vc_primitive>\r\n"
+				"   <to_encoder>\r\n"
+				"    <picture_fast_update>\r\n" 
+				"    </picture_fast_update>\r\n" 
+				"   </to_encoder>\r\n" 
+				"  </vc_primitive>\r\n" 
+				" </media_control>\r\n";
 
-static void set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
-{
+			nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/media_control+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END());
 
-	snprintf(hash_key, len, "%s%s%s",
-			 (char *) sip->sip_from->a_url->url_user,
-			 (char *) sip->sip_from->a_url->url_host,
-			 (char *) sip->sip_to->a_url->url_user
-			 );	
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_BROADCAST:
+		{
+			const char *ip = NULL, *port = NULL;
+			ip = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
+			port = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
+			if (ip && port) {
+				sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), msg->string_arg, 1);
+			}
 
+			if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+				nua_respond(tech_pvt->nh, SIP_200_OK,
+							SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+							SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+							SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
+				switch_channel_mark_answered(channel);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_NOMEDIA:
+		{
+			const char *uuid;
+			switch_core_session_t *other_session;
+			switch_channel_t *other_channel;
+			const char *ip = NULL, *port = NULL;
 
-#if 0
-	/* nicer one we cant use in both directions >=0 */
-	snprintf(hash_key, len, "%s%s%s%s%s%s",
-			 (char *) sip->sip_to->a_url->url_user,
-			 (char *) sip->sip_to->a_url->url_host,
-			 (char *) sip->sip_to->a_url->url_params,
-			 
-			 (char *) sip->sip_from->a_url->url_user,
-			 (char *) sip->sip_from->a_url->url_host,
-			 (char *) sip->sip_from->a_url->url_params
-			 );	
-#endif
+			switch_channel_set_flag(channel, CF_PROXY_MODE);
+			sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE);
 
-}
+			if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+				&& (other_session = switch_core_session_locate(uuid))) {
+				other_channel = switch_core_session_get_channel(other_session);
+				ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
+				port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
+				switch_core_session_rwunlock(other_session);
+				if (ip && port) {
+					sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1);
+				}
+			}
 
-static void set_chat_hash(private_object_t *tech_pvt, sip_t const *sip)
-{
-	char hash_key[256] = "";
-	char buf[512];
 
-	if (tech_pvt->hash_key || !sip || !sip->sip_from ||
-		!sip->sip_from->a_url ||
-		!sip->sip_from->a_url->url_user ||
-		!sip->sip_from->a_url->url_host) {
-		return;
-	}
-
-	if (find_reg_url(tech_pvt->profile, sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host, buf, sizeof(buf))) {
-		tech_pvt->chat_from = sip_header_as_string(tech_pvt->home, (const sip_header_t *)sip->sip_to);
-		tech_pvt->chat_to = switch_core_session_strdup(tech_pvt->session, buf);
-		set_hash_key(hash_key, sizeof(hash_key), sip);
-	} else {
-		return;
-	}
-
-	tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
-	switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
-
-}
-
-
-static void sip_i_message(int status,
-						char const *phrase, 
-						nua_t *nua,
-						sofia_profile_t *profile,
-						nua_handle_t *nh,
-						sofia_private_t *sofia_private,
-						sip_t const *sip,
-						tagi_t tags[])
-{
-	if (sip) {
-		sip_from_t const *from = sip->sip_from;
-		char *from_user = NULL;
-		char *from_host = NULL;
-		sip_to_t const *to = sip->sip_to;
-		char *to_user = NULL;
-		char *to_host = NULL;
-		sip_subject_t const *sip_subject = sip->sip_subject;
-		sip_payload_t *payload = sip->sip_payload;
-		const char *subject = "n/a";
-		char *msg = NULL;
-
-		if (sip->sip_content_type) {
-			if (strstr((char*)sip->sip_content_type->c_subtype, "composing")) {
-				return;
+			if (!tech_pvt->local_sdp_str) {
+				sofia_glue_tech_absorb_sdp(tech_pvt);
 			}
+			sofia_glue_do_invite(session);
 		}
+		break;
 
-		if (from) {
-			from_user = (char *) from->a_url->url_user;
-			from_host = (char *) from->a_url->url_host;
-		}
+	case SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Sending media re-direct:\n%s\n", 
+							  switch_channel_get_name(channel), msg->string_arg);
+			sofia_glue_tech_set_local_sdp(tech_pvt, msg->string_arg, SWITCH_TRUE);
 
-		if (to) {
-			to_user = (char *) to->a_url->url_user;
-			to_host = (char *) to->a_url->url_host;
+			sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
+			sofia_glue_do_invite(session);
 		}
+		break;
 
-        
-		if (!to_user) {
-			return;
-		}
 
-		if (payload) {
-			msg = payload->pl_data;
-		}
+	case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:
+		{
+			switch_t38_options_t *t38_options = (switch_t38_options_t *) msg->pointer_arg;
 
-		if (sip_subject) {
-			subject = sip_subject->g_value;
-		}
+			sofia_glue_set_image_sdp(tech_pvt, t38_options);
 
-		if (nh) {			
-			char hash_key[512];
-			private_object_t *tech_pvt;
-			switch_channel_t *channel;
-			switch_event_t *event;
-			char *to_addr;
-			char *from_addr;
-			char *p;
-			char *full_from;
-			char proto[512] = SOFIA_CHAT_PROTO;
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Sending request for image media. %s\n", 
+							  switch_channel_get_name(channel), tech_pvt->local_sdp_str);
+							  
 			
-			full_from = sip_header_as_string(profile->home, (void *)sip->sip_from);
+			sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
+			sofia_glue_do_invite(session);
+		}
+		break;
 
-			if ((p=strchr(to_user, '+'))) {
-				switch_copy_string(proto, to_user, sizeof(proto));
-				p = strchr(proto, '+');
-				*p++ = '\0';
-				
-				if ((to_addr = strdup(p))) {
-					if((p = strchr(to_addr, '+'))) {
-						*p = '@';
-					}
-				}
-				
-			} else {
-				to_addr = switch_mprintf("%s@%s", to_user, to_host);
-			}
+	case SWITCH_MESSAGE_INDICATE_MEDIA:
+		{
+			uint32_t send_invite = 1;
 
-			from_addr = switch_mprintf("%s@%s", from_user, from_host);
+			switch_channel_clear_flag(channel, CF_PROXY_MODE);
+			sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE);
 
+			if (!switch_channel_media_ready(channel)) {
+				if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
+					const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
 
-			set_hash_key(hash_key, sizeof(hash_key), sip);
-			if ((tech_pvt = (private_object_t *) switch_core_hash_find(profile->chat_hash, hash_key))) {
-				channel = switch_core_session_get_channel(tech_pvt->session);
-				if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
-					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
-					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
-					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", tech_pvt->hash_key);
-					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", to_addr);
-					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE");
-					if (msg) {
-						switch_event_add_body(event, "%s", msg);
+					tech_pvt->num_codecs = 0;
+					sofia_glue_tech_prepare_codecs(tech_pvt);
+					if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
+						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+						status = SWITCH_STATUS_FALSE;
+						goto end_lock;
 					}
-					if (switch_core_session_queue_event(tech_pvt->session, &event) != SWITCH_STATUS_SUCCESS) {
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
-						switch_event_fire(&event);
-					}
+					send_invite = 0;
 				}
-			} else {
-				switch_chat_interface_t *ci;
-				
-				if ((ci = switch_loadable_module_get_chat_interface(proto))) {
-					ci->chat_send(SOFIA_CHAT_PROTO, from_addr, to_addr, "", msg, full_from);
-				} else {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Chat Interface [%s]!\n", proto ? proto : "(none)");
+			}
+
+			if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+				sofia_glue_tech_prepare_codecs(tech_pvt);
+				if ((status = sofia_glue_tech_choose_port(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+					switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+					goto end_lock;
 				}
-				
 			}
-			switch_safe_free(to_addr);
-			switch_safe_free(from_addr);
-			if (full_from) {
-				su_free(profile->home, full_from);
+			sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 1);
+
+			if (send_invite) {
+				switch_channel_set_flag(channel, CF_REQ_MEDIA);
+				sofia_glue_do_invite(session);
 			}
 		}
+		break;
 
-	}
-}
+	case SWITCH_MESSAGE_INDICATE_DISPLAY:
+		{
+			if (!switch_strlen_zero(msg->string_arg)) {
+				char message[256] = "";
+				const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent");
 
-static void pass_sdp(private_object_t *tech_pvt, char *sdp) 
-{
-	char *val;
-	switch_channel_t *channel;
-	switch_core_session_t *other_session;
-	switch_channel_t *other_channel;
-	
-	channel = switch_core_session_get_channel(tech_pvt->session);
-	assert(channel != NULL);
-	
-	if ((val = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_VARIABLE)) && (other_session = switch_core_session_locate(val))) {
-		other_channel = switch_core_session_get_channel(other_session);
-		assert(other_channel != NULL);
-		if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-			switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
+				if (ua && switch_stristr("snom", ua)) {
+					snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", msg->string_arg, tech_pvt->caller_profile->destination_number);
+					nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR(message), TAG_END());
+				} else if (ua && switch_stristr("polycom", ua)) {
+					snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", msg->string_arg, tech_pvt->caller_profile->destination_number);
+					nua_update(tech_pvt->nh,
+							   TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)),
+							   TAG_END());
+				}
+			}
 		}
+		break;
 
-		if (!switch_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && (
-			switch_channel_test_flag(other_channel, CF_OUTBOUND) && 
-			//switch_channel_test_flag(other_channel, CF_NOMEDIA) && 
-			switch_channel_test_flag(channel, CF_OUTBOUND) && 
-			switch_channel_test_flag(channel, CF_NOMEDIA))) {
-			switch_ivr_nomedia(val, SMF_FORCE);
-			switch_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA);
-		}
-		
-		switch_core_session_rwunlock(other_session);
-	}
-}
+	case SWITCH_MESSAGE_INDICATE_HOLD:
+		{
+			sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+			sofia_glue_do_invite(session);
+			if (!switch_strlen_zero(msg->string_arg)) {
+				char message[256] = "";
+				const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent");
 
-static void sip_i_state(int status,
-						char const *phrase, 
-						nua_t *nua,
-						sofia_profile_t *profile,
-						nua_handle_t *nh,
-						sofia_private_t *sofia_private,
-						sip_t const *sip,
-						tagi_t tags[])
-	 
-{
-	const char *l_sdp = NULL, *r_sdp = NULL;
-	int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
-	int ss_state = nua_callstate_init;
-	switch_channel_t *channel = NULL;
-	private_object_t *tech_pvt = NULL;
-	switch_core_session_t *session = NULL;
-	const char *replaces_str = NULL;
-	char *uuid;
-	switch_core_session_t *other_session = NULL;
-	switch_channel_t *other_channel = NULL;
-	char st[80] = "";
-
-
-    if (sofia_private) {
-        if (!switch_strlen_zero(sofia_private->uuid)) {
-            if (!(session = switch_core_session_locate(sofia_private->uuid))) {
-                /* too late */
-                return;            
-            }
-        }
-    }
-
-	
-	tl_gets(tags, 
-			NUTAG_CALLSTATE_REF(ss_state),
-			NUTAG_OFFER_RECV_REF(offer_recv),
-			NUTAG_ANSWER_RECV_REF(answer_recv),
-			NUTAG_OFFER_SENT_REF(offer_sent),
-			NUTAG_ANSWER_SENT_REF(answer_sent),
-			SIPTAG_REPLACES_STR_REF(replaces_str),
-			SOATAG_LOCAL_SDP_STR_REF(l_sdp),
-			SOATAG_REMOTE_SDP_STR_REF(r_sdp),
-			TAG_END()); 
-
-	if (session) {
-		channel = switch_core_session_get_channel(session);
-		assert(channel != NULL);
-
-		tech_pvt = switch_core_session_get_private(session);
-		assert(tech_pvt != NULL);
-        assert(tech_pvt->nh != NULL);
-
-		if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
-            switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
-        }
-
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s]\n", 
-						  switch_channel_get_name(channel),
-						  nua_callstate_name(ss_state));
-
-		if (r_sdp) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp);			
-			tech_pvt->remote_sdp_str = switch_core_session_strdup(session, r_sdp);
-			switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
-			pass_sdp(tech_pvt, (char *)r_sdp);
-
+				if (ua && switch_stristr("snom", ua)) {
+					snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", msg->string_arg, tech_pvt->caller_profile->destination_number);
+					nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR(message), TAG_END());
+				} else if (ua && switch_stristr("polycom", ua)) {
+					snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", msg->string_arg, tech_pvt->caller_profile->destination_number);
+					nua_update(tech_pvt->nh,
+							   TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)),
+							   TAG_END());
+				}
+			}
 		}
-	}
+		break;
 
-	if (status == 988) {
-		goto done;
-	}
-
-	switch ((enum nua_callstate)ss_state) {
-	case nua_callstate_init:
+	case SWITCH_MESSAGE_INDICATE_UNHOLD:
+		{
+			sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+			sofia_glue_do_invite(session);
+		}
 		break;
-	case nua_callstate_authenticating:
-		break;
-	case nua_callstate_calling:
-		break;
-	case nua_callstate_proceeding:
-		if (channel) {
-			if (status == 180) {
-				switch_channel_mark_ring_ready(channel);
-				if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK)) {
-					if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-						if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
-							switch_core_session_message_t msg;
-							msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING;
-							msg.from = __FILE__;
-							switch_core_session_receive_message(other_session, &msg);
-							switch_core_session_rwunlock(other_session);
-						}
-						
-					} else {
-						switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
-					}
-				}
+	case SWITCH_MESSAGE_INDICATE_REDIRECT:
+		if (!switch_strlen_zero(msg->string_arg)) {
+			if (!switch_channel_test_flag(channel, CF_ANSWERED) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Redirecting to %s\n", msg->string_arg);
+				nua_respond(tech_pvt->nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg->string_arg), TAG_END());
+				sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+			} else {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too late for redirecting to %s, already answered\n", msg->string_arg);
 			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_DEFLECT:
+		{
+			char ref_to[128] = "";
+			const char *var;
 
-			if (r_sdp) {
-				if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-					switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
-                    switch_channel_mark_pre_answered(channel);
-					if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) && 
-						(uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
-						other_channel = switch_core_session_get_channel(other_session);
-						if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-							switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
-						}
-						
-						switch_channel_pre_answer(other_channel);
-						switch_core_session_rwunlock(other_session);
-					}
-                    goto done;
-				} else {
-					if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
-						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
-					} else {
-						if (tech_media(tech_pvt, (char *)r_sdp) != SWITCH_STATUS_SUCCESS) {
-							switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
-							nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
-						}
-					}
-					goto done;
-                }
+			if (!strstr(msg->string_arg, "sip:")) {
+				const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s";
+				switch_snprintf(ref_to, sizeof(ref_to), format, msg->string_arg, tech_pvt->profile->sipip);
+			} else {
+				switch_set_string(ref_to, msg->string_arg);
 			}
+			nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt->contact_url), TAG_END());
+			switch_mutex_unlock(tech_pvt->sofia_mutex);
+			sofia_wait_for_reply(tech_pvt, 9999, 300);
+			switch_mutex_lock(tech_pvt->sofia_mutex);
+			if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) {
+				msg->string_reply = switch_core_session_strdup(session, var); 
+			} else {
+				msg->string_reply = "no reply";
+			}
 		}
 		break;
-	case nua_callstate_completing:
-		nua_ack(nh, TAG_END());
-		break;
-	case nua_callstate_received: 
-		if (session && switch_core_session_running(session)) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Re-Entering Call State Received!\n");
-            goto done;
-		}
 
-		if (channel) {
-			if (r_sdp) {
-				if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA");
-					switch_channel_set_state(channel, CS_INIT);
-					switch_set_flag_locked(tech_pvt, TFLAG_READY);
-					switch_core_session_thread_launch(session);
-                    goto done;
-				} else {
-					sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-					sdp_session_t *sdp;
-					uint8_t match = 0;
-				
-					if (tech_pvt->num_codecs) {
-						if ((sdp = sdp_session(parser))) {
-							match = negotiate_sdp(session, sdp);
+	case SWITCH_MESSAGE_INDICATE_RESPOND:
+		if (msg->numeric_arg || msg->string_arg) {
+			int code = msg->numeric_arg;
+			const char *reason = NULL;
+			
+			if (code) {
+				reason = msg->string_arg;
+			} else {
+				if (!switch_strlen_zero(msg->string_arg)) {
+					if ((code = atoi(msg->string_arg))) {
+						if ((reason = strchr(msg->string_arg, ' '))) {
+							reason++;
 						}
 					}
+				}
+			}
 
-					if (parser) {
-						sdp_parser_free(parser);
-					}
+			if (!code) {
+				code = 488;
+			}
 
-					if (match) {
-						nua_handle_t *bnh;
-						sip_replaces_t *replaces;
-						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED");
-						switch_channel_set_state(channel, CS_INIT);
-						switch_set_flag_locked(tech_pvt, TFLAG_READY);
+			if (!switch_channel_test_flag(channel, CF_ANSWERED) && code >= 300) {
+				if (sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+					goto end_lock;
+				}
+			}
+			
+			if (switch_strlen_zero(reason) && code != 407 && code != 302) {
+				reason = sip_status_phrase(code);
+				if (switch_strlen_zero(reason)) {
+					reason = "Because";
+				}
+			}
 
-						switch_core_session_thread_launch(session);
-						
-						if (replaces_str && (replaces = sip_replaces_make(tech_pvt->home, replaces_str)) && (bnh = nua_handle_by_replaces(nua, replaces))) {
-							sofia_private_t *b_private;
+			if (code == 407 && !msg->numeric_arg) {
+				const char *to_uri = switch_channel_get_variable(channel, "sip_to_uri");
+				const char *to_host = reason;
 
-							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Replaces Attended Transfer\n");
-							while (switch_channel_get_state(channel) < CS_EXECUTE) {
-								switch_yield(10000);
-							}
+				if (switch_strlen_zero(to_host)) {
+					to_host = switch_channel_get_variable(channel, "sip_to_host");
+				}
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Challenging call %s\n", to_uri);
+				sofia_reg_auth_challenge(NULL, tech_pvt->profile, tech_pvt->nh, REG_INVITE, to_host, 0);
+				switch_channel_hangup(channel, SWITCH_CAUSE_USER_CHALLENGE);
+			} else if (code == 484 && msg->numeric_arg) {
+				const char *to = switch_channel_get_variable(channel, "sip_to_uri");
+				const char *max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE);
 
-							if ((b_private = nua_handle_magic(bnh))) {
-								char *br_b = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE);
-								char *br_a = b_private->uuid;
+				char *to_uri = NULL;
 
-								if (br_b) {
-									switch_ivr_uuid_bridge(br_a, br_b);
-									switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
-									switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
-								} else {
-									switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
-									switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-								}
-							} else {
-								switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
-								switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-							}
-							nua_handle_unref(bnh);
-						}
-                        goto done;
+				if (to) {
+					char *p;
+					to_uri = switch_core_session_sprintf(session, "sip:%s", to);
+					if ((p = strstr(to_uri, ":5060"))) {
+						*p = '\0';
 					}
+				}
 
-					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
-					nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
-								TAG_END());
+				if (!switch_channel_test_flag(channel, CF_ANSWERED) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Overlap Dial with %d %s\n", code, reason);
+					nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), TAG_IF(to_uri, SIPTAG_CONTACT_STR(to_uri)),
+								SIPTAG_SUPPORTED_STR(NULL), SIPTAG_ACCEPT_STR(NULL),
+								TAG_IF(!switch_strlen_zero(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)), TAG_END());
+					
+					sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
 				}
-			}
-		}
+			} else if (code == 302 && !switch_strlen_zero(msg->string_arg)) {
+				char *p;
 
-		break;		
-	case nua_callstate_early:
-		break;
-	case nua_callstate_completed:
-		if (tech_pvt && r_sdp) {
-			if (r_sdp) {
-				if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-                    goto done;
-				} else {
-					sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-					sdp_session_t *sdp;
-					uint8_t match = 0;
-
-					if (tech_pvt->num_codecs) {
-						if ((sdp = sdp_session(parser))) {
-							match = negotiate_sdp(session, sdp);
+				if ((p = strchr(msg->string_arg, ' '))) {
+					*p = '\0';
+					msg->string_arg = p;
+				}
+				
+				msg->message_id = SWITCH_MESSAGE_INDICATE_REDIRECT;
+				switch_core_session_receive_message(session, msg);
+				goto end_lock;
+			} else {
+				if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding with %d [%s]\n", code, reason);
+					if (!switch_strlen_zero(((char *) msg->pointer_arg))) {
+						sofia_glue_tech_set_local_sdp(tech_pvt, (char *) msg->pointer_arg, SWITCH_TRUE);
+						
+						if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+							sofia_glue_tech_patch_sdp(tech_pvt);
+							sofia_glue_tech_proxy_remote_addr(tech_pvt);
 						}
+						nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+									SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+									SOATAG_REUSE_REJECTED(1),
+									SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
+					} else {
+						nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), TAG_END());
 					}
-					if (match) {
-						if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
-                            goto done;
-                        }
-						set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
-						switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
-						activate_rtp(tech_pvt);
-						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n");
-						if (parser) {
-							sdp_parser_free(parser);
-						}
-					}
 				}
 			}
+
 		}
 		break;
-	case nua_callstate_ready:
-		if (tech_pvt && nh == tech_pvt->nh2) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cheater Reinvite!\n");
-			switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
-			tech_pvt->nh = tech_pvt->nh2;
-			tech_pvt->nh2 = NULL;
-			if (tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
-                activate_rtp(tech_pvt);
-            }
-			goto done;
+	case SWITCH_MESSAGE_INDICATE_RINGING:
+		if (!switch_channel_test_flag(channel, CF_RING_READY) && !sofia_test_flag(tech_pvt, TFLAG_BYE) &&
+			!switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) {
+			nua_respond(tech_pvt->nh, SIP_180_RINGING,
+						SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+						SIPTAG_HEADER_STR(generate_pai_str(session)), TAG_END());
+			switch_channel_mark_ring_ready(channel);
 		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		status = sofia_answer_channel(session);
+		break;
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+		{
+			char *sticky = NULL;
+			const char *val = NULL;
 
-		if (channel) {
-			if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
-				switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-                switch_channel_mark_answered(channel);
-                if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
-                    other_channel = switch_core_session_get_channel(other_session);
-                    switch_channel_answer(other_channel);
-                    switch_core_session_rwunlock(other_session);
-                }
-				goto done;
-			}
+			if (!sofia_test_flag(tech_pvt, TFLAG_ANS) && !sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
 
-			if (!r_sdp) {
-				r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
-			}
-			if (r_sdp) {
-				if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-					switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-                    switch_channel_mark_answered(channel);
-					if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
-						other_channel = switch_core_session_get_channel(other_session);
-						if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-							switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
+				sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+				switch_log_printf(SWITCH_CHANNEL_ID_LOG, msg->_file, msg->_func, msg->_line, NULL, SWITCH_LOG_INFO, "Sending early media\n");
+
+				/* Transmit 183 Progress with SDP */
+				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+					const char *sdp = NULL;
+					if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
+						sofia_glue_tech_set_local_sdp(tech_pvt, sdp, SWITCH_TRUE);
+					}
+					if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+						
+						sofia_glue_tech_patch_sdp(tech_pvt);
+						
+						if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+							status = SWITCH_STATUS_FALSE;
+							goto end_lock;
 						}
-						switch_channel_answer(other_channel);
-						switch_core_session_rwunlock(other_session);
 					}
-					goto done;
 				} else {
-					sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-					sdp_session_t *sdp;
-					uint8_t match = 0;
+					if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || !tech_pvt->iananame) {
+						sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
+						if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
+							const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
 
-					if (tech_pvt->num_codecs) {
-						if ((sdp = sdp_session(parser))) {
-							match = negotiate_sdp(session, sdp);
+							tech_pvt->num_codecs = 0;
+							sofia_glue_tech_prepare_codecs(tech_pvt);
+							if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
+								switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+								//nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+								status = SWITCH_STATUS_FALSE;
+								goto end_lock;
+							}
 						}
 					}
 
-					if (parser) {
-						sdp_parser_free(parser);
+					if ((status = sofia_glue_tech_choose_port(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+						switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+						goto end_lock;
 					}
+					sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+					if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+						switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+					}
+					if (tech_pvt->local_sdp_str) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Ring SDP:\n%s\n", tech_pvt->local_sdp_str);
+					}
+				}
+				switch_channel_mark_pre_answered(channel);
 
 
-					if (match) {
-						switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-						if (tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
-                            activate_rtp(tech_pvt);
-                            switch_channel_mark_answered(channel);
-                            goto done;
-                        }
-					}
-					
-					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
-					nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+				if (sofia_test_flag(tech_pvt, TFLAG_NAT) ||
+					(val = switch_channel_get_variable(channel, "sip-force-contact")) ||
+					((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val))) {
+					sticky = tech_pvt->record_route;
+					switch_channel_set_variable(channel, "sip_nat_detected", "true");
 				}
-			}
-			
-		}
-		
-		break;
-	case nua_callstate_terminating:
-		break;
-	case nua_callstate_terminated: 
-		if (session) {
-			if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
-                
-				switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-				if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) {
-					switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
-				} else {
-					snprintf(st, sizeof(st), "%d", status);
-					switch_channel_set_variable(channel, "sip_term_status", st);
-					terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__);
+
+				if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+					nua_respond(tech_pvt->nh,
+								SIP_183_SESSION_PROGRESS,
+								NUTAG_AUTOANSWER(0),
+								TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
+								SIPTAG_HEADER_STR(generate_pai_str(session)),
+								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+								SOATAG_REUSE_REJECTED(1),
+								SOATAG_ORDERED_USER(1),
+								SOATAG_ADDRESS(tech_pvt->adv_sdp_audio_ip),
+								SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END());
 				}
 			}
-
-            if (tech_pvt->sofia_private) {
-                free(tech_pvt->sofia_private);
-                tech_pvt->sofia_private = NULL;
-            }
-			tech_pvt->nh = NULL;
-		} else if (sofia_private) {
-            free(sofia_private);
-        }
-
-		if (nh) {
-            nua_handle_bind(nh, NULL);
-			nua_handle_destroy(nh);
 		}
 		break;
+	default:
+		break;
 	}
 
- done:
+ end_lock:
 
-    if (session) {
-        switch_core_session_rwunlock(session);
-    }
-}
+	switch_mutex_unlock(tech_pvt->sofia_mutex);
 
+  end:
 
-static char *get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t *mutex)
-{
-	switch_core_db_t *db;
-	switch_core_db_stmt_t *stmt;
-	char *sql = NULL, *ret = NULL;
-
-	if (mutex) {
-		switch_mutex_lock(mutex);
+	if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		status = SWITCH_STATUS_FALSE;
 	}
 
-	if (!dbname) {
-		goto end;
-	}
+	return status;
 
-	if (!(db = switch_core_db_open_file(dbname))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname);
-		goto end;
-	}
+}
 
-	sql = switch_mprintf("select passwd from sip_authentication where nonce='%q'", nonce);
-	if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error!\n");
-		goto fail;
-	} else {
-		int running = 1;
-		int colcount;
+static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event)
+{
+	struct private_object *tech_pvt = switch_core_session_get_private(session);
+	char *body;
+	nua_handle_t *msg_nh;
 
-		while (running < 5000) {
-			int result = switch_core_db_step(stmt);
+	switch_assert(tech_pvt != NULL);
 
-			if (result == SQLITE_ROW) {
-				if ((colcount = switch_core_db_column_count(stmt))) {
-					switch_copy_string(npassword, (char *)switch_core_db_column_text(stmt, 0), len);
-					ret = npassword;
-				}
-				break;
-			} else if (result == SQLITE_BUSY) {
-				running++;
-				switch_yield(1000);
-				continue;
-			}
-			break;
-		}
-			
-		switch_core_db_finalize(stmt);
+	if (!(body = switch_event_get_body(event))) {
+		body = "";
 	}
-	
 
- fail:
-
-	switch_core_db_close(db);
-
- end:
-	if (mutex) {
-		switch_mutex_unlock(mutex);
+	if (tech_pvt->hash_key) {
+		switch_mutex_lock(tech_pvt->sofia_mutex);
+		msg_nh = nua_handle(tech_pvt->profile->nua, NULL,
+							SIPTAG_FROM_STR(tech_pvt->chat_from),
+							NUTAG_URL(tech_pvt->chat_to), SIPTAG_TO_STR(tech_pvt->chat_to), SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END());
+		nua_handle_bind(msg_nh, &mod_sofia_globals.destroy_private);
+		nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END());
+		switch_mutex_unlock(tech_pvt->sofia_mutex);
 	}
 
-	if (sql) {
-		switch_safe_free(sql);
-	}
-	
-	return ret;
+	return SWITCH_STATUS_SUCCESS;
 }
 
+typedef switch_status_t (*sofia_command_t) (char **argv, int argc, switch_stream_handle_t *stream);
 
-typedef enum {
-	REG_REGISTER,
-	REG_INVITE
-} sofia_regtype_t;
+static const char *sofia_state_names[] = { 
+	"UNREGED",
+	"TRYING",
+	"REGISTER",
+	"REGED",
+	"UNREGISTER",
+	"FAILED",
+	"FAIL_WAIT",
+	"EXPIRED",
+	"NOREG",
+	NULL
+};
 
-static uint8_t handle_register(nua_t *nua,
-							   sofia_profile_t *profile,
-							   nua_handle_t *nh,
-							   sip_t const *sip,
-							   sofia_regtype_t regtype,
-							   char *key,
-							   uint32_t keylen)
+const char * sofia_state_string(int state) 
 {
-	sip_from_t const *from = NULL;
-	sip_expires_t const *expires = NULL;
-	sip_authorization_t const *authorization = NULL;
-	sip_contact_t const *contact = NULL;
-	switch_xml_t domain, xml, user, param, xparams;
-	char params[1024] = "";
-	char *sql;
-	switch_event_t *s_event;
-	const char *from_user = NULL;
-	const char *from_host = NULL;
-	char contact_str[1024] = "";
-	char buf[512];
-	const char *passwd = NULL;
-	const char *a1_hash = NULL;
-	uint8_t stale = 0, ret = 0, forbidden = 0;
-	auth_res_t auth_res;
-	long exptime = 60;
-	switch_event_t *event;
-	const char *rpid = "unknown";
-	const char *display = "\"user\"";
+	return sofia_state_names[state];
+}
 
-	/* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */
-	assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL);
+struct cb_helper {
+	sofia_profile_t *profile;
+	switch_stream_handle_t *stream;
+};
 
-	expires = sip->sip_expires;
-	authorization = sip->sip_authorization;
-	contact = sip->sip_contact;
-	from = sip->sip_from;
 
-	if (from) {
-		from_user = from->a_url->url_user;
-		from_host = from->a_url->url_host;
-	}
 
-	if (!from_user || !from_host) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete from header\n");
-		nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
-		return 1;
-	}
+static int show_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	struct cb_helper *cb = (struct cb_helper *) pArg;
+	char exp_buf[128] = "";
+	switch_time_exp_t tm;
 
-	if (contact->m_url) {
-		const char *port = contact->m_url->url_port;
-		display = contact->m_display;
+	if (argv[6]) {
+		switch_time_t etime = atoi(argv[6]);
+		switch_size_t retsize;
 
-		if (switch_strlen_zero(display)) {
-			if (from) {
-				display = from->a_display;
-				if (switch_strlen_zero(display)) {
-					display = "\"user\"";
-				}
-			}
-		}
-		
-		if (!port) {
-			port = "5060";
-		}
-
-		if (contact->m_url->url_params) {
-			snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s;%s>", 
-					 display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params);
-		} else {
-			snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s>", 
-					 display, contact->m_url->url_user, contact->m_url->url_host, port);
-		}
+		switch_time_exp_lt(&tm, switch_time_from_sec(etime));
+		switch_strftime_nocheck(exp_buf, &retsize, sizeof(exp_buf), "%Y-%m-%d %T", &tm);
 	}
-	
-	if (expires) {
-		exptime = expires->ex_delta;
-	} else if (contact->m_expires) {
-		exptime = atol(contact->m_expires);
-	} 
 
-	if (regtype == REG_REGISTER) {
-		authorization = sip->sip_authorization;
-	} else if (regtype == REG_INVITE) {
-		authorization = sip->sip_proxy_authorization;
-	}
+	cb->stream->write_function(cb->stream,
+							   "Call-ID:    \t%s\n"
+							   "User:       \t%s@%s\n"
+							   "Contact:    \t%s\n"
+							   "Agent:      \t%s\n"
+							   "Status:     \t%s(%s) EXP(%s)\n"
+							   "Host:       \t%s\n"
+							   "IP:         \t%s\n"
+							   "Port:       \t%s\n"
+							   "Auth-User:  \t%s\n"
+							   "Auth-Realm: \t%s\n\n",
+							   switch_str_nil(argv[0]), switch_str_nil(argv[1]), switch_str_nil(argv[2]), switch_str_nil(argv[3]),
+							   switch_str_nil(argv[7]), switch_str_nil(argv[4]), switch_str_nil(argv[5]), exp_buf, switch_str_nil(argv[11]),
+							   switch_str_nil(argv[12]), switch_str_nil(argv[13]), switch_str_nil(argv[14]), switch_str_nil(argv[15]));
+	return 0;
+}
 
-	if ((profile->pflags & PFLAG_BLIND_REG)) {
-		goto reg;
+static int show_reg_callback_xml(void *pArg, int argc, char **argv, char **columnNames)
+{
+	struct cb_helper *cb = (struct cb_helper *) pArg;
+	char exp_buf[128] = "";
+	switch_time_exp_t tm;
+	const int buflen = 2048;
+	char xmlbuf[2048];
+  
+	if (argv[6]) {
+		switch_time_t etime = atoi(argv[6]);
+		switch_size_t retsize;
+
+		switch_time_exp_lt(&tm, switch_time_from_sec(etime));
+		switch_strftime_nocheck(exp_buf, &retsize, sizeof(exp_buf), "%Y-%m-%d %T", &tm);
 	}
 
-	if (authorization) {
-		if ((auth_res = parse_auth(profile, authorization, sip->sip_request->rq_method_name, key, keylen)) == AUTH_STALE) {
-            stale = 1;
-        }
+	cb->stream->write_function(cb->stream,
+							   "    <registration>\n"
+							   "        <call-id>%s</call-id>\n"
+							   "        <user>%s@%s</user>\n"
+							   "        <contact>%s</contact>\n"
+							   "        <agent>%s</agent>\n"
+							   "        <status>%s(%s) exp(%s)</status>\n"
+							   "        <host>%s</host>\n"
+							   "        <network-ip>%s</network-ip>\n"
+							   "        <network-port>%s</network-port>\n"
+							   "        <sip-auth-user>%s</sip-auth-user>\n"
+							   "        <sip-auth-realm>%s</sip-auth-realm>\n"
+							   "    </registration>\n", 
+							   switch_str_nil(argv[0]), switch_str_nil(argv[1]), switch_str_nil(argv[2]), 
+							   switch_amp_encode(switch_str_nil(argv[3]),xmlbuf,buflen),
+							   switch_str_nil(argv[7]), switch_str_nil(argv[4]), switch_str_nil(argv[5]), exp_buf, switch_str_nil(argv[11]),
+							   switch_str_nil(argv[12]), switch_str_nil(argv[13]), switch_str_nil(argv[14]), switch_str_nil(argv[15]));
+	return 0;
+}
 
-		if (auth_res != AUTH_OK && !stale) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send %s for [%s@%s]\n",
-							  forbidden ? "forbidden" : "challange",
-							  from_user, from_host);
-			if (auth_res == AUTH_FORBIDDEN) {
-				nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
-			} else {
-				nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
-			}
-			return 1;
-		}
-	} 
+static const char *status_names[] = { "DOWN", "UP", NULL };
 
-	if (!authorization || stale) {
-		snprintf(params, sizeof(params), "from_user=%s&from_host=%s&contact=%s",
-				 from_user,
-				 from_host,
-				 contact_str
-				 );
+static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t *stream)
+{
+	sofia_profile_t *profile = NULL;
+	sofia_gateway_t *gp;
+	switch_hash_index_t *hi;
+	void *val;
+	const void *vvar;
+	int c = 0;
+	int ac = 0;
+	const char *line = "=================================================================================================";
 
-		
-		if (switch_xml_locate("directory", "domain", "name", from_host, &xml, &domain, params) != SWITCH_STATUS_SUCCESS) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find domain for [%s@%s]\n", from_user, from_host);
-			nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
-			return 1;
+	if (argc > 0) {
+		if (argc == 1) {
+			stream->write_function(stream, "Invalid Syntax!\n");
+			return SWITCH_STATUS_SUCCESS;
 		}
+		if (!strcasecmp(argv[0], "gateway")) {
+			if ((gp = sofia_reg_find_gateway(argv[1]))) {
+				switch_assert(gp->state < REG_STATE_LAST);
 
-		if (!(user = switch_xml_find_child(domain, "user", "id", from_user))) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", from_user, from_host);
-			nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
-			switch_xml_free(xml);
-			return 1;
-		}
-
-		if (!(xparams = switch_xml_child(user, "params"))) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find params for user [%s@%s]\n", from_user, from_host);
-			nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
-			switch_xml_free(xml);
-			return 1;
-		}
-	
-
-		for (param = switch_xml_child(xparams, "param"); param; param = param->next) {
-			const char *var = switch_xml_attr_soft(param, "name");
-			const char *val = switch_xml_attr_soft(param, "value");
-		
-			if (!strcasecmp(var, "password")) {
-				passwd = val;
+				stream->write_function(stream, "%s\n", line);
+				stream->write_function(stream, "Name    \t%s\n", switch_str_nil(gp->name));
+				stream->write_function(stream, "Scheme  \t%s\n", switch_str_nil(gp->register_scheme));
+				stream->write_function(stream, "Realm   \t%s\n", switch_str_nil(gp->register_realm));
+				stream->write_function(stream, "Username\t%s\n", switch_str_nil(gp->register_username));
+				stream->write_function(stream, "Password\t%s\n", switch_strlen_zero(gp->register_password) ? "no" : "yes");
+				stream->write_function(stream, "From    \t%s\n", switch_str_nil(gp->register_from));
+				stream->write_function(stream, "Contact \t%s\n", switch_str_nil(gp->register_contact));
+				stream->write_function(stream, "Exten   \t%s\n", switch_str_nil(gp->extension));
+				stream->write_function(stream, "To      \t%s\n", switch_str_nil(gp->register_to));
+				stream->write_function(stream, "Proxy   \t%s\n", switch_str_nil(gp->register_proxy));
+				stream->write_function(stream, "Context \t%s\n", switch_str_nil(gp->register_context));
+				stream->write_function(stream, "Expires \t%s\n", switch_str_nil(gp->expires_str));
+				stream->write_function(stream, "Freq    \t%d\n", gp->freq);
+				stream->write_function(stream, "Ping    \t%d\n", gp->ping);
+				stream->write_function(stream, "PingFreq\t%d\n", gp->ping_freq);
+				stream->write_function(stream, "State   \t%s\n", sofia_state_names[gp->state]);
+				stream->write_function(stream, "Status  \t%s%s\n", status_names[gp->status], gp->pinging ? " (ping)" : "");
+				stream->write_function(stream, "CallsIN \t%d\n", gp->ib_calls);
+				stream->write_function(stream, "CallsOUT\t%d\n", gp->ob_calls);
+				stream->write_function(stream, "%s\n", line);
+				sofia_reg_release_gateway(gp);
+			} else {
+				stream->write_function(stream, "Invalid Gateway!\n");
 			}
+		} else if (!strcasecmp(argv[0], "profile")) {
+			struct cb_helper cb;
+			char *sql = NULL;
 
-			if (!strcasecmp(var, "a1-hash")) {
-                a1_hash = val;
-			}
-		}
-	
-		if (passwd || a1_hash) {
-			switch_uuid_t uuid;
-			char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
-			char *sql, *auth_str;
+			if ((argv[1]) && (profile = sofia_glue_find_profile(argv[1]))) {
+				if (!argv[2] || strcasecmp(argv[2], "reg")) {
+					stream->write_function(stream, "%s\n", line);
+					stream->write_function(stream, "Name             \t%s\n", switch_str_nil(argv[1]));
+					stream->write_function(stream, "Domain Name      \t%s\n", profile->domain_name ? profile->domain_name : "N/A");
+					if (strcasecmp(argv[1], profile->name)) {
+					stream->write_function(stream, "Alias Of         \t%s\n", switch_str_nil(profile->name));
+					}
+					stream->write_function(stream, "DBName           \t%s\n", switch_str_nil(profile->dbname));
+					stream->write_function(stream, "Pres Hosts       \t%s\n", switch_str_nil(profile->presence_hosts));
+					stream->write_function(stream, "Dialplan         \t%s\n", switch_str_nil(profile->dialplan));
+					stream->write_function(stream, "Context          \t%s\n", switch_str_nil(profile->context));
+					stream->write_function(stream, "Challenge Realm  \t%s\n", 
+										   switch_strlen_zero(profile->challenge_realm) ? "auto_to" : profile->challenge_realm);
+					stream->write_function(stream, "RTP-IP           \t%s\n", switch_str_nil(profile->rtpip));
+					if (profile->extrtpip) {
+					stream->write_function(stream, "Ext-RTP-IP       \t%s\n", profile->extrtpip);
+					}
 
-			su_md5_t ctx;
-			char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1];
-			char *input;
+					stream->write_function(stream, "SIP-IP           \t%s\n", switch_str_nil(profile->sipip));
+					if (profile->extsipip) {
+					stream->write_function(stream, "Ext-SIP-IP       \t%s\n", profile->extsipip);
+					}
+					stream->write_function(stream, "URL              \t%s\n", switch_str_nil(profile->url));
+					stream->write_function(stream, "BIND-URL         \t%s\n", switch_str_nil(profile->bindurl));
+					if (sofia_test_pflag(profile, PFLAG_TLS)) {
+					stream->write_function(stream, "TLS-URL          \t%s\n", switch_str_nil(profile->tls_url));
+					stream->write_function(stream, "TLS-BIND-URL     \t%s\n", switch_str_nil(profile->tls_bindurl));
+					}
+					stream->write_function(stream, "HOLD-MUSIC       \t%s\n", switch_strlen_zero(profile->hold_music) ? "N/A" : profile->hold_music);
+					stream->write_function(stream, "OUTBOUND-PROXY   \t%s\n", switch_strlen_zero(profile->outbound_proxy) ? "N/A" : profile->outbound_proxy);
+					stream->write_function(stream, "CODECS           \t%s\n", switch_str_nil(profile->codec_string));
+					stream->write_function(stream, "TEL-EVENT        \t%d\n", profile->te);
+					if (profile->dtmf_type == DTMF_2833) {
+					stream->write_function(stream, "DTMF-MODE        \trfc2833\n");
+					} else if (profile->dtmf_type == DTMF_INFO) {
+					stream->write_function(stream, "DTMF-MODE        \tinfo\n");
+					} else {
+					stream->write_function(stream, "DTMF-MODE        \tnone\n");
+					}
+					stream->write_function(stream, "CNG              \t%d\n", profile->cng_pt);
+					stream->write_function(stream, "SESSION-TO       \t%d\n", profile->session_timeout);
+					stream->write_function(stream, "MAX-DIALOG       \t%d\n", profile->max_proceeding);
+					stream->write_function(stream, "NOMEDIA          \t%s\n", sofia_test_flag(profile, TFLAG_INB_NOMEDIA) ? "true" : "false");
+					stream->write_function(stream, "LATE-NEG         \t%s\n", sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION) ? "true" : "false");
+					stream->write_function(stream, "PROXY-MEDIA      \t%s\n", sofia_test_flag(profile, TFLAG_PROXY_MEDIA) ? "true" : "false");
+					stream->write_function(stream, "AGGRESSIVENAT    \t%s\n", sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? "true" : "false");
+					stream->write_function(stream, "STUN-ENABLED     \t%s\n", sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? "true" : "false");
+					stream->write_function(stream, "STUN-AUTO-DISABLE\t%s\n", sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? "true" : "false");
+					stream->write_function(stream, "CALLS-IN         \t%d\n", profile->ib_calls);
+					stream->write_function(stream, "FAILED-CALLS-IN  \t%d\n", profile->ib_failed_calls);
+					stream->write_function(stream, "CALLS-OUT        \t%d\n", profile->ob_calls);
+					stream->write_function(stream, "FAILED-CALLS-OUT \t%d\n", profile->ob_failed_calls);
+				}
+				stream->write_function(stream, "\nRegistrations:\n%s\n", line);
 
-            if (!a1_hash) {
-                input = switch_mprintf("%s:%s:%s", from_user, from_host, passwd);
-                su_md5_init(&ctx);
-                su_md5_strupdate(&ctx, input);
-                su_md5_hexdigest(&ctx, hexdigest);
-                su_md5_deinit(&ctx);
-                switch_safe_free(input);
+				cb.profile = profile;
+				cb.stream = stream;
+				
+				if (argv[3]) {
+					if (argv[4]) {
+						if (!strcasecmp(argv[3], "pres")) {
+							sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
+												 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
+												 "network_ip,network_port,sip_username,sip_realm"
+												 " from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", 
+												 profile->name, argv[4]);
+						}
+					} else {
+						sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
+											 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
+											 "network_ip,network_port,sip_username,sip_realm"
+											 " from sip_registrations where profile_name='%q' and contact like '%%%q%%'", 
+											 profile->name, argv[3]);
+					}
+				}
 
-                switch_uuid_get(&uuid);
-                switch_uuid_format(uuid_str, &uuid);
-                a1_hash = hexdigest;
-            }
+				if (!sql) {
+					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
+										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
+										 "network_ip,network_port,sip_username,sip_realm"
+										 " from sip_registrations where profile_name='%q'", 
+										 profile->name);
+				}
 
-			sql = switch_mprintf("delete from sip_authentication where user='%q' and host='%q';\n"
-                                 "insert into sip_authentication values('%q','%q','%q','%q', %ld)",
-                                 from_user,
-                                 from_host,
-                                 from_user,
-                                 from_host,
-                                 a1_hash,
-                                 uuid_str,
-                                 time(NULL) + profile->nonce_ttl);
-			auth_str = switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", from_host, uuid_str, 
-											  stale ? " stale=\"true\"," : "");
+				sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, show_reg_callback, &cb);
+				free(sql);
 
+				stream->write_function(stream, "%s\n", line);
 
-			if (regtype == REG_REGISTER) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", from_user, from_host);
-				nua_respond(nh, SIP_401_UNAUTHORIZED,
-							NUTAG_WITH_THIS(nua),
-							SIPTAG_WWW_AUTHENTICATE_STR(auth_str),
-							TAG_END());
-			} else if (regtype == REG_INVITE) {
-				nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,
-							NUTAG_WITH_THIS(nua),
-							SIPTAG_PROXY_AUTHENTICATE_STR(auth_str),
-							TAG_END());
-
+				sofia_glue_release_profile(profile);
+			} else {
+				stream->write_function(stream, "Invalid Profile!\n");
 			}
-
-			execute_sql(profile->dbname, sql, profile->ireg_mutex);
-			switch_safe_free(sql);
-			switch_safe_free(auth_str);
-			ret = 1;
 		} else {
-			ret = 0;
+			stream->write_function(stream, "Invalid Syntax!\n");
 		}
-		
-		switch_xml_free(xml);
 
-		if (ret) {
-			return ret;
-		}
+		return SWITCH_STATUS_SUCCESS;
 	}
- reg:
 
-	if (exptime) {
-		if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
-			sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Registered', '%q', %ld)", 
-								 from_user,
-								 from_host,
-								 contact_str,
-								 rpid,
-								 (long) time(NULL) + (long)exptime * 2);
+	stream->write_function(stream, "%25s\t%s\t  %32s\t%s\n", "Name", "   Type", "Data", "State");
+	stream->write_function(stream, "%s\n", line);
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+		switch_hash_this(hi, &vvar, NULL, &val);
+		profile = (sofia_profile_t *) val;
+		if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
 
-		} else {
-			sql = switch_mprintf("update sip_registrations set contact='%q', expires=%ld, rpid='%q' where user='%q' and host='%q'",
-								 contact_str,
-								 (long) time(NULL) + (long)exptime * 2,
-								 rpid,
-								 from_user,
-								 from_host);
-		
-		}
+			if (strcmp(vvar, profile->name)) {
+				ac++;
+				stream->write_function(stream, "%25s\t%s\t  %32s\t%s\n", vvar, "  alias", profile->name, "ALIASED");
+			} else {
+				stream->write_function(stream, "%25s\t%s\t  %32s\t%s (%u)\n", profile->name, "profile", profile->url,
+									   sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN", profile->inuse);
 
-		if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) {
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", profile->name);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-user", "%s", from_user);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-host", "%s", from_host);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", contact_str);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long)exptime);
-			switch_event_fire(&s_event);
-		}
+				if (sofia_test_pflag(profile, PFLAG_TLS)) {
+					stream->write_function(stream, "%25s\t%s\t  %32s\t%s (%u) (TLS)\n", profile->name, "profile", profile->tls_url,
+										   sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN", profile->inuse);
+				}
 
-		if (sql) {
-			execute_sql(profile->dbname, sql, profile->ireg_mutex);
-			switch_safe_free(sql);
-			sql = NULL;
-		}
-	
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Register:\nFrom:    [%s@%s]\nContact: [%s]\nExpires: [%ld]\n", 
-						  from_user, 
-						  from_host,
-					  contact_str,
-					  (long)exptime
-					  );
+				c++;
 
-
-		if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
-			
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Registered");
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
-			switch_event_fire(&event);
+				for (gp = profile->gateways; gp; gp = gp->next) {
+					switch_assert(gp->state < REG_STATE_LAST);
+					stream->write_function(stream, "%25s\t%s\t  %32s\t%s", gp->name, "gateway", gp->register_to, sofia_state_names[gp->state]);
+					if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) {
+						time_t now = switch_epoch_time_now(NULL);
+						if (gp->retry > now) {
+							stream->write_function(stream, " (retry: %ds)", gp->retry - now);
+						} else {
+							stream->write_function(stream, " (retry: NEVER)");
+						}
+					}
+					stream->write_function(stream, "\n");
+				}
+			}
 		}
-	} else {
-		if ((sql = switch_mprintf("delete from sip_subscriptions where user='%q' and host='%q'", from_user, from_host))) {
-			execute_sql(profile->dbname, sql, profile->ireg_mutex);
-			switch_safe_free(sql);
-			sql = NULL;
-		}
-		if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_PROTO, from_user, from_host);
-		
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "unavailable");
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
-			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
-			switch_event_fire(&event);
-		}
 	}
-
-
-	if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) {
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
-		switch_event_fire(&event);
-	}
-
-	if (regtype == REG_REGISTER) {
-		nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(contact),
-					NUTAG_WITH_THIS(nua),
-					TAG_END());
-		return 1;
-	}
-
-	return 0;
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+	stream->write_function(stream, "%s\n", line);
+	stream->write_function(stream, "%d profile%s %d alias%s\n", c, c == 1 ? "" : "s", ac, ac == 1 ? "" : "es");
+	return SWITCH_STATUS_SUCCESS;
 }
 
-
-static int sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
+static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handle_t *stream)
 {
-	sofia_profile_t *profile = (sofia_profile_t *) pArg;
-	//char *proto = argv[0];
-	char *user = argv[1];
-	char *host = argv[2];
-	switch_event_t *event;
-	char *status = NULL;
-	if (switch_strlen_zero(status)) {
-		status = "Available";
-	}
-	if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe");
-		switch_event_fire(&event);
-	}
-
-	return 0;
-}
-
-static int resub_callback(void *pArg, int argc, char **argv, char **columnNames)
-{
-	sofia_profile_t *profile = (sofia_profile_t *) pArg;
-	char *user = argv[0];
-	char *host = argv[1];
-	char *status = argv[2];
-	char *rpid = argv[3];
-	char *proto = argv[4];
-	switch_event_t *event;
-
-	if (switch_strlen_zero(proto)) {
-		proto = NULL;
-	}
-
-	if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%s", proto ? proto : SOFIA_CHAT_PROTO);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
-		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
-		switch_event_fire(&event);
-	}
-
-	return 0;
-}
-
-static int sub_callback(void *pArg, int argc, char **argv, char **columnNames)
-{
-	sofia_profile_t *profile = (sofia_profile_t *) pArg;
-	char *pl;
-	char *id, *note;
-	uint32_t in = atoi(argv[0]);
-	char *status = argv[1];
-	char *rpid = argv[2];
-	char *proto = argv[3];
-	char *user = argv[4];
-	char *host = argv[5];
-	char *sub_to_user = argv[6];
-	char *sub_to_host = argv[7];
-	char *event = argv[8];
-	char *contact = argv[9];
-	char *callid = argv[10];
-	char *full_from = argv[11];
-	char *full_via = argv[12];
-	nua_handle_t *nh;
-	char *to;
-	char *open;
-	char *tmp;
-
-	if (!rpid) {
-		rpid = "unknown";
-	}
-
-	if (in) {
-		note = switch_mprintf("<dm:note>%s</dm:note>", status);
-		open = "open";
-	} else {
-		note = NULL;
-		open = "closed";
-	}
-
-    if (!strcasecmp(sub_to_host, host)) {
-        /* same host */
-		id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
-	} else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) {
-		/*encapsulate*/
-		id = switch_mprintf("sip:%s+%s+%s@%s", proto, sub_to_user, sub_to_host, host);
-	} else {
-		id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
-	}
-
-	to = switch_mprintf("sip:%s@%s", user, host);
-	pl = switch_mprintf("<?xml version='1.0' encoding='UTF-8'?>\r\n"
-								"<presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n"
-								"xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n"
-								"xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n"
-								"xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n"
-								"entity='pres:%s'>\r\n"
-								"<tuple id='t6a5ed77e'>\r\n"
-								"<status>\r\n"
-								"<basic>%s</basic>\r\n"
-								"</status>\r\n"
-								"</tuple>\r\n"
-								"<dm:person id='p06360c4a'>\r\n"
-								"<rpid:activities>\r\n"
-								"<rpid:%s/>\r\n"
-								"</rpid:activities>%s</dm:person>\r\n"
-								"</presence>", id, open, rpid, note);
-
+	sofia_profile_t *profile = NULL;
+	sofia_gateway_t *gp;
+	switch_hash_index_t *hi;
+	void *val;
+	const void *vvar;
+	const int buflen = 2096;
+	char xmlbuf[2096];
+	int c = 0;
+	int ac = 0;
+  const char *header = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
 	
+  if (argc > 0) {
+		if (argc == 1) {
+			stream->write_function(stream, "Invalid Syntax!\n");
+			return SWITCH_STATUS_SUCCESS;
+		}
+		if (!strcasecmp(argv[0], "gateway")) {
+			if ((gp = sofia_reg_find_gateway(argv[1]))) {
+				switch_assert(gp->state < REG_STATE_LAST);
+				stream->write_function(stream, "%s\n", header);
+				stream->write_function(stream, "  <gateway>\n");
+				stream->write_function(stream, "    <name>%s</name>\n", switch_str_nil(gp->name));
+				stream->write_function(stream, "    <scheme>%s</scheme>\n", switch_str_nil(gp->register_scheme));
+				stream->write_function(stream, "    <realm>%s</realm>\n", switch_str_nil(gp->register_realm));
+				stream->write_function(stream, "    <username>%s</username>\n", switch_str_nil(gp->register_username));
+				stream->write_function(stream, "    <password>%s</password>\n", switch_strlen_zero(gp->register_password) ? "no" : "yes");
+				stream->write_function(stream, "    <from>%s</from>\n", switch_amp_encode(switch_str_nil(gp->register_from),xmlbuf,buflen));
+				stream->write_function(stream, "    <contact>%s</contact>\n", switch_amp_encode(switch_str_nil(gp->register_contact),xmlbuf,buflen));
+				stream->write_function(stream, "    <exten>%s</exten>\n", switch_amp_encode(switch_str_nil(gp->extension),xmlbuf,buflen));
+				stream->write_function(stream, "    <to>%s</to>\n", switch_str_nil(gp->register_to));
+				stream->write_function(stream, "    <proxy>%s</proxy>\n", switch_str_nil(gp->register_proxy));
+				stream->write_function(stream, "    <context>%s</context>\n", switch_str_nil(gp->register_context));
+				stream->write_function(stream, "    <expires>%s</expires>\n", switch_str_nil(gp->expires_str));
+				stream->write_function(stream, "    <freq>%d</freq>\n", gp->freq);
+				stream->write_function(stream, "    <ping>%d</ping>\n", gp->ping);
+				stream->write_function(stream, "    <pingfreq>%d</pingfreq>\n", gp->ping_freq);
+				stream->write_function(stream, "    <state>%s</state>\n", sofia_state_names[gp->state]);
+				stream->write_function(stream, "    <status>%s%s</status>\n", status_names[gp->status], gp->pinging ? " (ping)" : "");
+				stream->write_function(stream, "    <calls-in>%d</calls-in>\n", gp->ib_calls);
+				stream->write_function(stream, "    <calls-out>%d</calls-out>\n", gp->ob_calls);
 
-	nh = nua_handle(profile->nua, NULL,	TAG_END());
-	tmp = contact;
-	contact = get_url_from_contact(tmp, 0);
+				stream->write_function(stream, "  </gateway>\n");
+				sofia_reg_release_gateway(gp);
+			} else {
+				stream->write_function(stream, "Invalid Gateway!\n");
+			}
+		} else if (!strcasecmp(argv[0], "profile")) {
+			struct cb_helper cb;
+			char *sql = NULL;
 
-	nua_notify(nh,
-			   NUTAG_URL(contact),
-			   SIPTAG_TO_STR(full_from),
-			   SIPTAG_FROM_STR(id),
-			   SIPTAG_CONTACT_STR(profile->url),
-			   SIPTAG_CALL_ID_STR(callid),
-			   SIPTAG_VIA_STR(full_via),
-			   SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=3600"),
-			   SIPTAG_EVENT_STR(event),
-			   SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
-			   SIPTAG_PAYLOAD_STR(pl),
-			   TAG_END());
+			if ((argv[1]) && (profile = sofia_glue_find_profile(argv[1]))) {
+				stream->write_function(stream, "%s\n", header);
+				stream->write_function(stream, "<profile>\n");
+				if (!argv[2] || strcasecmp(argv[2], "reg")) {
+					stream->write_function(stream, "  <profile-info>\n");
+					stream->write_function(stream, "    <name>%s</name>\n", switch_str_nil(argv[1]));
+					stream->write_function(stream, "    <domain-name>%s</domain-name>\n", profile->domain_name ? profile->domain_name : "N/A");
+					if (strcasecmp(argv[1], profile->name)) {
+						stream->write_function(stream, "    <alias-of>%s</alias-of>\n", switch_str_nil(profile->name));
+					}
+					stream->write_function(stream, "    <db-name>%s</db-name>\n", switch_str_nil(profile->dbname));
+					stream->write_function(stream, "    <pres-hosts>%s</pres-hosts>\n", switch_str_nil(profile->presence_hosts));
+					stream->write_function(stream, "    <dialplan>%s</dialplan>\n", switch_str_nil(profile->dialplan));
+					stream->write_function(stream, "    <context>%s</context>\n", switch_str_nil(profile->context));
+					stream->write_function(stream, "    <challenge-realm>%s</challenge-realm>\n", 
+										   switch_strlen_zero(profile->challenge_realm) ? "auto_to" : profile->challenge_realm);
+					stream->write_function(stream, "    <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip));
+					stream->write_function(stream, "    <ext-rtp-ip>%s</ext-rtp-ip>\n", profile->extrtpip);
+					stream->write_function(stream, "    <sip-ip>%s</sip-ip>\n", switch_str_nil(profile->sipip));
+					stream->write_function(stream, "    <ext-sip-ip>%s</ext-sip-ip>\n", profile->extsipip);
+					stream->write_function(stream, "    <url>%s</url>\n", switch_str_nil(profile->url));
+					stream->write_function(stream, "    <bind-url>%s</bind-url>\n", switch_str_nil(profile->bindurl));
+					stream->write_function(stream, "    <tls-url>%s</tls-url>\n", switch_str_nil(profile->tls_url));
+					stream->write_function(stream, "    <tls-bind-url>%s</tls-bind-url>\n", switch_str_nil(profile->tls_bindurl));
+					stream->write_function(stream, "    <hold-music>%s</hold-music>\n", switch_strlen_zero(profile->hold_music) ? "N/A" : profile->hold_music);
+					stream->write_function(stream, "    <outbound-proxy>%s</outbound-proxy>\n", switch_strlen_zero(profile->outbound_proxy) ? "N/A" : profile->outbound_proxy);
+					stream->write_function(stream, "    <codecs>%s</codecs>\n", switch_str_nil(profile->codec_string));
+					stream->write_function(stream, "    <tel-event>%d</tel-event>\n", profile->te);
+					stream->write_function(stream, "    <dtmf-mode>rfc2833</dtmf-mode>\n");
+					stream->write_function(stream, "    <dtmf-mode>info</dtmf-mode>\n");
+					stream->write_function(stream, "    <dtmf-mode>none</dtmf-mode>\n");
+					stream->write_function(stream, "    <cng>%d</cng>\n", profile->cng_pt);
+					stream->write_function(stream, "    <session-to>%d</session-to>\n", profile->session_timeout);
+					stream->write_function(stream, "    <max-dialog>%d</max-dialog>\n", profile->max_proceeding);
+					stream->write_function(stream, "    <nomedia>%s</nomedia>\n", sofia_test_flag(profile, TFLAG_INB_NOMEDIA) ? "true" : "false");
+					stream->write_function(stream, "    <late-neg>%s</late-neg>\n", sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION) ? "true" : "false");
+					stream->write_function(stream, "    <proxy-media>%s</proxy-media>\n", sofia_test_flag(profile, TFLAG_PROXY_MEDIA) ? "true" : "false");
+					stream->write_function(stream, "    <aggressive-nat>%s</aggressive-nat>\n", 
+										   sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? "true" : "false");
+					stream->write_function(stream, "    <stun-enabled>%s</stun-enabled>\n", sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? "true" : "false");
+					stream->write_function(stream, "    <stun-auto-disable>%s</stun-auto-disable>\n", 
+										   sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? "true" : "false");
+					stream->write_function(stream, "    <calls-in>%d</calls-in>\n", profile->ib_calls);
+					stream->write_function(stream, "    <calls-out>%d</calls-out>\n", profile->ob_calls);
+					stream->write_function(stream, "    <failed-calls-in>%d</failed-calls-in>\n", profile->ib_failed_calls);
+					stream->write_function(stream, "    <failed-calls-out>%d</failed-calls-out>\n", profile->ob_failed_calls);
+					stream->write_function(stream, "  </profile-info>\n");
+				}
+				stream->write_function(stream, "  <registrations>\n");
 
-	switch_safe_free(id);
-	switch_safe_free(note);
-	switch_safe_free(pl);
-	switch_safe_free(to);
-
-	return 0;
-}
-
-static void sip_i_subscribe(int status,
-						char const *phrase, 
-						nua_t *nua,
-						sofia_profile_t *profile,
-						nua_handle_t *nh,
-						sofia_private_t *sofia_private,
-						sip_t const *sip,
-						tagi_t tags[])
-{
-		if (sip) {
-			long exp, exp_raw;
-			sip_to_t const *to = sip->sip_to;
-			sip_from_t const *from = sip->sip_from;
-			sip_contact_t const *contact = sip->sip_contact;
-			char *from_user = NULL;
-			char *from_host = NULL;
-			char *to_user = NULL;
-			char *to_host = NULL;
-			char *sql, *event = NULL;
-			char *proto = "sip";
-			char *d_user = NULL;
-			char *contact_str = "";
-			char *call_id = NULL;
-			char *to_str = NULL;
-			char *full_from = NULL;
-			char *full_via = NULL;
-			switch_core_db_t *db;
-			char *errmsg;
-			char *sstr;
-			const char *display = "\"user\"";
-			switch_event_t *sevent;
-
-			if (contact) {
-				char *port = (char *) contact->m_url->url_port;
-
-				display = contact->m_display;
+				cb.profile = profile;
+				cb.stream = stream;
 				
-				if (switch_strlen_zero(display)) {
-					if (from) {
-						display = from->a_display;
-						if (switch_strlen_zero(display)) {
-							display = "\"user\"";
+				if (argv[3]) {
+					if (argv[4]) {
+						if (!strcasecmp(argv[3], "pres")) {
+							sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
+												 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
+												 "network_ip,network_port,sip_username,sip_realm"
+												 " from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", 
+												 profile->name, argv[4]);
 						}
+					} else {
+						sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
+											 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
+											 "network_ip,network_port,sip_username,sip_realm"
+											 " from sip_registrations where profile_name='%q' and contact like '%%%q%%'", 
+											 profile->name, argv[3]);
 					}
-				} else {
-					display = "\"user\"";
 				}
 
-				if (!port) {
-					port = "5060";
+				if (!sql) {
+					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
+										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
+										 "network_ip,network_port,sip_username,sip_realm"
+										 " from sip_registrations where profile_name='%q'", 
+										 profile->name);
 				}
 
-				if (contact->m_url->url_params) {
-					contact_str = switch_mprintf("%s <sip:%s@%s:%s;%s>", 
-												 display,
-												 contact->m_url->url_user,
-												 contact->m_url->url_host, port, contact->m_url->url_params);
-				} else {
-					contact_str = switch_mprintf("%s <sip:%s@%s:%s>", 
-												 display,
-												 contact->m_url->url_user,
-												 contact->m_url->url_host, port);
-				}
-			}
-			
-			if (to) {
-				to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host);//, to->a_url->url_port);
-			}
+				sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, show_reg_callback_xml, &cb);
+				free(sql);
 
-			if (to) {
-				to_user = (char *) to->a_url->url_user;
-				to_host = (char *) to->a_url->url_host;
+				stream->write_function(stream, "  </registrations>\n");
+				stream->write_function(stream, "</profile>\n");
+
+				sofia_glue_release_profile(profile);
+			} else {
+				stream->write_function(stream, "Invalid Profile!\n");
 			}
+		} else {
+			stream->write_function(stream, "Invalid Syntax!\n");
+		}
 
+		return SWITCH_STATUS_SUCCESS;
+	}
 
-			if (strstr(to_user, "ext+") || strstr(to_user, "user+") || strstr(to_user, "conf+")) {
-				char proto[80];
-				char *p;
+  stream->write_function(stream, "%s\n", header);
+  stream->write_function(stream, "<profiles>\n");
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+		switch_hash_this(hi, &vvar, NULL, &val);
+		profile = (sofia_profile_t *) val;
+		if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
 
-				switch_copy_string(proto, to_user, sizeof(proto));
-				if ((p = strchr(proto, '+'))) {
-					*p = '\0';
+			if (strcmp(vvar, profile->name)) {
+				ac++;
+				stream->write_function(stream, "<alias>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s</state>\n</alias>\n", vvar, "alias", profile->name, "ALIASED");
+			} else {
+				stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%u)</state>\n</profile>\n", profile->name, "profile", profile->url,
+									   sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN", profile->inuse);
+
+				if (sofia_test_pflag(profile, PFLAG_TLS)) {
+					stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%u) (TLS)</state>\n</profile>\n", profile->name, "profile", profile->tls_url,
+										   sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN", profile->inuse);
 				}
-				
-				if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-					switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
-					switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "login", "%s", profile->name);
-					switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s",  to_user, to_host);
-					switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "rpid", "unknown");
-					switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call");
-					switch_event_fire(&sevent);
-				}
-			}
 
-			if (strchr(to_user, '+')) {
-				char *h;
-				if ((proto = (d_user = strdup(to_user)))) {
-					if ((to_user = strchr(d_user, '+'))) {
-						*to_user++ = '\0';
-						if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
-							*h++ = '\0';
-							to_host = h;
+				c++;
+
+				for (gp = profile->gateways; gp; gp = gp->next) {
+					switch_assert(gp->state < REG_STATE_LAST);
+					stream->write_function(stream, "<gateway>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s</state>\n</gateway>\n", gp->name, "gateway", gp->register_to, sofia_state_names[gp->state]);
+					if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) {
+						time_t now = switch_epoch_time_now(NULL);
+						if (gp->retry > now) {
+							stream->write_function(stream, " (retry: %ds)", gp->retry - now);
+						} else {
+							stream->write_function(stream, " (retry: NEVER)");
 						}
 					}
+					stream->write_function(stream, "\n");
 				}
-
-				if (!(proto && to_user && to_host)) {
-					nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
-					goto end;
-				}
 			}
+		}
+	}
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+	stream->write_function(stream, "</profiles>\n");
+	return SWITCH_STATUS_SUCCESS;
+}
 
-			call_id = sip_header_as_string(profile->home, (void *)sip->sip_call_id);
-			event = sip_header_as_string(profile->home, (void *)sip->sip_event);
-			full_from = sip_header_as_string(profile->home, (void *)sip->sip_from);
-			full_via = sip_header_as_string(profile->home, (void *)sip->sip_via);
+static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t *stream)
+{
+	sofia_profile_t *profile = NULL;
+	char *profile_name = argv[0];
+	const char *err;
+	switch_xml_t xml_root;
 
-			exp_raw = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
-			exp = (long) time(NULL) + exp_raw;
-			
-            if (sip && sip->sip_from) {
-                from_user = (char *) sip->sip_from->a_url->url_user;
-                from_host = (char *) sip->sip_from->a_url->url_host;
-            } else {
-                from_user = "n/a";
-                from_host = "n/a";
-            }
+	if (argc < 2) {
+		stream->write_function(stream, "Invalid Args!\n");
+		return SWITCH_STATUS_SUCCESS;
+	}
 
-			if ((sql = switch_mprintf("delete from sip_subscriptions where "
-											  "proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n"
-											  "insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)",
-											  proto,
-											  from_user,
-											  from_host,
-											  to_user,
-											  to_host,
-											  event,
-											  proto,
-											  from_user,
-											  from_host,
-											  to_user,
-											  to_host,
-											  event,
-											  contact_str,
-											  call_id,
-											  full_from,
-											  full_via,
-											  exp
-									  ))) {
-				execute_sql(profile->dbname, sql, profile->ireg_mutex);
-				switch_safe_free(sql);
+	if (!strcasecmp(argv[1], "start")) {
+		if (argc > 2 && !strcasecmp(argv[2], "reloadxml")) {
+			if ((xml_root = switch_xml_open_root(1, &err))) {
+				switch_xml_free(xml_root);
 			}
+			stream->write_function(stream, "Reload XML [%s]\n", err);
+		}
+		if (config_sofia(1, argv[0]) == SWITCH_STATUS_SUCCESS) {
+			stream->write_function(stream, "%s started successfully\n", argv[0]);
+		} else {
+			stream->write_function(stream, "Failure starting %s\n", argv[0]);
+		}
+		return SWITCH_STATUS_SUCCESS;
+	}
 
-			sstr = switch_mprintf("active;expires=%ld", exp_raw);
+	if (argv[1] && !strcasecmp(argv[0], "restart") && !strcasecmp(argv[1], "all")) {
+		sofia_glue_restart_all_profiles();
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
+	if (switch_strlen_zero(profile_name) || !(profile = sofia_glue_find_profile(profile_name))) {
+		stream->write_function(stream, "Invalid Profile [%s]", switch_str_nil(profile_name));
+		return SWITCH_STATUS_SUCCESS;
+	}
 
-			nua_respond(nh, SIP_202_ACCEPTED,
-						NUTAG_WITH_THIS(nua),
-						SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
-						SIPTAG_FROM(sip->sip_to),
-						SIPTAG_TO(sip->sip_from),
-						SIPTAG_CONTACT_STR(to_str),
-						TAG_END());
+	if (!strcasecmp(argv[1], "killgw")) {
+		sofia_gateway_t *gateway_ptr;
+		if (argc < 3) {
+			stream->write_function(stream, "-ERR missing gw name\n");
+			goto done;
+		}
 
+		if ((gateway_ptr = sofia_reg_find_gateway(argv[2]))) { 			
+			sofia_glue_del_gateway(gateway_ptr);
+			sofia_reg_release_gateway(gateway_ptr);
+			stream->write_function(stream, "+OK gateway marked for deletion.\n");
+		} else {
+			stream->write_function(stream, "-ERR no such gateway.\n");
+		}
 
+		goto done;
+	}
 
-			switch_safe_free(sstr);
-			
-			if (!(db = switch_core_db_open_file(profile->dbname))) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-				goto end;
+	if (!strcasecmp(argv[1], "stun-auto-disable")) {
+		if (argv[2]) {
+			int is_true = switch_true(argv[2]);
+			if (is_true) {
+				sofia_set_pflag(profile, PFLAG_STUN_AUTO_DISABLE);
+			} else {
+				sofia_clear_pflag(profile, PFLAG_STUN_AUTO_DISABLE);
 			}
-			if ((sql = switch_mprintf("select * from sip_subscriptions where user='%q' and host='%q'", 
-									  to_user, to_host, to_user, to_host))) {
-				switch_mutex_lock(profile->ireg_mutex);
-				switch_core_db_exec(db, sql, sub_reg_callback, profile, &errmsg);
-				switch_mutex_unlock(profile->ireg_mutex);
-				switch_safe_free(sql);
-			}
-			switch_core_db_close(db);
-		end:
-		
-			if (event) {
-				su_free(profile->home, event);
-			}
-			if (call_id) {
-				su_free(profile->home, call_id);
-			}
-			if (full_from) {
-				su_free(profile->home, full_from);
-			}
-			if (full_via) {
-				su_free(profile->home, full_via);
-			}
-
-			switch_safe_free(d_user);
-			switch_safe_free(to_str);
-			switch_safe_free(contact_str);
 		}
-}
 
-static void sip_r_subscribe(int status,
-						char const *phrase, 
-						nua_t *nua,
-						sofia_profile_t *profile,
-						nua_handle_t *nh,
-						sofia_private_t *sofia_private,
-						sip_t const *sip,
-						tagi_t tags[])
-{
-
-}
-
-
-/*---------------------------------------*/
-static void sip_i_refer(nua_t *nua,
-						sofia_profile_t *profile,
-						nua_handle_t *nh,
-                        switch_core_session_t *session,
-						sip_t const *sip,
-						tagi_t tags[])
-{
-	/* Incoming refer */
-	sip_from_t const *from;
-	sip_to_t const *to;
-	sip_refer_to_t const *refer_to;
-    private_object_t *tech_pvt = NULL;
-    char *etmp = NULL, *exten = NULL;
-    switch_channel_t *channel_a = NULL, *channel_b = NULL;
-
-    tech_pvt = switch_core_session_get_private(session);
-    channel_a = switch_core_session_get_channel(session);
-
-    if (!sip->sip_cseq || !(etmp = switch_mprintf("refer;id=%u", sip->sip_cseq->cs_seq))) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
-        goto done;
-    }
-
-
-    if (switch_channel_test_flag(channel_a, CF_NOMEDIA)) {
-        nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-                   NUTAG_SUBSTATE(nua_substate_terminated),
-                   SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"),
-                   SIPTAG_EVENT_STR(etmp),
-                   TAG_END());
-        goto done;
-    }
+		stream->write_function(stream, "+OK stun-auto-disable=%s", sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? "true" : "false");
 		
-    from = sip->sip_from;
-    to = sip->sip_to;
+		goto done;
+	}
 
-    if ((refer_to = sip->sip_refer_to)) {
-        if (profile->pflags & PFLAG_FULL_ID) {
-            exten = switch_mprintf("%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host);
-        } else {
-            exten = (char *) refer_to->r_url->url_user;
-        }
-
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host);
-
-        if (refer_to->r_url->url_headers) {
-            sip_replaces_t *replaces;
-            nua_handle_t *bnh;
-            char *rep;
-
-            if ((rep = strchr(refer_to->r_url->url_headers, '='))) {
-                char *br_a = NULL, *br_b = NULL;
-                char *buf;
-                rep++;
-
-					
-
-                if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
-                    rep = url_unescape(buf, (const char *) rep); 
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Replaces: [%s]\n", rep);
-                } else {
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
-                    goto done;
-                }
-                if ((replaces = sip_replaces_make(tech_pvt->home, rep)) && (bnh = nua_handle_by_replaces(nua, replaces))) {
-                    sofia_private_t *b_private = NULL;
-                    private_object_t *b_tech_pvt = NULL;
-                    switch_core_session_t *b_session = NULL;
-
-                    switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep);	
-                    if ((b_private = nua_handle_magic(bnh))) {
-                        if (!(b_session = switch_core_session_locate(b_private->uuid))) {
-                            goto done;
-                        }
-                        b_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session);
-                        channel_b = switch_core_session_get_channel(b_session);
-				
-                        br_a = switch_channel_get_variable(channel_a, SWITCH_BRIDGE_VARIABLE);
-                        br_b = switch_channel_get_variable(channel_b, SWITCH_BRIDGE_VARIABLE);
-
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", br_a, br_b);
-                            
-                        if (br_a && br_b) {
-                            switch_ivr_uuid_bridge(br_a, br_b);
-                            switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
-                            switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                            switch_set_flag_locked(b_tech_pvt, TFLAG_BYE);
-                            nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-                                       NUTAG_SUBSTATE(nua_substate_terminated),
-                                       SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-                                       SIPTAG_EVENT_STR(etmp),
-                                       TAG_END());
-                                
-                        } else {
-                            if (!br_a && !br_b) {
-                                switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-                                switch_set_flag_locked(b_tech_pvt, TFLAG_XFER);
-                                b_tech_pvt->xferto = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session));
-                            } else if (!br_a && br_b) {
-                                switch_core_session_t *br_b_session;
-
-                                if ((br_b_session = switch_core_session_locate(br_b))) {
-                                    private_object_t *br_b_tech_pvt = switch_core_session_get_private(br_b_session);
-                                    switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session);
-                                    
-                                    switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-										
-                                    switch_channel_clear_state_handler(br_b_channel, NULL);
-                                    switch_channel_set_state_flag(br_b_channel, CF_TRANSFER);
-                                    switch_channel_set_state(br_b_channel, CS_TRANSMIT);
-
-                                    switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
-                                    tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(session, b_tech_pvt->local_sdp_audio_ip);
-                                    tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port;
-
-                                    tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, br_b_tech_pvt->remote_sdp_audio_ip);
-                                    tech_pvt->remote_sdp_audio_port = br_b_tech_pvt->remote_sdp_audio_port;
-                                    activate_rtp(tech_pvt);
-	
-                                    br_b_tech_pvt->kick = switch_core_session_strdup(br_b_session, switch_core_session_get_uuid(session));
-										
-
-                                    switch_core_session_rwunlock(br_b_session);
-                                }
-
-                                switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
-                            }
-                            switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                            nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-                                       NUTAG_SUBSTATE(nua_substate_terminated),
-                                       SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-                                       SIPTAG_EVENT_STR(etmp),
-                                       TAG_END());
-
-                        }
-                        if (b_session) {
-                            switch_core_session_rwunlock(b_session);
-                        }
-                    }
-                    nua_handle_unref(bnh);
-                } else { /* the other channel is on a different box, we have to go find them */
-                    if (exten && (br_a = switch_channel_get_variable(channel_a, SWITCH_BRIDGE_VARIABLE))) {
-                        switch_core_session_t *a_session;
-                        switch_channel_t *channel = switch_core_session_get_channel(session);
-							
-                        if ((a_session = switch_core_session_locate(br_a))) {
-                            switch_core_session_t *tsession;
-                            switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
-                            uint32_t timeout = 60;
-                            char *tuuid_str;
-
-                            channel = switch_core_session_get_channel(a_session);
-
-                            exten = switch_mprintf("sofia/%s/%s@%s:%s", 
-                                                   profile->name,
-                                                   (char *) refer_to->r_url->url_user,
-                                                   (char *) refer_to->r_url->url_host,
-                                                   refer_to->r_url->url_port
-                                                   );
-
-                            switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
-								
-                            if (switch_ivr_originate(a_session,
-                                                     &tsession,
-                                                     &cause,
-                                                     exten,
-                                                     timeout,
-                                                     &noop_state_handler,
-                                                     NULL,
-                                                     NULL,
-                                                     NULL) != SWITCH_STATUS_SUCCESS) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", exten);
-                                nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-                                           NUTAG_SUBSTATE(nua_substate_terminated),
-                                           SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"),
-                                           SIPTAG_EVENT_STR(etmp),
-                                           TAG_END());
-                                goto done;
-                            } 
-
-                            switch_core_session_rwunlock(a_session);
-                            tuuid_str = switch_core_session_get_uuid(tsession);
-                            switch_ivr_uuid_bridge(br_a, tuuid_str);
-                            switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
-                            switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                            nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-                                       NUTAG_SUBSTATE(nua_substate_terminated),
-                                       SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-                                       SIPTAG_EVENT_STR(etmp),
-                                       TAG_END());
-                        } else {
-                            goto error;
-                        }
-
-                    } else { error:
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s]\n", br_a);
-                        switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
-                        nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-                                   NUTAG_SUBSTATE(nua_substate_terminated),
-                                   SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"),
-                                   SIPTAG_EVENT_STR(etmp),
-                                   TAG_END());
-                    }
-                }
-            } else {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot parse Replaces!\n");
-            }
-            goto done;
-        }
-
-    } else {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Refer-To\n");
-        goto done;
-    }
-
-    if (exten) {
-        switch_channel_t *channel = switch_core_session_get_channel(session);
-        char *br;
-				
-        if ((br = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) {
-            switch_core_session_t *b_session;
-				
-            if ((b_session = switch_core_session_locate(br))) {
-                switch_channel_set_variable(channel, "TRANSFER_FALLBACK", from->a_user);
-                switch_ivr_session_transfer(b_session, exten, profile->dialplan, profile->context);
-                switch_core_session_rwunlock(b_session);
-            } 
-
-            switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "BLIND_TRANSFER");
-                
-            /*
-              nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-              NUTAG_SUBSTATE(nua_substate_terminated),
-              SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-              SIPTAG_EVENT_STR(etmp),
-              TAG_END());
-            */
-        } else {
-            exten = switch_mprintf("sip:%s@%s:%s", 
-                                   (char *) refer_to->r_url->url_user,
-                                   (char *) refer_to->r_url->url_host,
-                                   refer_to->r_url->url_port);
-            tech_pvt->dest = switch_core_session_strdup(session, exten);
-				
-				
-            switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-
-            /*
-              nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-              NUTAG_SUBSTATE(nua_substate_terminated),
-              SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-              SIPTAG_EVENT_STR(etmp),
-              TAG_END());
-            */
-            do_xfer_invite(session);
-
-        }
-    }
-
- done:
-    if (exten && strchr(exten, '@')) {
-        switch_safe_free(exten);
-    }
-    if (etmp) {
-        switch_safe_free(etmp);
-    }
-	
-
-}
-
-
-static void sip_i_publish(nua_t *nua, 
-						  sofia_profile_t *profile,
-						  nua_handle_t *nh, 
-						  sofia_private_t *sofia_private,
-						  sip_t const *sip,
-						  tagi_t tags[])
-{
-	if (sip) {
-		sip_from_t const *from = sip->sip_from;
-		char *from_user = NULL;
-		char *from_host = NULL;
-		char *rpid = "unknown";
-		sip_payload_t *payload = sip->sip_payload;
-		char *event_type;
-
-		if (from) {
-			from_user = (char *) from->a_url->url_user;
-			from_host = (char *) from->a_url->url_host;
+	if (!strcasecmp(argv[1], "stun-enabled")) {
+		if (argv[2]) {
+			int is_true = switch_true(argv[2]);
+			if (is_true) {
+				sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+			} else {
+				sofia_clear_pflag(profile, PFLAG_STUN_ENABLED);
+			}
 		}
 
-		if (payload) {
-			switch_xml_t xml, note, person, tuple, status, basic, act;
-			switch_event_t *event;
-			uint8_t in = 0;
-			char *sql;
+		stream->write_function(stream, "+OK stun-enabled=%s", sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? "true" : "false");
+		
+		goto done;
+	}
 
-			if ((xml = switch_xml_parse_str(payload->pl_data, strlen(payload->pl_data)))) {
-				char *status_txt = "", *note_txt = "";
-				
-				if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status")) && (basic = switch_xml_child(status, "basic"))) {
-					status_txt = basic->txt;
-				}
-					
-				if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) {
-					note_txt = note->txt;
-				}
 
-				if (person && (act = switch_xml_child(person, "rpid:activities"))) {
-					if ((rpid = strchr(act->child->name, ':'))) {
-						rpid++;
-					} else {
-						rpid = act->child->name;
-					}
-				}
+	if (!strcasecmp(argv[1], "rescan")) {
 
-				if (!strcasecmp(status_txt, "open")) {
-					if (switch_strlen_zero(note_txt)) {
-						note_txt = "Available";
-					}
-					in = 1;
-				} else if (!strcasecmp(status_txt, "closed")) {
-					if (switch_strlen_zero(note_txt)) {
-						note_txt = "Unavailable";
-					}
-				}
-				
-				if ((sql = switch_mprintf("update sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'", 
-										  note_txt, rpid, from_user, from_host))) {
-					execute_sql(profile->dbname, sql, profile->ireg_mutex);
-					switch_safe_free(sql);
-				}
-				
-				event_type = sip_header_as_string(profile->home, (void *)sip->sip_event);
-
-				if (in) {
-					if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
-						
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", note_txt);
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
-						switch_event_fire(&event);
-					}
-				} else {
-					if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
-
-						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
-						switch_event_fire(&event);
-					}
-				}
-
-				if (event_type) {
-					su_free(profile->home, event_type);
-				}				
-
-				switch_xml_free(xml);
+		if (argc > 2 && !strcasecmp(argv[2], "reloadxml")) {
+			if ((xml_root = switch_xml_open_root(1, &err))) {
+				switch_xml_free(xml_root);
 			}
+			stream->write_function(stream, "Reload XML [%s]\n", err);
+		}
 			
+		if (reconfig_sofia(profile) == SWITCH_STATUS_SUCCESS) {
+			stream->write_function(stream, "+OK scan complete\n");
+		} else {
+			stream->write_function(stream, "-ERR cannot find config for profile %s\n", profile->name);
 		}
-		
+		goto done;
 	}
 
-	nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+	if (!strcasecmp(argv[1], "flush_inbound_reg")) {
+		int reboot = 0;
 
-}
+		if (argc > 2) {
+			if (!strcasecmp(argv[2], "reboot")) {
+				reboot = 1;
+				argc = 2;
+			}
+		}
 
-static void sip_i_info(nua_t *nua,
-                       sofia_profile_t *profile,
-                       nua_handle_t *nh,
-                       switch_core_session_t *session,
-                       sip_t const *sip,
-                       tagi_t tags[]) {
+		if (argc > 2) {
+			if (argc > 3 && !strcasecmp(argv[3], "reboot")) {
+				reboot = 1;
+			}
 
-	//placeholder for string searching
-	char *signal_ptr;
+			sofia_reg_expire_call_id(profile, argv[2], reboot);
+			stream->write_function(stream, "+OK %s all registrations matching specified call_id\n", reboot ? "rebooting" : "flushing");
+		} else {
+			sofia_reg_check_expire(profile, 0, reboot);
+			stream->write_function(stream, "+OK %s all registrations\n", reboot ? "rebooting" : "flushing");
+		}
 
-	//Try and find signal information in the payload
-	signal_ptr = strstr(sip->sip_payload->pl_data, "Signal=");
+		goto done;
+	}
 
-	//See if we found a match
-	if(signal_ptr) {
-		struct private_object *tech_pvt = NULL;
-		switch_channel_t *channel = NULL;
-		char dtmf_digit[2] = {0,0};
+	if (!strcasecmp(argv[1], "register")) {
+		char *gname = argv[2];
+		sofia_gateway_t *gateway_ptr;
 
-		//Get the channel
-		channel = switch_core_session_get_channel(session);
+		if (switch_strlen_zero(gname)) {
+			stream->write_function(stream, "No gateway name provided!\n");
+			goto done;
+		}
 
-		//Barf if we didn't get it
-		assert(channel != NULL);
+		if (!strcasecmp(gname, "all")) {
+			for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+				gateway_ptr->retry = 0;
+				gateway_ptr->state = REG_STATE_UNREGED;
+			}
+			stream->write_function(stream, "+OK\n");
+		} else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
+			gateway_ptr->retry = 0;
+			gateway_ptr->state = REG_STATE_UNREGED;
+			stream->write_function(stream, "+OK\n");
+			sofia_reg_release_gateway(gateway_ptr);
+		} else {
+			stream->write_function(stream, "Invalid gateway!\n");
+		}
 
-		//make sure we have our privates
-		tech_pvt = switch_core_session_get_private(session);
+		goto done;
+	}
 
-		//Barf if we didn't get it
-		assert(tech_pvt != NULL);
+	if (!strcasecmp(argv[1], "unregister")) {
+		char *gname = argv[2];
+		sofia_gateway_t *gateway_ptr;
 
-		//move signal_ptr where we need it (right past Signal=)
-		signal_ptr = signal_ptr + 7;
+		if (switch_strlen_zero(gname)) {
+			stream->write_function(stream, "No gateway name provided!\n");
+			goto done;
+		}
 
-		//put the digit somewhere we can muck with
-		strncpy(dtmf_digit, signal_ptr, 1);
-
-		//queue it up
-		switch_channel_queue_dtmf(channel, dtmf_digit);
-		
-		//print debug info
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INFO DTMF(%s)\n", dtmf_digit);
-
-	} else { //unknown info type
-		sip_from_t const *from;
-
-		from = sip->sip_from;
-
-		//print in the logs if something comes through we don't understand
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unknown INFO Recieved: %s%s" URL_PRINT_FORMAT "[%s]\n",
-		                  from->a_display ? from->a_display : "", from->a_display ? " " : "",
-		                  URL_PRINT_ARGS(from->a_url), sip->sip_payload->pl_data);
+		if (!strcasecmp(gname, "all")) {
+			for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+				gateway_ptr->retry = 0;
+				gateway_ptr->state = REG_STATE_UNREGISTER;
+			}
+			stream->write_function(stream, "+OK\n");
+		} else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
+			gateway_ptr->retry = 0;
+			gateway_ptr->state = REG_STATE_UNREGISTER;
+			stream->write_function(stream, "+OK\n");
+			sofia_reg_release_gateway(gateway_ptr);
+		} else {
+			stream->write_function(stream, "Invalid gateway!\n");
+		}
+		goto done;
 	}
 
-	return;
-}
+	if (!strcasecmp(argv[1], "stop") || !strcasecmp(argv[1], "restart")) {
+		int rsec = 10;
+		int diff = (int) (switch_epoch_time_now(NULL) - profile->started);
+		int remain = rsec - diff;
+		if (diff < rsec) {
+			stream->write_function(stream, "Profile %s must be up for at least %d seconds to stop/restart.\nPlease wait %d second%s\n",
+								   profile->name, rsec, remain, remain == 1 ? "" : "s");
+		} else {
 
+			if (argc > 2 && !strcasecmp(argv[2], "reloadxml")) {
+				if ((xml_root = switch_xml_open_root(1, &err))) {
+					switch_xml_free(xml_root);
+				}
+				stream->write_function(stream, "Reload XML [%s]\n", err);
+			}
 
-#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri")
-static const char * _url_set_chanvars(switch_core_session_t *session, url_t *url, const char * user_var, const char * host_var, const char * port_var, const char * uri_var)
-{
-	const char *user = NULL, *host = NULL, *port = NULL;
-	char *uri = NULL;
-	switch_channel_t *channel = switch_core_session_get_channel(session);
-
-	if (url) {
-		user = url->url_user;
-		host = url->url_host;
-		port = url->url_port;
+			if (!strcasecmp(argv[1], "stop")) {
+				sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+				stream->write_function(stream, "stopping: %s", profile->name);
+			} else {
+				sofia_set_pflag_locked(profile, PFLAG_RESPAWN);
+				sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+				stream->write_function(stream, "restarting: %s", profile->name);
+			}
+		}
+		goto done;
 	}
-
-	if (user) {
-		switch_channel_set_variable(channel, user_var, user);
+	
+	if (!strcasecmp(argv[1], "siptrace")) {
+		if (argc > 2) {
+			int value = switch_true(argv[2]);
+			nua_set_params(profile->nua, TPTAG_LOG(value), TAG_END());
+			stream->write_function(stream, "%s sip debugging on %s", value ? "Enabled" : "Disabled", profile->name);
+		} else {
+			stream->write_function(stream, "Usage: sofia profile <name> siptrace <on/off>\n");
+		}
+		goto done;
 	}
 
-	if (!port) {
-		port = "5060";
-	}
+	stream->write_function(stream, "-ERR Unknown command!\n");
 
-	switch_channel_set_variable(channel, port_var, port);
-	if (host) {
-		if (user) {
-			uri = switch_core_session_sprintf(session, "%s@%s:%s", user, host, port);
-		} else {
-			uri = switch_core_session_sprintf(session, "%s:%s", host, port);
-		}
-		switch_channel_set_variable_nodup(channel, uri_var, uri);
-		switch_channel_set_variable(channel, host_var, host);
+  done:
+	if (profile) {
+		sofia_glue_release_profile(profile);
 	}
 
-	return uri;
+	return SWITCH_STATUS_SUCCESS;
 }
 
-static void process_rpid(sip_unknown_t *un, private_object_t *tech_pvt)
+static int contact_callback(void *pArg, int argc, char **argv, char **columnNames)
 {
-	int argc, x, screen = 1;
-	char *mydata, *argv[10] = { 0 };
-	if (!switch_strlen_zero(un->un_value)) { 
-		if ((mydata = strdup(un->un_value))) {
-			argc = switch_separate_string(mydata, ';', argv, (sizeof(argv) / sizeof(argv[0]))); 
+	struct cb_helper *cb = (struct cb_helper *) pArg;
+	char *contact;
 
-			// Do We really need this at this time 
-			// clid_uri = argv[0];
-
-			for (x=1; x < argc && argv[x]; x++){
-				// we dont need to do anything with party yet we should only be seeing party=calling here anyway
-				// maybe thats a dangerous assumption bit oh well yell at me later
-				// if (!strncasecmp(argv[x], "party", 5)) {
-				//	party = argv[x];
-				// } else 
-				if (!strncasecmp(argv[x], "privacy=", 8)) {
-					char *arg = argv[x] + 9;
-
-					if (!strcasecmp(arg, "yes")) {
-						switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
-					} else if (!strcasecmp(arg, "full")) {
-						switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
-					} else if (!strcasecmp(arg, "name")) {
-						switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
-					} else if (!strcasecmp(arg, "number")) {
-						switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER);
-					} else {
-						switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
-						switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER);
-					}
-
-				} else if (!strncasecmp(argv[x], "screen=", 7) && screen > 0) {
-					char *arg = argv[x] + 8;
-					if (!strcasecmp(arg, "no")) {
-						screen = 0;
-						switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
-					}
-				}
-			}
-			free(mydata);
-		}
+	if (!switch_strlen_zero(argv[0]) && (contact = sofia_glue_get_url_from_contact(argv[0], 1)) ) {
+		cb->stream->write_function(cb->stream, "%ssofia/%s/sip:%s,", argv[2], argv[1], sofia_glue_strip_proto(contact));
+		free(contact);
 	}
+
+	return 0;
 }
 
-static void sip_i_invite(nua_t *nua, 
-						 sofia_profile_t *profile,
-						 nua_handle_t *nh, 
-						 sofia_private_t *sofia_private,
-						 sip_t const *sip,
-						 tagi_t tags[])
+SWITCH_STANDARD_API(sofia_contact_function)
 {
-	switch_core_session_t *session = NULL;
-	char key[128] = "";
-	sip_unknown_t *un;
-	private_object_t *tech_pvt = NULL;
-	switch_channel_t *channel = NULL;
-	const char *channel_name = NULL;
-	const char *displayname = NULL;
-	const char *destination_number = NULL;
-	const char *from_user = NULL, *from_host = NULL;
-	const char *context;
-	char network_ip[80];
+	char *data;
+	char *user = NULL;
+	char *domain = NULL;
+	char *concat = NULL;
+	char *profile_name = NULL;
+	char *p;
+	sofia_profile_t *profile = NULL;
+	const char *exclude_contact = NULL;
+	char *reply = "error/facility_not_subscribed";
+	
+	if (!cmd) {
+		stream->write_function(stream, "%s", "");
+		return SWITCH_STATUS_SUCCESS;
+	}
 
-	if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
-		nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
-		return;
+	if (session) {
+		switch_channel_t *channel = switch_core_session_get_channel(session);
+		exclude_contact = switch_channel_get_variable(channel, "sip_exclude_contact");
 	}
 
 
-	if (!(sip->sip_contact && sip->sip_contact->m_url)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
-		nua_respond(nh, 400, "Missing Contact Header", TAG_END());
-		return;
+	data = strdup(cmd);
+	switch_assert(data);
+
+	if ((p = strchr(data, '/'))) {
+		profile_name = data;
+		*p++ = '\0';
+		user = p;
+	} else {
+		user = data;
 	}
 
-	if ((profile->pflags & PFLAG_AUTH_CALLS)) {
-		if (handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key))) {
-			return;
+	if ((domain = strchr(user, '@'))) {
+		*domain++ = '\0';
+		if ( (concat = strchr( domain, '/')) ) {
+		    *concat++ = '\0';
 		}
 	}
-
-	if (!(session = switch_core_session_request(&sofia_endpoint_interface, NULL))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Session Alloc Failed!\n");
-		nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
-		return;
+	else {
+		if ( (concat = strchr( user, '/')) ) {
+		    *concat++ = '\0';
+		}
 	}
 
-	if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
-		terminate_session(&session, SWITCH_CAUSE_SWITCH_CONGESTION, __LINE__);
-		return;
+	if (!profile_name && domain) {
+		profile_name = domain;
 	}
 
-	if (!switch_strlen_zero(key)) {
-		tech_pvt->key = switch_core_session_strdup(session, key);
-	}
+	if (user && profile_name) {
+		char *sql;
 
-	get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *)msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_addr);
+		if (!(profile = sofia_glue_find_profile(profile_name))) {
+			profile_name = domain;
+			domain = NULL;
+		}
 
-	channel = switch_core_session_get_channel(session);
+		if (!profile && profile_name) {
+			profile = sofia_glue_find_profile(profile_name);
+		}
 
-	if (sip->sip_from && sip->sip_from->a_url) {
-		from_user = sip->sip_from->a_url->url_user;
-		from_host = sip->sip_from->a_url->url_host;
-		channel_name = url_set_chanvars(session, sip->sip_from->a_url, sip_from);
+		if (profile) {
+			struct cb_helper cb;
+			switch_stream_handle_t mystream = { 0 };
 
-		if (!switch_strlen_zero(from_user)) {
-			if (*from_user == '+') {
-				switch_channel_set_variable(channel, "sip_from_user_stripped", (const char *)(from_user+1));
+			if (!domain || !strchr(domain, '.')) {
+				domain = profile->name;
+			}
+
+			SWITCH_STANDARD_STREAM(mystream);
+			switch_assert(mystream.data);
+			cb.profile = profile;
+			cb.stream = &mystream;
+
+			if (exclude_contact) {
+				sql = switch_mprintf("select contact, profile_name, '%q' "
+									 "from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%') "
+									 "and contact not like '%%%s%%'",
+									 ( concat != NULL ) ? concat : "", user, domain, domain, exclude_contact);
 			} else {
-				switch_channel_set_variable(channel, "sip_from_user_stripped", from_user);
+				sql = switch_mprintf("select contact, profile_name, '%q' "
+									 "from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')", 
+									 ( concat != NULL ) ? concat : "", user, domain, domain);
 			}
-		}
 
-		if (!switch_strlen_zero(sip->sip_from->a_display)) {
-			char *tmp;
-			tmp = switch_core_session_strdup(session, sip->sip_from->a_display);
-			if (*tmp == '"') {
-				char *p;
+			switch_assert(sql);
+			sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, contact_callback, &cb);
+			switch_safe_free(sql);
+			reply = (char *) mystream.data;
+			if (!switch_strlen_zero(reply) && end_of(reply) == ',') {
+				end_of(reply) = '\0';
+			}
 
-				tmp++;
-				if ((p = strchr(tmp, '"'))) {
-					*p = '\0';
-				}
+			if (switch_strlen_zero(reply)) {
+				reply = "error/user_not_registered";
 			}
-			displayname = tmp;
-		} else {
-			displayname = switch_strlen_zero(from_user) ? "unkonwn" : from_user;
-		}
-	}
 
-	if (sip->sip_request->rq_url) {
-		const char * req_uri = url_set_chanvars(session, sip->sip_request->rq_url, sip_req);
-		if (profile->pflags & PFLAG_FULL_ID)  {
-			destination_number = req_uri;
-		} else {
-			destination_number = sip->sip_request->rq_url->url_user;
+			stream->write_function(stream, "%s", reply);
+			reply = NULL;
+			
+			switch_safe_free(mystream.data);
 		}
 	}
 
-	if (sip->sip_to && sip->sip_to->a_url) {
-		url_set_chanvars(session, sip->sip_to->a_url, sip_to);
+	if (reply) {
+		stream->write_function(stream, "%s", reply);
 	}
 
-	if (sip->sip_contact && sip->sip_contact->m_url) {
-		const char *contact_uri = url_set_chanvars(session, sip->sip_contact->m_url, sip_contact);
-		if (!channel_name) {
-			channel_name = contact_uri;
-		}
+	switch_safe_free(data);
+
+	if (profile) {
+		sofia_glue_release_profile(profile);
 	}
 
-	attach_private(session, profile, tech_pvt, channel_name);
-	tech_set_codecs(tech_pvt);
+	return SWITCH_STATUS_SUCCESS;
+}
 
-	switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "INBOUND CALL");
-	set_chat_hash(tech_pvt, sip);
+SWITCH_STANDARD_API(sofia_function)
+{
+	char *argv[1024] = { 0 };
+	int argc = 0;
+	char *mycmd = NULL;
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	sofia_command_t func = NULL;
+	int lead = 1;
+	const char *usage_string = "USAGE:\n"
+		"--------------------------------------------------------------------------------\n"
+		"sofia help\n"
+		"sofia profile <profile_name> [[start|stop|restart|rescan] [reloadxml]|flush_inbound_reg [<call_id>] [reboot]|[register|unregister] [<gateway name>|all]|killgw <gateway name>|[stun-auto-disable|stun-enabled] [true|false]]|siptrace [on|off]\n"
+		"sofia status profile <name> [ reg <contact str> ] | [ pres <pres str> ]\n"
+		"sofia status gateway <name>\n"
+		"sofia loglevel <all|default|tport|iptsec|nea|nta|nth_client|nth_server|nua|soa|sresolv|stun> [0-9]\n"
+		"--------------------------------------------------------------------------------\n";
 
-	if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
-		switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-		switch_channel_set_flag(channel, CF_NOMEDIA);
+	if (session) {
+		return SWITCH_STATUS_FALSE;
 	}
 
-	if (!tech_pvt->call_id && sip->sip_call_id && sip->sip_call_id->i_id) {
-		tech_pvt->call_id = switch_core_session_strdup(session, sip->sip_call_id->i_id);
-		switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id);
+	if (switch_strlen_zero(cmd)) {
+		stream->write_function(stream, "%s", usage_string);
+		goto done;
 	}
 
-	if (sip->sip_via) {
-		if (sip->sip_via->v_host) {
-			switch_channel_set_variable(channel, "sip_via_host", sip->sip_via->v_host);
-		}
-		if (sip->sip_via->v_port) {
-			switch_channel_set_variable(channel, "sip_via_port", sip->sip_via->v_port);
-		}
-		if (sip->sip_via->v_rport) {
-			switch_channel_set_variable(channel, "sip_via_rport", sip->sip_via->v_rport);
-		}
+	if (!(mycmd = strdup(cmd))) {
+		status = SWITCH_STATUS_MEMERR;
+		goto done;
 	}
 
-	if (sip->sip_max_forwards) {
-		char max_forwards[32];
-		snprintf(max_forwards, sizeof(max_forwards), "%u", sip->sip_max_forwards->mf_count);
-		switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
+	if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
+		stream->write_function(stream, "%s", usage_string);
+		goto done;
 	}
 
-	if (profile->context && !strcasecmp(profile->context, "_domain_")) {
-		context = from_host;
+	if (!strcasecmp(argv[0], "profile")) {
+		func = cmd_profile;
+	} else if (!strcasecmp(argv[0], "status")) {
+		func = cmd_status;
+	} else if (!strcasecmp(argv[0], "xmlstatus")) {
+		func = cmd_xml_status;
+	} else if (!strcasecmp(argv[0], "tracelevel")) {
+		if (argv[1]) {
+			mod_sofia_globals.tracelevel = switch_log_str2level(argv[1]);
+		}
+		stream->write_function(stream, "+OK tracelevel is %s", switch_log_level2str(mod_sofia_globals.tracelevel));
+        goto done;
+	} else if (!strcasecmp(argv[0], "loglevel")) {
+		if (argc > 2 && argv[2] && switch_is_number(argv[2])) {
+			int level = atoi(argv[2]);
+			if (sofia_set_loglevel(argv[1], level) == SWITCH_STATUS_SUCCESS) {
+				stream->write_function(stream, "Sofia log level for component [%s] has been set to [%d]", argv[1], level);
+			} else {
+				stream->write_function(stream, "%s", usage_string);
+			}
+		} else if (argc > 1 && argv[1]) {
+			int level = sofia_get_loglevel(argv[1]);
+			if (level >= 0) {
+				stream->write_function(stream, "Sofia-sip loglevel for [%s] is [%d]", argv[1], level);
+			} else {
+				stream->write_function(stream, "%s", usage_string);
+			}
+		} else {
+			stream->write_function(stream, "%s", usage_string);
+		}
+		goto done;
+	} else if (!strcasecmp(argv[0], "help")) {
+		stream->write_function(stream, "%s", usage_string);
+		goto done;
+	}
+
+	if (func) {
+		status = func(&argv[lead], argc - lead, stream);
 	} else {
-		context = profile->context;
+		stream->write_function(stream, "Unknown Command [%s]\n", argv[0]);
 	}
 
-	tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
-														from_user,
-														profile->dialplan,
-														displayname,
-														from_user,
-														network_ip,
-														NULL,
-														NULL,
-														NULL,
-														modname,
-														context,
-														destination_number);
+  done:
+	switch_safe_free(mycmd);
+	return status;
+}
 
-	if (tech_pvt->caller_profile) {
-				
-		/* Loop thru unknown Headers Here so we can do something with them */
-		for (un=sip->sip_unknown; un; un=un->un_next) {
-			if (!strncasecmp(un->un_name, "Alert-Info", 10)) {
-				if (!switch_strlen_zero(un->un_value)) { 
-					switch_channel_set_variable(channel, "alert_info", un->un_value);
-				}
-			} else if (!strncasecmp(un->un_name, "Remote-Party-ID", 15)) {
-				process_rpid(un, tech_pvt);
-			} else if (!strncasecmp(un->un_name, "X-", 2)) {
-				if (!switch_strlen_zero(un->un_value)) { 
-					char *new_name;
-					if ((new_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) {
-						switch_channel_set_variable(channel, new_name, un->un_value);
-						free(new_name);
-					}
-				}
-			}
-		}
+switch_io_routines_t sofia_io_routines = {
+	/*.outgoing_channel */ sofia_outgoing_channel,
+	/*.read_frame */ sofia_read_frame,
+	/*.write_frame */ sofia_write_frame,
+	/*.kill_channel */ sofia_kill_channel,
+	/*.send_dtmf */ sofia_send_dtmf,
+	/*.receive_message */ sofia_receive_message,
+	/*.receive_event */ sofia_receive_event,
+	/*.state_change */ NULL,
+	/*.read_video_frame */ sofia_read_video_frame,
+	/*.write_video_frame */ sofia_write_video_frame
+};
 
-		switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
-	}
+switch_state_handler_table_t sofia_event_handlers = {
+	/*.on_init */ sofia_on_init,
+	/*.on_routing */ sofia_on_routing,
+	/*.on_execute */ sofia_on_execute,
+	/*.on_hangup */ sofia_on_hangup,
+	/*.on_exchange_media */ sofia_on_exchange_media,
+	/*.on_soft_execute */ sofia_on_soft_execute,
+	/*.on_consume_media */ NULL,
+	/*.on_hibernate */ sofia_on_hibernate,
+	/*.on_reset */ sofia_on_reset,
+	/*.on_park*/ NULL,
+	/*.on_reporting*/ NULL,
+	/*.on_destroy*/ sofia_on_destroy
+};
 
-	if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) {
-		abort();
-	}
-	memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private));
-	switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
-	nua_handle_bind(nh, tech_pvt->sofia_private);
-	tech_pvt->nh = nh;
+static switch_status_t sofia_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
+{
+	return SWITCH_STATUS_SUCCESS;
 }
 
-static void sip_i_register(nua_t *nua,
-						   sofia_profile_t *profile,
-						   nua_handle_t *nh,
-						   sofia_private_t *sofia_private,
-						   sip_t const *sip,
-						   tagi_t tags[])
+static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+												  switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
+												  switch_memory_pool_t **pool, switch_originate_flag_t flags)
 {
-    char key[128] = "";
+	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	switch_core_session_t *nsession = NULL;
+	char *data, *profile_name, *dest;
+	sofia_profile_t *profile = NULL;
+	switch_caller_profile_t *caller_profile = NULL;
+	private_object_t *tech_pvt = NULL;
+	switch_channel_t *nchannel;
+	char *host = NULL, *dest_to = NULL;
+	const char *hval = NULL;
 
-	if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
-		nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
-		return;
+	*new_session = NULL;
+
+	if (!(nsession = switch_core_session_request(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
+		goto error;
 	}
 
-	if (!(sip->sip_contact && sip->sip_contact->m_url)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
-		nua_respond(nh, 400, "Missing Contact Header", TAG_END());
-		return;
+	if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
+		goto error;
 	}
+	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(nsession));
+	switch_mutex_init(&tech_pvt->sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(nsession));
 
-	handle_register(nua, profile, nh, sip, REG_REGISTER, key, sizeof(key));
-}
+	data = switch_core_session_strdup(nsession, outbound_profile->destination_number);
+	if ((dest_to = strchr(data, '^'))) {
+		*dest_to++ = '\0';
+	}
+	profile_name = data;
 
+	nchannel = switch_core_session_get_channel(nsession);
 
-static void sip_i_options(int status,
-						  char const *phrase,
-						  nua_t *nua,
-						  sofia_profile_t *profile,
-						  nua_handle_t *nh,
-						  sofia_private_t *sofia_private,
-						  sip_t const *sip,
-						  tagi_t tags[])
-{
-	nua_respond(nh, SIP_200_OK, 
-				//SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-				//SOATAG_AUDIO_AUX("cn telephone-event"),
-				//NUTAG_INCLUDE_EXTRA_SDP(1),
-				TAG_END());
-}
+	if ((hval = switch_event_get_header(var_event, "sip_invite_to_uri"))) {
+		dest_to = switch_core_session_strdup(nsession, hval);
+	}
 
+	if (!strncasecmp(profile_name, "gateway", 7)) {
+		char *gw, *params;
+		sofia_gateway_t *gateway_ptr = NULL;
 
-static void sip_r_register(int status,
-						   char const *phrase,
-						   nua_t *nua,
-						   sofia_profile_t *profile,
-						   nua_handle_t *nh,
-						   sofia_private_t *sofia_private,
-						   sip_t const *sip,
-						   tagi_t tags[])
-{
-	if (sofia_private && sofia_private->oreg) {
-		if (status == 200) {
-			sofia_private->oreg->state = REG_STATE_REGISTER;
-		} else {
-			sofia_private->oreg->state = REG_STATE_FAILED;
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received %d on register!\n", status);
+		if (!(gw = strchr(profile_name, '/'))) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
+			cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+			goto error;
 		}
-	}
-}
 
-static void sip_r_challenge(int status,
-                            char const *phrase,
-                            nua_t *nua,
-                            sofia_profile_t *profile,
-                            nua_handle_t *nh,
-                            switch_core_session_t *session,
-                            sip_t const *sip,
-                            tagi_t tags[])
-{
-	outbound_reg_t *oreg = NULL;
-	sip_www_authenticate_t const *authenticate = NULL;
-	char const *realm = NULL; 
-	char *p = NULL, *duprealm = NULL, *qrealm = NULL;
-	char const *scheme = NULL;
-	int indexnum;
-	char *cur;
-	char authentication[256] = "";
-	int ss_state;
-	
-	if (session) {
-		private_object_t *tech_pvt;
-		if ((tech_pvt = switch_core_session_get_private(session)) && switch_test_flag(tech_pvt, TFLAG_REFER)) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received reply from refer\n");
-			return;
+		*gw++ = '\0';
+
+		if (!(dest = strchr(gw, '/'))) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
+			cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+			goto error;
 		}
-	}
 
+		*dest++ = '\0';
 
-	if (sip->sip_www_authenticate) {
-		authenticate = sip->sip_www_authenticate;
-	} else if (sip->sip_proxy_authenticate) {
-		authenticate = sip->sip_proxy_authenticate;
-	} else {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing Authenticate Header!\n");
-		return;
-	}
-	scheme = (char const *) authenticate->au_scheme;
-	if (authenticate->au_params) {
-		for(indexnum = 0; (cur=(char*)authenticate->au_params[indexnum]); indexnum++) {
-			if ((realm = strstr(cur, "realm="))) {
-				realm += 6;
-				break;
-			}
+		if (!(gateway_ptr = sofia_reg_find_gateway(gw))) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Gateway\n");
+			cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+			goto error;
 		}
-	}
 
-	if (!(scheme && realm)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No scheme and realm!\n");
-		return;
-	}
+		if (gateway_ptr->status != SOFIA_GATEWAY_UP) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway is down!\n");
+			cause = SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
+			sofia_reg_release_gateway(gateway_ptr);
+			gateway_ptr = NULL;
+			goto error;
+		}
 
-	if (profile) {
-		outbound_reg_t *oregp;
+		tech_pvt->transport = gateway_ptr->register_transport;
 
-		if ((duprealm = strdup(realm))) {
-			qrealm = duprealm;
-	
-			while(*qrealm && *qrealm == '"') {
-				qrealm++;
-			}
+		/*
+		 * Handle params, strip them off the destination and add them to the
+		 * invite contact.
+		 *
+		 * TODO:
+		 *  - Add parameters back to destination url?
+		 */
+		if ((params = strchr(dest, ';'))) {
+			char *tp_param;
 
-			if ((p = strchr(qrealm, '"'))) {
-				*p = '\0';
-			}
+			*params++ = '\0';
 
-			for (oregp = profile->registrations; oregp; oregp = oregp->next) {
-				if (scheme && qrealm && !strcasecmp(oregp->register_scheme, scheme) && !strcasecmp(oregp->register_realm, qrealm)) {
-					oreg = oregp;
-					break;
+			if ((tp_param = (char *) switch_stristr("port=", params))) {
+				tp_param += 5;
+				tech_pvt->transport = sofia_glue_str2transport(tp_param);
+				if (tech_pvt->transport == SOFIA_TRANSPORT_UNKNOWN) {
+					cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+					goto error;
 				}
 			}
-			if (!oreg) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Match for Scheme [%s] Realm [%s]\n", scheme, qrealm);
-				return;
-			}
-			switch_safe_free(duprealm);
-		} else {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
-			return;
 		}
-	}
-		
-	snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, 
-			 oreg->register_username,
-			 oreg->register_password);
-		
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authenticating '%s' with '%s'.\n",
-					  profile->username, authentication);
-		
-		
-	ss_state = nua_callstate_authenticating;
-		
-	tl_gets(tags,
-			NUTAG_CALLSTATE_REF(ss_state),
-			SIPTAG_WWW_AUTHENTICATE_REF(authenticate),
-			TAG_END());
-		
-	nua_authenticate(nh, SIPTAG_EXPIRES_STR(oreg->expires_str), NUTAG_AUTH(authentication), TAG_END());
-	
-}
 
-static void event_callback(nua_event_t event,
-						   int status,
-						   char const *phrase,
-						   nua_t *nua,
-						   sofia_profile_t *profile,
-						   nua_handle_t *nh,
-						   sofia_private_t *sofia_private,
-						   sip_t const *sip,
-						   tagi_t tags[])
-{
-	struct private_object *tech_pvt = NULL;
-	auth_res_t auth_res = AUTH_FORBIDDEN;
-	switch_core_session_t *session = NULL;
-    switch_channel_t *channel = NULL;
+		if (tech_pvt->transport != gateway_ptr->register_transport) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+							  "You are trying to use a different transport type for this gateway (overriding the register-transport), this is unsupported!\n");
+			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+			goto error;
+		}
 
-    if (sofia_private) {
-        if (!switch_strlen_zero(sofia_private->uuid)) {
+		profile = gateway_ptr->profile;
+		tech_pvt->gateway_name = switch_core_session_strdup(nsession, gateway_ptr->name);
+		switch_channel_set_variable(nchannel, "sip_gateway_name", gateway_ptr->name);
 
-            if ((session = switch_core_session_locate(sofia_private->uuid))) {
-                tech_pvt = switch_core_session_get_private(session);
-                channel = switch_core_session_get_channel(tech_pvt->session);
-                if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
-                    switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
-                }
-                if (!tech_pvt->call_id && sip && sip->sip_call_id && sip->sip_call_id->i_id) {
-                    tech_pvt->call_id = switch_core_session_strdup(session, (char *)sip->sip_call_id->i_id);
-                    switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id);
-                }
-            } else {
-                /* too late */
-                return;            
-            }
-        }
-    }
+		if (!sofia_test_flag(gateway_ptr, REG_FLAG_CALLERID)) {
+			tech_pvt->gateway_from_str = switch_core_session_strdup(nsession, gateway_ptr->register_from);
+		}
 
+		if (!strchr(dest, '@')) {
+			tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s@%s", dest, sofia_glue_strip_proto(gateway_ptr->register_proxy));
+		} else {
+			tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s", dest);
+		}
 
-	if (status != 100 && status != 200) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n",
-						  nua_event_name (event), status, phrase,
-						  session ? switch_channel_get_name(channel) : "n/a"
-						  );
-	}
+		if (params) {
+			tech_pvt->invite_contact = switch_core_session_sprintf(nsession, "%s;%s", gateway_ptr->register_contact, params);
+		} else {
+			tech_pvt->invite_contact = switch_core_session_strdup(nsession, gateway_ptr->register_contact);
+		}
+		
+		gateway_ptr->ob_calls++;
+		
+		if (!switch_strlen_zero(gateway_ptr->from_domain) && !switch_channel_get_variable(nchannel, "sip_invite_domain")) {
+			switch_channel_set_variable(nchannel, "sip_invite_domain", gateway_ptr->from_domain);
+		}
 
-	if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
-		sip_authorization_t const *authorization = NULL;
-
-        if (sip->sip_authorization) {
-			authorization = sip->sip_authorization;
-		} else if (sip->sip_proxy_authorization) {
-			authorization = sip->sip_proxy_authorization;
+		if (!switch_strlen_zero(gateway_ptr->outbound_sticky_proxy) && !switch_channel_get_variable(nchannel, "sip_route_uri")) {
+			switch_channel_set_variable(nchannel, "sip_route_uri", gateway_ptr->outbound_sticky_proxy);
 		}
+		
+		if (gateway_ptr->ob_vars) {
+			switch_event_header_t *hp;
+			for(hp = gateway_ptr->ob_vars->headers; hp; hp = hp->next) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s setting variable [%s]=[%s]\n",
+								  switch_channel_get_name(nchannel), hp->name, hp->value);
+				switch_channel_set_variable(nchannel, hp->name, hp->value);
+			}
+		}
 
-		if (authorization) {
-			auth_res = parse_auth(profile, authorization, (char *)sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key));
+	} else {
+		if (!(dest = strchr(profile_name, '/'))) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
+			cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+			goto error;
 		}
+		*dest++ = '\0';
 
-		if (auth_res != AUTH_OK) {
-			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-			nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
-			goto done;
+		if (!(profile = sofia_glue_find_profile(profile_name))) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
+			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+			goto error;
 		}
 
-		if (channel) {
-			switch_channel_set_variable(channel, "sip_authorized", "true");
+		if (profile->domain_name && profile->domain_name != profile->name) {
+			profile_name = profile->domain_name;
 		}
-	}
 
-	if (sip && (status == 401 || status == 407)) {
-		sip_r_challenge(status, phrase, nua, profile, nh, session, sip, tags);
-		goto done;
-	}
-	
-	switch (event) {
-	case nua_r_shutdown:    
-	case nua_r_get_params:    
-	case nua_r_invite:
-    case nua_r_unregister:
-    case nua_r_options:
-	case nua_i_fork:
-	case nua_r_info:
-    case nua_r_bye:
-	case nua_i_bye:
-	case nua_r_unsubscribe:
-	case nua_r_publish:
-	case nua_r_message:
-	case nua_r_notify:
-    case nua_i_notify:
-	case nua_i_cancel:
-	case nua_i_error:
-	case nua_i_active:
-	case nua_i_ack:
-	case nua_i_terminated:
-	case nua_r_set_params:
-        break;
-	case nua_r_register:
-		sip_r_register(status, phrase, nua, profile, nh, sofia_private, sip, tags);
-		break;
-	case nua_i_options:
-		sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, tags);
-		break;
-    case nua_i_invite:
-        if (!session) {
-            sip_i_invite(nua, profile, nh, sofia_private, sip, tags);
-        }
-		break;
-	case nua_i_publish:
-		sip_i_publish(nua, profile, nh, sofia_private, sip, tags);
-		break;
-    case nua_i_register:
- 		sip_i_register (nua, profile, nh, sofia_private, sip, tags);
-        break;
-	case nua_i_prack:
-		break;
-	case nua_i_state:
-		sip_i_state(status, phrase, nua, profile, nh, sofia_private, sip, tags);
-		break;
-	case nua_i_message:
-		sip_i_message(status, phrase, nua, profile, nh, sofia_private, sip, tags);
-		break;
-	case nua_i_info:
-		sip_i_info(nua, profile, nh, session, sip, tags);
-		break;
-	case nua_r_refer:
-		break;
-	case nua_i_refer:
-        if (session) {
-            sip_i_refer(nua, profile, nh, session, sip, tags);
-        }
-		break;
-    case nua_r_subscribe:
-		sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
-		break;
-	case nua_i_subscribe:
-		sip_i_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
-		break;
-	default:
-		if (status > 100) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d: %03d %s\n", 
-							  nua_event_name (event), event, status, phrase);
-        } else {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d\n", nua_event_name (event), event);
-        }
-		break;
-	}
-
- done:
-
-	if (session) {
-		switch_core_session_rwunlock(session);
-	}
-}
-
-
-static void unreg(sofia_profile_t *profile)
-{
-	outbound_reg_t *oregp;
-    for (oregp = profile->registrations; oregp; oregp = oregp->next) {
-        if (oregp->sofia_private) {
-            free(oregp->sofia_private);
-            nua_handle_bind(oregp->nh, NULL);
-            oregp->sofia_private = NULL;
-        }
-		nua_handle_destroy(oregp->nh);
-	}
-}
-
-static void check_oreg(sofia_profile_t *profile, time_t now)
-{
-	outbound_reg_t *oregp;
-	for (oregp = profile->registrations; oregp; oregp = oregp->next) {
-		int ss_state = nua_callstate_authenticating;
-		reg_state_t ostate = oregp->state;
-
-		switch(ostate) {
-		case REG_STATE_REGISTER:
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,  "registered %s\n", oregp->name);
-			oregp->expires = now + oregp->freq;
-			oregp->state = REG_STATE_REGED;
-			break;
-		case REG_STATE_UNREGED:
-			if ((oregp->nh = nua_handle(oregp->profile->nua, NULL,
-										NUTAG_URL(oregp->register_proxy),
-										SIPTAG_TO_STR(oregp->register_to),
-										NUTAG_CALLSTATE_REF(ss_state),
-										SIPTAG_FROM_STR(oregp->register_from), TAG_END()))) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,  "registering %s\n", oregp->name);	
-                
-                if (!(oregp->sofia_private = malloc(sizeof(*oregp->sofia_private)))) {
-                    abort();
-                }
-                memset(oregp->sofia_private, 0, sizeof(*oregp->sofia_private));
-
-				oregp->sofia_private->oreg = oregp;
-				nua_handle_bind(oregp->nh, oregp->sofia_private);
-
-				nua_register(oregp->nh,
-							SIPTAG_FROM_STR(oregp->register_from),
-							SIPTAG_CONTACT_STR(oregp->register_from),
-							SIPTAG_EXPIRES_STR(oregp->expires_str),
-							NUTAG_REGISTRAR(oregp->register_proxy),
-							NUTAG_OUTBOUND("no-options-keepalive"),
-							NUTAG_OUTBOUND("no-validate"),
-							NUTAG_KEEPALIVE(0),
-							TAG_NULL());
-				oregp->retry = now + 10;
-				oregp->state = REG_STATE_TRYING;
+		if (!strncasecmp(dest, "sip:", 4) || !strncasecmp(dest, "sips:", 5)) {
+			tech_pvt->dest = switch_core_session_strdup(nsession, dest);
+		} else if ((host = strchr(dest, '%'))) {
+			char buf[1024];
+			*host = '@';
+			tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
+			*host++ = '\0';
+			if (sofia_reg_find_reg_url(profile, dest, host, buf, sizeof(buf))) {
+				tech_pvt->dest = switch_core_session_strdup(nsession, buf);
+				tech_pvt->local_url = switch_core_session_sprintf(nsession, "%s@%s", dest, host);
 			} else {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,  "Error registering %s\n", oregp->name);
-				oregp->state = REG_STATE_FAILED;
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, host);
+				cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
+				goto error;
 			}
-			break;
-
-		case REG_STATE_TRYING:
-			if (oregp->retry && now >= oregp->retry) {
-				oregp->state = REG_STATE_UNREGED;
-				oregp->retry = 0;
+		} else if (!(host = strchr(dest, '@'))) {
+			char buf[1024];
+			tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
+			if (sofia_reg_find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) {
+				tech_pvt->dest = switch_core_session_strdup(nsession, buf);
+				tech_pvt->local_url = switch_core_session_sprintf(nsession, "%s@%s", dest, profile_name);
+				host = profile_name;
+			} else {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, profile_name);
+				cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
+				goto error;
 			}
-			break;
-		default:
-			if (oregp->expires && now >= oregp->expires) {
-				oregp->state = REG_STATE_UNREGED;
-				oregp->expires = 0;
-			}
-			break;
+		} else {
+			tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
+			switch_snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest);
 		}
 	}
 
-}
+	sofia_glue_get_user_host(switch_core_session_strdup(nsession, tech_pvt->dest), NULL, &tech_pvt->remote_ip);
 
-#define IREG_SECONDS 30
-#define OREG_SECONDS 1
-static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void *obj)
-{
-	sofia_profile_t *profile = (sofia_profile_t *) obj;
-	switch_memory_pool_t *pool;
-	sip_alias_node_t *node;
-	uint32_t ireg_loops = 0;
-	uint32_t oreg_loops = 0;
-	switch_core_db_t *db;
-	switch_event_t *s_event;
-
-	profile->s_root = su_root_create(NULL);
-	profile->home = su_home_new(sizeof(*profile->home));
-
-	profile->nua = nua_create(profile->s_root, /* Event loop */
-							  event_callback, /* Callback for processing events */
-							  profile, /* Additional data to pass to callback */
-							  NUTAG_URL(profile->bindurl),
-							  NTATAG_UDP_MTU(65536),
-							  TAG_END()); /* Last tag should always finish the sequence */
-
-	nua_set_params(profile->nua,
-				   //NUTAG_EARLY_MEDIA(1),				   
-				   NUTAG_AUTOANSWER(0),
-				   NUTAG_AUTOALERT(0),
-				   NUTAG_ALLOW("REGISTER"),
-				   NUTAG_ALLOW("REFER"),
-				   NUTAG_ALLOW("INFO"),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("NOTIFY")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("SUBSCRIBE")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence.winfo")),
-				   SIPTAG_SUPPORTED_STR("100rel, precondition"),
-				   SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT),
-				   TAG_END());
-				   
-
-	for (node = profile->aliases; node; node = node->next) {
-		node->nua = nua_create(profile->s_root, /* Event loop */
-							   event_callback, /* Callback for processing events */
-							   profile, /* Additional data to pass to callback */
-							   NUTAG_URL(node->url),
-							   TAG_END()); /* Last tag should always finish the sequence */
-
-		nua_set_params(node->nua,
-				   NUTAG_EARLY_MEDIA(1),				   
-					   NUTAG_AUTOANSWER(0),
-					   NUTAG_AUTOALERT(0),
-					   NUTAG_ALLOW("REGISTER"),
-					   NUTAG_ALLOW("REFER"),
-					   NUTAG_ALLOW("INFO"),
-					   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
-					   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-					   SIPTAG_SUPPORTED_STR("100rel, precondition"),
-					   SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT),
-					   TAG_END());
-		
+	if (dest_to) {
+		if (strchr(dest_to, '@')) {
+			tech_pvt->dest_to = switch_core_session_sprintf(nsession, "sip:%s", dest_to);
+		} else {
+			tech_pvt->dest_to = switch_core_session_sprintf(nsession, "sip:%s@%s", dest_to, host);
+		}
 	}
 
 
-	if ((db = switch_core_db_open_file(profile->dbname))) {
-		switch_core_db_test_reactive(db, "select contact from sip_registrations", reg_sql);
-		switch_core_db_test_reactive(db, "select contact from sip_subscriptions", sub_sql);
-		switch_core_db_test_reactive(db, "select * from sip_authentication", auth_sql);
-	} else {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n");
-		return NULL;
+	if (!tech_pvt->dest_to) {
+		tech_pvt->dest_to = tech_pvt->dest;
 	}
 
+	sofia_glue_attach_private(nsession, profile, tech_pvt, dest);
 
-	switch_mutex_init(&profile->ireg_mutex, SWITCH_MUTEX_NESTED, profile->pool);
-	switch_mutex_init(&profile->oreg_mutex, SWITCH_MUTEX_NESTED, profile->pool);
-
-	ireg_loops = IREG_SECONDS;
-	oreg_loops = OREG_SECONDS;
-
-	if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
-		switch_event_fire(&s_event);
+	if (tech_pvt->local_url) {
+		switch_channel_set_variable(nchannel, "sip_local_url", tech_pvt->local_url);
+		if (profile->pres_type) {
+			switch_channel_set_variable(nchannel, "presence_id", tech_pvt->local_url);
+		}
 	}
+	switch_channel_set_variable(nchannel, "sip_destination_url", tech_pvt->dest);
 
-	if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._tcp");
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
-		switch_event_fire(&s_event);
+	caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
+	caller_profile->destination_number = switch_core_strdup(caller_profile->pool, dest);
+	switch_channel_set_caller_profile(nchannel, caller_profile);
+	switch_channel_set_flag(nchannel, CF_OUTBOUND);
+	sofia_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
+	sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
+	if (switch_channel_get_state(nchannel) == CS_NEW) {
+		switch_channel_set_state(nchannel, CS_INIT);
 	}
+	tech_pvt->caller_profile = caller_profile;
+	*new_session = nsession;
+	cause = SWITCH_CAUSE_SUCCESS;
 
-	if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._sctp");
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
-		switch_event_fire(&s_event);
+	if ((hval = switch_event_get_header(var_event, "sip_auto_answer")) && switch_true(hval)) {
+		switch_channel_set_variable_printf(nchannel, "sip_h_Call-Info", "<sip:%s>;answer-after=0", profile->sipip);
+		switch_channel_set_variable(nchannel, "sip_invite_params", "intercom=true");
 	}
 
+	if (session) {
+		switch_channel_t *o_channel = switch_core_session_get_channel(session);
+		const char *vval = NULL;
 
-	switch_mutex_lock(globals.hash_mutex);
-	switch_core_hash_insert(globals.profile_hash, profile->name, profile);
-	switch_mutex_unlock(globals.hash_mutex);
+		if ((vval = switch_channel_get_variable(o_channel, "sip_auto_answer")) && switch_true(vval)) {
+			switch_channel_set_variable_printf(nchannel, "sip_h_Call-Info", "<sip:%s>;answer-after=0", profile->sipip);
+			switch_channel_set_variable(nchannel, "sip_invite_params", "intercom=true");
+		}
+		
+		switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
+		switch_ivr_transfer_variable(session, nsession, "sip_auto_answer");
+		switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T);
+		switch_ivr_transfer_variable(session, nsession, "sip_video_fmtp");
+		switch_ivr_transfer_variable(session, nsession, "sip-force-contact");
+		switch_ivr_transfer_variable(session, nsession, "sip_sticky_contact");
+		switch_ivr_transfer_variable(session, nsession, "sip_cid_type");
 
-	if (profile->pflags & PFLAG_PRESENCE) {
-		establish_presence(profile);
-	}
+		if (switch_core_session_compare(session, nsession)) {
+			/* It's another sofia channel! so lets cache what they use as a pt for telephone event so 
+			   we can keep it the same
+			 */
+			private_object_t *ctech_pvt;
+			ctech_pvt = switch_core_session_get_private(session);
+			switch_assert(ctech_pvt != NULL);
+			tech_pvt->bte = ctech_pvt->te;
+			tech_pvt->bcng_pt = ctech_pvt->cng_pt;
+		}
 
+		if (switch_channel_test_flag(o_channel, CF_PROXY_MEDIA)) {
+			const char *r_sdp = switch_channel_get_variable(o_channel, SWITCH_R_SDP_VARIABLE);
 
-
-
-	while(globals.running == 1) {
-		if (++ireg_loops >= IREG_SECONDS) {
-			check_expire(db, profile, time(NULL));
-			ireg_loops = 0;
+			if (switch_stristr("m=video", r_sdp)) {
+				sofia_glue_tech_choose_video_port(tech_pvt, 1);
+				tech_pvt->video_rm_encoding = "PROXY-VID";
+				tech_pvt->video_rm_rate = 90000;
+				tech_pvt->video_codec_ms = 0;
+				switch_channel_set_flag(tech_pvt->channel, CF_VIDEO);
+				sofia_set_flag(tech_pvt, TFLAG_VIDEO);
+			}
 		}
+	}
 
-		if (++oreg_loops >= OREG_SECONDS) {
-			check_oreg(profile, time(NULL));
-			oreg_loops = 0;
-		}
+	goto done;
 
-		su_root_step(profile->s_root, 1000);
+  error:
+	if (nsession) {
+		switch_core_session_destroy(&nsession);
 	}
+	*pool = NULL;
 
-	switch_core_db_close(db);
-	unreg(profile);
-	su_home_unref(profile->home);
-	
+  done:
 
-	if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
-		switch_event_fire(&s_event);
+	if (profile) {
+		if (cause == SWITCH_CAUSE_SUCCESS) {
+			profile->ob_calls++;
+		} else {
+			profile->ob_failed_calls++;
+		}
+		sofia_glue_release_profile(profile);
 	}
-
-	su_root_destroy(profile->s_root);
-	pool = profile->pool;
-	switch_core_destroy_memory_pool(&pool);
-	switch_mutex_lock(globals.mutex);
-	globals.running = 0;
-	switch_mutex_unlock(globals.mutex);
-	
-	return NULL;
+	return cause;
 }
 
-static void launch_profile_thread(sofia_profile_t *profile)
+
+static int notify_callback(void *pArg, int argc, char **argv, char **columnNames)
 {
-	switch_thread_t *thread;
-	switch_threadattr_t *thd_attr = NULL;
-	
-	switch_threadattr_create(&thd_attr, profile->pool);
-	switch_threadattr_detach_set(thd_attr, 1);
-	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
-	switch_thread_create(&thread, thd_attr, profile_thread_run, profile, profile->pool);
-}
 
+	nua_handle_t *nh;
+	sofia_profile_t *ext_profile = NULL, *profile = (sofia_profile_t *) pArg;
+	char *user = argv[0];
+	char *host = argv[1];
+	char *contact_in = argv[2];
+	char *profile_name = argv[3];
+	char *ct = argv[4];
+	char *es = argv[5];
+	char *body = argv[6];
+	char *id = NULL;
+	char *p , *contact;
 
+	
+	if (profile_name && strcasecmp(profile_name, profile->name)) {
+        if ((ext_profile = sofia_glue_find_profile(profile_name))) {
+            profile = ext_profile;
+        }
+    }
 
-static switch_status_t config_sofia(int reload)
-{
-	char *cf = "sofia.conf";
-	switch_xml_t cfg, xml = NULL, xprofile, param, settings, profiles, registration, registrations;
-	switch_status_t status = SWITCH_STATUS_SUCCESS;
-	sofia_profile_t *profile = NULL;
-	char url[512] = "";
-	switch_mutex_lock(globals.mutex);
-	globals.running = 1;
-	switch_mutex_unlock(globals.mutex);
-
-	if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
-		status = SWITCH_STATUS_FALSE;
-		goto done;
+	id = switch_mprintf("sip:%s@%s", user, host);
+	switch_assert(id);
+	contact = sofia_glue_get_url_from_contact(contact_in, 1);
+				
+	if ((p = strstr(contact, ";fs_"))) {
+		*p = '\0';
 	}
 
-	if ((settings = switch_xml_child(cfg, "global_settings"))) {
-		for (param = switch_xml_child(settings, "param"); param; param = param->next) {
-			char *var = (char *) switch_xml_attr_soft(param, "name");
-			char *val = (char *) switch_xml_attr_soft(param, "value");
-			if (!strcasecmp(var, "log-level")) {
-				su_log_set_level(NULL, atoi(val));
-			} else if (!strcasecmp(var, "log-level-trace")) {
-				su_log_set_level(tport_log, atoi(val));
-			}
-		}
-	}
+	nh = nua_handle(profile->nua, 
+					NULL, 
+					NUTAG_URL(contact), 
+					SIPTAG_FROM_STR(id), 
+					SIPTAG_TO_STR(id), 
+					SIPTAG_CONTACT_STR(profile->url), 
+					TAG_END());
+				
+	nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
 
-	if ((profiles = switch_xml_child(cfg, "profiles"))) {
-		for (xprofile = switch_xml_child(profiles, "profile"); xprofile; xprofile = xprofile->next) {
-			if (!(settings = switch_xml_child(xprofile, "settings"))) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Settings, check the new config!\n", cf);
-			} else {
-				char *xprofilename = (char *) switch_xml_attr_soft(xprofile, "name");
-				switch_memory_pool_t *pool = NULL;
+	nua_notify(nh,
+			   NUTAG_NEWSUB(1),
+			   SIPTAG_EVENT_STR(es), 
+			   SIPTAG_CONTENT_TYPE_STR(ct), 
+			   TAG_IF(!switch_strlen_zero(body), SIPTAG_PAYLOAD_STR(body)),
+			   TAG_END());
 
 				
-				/* Setup the pool */
-				if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
-					goto done;
-				}
+	free(id);
+	free(contact);
 
-				if (!(profile = (sofia_profile_t *) switch_core_alloc(pool, sizeof(*profile)))) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
-					goto done;
-				}
+	if (ext_profile) {
+		sofia_glue_release_profile(ext_profile);
+	}	
 
-				if (!xprofilename) {
-					xprofilename = "unnamed";
-				}
-		
-				profile->pool = pool;
+	return 0;
+}
 
-				profile->name = switch_core_strdup(profile->pool, xprofilename);
-				snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
-				profile->dbname = switch_core_strdup(profile->pool, url);
-				switch_core_hash_init(&profile->chat_hash, profile->pool);
+static void general_event_handler(switch_event_t *event)
+{
+	switch (event->event_id) {
+	case SWITCH_EVENT_NOTIFY:
+		{
+			const char *profile_name = switch_event_get_header(event, "profile");
+			const char *ct = switch_event_get_header(event, "content-type");
+			const char *es = switch_event_get_header(event, "event-string");
+			const char *user = switch_event_get_header(event, "user");
+			const char *host = switch_event_get_header(event, "host");
+			const char *call_id = switch_event_get_header(event, "call-id");
+			const char *uuid = switch_event_get_header(event, "uuid");
+			const char *body = switch_event_get_body(event);
+			const char *to_uri = switch_event_get_header(event, "to-uri");
+			const char *from_uri = switch_event_get_header(event, "from-uri");
+			sofia_profile_t *profile;
 
-				profile->dtmf_duration = 100;		
-				profile->codec_ms = 20;
 
-				for (param = switch_xml_child(settings, "param"); param; param = param->next) {
-					char *var = (char *) switch_xml_attr_soft(param, "name");
-					char *val = (char *) switch_xml_attr_soft(param, "value");
-
-					if (!strcasecmp(var, "debug")) {
-						profile->debug = atoi(val);
-					} else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_TIMER);
-					} else if (!strcasecmp(var, "inbound-no-media") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_INB_NOMEDIA);
-					} else if (!strcasecmp(var, "inbound-late-negotiation") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_LATE_NEGOTIATION);
-					} else if (!strcasecmp(var, "rfc2833-pt")) {
-						profile->te = (switch_payload_t) atoi(val);
-					} else if (!strcasecmp(var, "sip-port")) {
-						profile->sip_port = atoi(val);
-					} else if (!strcasecmp(var, "vad")) {
-						if (!strcasecmp(val, "in")) {
-							switch_set_flag(profile, TFLAG_VAD_IN);
-						} else if (!strcasecmp(val, "out")) {
-							switch_set_flag(profile, TFLAG_VAD_OUT);
-						} else if (!strcasecmp(val, "both")) {
-							switch_set_flag(profile, TFLAG_VAD_IN);
-							switch_set_flag(profile, TFLAG_VAD_OUT);
-						} else {
-							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invald option %s for VAD\n", val);
-						}
-					} else if (!strcasecmp(var, "ext-rtp-ip")) {
-						profile->extrtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
-					} else if (!strcasecmp(var, "rtp-ip")) {
-						profile->rtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
-					} else if (!strcasecmp(var, "sip-ip")) {
-						profile->sipip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
-					} else if (!strcasecmp(var, "sip-domain")) {
-						profile->sipdomain = switch_core_strdup(profile->pool, val);
-					} else if (!strcasecmp(var, "rtp-timer-name")) {
-						profile->timer_name = switch_core_strdup(profile->pool, val);
-					} else if (!strcasecmp(var, "manage-presence")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_PRESENCE;
-						}
-					} else if (!strcasecmp(var, "pass-rfc2833")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_PASS_RFC2833;
-						}
-					} else if (!strcasecmp(var, "disable-transcoding")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_DISABLE_TRANSCODING;
-						}
-					} else if (!strcasecmp(var, "auth-calls")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_AUTH_CALLS;
-						}
-					} else if (!strcasecmp(var, "nonce-ttl")) {
-                        profile->nonce_ttl = atoi(val);
-					} else if (!strcasecmp(var, "accept-blind-reg")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_BLIND_REG;
-						}
-					} else if (!strcasecmp(var, "auth-all-packets")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_AUTH_ALL;
-						}
-					} else if (!strcasecmp(var, "full-id-in-dialplan")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_FULL_ID;
-						}
-					} else if (!strcasecmp(var, "ext-sip-ip")) {
-						profile->extsipip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
-					} else if (!strcasecmp(var, "bitpacking")) {
-						if (!strcasecmp(val, "aal2")) {
-							profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
-						} 
-					} else if (!strcasecmp(var, "username")) {
-						profile->username = switch_core_strdup(profile->pool, val);
-					} else if (!strcasecmp(var, "context")) {
-						profile->context = switch_core_strdup(profile->pool, val);
-					} else if (!strcasecmp(var, "alias")) {
-						sip_alias_node_t *node;
-						if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) {
-							if ((node->url = switch_core_strdup(profile->pool, val))) {
-								node->next = profile->aliases;
-								profile->aliases = node;
-							}
-						}
-					} else if (!strcasecmp(var, "dialplan")) {
-						profile->dialplan = switch_core_strdup(profile->pool, val);
-					} else if (!strcasecmp(var, "max-calls")) {
-						profile->max_calls = atoi(val);
-					} else if (!strcasecmp(var, "codec-prefs")) {
-						profile->codec_string = switch_core_strdup(profile->pool, val);
-					} else if (!strcasecmp(var, "codec-ms")) {
-						profile->codec_ms = atoi(val);
-					} else if (!strcasecmp(var, "dtmf-duration")) {
-						int dur = atoi(val);
-						if (dur > 10 && dur < 8000) {
-							profile->dtmf_duration = dur;
-						} else {
-							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds!\n");
-						}
-					}
+			if (to_uri || from_uri) {
+				
+				if (!to_uri) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing To-URI header\n");
+					return;
 				}
-
-                if (!profile->sipip) {
-                    profile->sipip = switch_core_strdup(profile->pool, globals.guess_ip);
-                }
-
-                if (!profile->rtpip) {
-                    profile->rtpip = switch_core_strdup(profile->pool, globals.guess_ip);
-                }
-
-                if (profile->nonce_ttl < 60) {
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting nonce TTL to 60 seconds\n");
-                    profile->nonce_ttl = 60;
-                }
-
-				if (switch_test_flag(profile, TFLAG_TIMER) && !profile->timer_name) {
-					profile->timer_name = switch_core_strdup(profile->pool, "soft");			
+				
+				if (!from_uri) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing From-URI header\n");
+					return;
 				}
-
-				if (!profile->username) {
-					profile->username = switch_core_strdup(profile->pool, "FreeSWITCH");
+				
+				if (!es) {
+					es = "message-summary";
 				}
 
-				if (!profile->rtpip) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Setting ip to '127.0.0.1'\n");
-					profile->rtpip = switch_core_strdup(profile->pool, "127.0.0.1");
+				if (!ct) {
+					ct = "application/simple-message-summary";
 				}
 
-				if (!profile->sip_port) {
-					profile->sip_port = 5060;
+				if (!profile_name) {
+					profile_name = "default";
 				}
-
-				if (!profile->dialplan) {
-					profile->dialplan = switch_core_strdup(profile->pool, "XML");
+				
+				if (!(profile = sofia_glue_find_profile(profile_name))) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
+					return;
 				}
 
-				if (!profile->sipdomain) {
-					profile->sipdomain = switch_core_strdup(profile->pool, profile->sipip);
+				
+				if (to_uri && from_uri && ct && es && profile_name && (profile = sofia_glue_find_profile(profile_name))) {
+					nua_handle_t *nh = nua_handle(profile->nua, 
+												  NULL, 
+												  NUTAG_URL(to_uri), 
+												  SIPTAG_FROM_STR(from_uri), 
+												  SIPTAG_TO_STR(to_uri), 
+												  SIPTAG_CONTACT_STR(profile->url), 
+												  TAG_END());
+				
+					nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
+				
+					nua_notify(nh,
+							   NUTAG_NEWSUB(1),
+							   NUTAG_WITH_THIS(profile->nua),
+							   SIPTAG_EVENT_STR(es), 
+							   TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(ct)),
+							   TAG_IF(!switch_strlen_zero(body), SIPTAG_PAYLOAD_STR(body)),
+							   TAG_END());
+				
+					sofia_glue_release_profile(profile);
 				}
-				if (profile->extsipip) {
-					profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->extsipip, profile->sip_port);
-					profile->bindurl = switch_core_sprintf(profile->pool, "%s;maddr=%s", profile->url, profile->sipip);
-				} else {
-					profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->sipip, profile->sip_port);
-					profile->bindurl = profile->url;
-				}
+
+				return;
 			}
-			if (profile) {
-				if ((registrations = switch_xml_child(xprofile, "registrations"))) {
-					for (registration = switch_xml_child(registrations, "registration"); registration; registration = registration->next) {
-						char *name = (char *) switch_xml_attr_soft(registration, "name");
-						outbound_reg_t *oreg;
 
-						if (switch_strlen_zero(name)) {
-							name = "anonymous";
-						}
+			if (uuid && ct && es) {
+				switch_core_session_t *session;
+				private_object_t *tech_pvt;
 
-						if ((oreg = switch_core_alloc(profile->pool, sizeof(*oreg)))) {
-							oreg->pool = profile->pool;
-							oreg->profile = profile;
-							oreg->name = switch_core_strdup(oreg->pool, name);
-							oreg->freq = 0;
-
-							for (param = switch_xml_child(registration, "param"); param; param = param->next) {
-								char *var = (char *) switch_xml_attr_soft(param, "name");
-								char *val = (char *) switch_xml_attr_soft(param, "value");
-								
-								if (!strcmp(var, "register-scheme")) {
-									oreg->register_scheme = switch_core_strdup(oreg->pool, val);
-								} else if (!strcmp(var, "register-realm")) {
-									oreg->register_realm = switch_core_strdup(oreg->pool, val);
-								} else if (!strcmp(var, "register-username")) {
-									oreg->register_username = switch_core_strdup(oreg->pool, val);
-								} else if (!strcmp(var, "register-password")) {
-									oreg->register_password = switch_core_strdup(oreg->pool, val);
-								} else if (!strcmp(var, "register-from")) {
-									oreg->register_from = switch_core_strdup(oreg->pool, val);
-								} else if (!strcmp(var, "register-to")) {
-									oreg->register_to = switch_core_strdup(oreg->pool, val);
-								} else if (!strcmp(var, "register-proxy")) {
-									oreg->register_proxy = switch_core_strdup(oreg->pool, val);
-								} else if (!strcmp(var, "register-frequency")) {
-									oreg->expires_str = switch_core_strdup(oreg->pool, val);
-								}
-							}
-							if (switch_strlen_zero(oreg->register_scheme)) {
-								oreg->register_scheme = switch_core_strdup(oreg->pool, "Digest");
-							}
-							if (switch_strlen_zero(oreg->register_realm)) {
-								oreg->register_realm = switch_core_strdup(oreg->pool, "freeswitch.org");
-							}
-							if (switch_strlen_zero(oreg->register_username)) {
-								oreg->register_username = switch_core_strdup(oreg->pool, "freeswitch");
-							}
-							if (switch_strlen_zero(oreg->register_password)) {
-								oreg->register_password = switch_core_strdup(oreg->pool, "works");
-							}							
-							if (switch_strlen_zero(oreg->register_from)) {
-								oreg->register_from = switch_core_strdup(oreg->pool, "FreeSWITCH <sip:freeswitch@freeswitch.org>");
-							}
-							if (switch_strlen_zero(oreg->register_to)) {
-								oreg->register_to = switch_core_strdup(oreg->pool, "sip:freeswitch@freeswitch.org");
-							}
-							if (switch_strlen_zero(oreg->register_proxy)) {
-								oreg->register_proxy = switch_core_strdup(oreg->pool, "sip:freeswitch@freeswitch.org");
-							}
-
-							if (switch_strlen_zero(oreg->expires_str)) {
-								oreg->expires_str = switch_core_strdup(oreg->pool, "300");
-							}
-
-							if ((oreg->freq = atoi(oreg->expires_str)) < 5) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Freq: %d.  Setting Register-Frequency to 5\n", oreg->freq);
-                                oreg->freq = 5;
-                            }
-                            oreg->freq -= 2;
-
-							oreg->next = profile->registrations;
-							profile->registrations = oreg;
-
-						}
+				if ((session = switch_core_session_locate(uuid))) {
+					if ((tech_pvt = switch_core_session_get_private(session))) {
+						nua_notify(tech_pvt->nh,
+								   NUTAG_NEWSUB(1),
+								   SIPTAG_EVENT_STR(es), 
+								   SIPTAG_CONTENT_TYPE_STR(ct), 
+								   TAG_IF(!switch_strlen_zero(body), SIPTAG_PAYLOAD_STR(body)),
+								   TAG_END());
 					}
+					switch_core_session_rwunlock(session);
 				}
+			} else if (profile_name && ct && es && user && host && (profile = sofia_glue_find_profile(profile_name))) {
+				char *sql;
 
-				if (profile->sipip) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url);
-					launch_profile_thread(profile);
+				if (call_id) {
+					sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,'%q','%q','%q' "
+										 "from sip_registrations where call_id='%q'", ct, es, switch_str_nil(body), call_id
+										 );
 				} else {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to start Profile %s due to no configured sip-ip\n", profile->name);
+					sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,'%q','%q','%q' "
+										 "from sip_registrations where sip_user='%s' and sip_host='%q'",
+										 ct, es, switch_str_nil(body), switch_str_nil(user), switch_str_nil(host)
+										 );
 				}
-				profile = NULL;
-			}
-		}
-	}
- done:
-	if (xml) {
-		switch_xml_free(xml);
-	}
+				
 
-	return status;
+				switch_mutex_lock(profile->ireg_mutex);
+				sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, notify_callback, profile);
+				switch_mutex_unlock(profile->ireg_mutex);
+				sofia_glue_release_profile(profile);
 
-}
-
-static void event_handler(switch_event_t *event)
-{
-	char *subclass, *sql;
-
-	if ((subclass = switch_event_get_header(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_REGISTER)) {
-		char *from_user = switch_event_get_header(event, "orig-from-user");
-		char *from_host = switch_event_get_header(event, "orig-from-host");
-		char *contact_str = switch_event_get_header(event, "orig-contact");
-		char *exp_str = switch_event_get_header(event, "orig-expires");
-		char *rpid = switch_event_get_header(event, "orig-rpid");
-		long expires = (long)time(NULL) + atol(exp_str);
-		char *profile_name = switch_event_get_header(event, "orig-profile-name");
-		sofia_profile_t *profile;
-		char buf[512];
-
-		if (!rpid) {
-			rpid = "unknown";
-		}
-
-		if (!profile_name || !(profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, profile_name))) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
-			return;
-		}
-
-
-		if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
-			sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Regestered', '%q', %ld)", 
-								 from_user,
-								 from_host,
-								 contact_str,
-								 rpid,
-								 expires);
-		} else {
-			sql = switch_mprintf("update sip_registrations set contact='%q', rpid='%q', expires=%ld where user='%q' and host='%q'",
-								 contact_str,
-								 rpid,
-								 expires,
-								 from_user,
-								 from_host);
+				free(sql);
+			}
 			
 		}
-	
-		if (sql) {
-			execute_sql(profile->dbname, sql, profile->ireg_mutex);
-			switch_safe_free(sql);
-			sql = NULL;
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Propagating registration for %s@%s->%s\n", 
-							  from_user, from_host, contact_str);
+		break;
+	case SWITCH_EVENT_SEND_MESSAGE:
+		{
+			const char *profile_name = switch_event_get_header(event, "profile");
+			const char *ct = switch_event_get_header(event, "content-type");
+			const char *user = switch_event_get_header(event, "user");
+			const char *host = switch_event_get_header(event, "host");
+			const char *body = switch_event_get_body(event);
+			sofia_profile_t *profile;
+			nua_handle_t *nh;
 
-		}
+			if (profile_name && ct && user && host) {
+				char *id = NULL;
+				char *contact, *p;
+				char buf[512] = "";
 
-	}
-}
+				if (!(profile = sofia_glue_find_profile(profile_name))) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
+					return;
+				}
 
 
-static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint)
-{
-	char buf[256];
-	char *user, *host;
-	sofia_profile_t *profile;
-	char *ffrom = NULL;
-	nua_handle_t *msg_nh;
-	char *contact;
+				if (!sofia_reg_find_reg_url(profile, user, host, buf, sizeof(buf))) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find user %s@%s\n", user, host);
+					return;
+				}
 
-	if (to && (user = strdup(to))) {
-		if ((host = strchr(user, '@'))) {
-			*host++ = '\0';
-		}
-		
-		if (!host || !(profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, host))) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n", 
-                              proto,
-                              from,
-                              to,
-                              body ? body : "[no body]",
-                              host ? host : "NULL");
-			return SWITCH_STATUS_FALSE;
-		}
+				id = switch_mprintf("sip:%s@%s", user, host);
 
-        if (!find_reg_url(profile, user, host, buf, sizeof(buf))) {
-			return SWITCH_STATUS_FALSE;
-		}
+				switch_assert(id);
+				contact = sofia_glue_get_url_from_contact(buf, 0);
+				
+				if ((p = strstr(contact, ";fs_"))) {
+					*p = '\0';
+				}
+				
+				nh = nua_handle(profile->nua, 
+								NULL, 
+								NUTAG_URL(contact), 
+								SIPTAG_FROM_STR(id), 
+								SIPTAG_TO_STR(id), 
+								SIPTAG_CONTACT_STR(profile->url), 
+								TAG_END());
+				
+				nua_message(nh,
+							NUTAG_NEWSUB(1),
+ 							SIPTAG_CONTENT_TYPE_STR(ct), 
+							TAG_IF(!switch_strlen_zero(body), SIPTAG_PAYLOAD_STR(body)),
+							TAG_END());
 
-		if (!strcmp(proto, SOFIA_CHAT_PROTO)) {
-			from = hint;
-		} else {
-			char *fp, *p, *fu = NULL;
-
-			if (!(fp = strdup(from))) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
-				return SWITCH_STATUS_FALSE;
+				
+				free(id);
+				sofia_glue_release_profile(profile);
 			}
 
-			if ((p = strchr(fp, '@'))) {
-				*p = '\0';
-				fu = strdup(fp);
-				*p = '+';
-			}
-			
-			ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fu, proto, fp, profile->name);			
-			from = ffrom;
-			switch_safe_free(fu);
-			switch_safe_free(fp);
 		}
+		break;
+	case SWITCH_EVENT_SEND_INFO:
+		{
+			const char *profile_name = switch_event_get_header(event, "profile");
+			const char *ct = switch_event_get_header(event, "content-type");
+			const char *to_uri = switch_event_get_header(event, "to-uri");
+			const char *local_user_full = switch_event_get_header(event, "local-user");
+			const char *from_uri = switch_event_get_header(event, "from-uri");
+			const char *call_info = switch_event_get_header(event, "call-info");
+			const char *alert_info = switch_event_get_header(event, "alert-info");
+			const char *call_id = switch_event_get_header(event, "call-id");
+			const char *body = switch_event_get_body(event);
+			sofia_profile_t *profile = NULL;
+			nua_handle_t *nh;
+			char *local_dup = NULL;
+			char *local_user, *local_host;
+			char buf[1024] = "";
+			char *p;
 
-		contact = get_url_from_contact(buf, 1);
-		msg_nh = nua_handle(profile->nua, NULL,
-							SIPTAG_FROM_STR(from),
-							NUTAG_URL(contact),
-							SIPTAG_TO_STR(buf), // if this cries, add contact here too, change the 1 to 0 and omit the safe_free
-							SIPTAG_CONTACT_STR(profile->url),
-							TAG_END());
+			if (!profile_name) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Profile Name\n");
+                goto done;
+            }
 
-		switch_safe_free(contact);
+            if (!call_id && !to_uri && !local_user_full) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing To-URI header\n");
+                goto done;
+            }
 
+            if (!call_id && !from_uri) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing From-URI header\n");
+                goto done;
+            }
 
-		nua_message(msg_nh,
-					SIPTAG_CONTENT_TYPE_STR("text/html"),
-					SIPTAG_PAYLOAD_STR(body),
-					TAG_END());
-		
-		
-		switch_safe_free(ffrom);
-		free(user);
-	}
-		
-	return SWITCH_STATUS_SUCCESS;
-}
 
-static void cancel_presence(void) 
-{
-	char *sql, *errmsg = NULL;
-	switch_core_db_t *db;
-	sofia_profile_t *profile;
-	switch_hash_index_t *hi;
-    void *val;
+            if (!(profile = sofia_glue_find_profile(profile_name))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
+                goto done;
+            }
 
-	if ((sql = switch_mprintf("select 0,'unavailable','unavailable',* from sip_subscriptions where event='presence'"))) {
-		for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
-			switch_hash_this(hi, NULL, NULL, &val);
-			profile = (sofia_profile_t *) val;
-			if (!(profile->pflags & PFLAG_PRESENCE)) {
-				continue;
-			}
+			if (call_id) {
+				nh = nua_handle_by_call_id(profile->nua, call_id);
 
-			if (!(db = switch_core_db_open_file(profile->dbname))) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-				continue;
+				if (!nh) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Call-ID %s\n", call_id);
+					goto done;
+				}
 			}
-			switch_mutex_lock(profile->ireg_mutex);
-			switch_core_db_exec(db, sql, sub_callback, profile, &errmsg);
-			switch_mutex_unlock(profile->ireg_mutex);
-			switch_core_db_close(db);
-		}
-		switch_safe_free(sql);
-	}
 
-}
+			else {
+				if (local_user_full) {
+					local_dup = strdup(local_user_full);
+					local_user = local_dup;
+					if ((local_host = strchr(local_user, '@'))) {
+						*local_host++ = '\0';
+					}
 
-static void establish_presence(sofia_profile_t *profile) 
-{
-	char *sql, *errmsg = NULL;
-	switch_core_db_t *db;
+					if (!local_user || !local_host || !sofia_reg_find_reg_url(profile, local_user, local_host, buf, sizeof(buf))) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find local user\n");
+						goto done;
+					}
 
-	if (!(db = switch_core_db_open_file(profile->dbname))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-		return;
-	}
+					to_uri = sofia_glue_get_url_from_contact(buf, 0);
+					
+					if ((p = strstr(to_uri, ";fs_"))) {
+						*p = '\0';
+					}
 
-	if ((sql = switch_mprintf("select user,host,'Registered','unknown','' from sip_registrations"))) {
-		switch_mutex_lock(profile->ireg_mutex);
-		switch_core_db_exec(db, sql, resub_callback, profile, &errmsg);
-		switch_mutex_unlock(profile->ireg_mutex);
-		switch_safe_free(sql);
-	}
+				}
 
-	if ((sql = switch_mprintf("select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions "
-							  "where proto='ext' or proto='user' or proto='conf'"))) {
-		switch_mutex_lock(profile->ireg_mutex);
-		switch_core_db_exec(db, sql, resub_callback, profile, &errmsg);
-		switch_mutex_unlock(profile->ireg_mutex);
-		switch_safe_free(sql);
-	}
 
-	switch_core_db_close(db);
-
-}
-
-
-
-static char *translate_rpid(char *in, char *ext)
-{
-	char *r = NULL;
-
-	if (in && (strstr(in, "null") || strstr(in, "NULL"))) {
-		in = NULL;
-	}
-
-	if (!in) {
-		in = ext;
-	}
-
-	if (!in) {
-		return NULL;
-	}
-	
-	if (!strcasecmp(in, "dnd")) {
-		r = "busy";
-	}
-
-	if (ext && !strcasecmp(ext, "away")) {
-		r = "idle";
-	}
-	
-	return r;
-}
-
-static void pres_event_handler(switch_event_t *event)
-{
-	sofia_profile_t *profile;
-	switch_hash_index_t *hi;
-    void *val;
-	char *from = switch_event_get_header(event, "from");
-	char *proto = switch_event_get_header(event, "proto");
-	char *rpid = switch_event_get_header(event, "rpid");
-	char *status= switch_event_get_header(event, "status");
-	char *event_type = switch_event_get_header(event, "event_type");
-	//char *event_subtype = switch_event_get_header(event, "event_subtype");
-	char *sql = NULL;
-	char *euser = NULL, *user = NULL, *host = NULL;
-	char *errmsg;
-	switch_core_db_t *db;
-
-
-	if (rpid && !strcasecmp(rpid, "n/a")) {
-		rpid = NULL;
-	}
-
-	if (status && !strcasecmp(status, "n/a")) {
-		status = NULL;
-	}
-
-	if (rpid) {
-		rpid = translate_rpid(rpid, status);
-	} 
-
-	if (!status) {
-		status = "Available";
-
-		if (rpid) {
-			if (!strcasecmp(rpid, "busy")) {
-				status = "Busy";
-			} else if (!strcasecmp(rpid, "unavailable")) {
-				status = "Idle";
-			} else if (!strcasecmp(rpid, "away")) {
-				status = "Idle";
+				nh = nua_handle(profile->nua, 
+								NULL, 
+								NUTAG_URL(to_uri), 
+								SIPTAG_FROM_STR(from_uri), 
+								SIPTAG_TO_STR(to_uri), 
+								SIPTAG_CONTACT_STR(profile->url), 
+								TAG_END());
+				
+				nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
 			}
-		}
-	}
 
-	if (!rpid) {
-		rpid = "unknown";
-	}
+			nua_info(nh,
+					 NUTAG_WITH_THIS(profile->nua),
+					 TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(ct)),
+					 TAG_IF(alert_info, SIPTAG_ALERT_INFO_STR(alert_info)),
+					 TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
+					 TAG_IF(!switch_strlen_zero(body), SIPTAG_PAYLOAD_STR(body)),
+					 TAG_END());
 
-	if (event->event_id == SWITCH_EVENT_ROSTER) {
-
-		if (from) {
-			sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence' and full_from like '%%%q%%'", status, rpid, from);
-		} else {
-			sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence'", status, rpid);
-		}
-
-		for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
-			switch_hash_this(hi, NULL, NULL, &val);
-			profile = (sofia_profile_t *) val;
-			if (!(profile->pflags & PFLAG_PRESENCE)) {
-				continue;
+			if (call_id && nh) {
+				nua_handle_unref(nh);
 			}
 
-			if (sql) {
-				if (!(db = switch_core_db_open_file(profile->dbname))) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-					continue;
-				}
-				switch_mutex_lock(profile->ireg_mutex);
-				switch_core_db_exec(db, sql, sub_callback, profile, &errmsg);
-				switch_mutex_unlock(profile->ireg_mutex);
-				switch_core_db_close(db);
+			if (profile) {
+				sofia_glue_release_profile(profile);
 			}
+			
+		done:
 
+			switch_safe_free(local_dup);
+			
 		}
+		break;
+	case SWITCH_EVENT_TRAP:
+		{
+			const char *cond = switch_event_get_header(event, "condition");
 
-		return;
-	}
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "EVENT_TRAP: IP change detected\n");
 
-	if (switch_strlen_zero(event_type)) {
-		event_type="presence";
-	}
+			if (cond && !strcmp(cond, "network-address-change") && mod_sofia_globals.auto_restart) {
+				const char *old_ip4 = switch_event_get_header_nil(event, "network-address-previous-v4");
+				const char *new_ip4 = switch_event_get_header_nil(event, "network-address-change-v4");
+				const char *old_ip6 = switch_event_get_header_nil(event, "network-address-previous-v6");
+				const char *new_ip6 = switch_event_get_header_nil(event, "network-address-change-v6");
+				switch_hash_index_t *hi;
+				const void *var;
+				void *val;
+				sofia_profile_t *profile;
 
-	if ((user = strdup(from))) {
-		if ((host = strchr(user, '@'))) {
-			char *p;
-			*host++ = '\0';
-			if ((p = strchr(host, '/'))) {
-				*p = '\0';
-			}
-		} else {
-			switch_safe_free(user);
-			return;
-		}
-		if ((euser = strchr(user, '+'))) {
-			euser++;
-		} else {
-			euser = user;
-		}
-		
-	} else {
-		return;
-	}
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IP change detected [%s]->[%s] [%s]->[%s]\n", old_ip4, new_ip4, old_ip6, new_ip6);
 
+				switch_mutex_lock(mod_sofia_globals.hash_mutex);
+				if (mod_sofia_globals.profile_hash) {
+					for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+						int rb = 0;
+						switch_hash_this(hi, &var, NULL, &val);
+						if ((profile = (sofia_profile_t *) val) && profile->auto_restart) {
+							if (!strcmp(profile->sipip, old_ip4)) {
+								profile->sipip = switch_core_strdup(profile->pool, new_ip4);
+								rb++;
+							}
+							if (!strcmp(profile->rtpip, old_ip4)) {
+								profile->rtpip = switch_core_strdup(profile->pool, new_ip4);
+								rb++;
+							}
+							if (!strcmp(profile->sipip, old_ip6)) {
+								profile->sipip = switch_core_strdup(profile->pool, new_ip6);
+								rb++;
+							}
+							if (!strcmp(profile->rtpip, old_ip6)) {
+								profile->rtpip = switch_core_strdup(profile->pool, new_ip6);
+								rb++;
+							}
 
-	switch(event->event_id) {
-    case SWITCH_EVENT_PRESENCE_PROBE: 
-        if (proto) {
-            switch_core_db_t *db = NULL;
-            char *to = switch_event_get_header(event, "to");
-            char *user, *euser, *host, *p;
-
-            if (!to || !(user = strdup(to))) {
-                return;
-            }
-
-            if ((host = strchr(user, '@'))) {
-                *host++ = '\0';
-            }
-            euser = user;
-            if ((p = strchr(euser, '+'))) {
-                euser = (p+1);
-            }
-
-            if (euser && host && 
-                (sql = switch_mprintf("select user,host,status,rpid,'' from sip_registrations where user='%q' and host='%q'", euser, host)) &&
-                (profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, host))) {
-                if (!(db = switch_core_db_open_file(profile->dbname))) {
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-                    switch_safe_free(user);
-                    switch_safe_free(sql);
-                    return;
-                }
-
-                switch_mutex_lock(profile->ireg_mutex);
-                switch_core_db_exec(db, sql, resub_callback, profile, &errmsg);
-                switch_mutex_unlock(profile->ireg_mutex);
-                switch_safe_free(sql);
-            }
-            switch_safe_free(user);
-            switch_core_db_close(db);
-        }
-        return;
-	case SWITCH_EVENT_PRESENCE_IN:
-		sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'", 
-							 status , rpid, proto, event_type, euser, host);
+							if (rb) {
+								sofia_set_pflag_locked(profile, PFLAG_RESPAWN);
+								sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+							}
+						}
+					}
+				}
+				switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+				sofia_glue_restart_all_profiles();
+			}
+			
+		}
 		break;
-	case SWITCH_EVENT_PRESENCE_OUT:
-		sql = switch_mprintf("select 0,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'", 
-							 status, rpid, proto, event_type, euser, host);
-		break;
 	default:
 		break;
 	}
-
-    for (hi = switch_hash_first(apr_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
-        switch_hash_this(hi, NULL, NULL, &val);
-        profile = (sofia_profile_t *) val;
-        if (!(profile->pflags & PFLAG_PRESENCE)) {
-			continue;
-        }
-
-		if (sql) {
-			if (!(db = switch_core_db_open_file(profile->dbname))) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
-				continue;
-			}
-			switch_mutex_lock(profile->ireg_mutex);
-			switch_core_db_exec(db, sql, sub_callback, profile, &errmsg);
-			switch_mutex_unlock(profile->ireg_mutex);
-			
-			switch_core_db_close(db);
-		}
-	}
-
-	switch_safe_free(sql);
-	switch_safe_free(user);
 }
 
-
-SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
+SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
 {
+	switch_chat_interface_t *chat_interface;
+	switch_api_interface_t *api_interface;
+	switch_management_interface_t *management_interface;
+	struct in_addr in;
 
 	silence_frame.data = silence_data;
 	silence_frame.datalen = sizeof(silence_data);
 	silence_frame.buflen = sizeof(silence_data);
 	silence_frame.flags = SFF_CNG;
 
+	memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals));
+	mod_sofia_globals.destroy_private.destroy_nh = 1;
+	mod_sofia_globals.destroy_private.is_static = 1;
+	mod_sofia_globals.keep_private.is_static = 1;
+	mod_sofia_globals.pool = pool;
+	switch_mutex_init(&mod_sofia_globals.mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool);
 
-	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
-		return SWITCH_STATUS_TERM;
-	}
+	switch_find_local_ip(mod_sofia_globals.guess_ip, sizeof(mod_sofia_globals.guess_ip), &mod_sofia_globals.guess_mask, AF_INET);
+	in.s_addr = mod_sofia_globals.guess_mask;
+	switch_set_string(mod_sofia_globals.guess_mask_str, inet_ntoa(in));
+	gethostname(mod_sofia_globals.hostname, sizeof(mod_sofia_globals.hostname));
 
-	memset(&globals, 0, sizeof(globals));
-	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
 
-    switch_find_local_ip(globals.guess_ip, sizeof(globals.guess_ip), AF_INET);
+	switch_core_hash_init(&mod_sofia_globals.profile_hash, mod_sofia_globals.pool);
+	switch_core_hash_init(&mod_sofia_globals.gateway_hash, mod_sofia_globals.pool);
+	switch_mutex_init(&mod_sofia_globals.hash_mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool);
 
-	if (switch_event_bind((char *) modname, SWITCH_EVENT_CUSTOM, MULTICAST_EVENT, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+	switch_mutex_lock(mod_sofia_globals.mutex);
+	mod_sofia_globals.running = 1;
+	switch_mutex_unlock(mod_sofia_globals.mutex);
+
+	mod_sofia_globals.auto_nat = (switch_core_get_variable("nat_type") ? 1 : 0);
+
+	switch_queue_create(&mod_sofia_globals.presence_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
+	switch_queue_create(&mod_sofia_globals.mwi_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
+
+	if (config_sofia(0, NULL) != SWITCH_STATUS_SUCCESS) {
+		mod_sofia_globals.running = 0;
+		return SWITCH_STATUS_GENERR;
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for profiles to start\n");
+	switch_yield(1500000);
+
+	if (switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, MULTICAST_EVENT, event_handler, NULL,
+									&mod_sofia_globals.custom_node) != SWITCH_STATUS_SUCCESS) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
 		return SWITCH_STATUS_TERM;
 	}
 
-	su_init();
-	su_log_redirect(NULL, logger, NULL);
-	su_log_redirect(tport_log, logger, NULL);
+	if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+									&mod_sofia_globals.in_node) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
+		return SWITCH_STATUS_GENERR;
+	}
 
-	switch_core_hash_init(&globals.profile_hash, module_pool);
-	switch_mutex_init(&globals.hash_mutex, SWITCH_MUTEX_NESTED, module_pool);
+	if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+									&mod_sofia_globals.out_node) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
+		return SWITCH_STATUS_GENERR;
+	}
 
-	config_sofia(0);
+	if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+									&mod_sofia_globals.probe_node) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
+		return SWITCH_STATUS_GENERR;
+	}
 
+	if (switch_event_bind_removable(modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+									&mod_sofia_globals.roster_node) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
+		return SWITCH_STATUS_GENERR;
+	}
 
-	if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+	if (switch_event_bind_removable(modname, SWITCH_EVENT_MESSAGE_WAITING, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_mwi_event_handler, NULL,
+									&mod_sofia_globals.mwi_node) != SWITCH_STATUS_SUCCESS) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
 		return SWITCH_STATUS_GENERR;
 	}
 
-	if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+	if (switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
 		return SWITCH_STATUS_GENERR;
 	}
 
-	if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+	if (switch_event_bind(modname, SWITCH_EVENT_NOTIFY, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
 		return SWITCH_STATUS_GENERR;
 	}
 
-	if (switch_event_bind((char *) modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+	if (switch_event_bind(modname, SWITCH_EVENT_SEND_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
 		return SWITCH_STATUS_GENERR;
 	}
 
+	if (switch_event_bind(modname, SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
 	/* connect my internal structure to the blank pointer passed to me */
-	*module_interface = &sofia_module_interface;
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+	sofia_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+	sofia_endpoint_interface->interface_name = "sofia";
+	sofia_endpoint_interface->io_routines = &sofia_io_routines;
+	sofia_endpoint_interface->state_handler = &sofia_event_handlers;
 
+	management_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_MANAGEMENT_INTERFACE);
+	management_interface->relative_oid = "1";
+	management_interface->management_function = sofia_manage;
+
+	SWITCH_ADD_API(api_interface, "sofia", "Sofia Controls", sofia_function, "<cmd> <args>");
+	switch_console_set_complete("add sofia help");
+	switch_console_set_complete("add sofia status");
+	switch_console_set_complete("add sofia loglevel");
+	switch_console_set_complete("add sofia profile");
+	switch_console_set_complete("add sofia profile restart all");
+
+	SWITCH_ADD_API(api_interface, "sofia_contact", "Sofia Contacts", sofia_contact_function, "[profile/]<user>@<domain>");
+	SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
+
 	/* indicate that the module should continue to be loaded */
 	return SWITCH_STATUS_SUCCESS;
-
 }
 
-SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown)
 {
+	int sanity = 0;
 
-	cancel_presence();
-
-	switch_mutex_lock(globals.mutex);
-	if (globals.running == 1) {
-		globals.running = -1;
+	switch_mutex_lock(mod_sofia_globals.mutex);
+	if (mod_sofia_globals.running == 1) {
+		mod_sofia_globals.running = 0;
 	}
-	switch_mutex_unlock(globals.mutex);
+	switch_mutex_unlock(mod_sofia_globals.mutex);
 
-	while(globals.running) {
-		switch_yield(1000);
+	switch_event_unbind(&mod_sofia_globals.in_node);
+	switch_event_unbind(&mod_sofia_globals.probe_node);
+	switch_event_unbind(&mod_sofia_globals.out_node);
+	switch_event_unbind(&mod_sofia_globals.roster_node);
+	switch_event_unbind(&mod_sofia_globals.custom_node);
+	switch_event_unbind(&mod_sofia_globals.mwi_node);
+	switch_event_unbind_callback(general_event_handler);
+	
+	while (mod_sofia_globals.threads) {
+		switch_cond_next();
+		if (++sanity >= 60000) {
+			break;
+		}
 	}
 
+	//switch_yield(1000000);
 	su_deinit();
 
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	switch_core_hash_destroy(&mod_sofia_globals.profile_hash);
+	switch_core_hash_destroy(&mod_sofia_globals.gateway_hash);
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
 	return SWITCH_STATUS_SUCCESS;
 }
 
@@ -5897,5 +3394,5 @@
  * c-basic-offset:4
  * End:
  * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
  */
Property changes on: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.h (14389 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.h	2009-07-27 19:05:59 UTC (rev 14389)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.h	2009-07-27 20:18:20 UTC (rev 14390)
@@ -1,6 +1,6 @@
 /* 
  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
  *
  * Version: MPL 1.1
  *
@@ -17,13 +17,13 @@
  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
  *
  * The Initial Developer of the Original Code is
- * Anthony Minessale II <anthmct@yahoo.com>
+ * Anthony Minessale II <anthm@freeswitch.org>
  * Portions created by the Initial Developer are Copyright (C)
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  * 
- * Anthony Minessale II <anthmct@yahoo.com>
+ * Anthony Minessale II <anthm@freeswitch.org>
  * Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
  * Paul D. Tinsley <pdt at jackhammer.org>
  * Bret McDanel <trixter AT 0xdecafbad.com>
@@ -36,23 +36,33 @@
 
 /*Defines etc..*/
 /*************************************************************************************************************************************************************/
+#define MANUAL_BYE
+
 #define IREG_SECONDS 30
 #define GATEWAY_SECONDS 1
-
+#define SOFIA_QUEUE_SIZE 50000
 #define HAVE_APR
 #include <switch.h>
 #include <switch_version.h>
-#ifdef SWITCH_HAVE_ODBC
-#include <switch_odbc.h>
+#define SOFIA_NAT_SESSION_TIMEOUT 20
+#define SOFIA_MAX_ACL 100
+#ifdef _MSC_VER
+#define HAVE_FUNCTION 1
+#else
+#define HAVE_FUNC 1
 #endif
 
-#define SOFIA_MAX_ACL 100
-
+#define MAX_CODEC_CHECK_FRAMES 50
+#define MAX_MISMATCH_FRAMES 3
 #define MODNAME "mod_sofia"
+#define SOFIA_DEFAULT_CONTACT_USER MODNAME
 static const switch_state_handler_table_t noop_state_handler = { 0 };
 struct sofia_gateway;
 typedef struct sofia_gateway sofia_gateway_t;
 
+struct sofia_gateway_subscription;
+typedef struct sofia_gateway_subscription sofia_gateway_subscription_t;
+
 struct sofia_profile;
 typedef struct sofia_profile sofia_profile_t;
 #define NUA_MAGIC_T sofia_profile_t
@@ -65,12 +75,17 @@
 
 #define SOFIA_SESSION_TIMEOUT "sofia_session_timeout"
 #define MY_EVENT_REGISTER "sofia::register"
+#define MY_EVENT_UNREGISTER "sofia::unregister"
 #define MY_EVENT_EXPIRE "sofia::expire"
+#define MY_EVENT_GATEWAY_STATE "sofia::gateway_state"
+#define MY_EVENT_NOTIFY_REFER "sofia::notify_refer"
+
 #define MULTICAST_EVENT "multicast::event"
 #define SOFIA_REPLACES_HEADER "_sofia_replaces_"
 #define SOFIA_USER_AGENT "FreeSWITCH-mod_sofia/" SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO "-" SWITCH_VERSION_REVISION
 #define SOFIA_CHAT_PROTO "sip"
 #define SOFIA_SIP_HEADER_PREFIX "sip_h_"
+#define SOFIA_SIP_BYE_HEADER_PREFIX "sip_bye_h_"
 #define SOFIA_SIP_HEADER_PREFIX_T "~sip_h_"
 #define SOFIA_DEFAULT_PORT "5060"
 #define SOFIA_DEFAULT_TLS_PORT "5061"
@@ -79,7 +94,6 @@
 #define SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE "sip_secure_media_confirmed"
 #define SOFIA_HAS_CRYPTO_VARIABLE "sip_has_crypto"
 #define SOFIA_CRYPTO_MANDATORY_VARIABLE "sip_crypto_mandatory"
-#define SOFIA_AUTO_PORT -1
 
 #include <sofia-sip/nua.h>
 #include <sofia-sip/sip_status.h>
@@ -90,7 +104,14 @@
 #include <sofia-sip/su_log.h>
 #include <sofia-sip/nea.h>
 #include <sofia-sip/msg_addr.h>
+#include <sofia-sip/tport_tag.h>
+#include <sofia-sip/sip_extra.h>
+#include "nua_stack.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/sip_parser.h"
+#include "sofia-sip/tport_tag.h"
 
+
 typedef enum {
 	DTMF_2833,
 	DTMF_INFO,
@@ -100,10 +121,17 @@
 struct sofia_private {
 	char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
 	sofia_gateway_t *gateway;
+	char gateway_name[256];
+	char auth_gateway_name[256];
+	int destroy_nh;
+	int destroy_me;
+	int is_call;
+	int is_static;
 };
 
 #define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);}
 #define set_anchor(t,m) if (t->Anchor) {delete t->Anchor;} t->Anchor = new SipMessage(m);
+#define sofia_private_free(_pvt) if (_pvt && ! _pvt->is_static) {free(_pvt); _pvt = NULL;}
 
 /* Local Structures */
 /*************************************************************************************************************************************************************/
@@ -121,63 +149,102 @@
 } MFLAGS;
 
 typedef enum {
-	PFLAG_AUTH_CALLS = (1 << 0),
-	PFLAG_BLIND_REG = (1 << 1),
-	PFLAG_AUTH_ALL = (1 << 2),
-	PFLAG_FULL_ID = (1 << 3),
-	PFLAG_PRESENCE = (1 << 4),
-	PFLAG_PASS_RFC2833 = (1 << 5),
-	PFLAG_DISABLE_TRANSCODING = (1 << 6),
-	PFLAG_REWRITE_TIMESTAMPS = (1 << 7),
-	PFLAG_RUNNING = (1 << 8),
-	PFLAG_RESPAWN = (1 << 9),
-	PFLAG_GREEDY = (1 << 10),
-	PFLAG_MULTIREG = (1 << 11),
-	PFLAG_SUPRESS_CNG = (1 << 12),
-	PFLAG_TLS = (1 << 13),
-	PFLAG_CHECKUSER = (1 << 14),
-	PFLAG_SECURE = (1 << 15),
-	PFLAG_BLIND_AUTH = (1 << 16),
-	PFLAG_WORKER_RUNNING = (1 << 17),
-	PFLAG_UNREG_OPTIONS_FAIL = (1 << 18)
+	PFLAG_AUTH_CALLS,
+	PFLAG_BLIND_REG,
+	PFLAG_AUTH_ALL,
+	PFLAG_FULL_ID,
+	PFLAG_MULTIREG_CONTACT,
+	PFLAG_PASS_RFC2833,
+	PFLAG_DISABLE_TRANSCODING,
+	PFLAG_REWRITE_TIMESTAMPS,
+	PFLAG_RUNNING,
+	PFLAG_RESPAWN,
+	PFLAG_GREEDY,
+	PFLAG_MULTIREG,
+	PFLAG_SUPPRESS_CNG,
+	PFLAG_TLS,
+	PFLAG_CHECKUSER,
+	PFLAG_SECURE,
+	PFLAG_BLIND_AUTH,
+	PFLAG_WORKER_RUNNING,
+	PFLAG_UNREG_OPTIONS_FAIL,
+	PFLAG_DISABLE_TIMER,
+	PFLAG_DISABLE_100REL,
+	PFLAG_AGGRESSIVE_NAT_DETECTION,
+	PFLAG_RECIEVED_IN_NAT_REG_CONTACT,
+	PFLAG_3PCC,
+	PFLAG_DISABLE_RTP_AUTOADJ,
+	PFLAG_DISABLE_SRTP_AUTH,
+	PFLAG_FUNNY_STUN,
+	PFLAG_STUN_ENABLED,
+	PFLAG_STUN_AUTO_DISABLE,
+	PFLAG_3PCC_PROXY,
+	PFLAG_CALLID_AS_UUID,
+	PFLAG_UUID_AS_CALLID,
+	PFLAG_SCROOGE,
+	PFLAG_MANAGE_SHARED_APPEARANCE,
+	PFLAG_DISABLE_SRV,
+	PFLAG_DISABLE_NAPTR,
+	PFLAG_AUTOFLUSH,
+	PFLAG_NAT_OPTIONS_PING,
+	PFLAG_AUTOFIX_TIMING,
+	PFLAG_MESSAGE_QUERY_ON_REGISTER,
+	PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE,
+	PFLAG_MANUAL_REDIRECT,
+	PFLAG_AUTO_NAT,
+	/* No new flags below this line */
+	PFLAG_MAX
 } PFLAGS;
 
 typedef enum {
 	PFLAG_NDLB_TO_IN_200_CONTACT = (1 << 0),
-	PFLAG_NDLB_BROKEN_AUTH_HASH = (1 << 1)
+	PFLAG_NDLB_BROKEN_AUTH_HASH = (1 << 1),
+	PFLAG_NDLB_SENDRECV_IN_SESSION = (1 << 2)
 } sofia_NDLB_t;
 
 typedef enum {
-	TFLAG_IO = (1 << 0),
-	TFLAG_CHANGE_MEDIA = (1 << 1),
-	TFLAG_OUTBOUND = (1 << 2),
-	TFLAG_READING = (1 << 3),
-	TFLAG_WRITING = (1 << 4),
-	TFLAG_HUP = (1 << 5),
-	TFLAG_RTP = (1 << 6),
-	TFLAG_BYE = (1 << 7),
-	TFLAG_ANS = (1 << 8),
-	TFLAG_EARLY_MEDIA = (1 << 9),
-	TFLAG_SECURE = (1 << 10),
-	TFLAG_VAD_IN = (1 << 11),
-	TFLAG_VAD_OUT = (1 << 12),
-	TFLAG_VAD = (1 << 13),
-	TFLAG_TIMER = (1 << 14),
-	TFLAG_READY = (1 << 15),
-	TFLAG_REINVITE = (1 << 16),
-	TFLAG_REFER = (1 << 17),
-	TFLAG_NOHUP = (1 << 18),
-	TFLAG_XFER = (1 << 19),
-	TFLAG_RESERVED = (1 << 20),
-	TFLAG_BUGGY_2833 = (1 << 21),
-	TFLAG_SIP_HOLD = (1 << 22),
-	TFLAG_INB_NOMEDIA = (1 << 23),
-	TFLAG_LATE_NEGOTIATION = (1 << 24),
-	TFLAG_SDP = (1 << 25),
-	TFLAG_VIDEO = (1 << 26),
-	TFLAG_TPORT_LOG = (1 << 27),
-	TFLAG_SENT_UPDATE = (1 << 28),
-	TFLAG_PROXY_MEDIA = (1 << 29)
+	STUN_FLAG_SET = (1 << 0),
+	STUN_FLAG_PING = (1 << 1),
+	STUN_FLAG_FUNNY = (1 << 2)
+} STUNFLAGS;
+
+typedef enum {
+	TFLAG_IO,
+	TFLAG_CHANGE_MEDIA,
+	TFLAG_OUTBOUND,
+	TFLAG_READING,
+	TFLAG_WRITING,
+	TFLAG_HUP,
+	TFLAG_RTP,
+	TFLAG_BYE,
+	TFLAG_ANS,
+	TFLAG_EARLY_MEDIA,
+	TFLAG_SECURE,
+	TFLAG_VAD_IN,
+	TFLAG_VAD_OUT,
+	TFLAG_VAD,
+	TFLAG_3PCC,
+	TFLAG_READY,
+	TFLAG_REINVITE,
+	TFLAG_REFER,
+	TFLAG_NOHUP,
+	TFLAG_NOSDP_REINVITE,
+	TFLAG_NAT,
+	TFLAG_USEME,
+	TFLAG_SIP_HOLD,
+	TFLAG_INB_NOMEDIA,
+	TFLAG_LATE_NEGOTIATION,
+	TFLAG_SDP,
+	TFLAG_VIDEO,
+	TFLAG_TPORT_LOG,
+	TFLAG_SENT_UPDATE,
+	TFLAG_PROXY_MEDIA,
+	TFLAG_HOLD_LOCK,
+	TFLAG_3PCC_HAS_ACK,
+	TFLAG_PASS_RFC2833,
+
+	/* No new flags below this line */
+	TFLAG_MAX
 } TFLAGS;
 
 struct mod_sofia_globals {
@@ -190,14 +257,33 @@
 	int32_t threads;
 	switch_mutex_t *mutex;
 	char guess_ip[80];
+	char hostname[512];
 	switch_queue_t *presence_queue;
 	switch_queue_t *mwi_queue;
+	struct sofia_private destroy_private;
+	struct sofia_private keep_private;
+	switch_event_node_t *in_node;
+	switch_event_node_t *probe_node;
+	switch_event_node_t *out_node;
+	switch_event_node_t *roster_node;
+	switch_event_node_t *custom_node;
+	switch_event_node_t *mwi_node;
+	int guess_mask;
+	char guess_mask_str[16];
+	int debug_presence;
+	int auto_restart;
+	int auto_nat;
+	int tracelevel;
+	int rewrite_multicasted_fs_path;
 };
 extern struct mod_sofia_globals mod_sofia_globals;
 
 typedef enum {
-	REG_FLAG_AUTHED = (1 << 0),
-	REG_FLAG_CALLERID = (1 << 1)
+	REG_FLAG_AUTHED,
+	REG_FLAG_CALLERID,
+
+	/* No new flags below this line */
+	REG_FLAG_MAX
 } reg_flags_t;
 
 typedef enum {
@@ -207,6 +293,7 @@
 	REG_STATE_REGED,
 	REG_STATE_UNREGISTER,
 	REG_STATE_FAILED,
+	REG_STATE_FAIL_WAIT,
 	REG_STATE_EXPIRED,
 	REG_STATE_NOREG,
 	REG_STATE_LAST
@@ -220,33 +307,99 @@
 	SOFIA_TRANSPORT_SCTP
 } sofia_transport_t;
 
+typedef enum {
+	SOFIA_GATEWAY_DOWN,
+	SOFIA_GATEWAY_UP
+} sofia_gateway_status_t;
+
+typedef enum {
+	SUB_STATE_UNSUBED,
+	SUB_STATE_TRYING,
+	SUB_STATE_SUBSCRIBE,
+	SUB_STATE_SUBED,
+	SUB_STATE_UNSUBSCRIBE,
+	SUB_STATE_FAILED,
+	SUB_STATE_EXPIRED,
+	SUB_STATE_NOSUB,
+	v_STATE_LAST
+} sub_state_t;
+
+struct sofia_gateway_subscription {
+	sofia_gateway_t *gateway;
+	char *expires_str;
+	char *event;  /* eg, 'message-summary' to subscribe to MWI events */
+	char *content_type;  /* eg, application/simple-message-summary in the case of MWI events */
+	uint32_t freq;
+	int32_t retry_seconds;
+	time_t expires;
+	time_t retry;
+	sub_state_t state;
+	struct sofia_gateway_subscription *next;
+};
+
 struct sofia_gateway {
 	sofia_private_t *sofia_private;
 	nua_handle_t *nh;
+	nua_handle_t *sub_nh;
 	sofia_profile_t *profile;
 	char *name;
 	char *register_scheme;
 	char *register_realm;
 	char *register_username;
+	char *auth_username;
 	char *register_password;
 	char *register_from;
 	char *register_contact;
+	char *extension;
 	char *register_to;
 	char *register_proxy;
+	char *register_sticky_proxy;
+	char *outbound_sticky_proxy;
 	char *register_context;
 	char *expires_str;
 	char *register_url;
+	char *from_domain;
 	sofia_transport_t register_transport;
 	uint32_t freq;
 	time_t expires;
 	time_t retry;
-	uint32_t flags;
+	time_t ping;
+	int pinging;
+	sofia_gateway_status_t status;
+	uint32_t ping_freq;
+	uint8_t flags[REG_FLAG_MAX];
 	int32_t retry_seconds;
 	reg_state_t state;
 	switch_memory_pool_t *pool;
+	int deleted;
+	switch_event_t *ib_vars;
+	switch_event_t *ob_vars;
+	uint32_t ib_calls;
+	uint32_t ob_calls;
+	char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+	int failures;
 	struct sofia_gateway *next;
+	sofia_gateway_subscription_t *subscriptions;
 };
 
+typedef enum {
+	PRES_TYPE_NONE = 0,
+	PRES_TYPE_FULL = 1,
+	PRES_TYPE_PASSIVE = 2
+} sofia_presence_type_t;
+
+typedef enum {
+	MEDIA_OPT_NONE = 0,
+	MEDIA_OPT_MEDIA_ON_HOLD = (1 << 0),
+	MEDIA_OPT_BYPASS_AFTER_ATT_XFER = (1 << 1)
+} sofia_media_options_t;
+
+typedef enum {
+	CID_TYPE_RPID,
+	CID_TYPE_PID,
+	CID_TYPE_NONE
+} sofia_cid_type_t;
+
 struct sofia_profile {
 	int debug;
 	char *name;
@@ -260,27 +413,40 @@
 	char *extsipip;
 	char *username;
 	char *url;
+	char *public_url;
 	char *bindurl;
 	char *tls_url;
+	char *tls_public_url;
 	char *tls_bindurl;
+	char *tcp_public_contact;
+	char *tls_public_contact;
+	char *tcp_contact;
+	char *tls_contact;
+	char *sla_contact;
 	char *sipdomain;
 	char *timer_name;
 	char *hold_music;
+	char *outbound_proxy;
 	char *bind_params;
 	char *tls_bind_params;
 	char *tls_cert_dir;
 	char *reg_domain;
+	char *reg_db_domain;
 	char *user_agent;
 	char *record_template;
+	char *presence_hosts;
+	char *challenge_realm;
+	sofia_cid_type_t cid_type;
 	sofia_dtmf_t dtmf_type;
-	int sip_port;
-	int tls_sip_port;
+	int auto_restart;
+	switch_port_t sip_port;
+	switch_port_t tls_sip_port;
 	int tls_version;
 	char *codec_string;
 	int running;
 	int dtmf_duration;
-	unsigned int flags;
-	unsigned int pflags;
+	uint8_t flags[TFLAG_MAX];
+	uint8_t pflags[PFLAG_MAX];
 	unsigned int mflags;
 	unsigned int ndlb;
 	uint32_t max_calls;
@@ -296,7 +462,6 @@
 	switch_mutex_t *gateway_mutex;
 	sofia_gateway_t *gateways;
 	su_home_t *home;
-	switch_hash_t *sub_hash;
 	switch_hash_t *chat_hash;
 	switch_core_db_t *master_db;
 	switch_thread_rwlock_t *rwlock;
@@ -304,6 +469,7 @@
 	uint32_t inuse;
 	time_t started;
 	uint32_t session_timeout;
+	uint32_t minimum_session_expires;
 	uint32_t max_proceeding;
 	uint32_t rtp_timeout_sec;
 	uint32_t rtp_hold_timeout_sec;
@@ -316,12 +482,28 @@
 	uint32_t acl_count;
 	char *reg_acl[SOFIA_MAX_ACL];
 	uint32_t reg_acl_count;
-
+	char *nat_acl[SOFIA_MAX_ACL];
+	uint32_t nat_acl_count;
+	int rport_level;
+	sofia_presence_type_t pres_type;
+	sofia_media_options_t media_options;
+	uint32_t force_subscription_expires;
+	switch_rtp_bug_flag_t auto_rtp_bugs;
+	uint32_t ib_calls;
+	uint32_t ob_calls;
+	uint32_t ib_failed_calls;
+	uint32_t ob_failed_calls;
+	uint32_t timer_t1;
+	uint32_t timer_t1x64;
+	uint32_t timer_t2;
+	uint32_t timer_t4;
+	char *contact_user;
+	char *local_network;
 };
 
 struct private_object {
 	sofia_private_t *sofia_private;
-	uint32_t flags;
+	uint8_t flags[TFLAG_MAX];
 	switch_payload_t agreed_pt;
 	switch_core_session_t *session;
 	switch_channel_t *channel;
@@ -352,18 +534,25 @@
 	char *from_address;
 	char *to_address;
 	char *callid;
-	char *far_end_contact;
 	char *contact_url;
 	char *from_str;
 	char *rpid;
+	char *asserted_id;
+	char *preferred_id;
+	char *privacy;
 	char *gateway_from_str;
 	char *rm_encoding;
 	char *iananame;
 	char *rm_fmtp;
 	char *fmtp_out;
 	char *remote_sdp_str;
+	int crypto_tag;
+	unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
+	unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
+	switch_rtp_crypto_key_type_t crypto_send_type;
+	switch_rtp_crypto_key_type_t crypto_recv_type;
+	switch_rtp_crypto_key_type_t crypto_type;
 	char *local_sdp_str;
-	char *orig_local_sdp_str;
 	char *dest;
 	char *dest_to;
 	char *key;
@@ -380,15 +569,16 @@
 	char *gateway_name;
 	char *local_crypto_key;
 	char *remote_crypto_key;
-	int crypto_tag;
-	unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
-	unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
-	switch_rtp_crypto_key_type_t crypto_send_type;
-	switch_rtp_crypto_key_type_t crypto_recv_type;
-	switch_rtp_crypto_key_type_t crypto_type;
+	char *record_route;
+	char *extrtpip;
+	char *stun_ip;
+	char *route_uri;
+	switch_port_t stun_port;
+	uint32_t stun_flags;
 	unsigned long rm_rate;
 	switch_payload_t pt;
 	switch_mutex_t *flag_mutex;
+	switch_mutex_t *sofia_mutex;
 	switch_payload_t te;
 	switch_payload_t bte;
 	switch_payload_t cng_pt;
@@ -420,6 +610,21 @@
 	uint32_t video_count;
 	sofia_dtmf_t dtmf_type;
 	int q850_cause;
+	char *remote_ip;
+	int remote_port;
+	int got_bye;
+	int hold_laps;
+	switch_thread_id_t locker;
+	switch_size_t last_ts;
+	uint32_t check_frames;
+	uint32_t mismatch_count;
+	uint32_t last_codec_ms;
+	nua_event_t want_event;
+	switch_rtp_bug_flag_t rtp_bugs;
+	switch_codec_implementation_t read_impl;
+	switch_codec_implementation_t write_impl;
+	char *user_via;
+	char *redirected;
 };
 
 struct callback_t {
@@ -430,7 +635,8 @@
 
 typedef enum {
 	REG_REGISTER,
-	REG_INVITE
+	REG_AUTO_REGISTER,
+	REG_INVITE,
 } sofia_regtype_t;
 
 typedef enum {
@@ -439,16 +645,31 @@
 	AUTH_STALE,
 } auth_res_t;
 
-#define sofia_test_pflag(obj, flag) ((obj)->pflags & flag)
-#define sofia_set_pflag(obj, flag) (obj)->pflags |= (flag)
+typedef struct {
+        char *to;
+        char *contact;
+        char *route;
+        char *route_uri;
+} sofia_destination_t;
+
+#define sofia_test_pflag(obj, flag) ((obj)->pflags[flag] ? 1 : 0)
+#define sofia_set_pflag(obj, flag) (obj)->pflags[flag] = 1
 #define sofia_set_pflag_locked(obj, flag) assert(obj->flag_mutex != NULL);\
 switch_mutex_lock(obj->flag_mutex);\
-(obj)->pflags |= (flag);\
+(obj)->pflags[flag] = 1;\
 switch_mutex_unlock(obj->flag_mutex);
-#define sofia_clear_pflag_locked(obj, flag) switch_mutex_lock(obj->flag_mutex); (obj)->pflags &= ~(flag); switch_mutex_unlock(obj->flag_mutex);
-#define sofia_clear_pflag(obj, flag) (obj)->pflags &= ~(flag)
-#define sofia_copy_pflags(dest, src, flags) (dest)->pflags &= ~(flags);	(dest)->pflags |= ((src)->pflags & (flags))
+#define sofia_clear_pflag_locked(obj, flag) switch_mutex_lock(obj->flag_mutex); (obj)->pflags[flag] = 0; switch_mutex_unlock(obj->flag_mutex);
+#define sofia_clear_pflag(obj, flag) (obj)->pflags[flag] = 0
 
+#define sofia_set_flag_locked(obj, flag) assert(obj->flag_mutex != NULL);\
+switch_mutex_lock(obj->flag_mutex);\
+(obj)->flags[flag] = 1;\
+switch_mutex_unlock(obj->flag_mutex);
+#define sofia_set_flag(obj, flag) (obj)->flags[flag] = 1
+#define sofia_clear_flag(obj, flag) (obj)->flags[flag] = 0
+#define sofia_clear_flag_locked(obj, flag) switch_mutex_lock(obj->flag_mutex); (obj)->flags[flag] = 0; switch_mutex_unlock(obj->flag_mutex);
+#define sofia_test_flag(obj, flag) ((obj)->flags[flag] ? 1 : 0)
+
 /* Function Prototypes */
 /*************************************************************************************************************************************************************/
 
@@ -487,8 +708,17 @@
 
 void launch_sofia_profile_thread(sofia_profile_t *profile);
 
-switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint);
+switch_status_t sofia_presence_chat_send(const char *proto, const char *from, const char *to, const char *subject,
+						  const char *body, const char *type, const char *hint);
 void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt);
+
+/*
+ * \brief Sets the "ep_codec_string" channel variable, parsing r_sdp and taing codec_string in consideration 
+ * \param channel Current channel
+ * \param codec_string The profile's codec string or NULL if inexistant
+ * \param sdp The parsed SDP content
+ */
+void sofia_glue_set_r_sdp_codec_string(switch_channel_t *channel,const char *codec_string, sdp_session_t *sdp);
 switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_sdp);
 char *sofia_reg_find_reg_url(sofia_profile_t *profile, const char *user, const char *host, char *val, switch_size_t len);
 void event_handler(switch_event_t *event);
@@ -496,14 +726,17 @@
 void sofia_presence_mwi_event_handler(switch_event_t *event);
 void sofia_presence_cancel(void);
 switch_status_t config_sofia(int reload, char *profile_name);
-void sofia_reg_auth_challange(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_regtype_t regtype, const char *realm, int stale);
-auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, sip_authorization_t const *authorization, sip_t const *sip, const char *regstr, 
-								char *np, size_t nplen, char *ip, switch_event_t **v_event, long exptime, sofia_regtype_t regtype, const char *to_user);
+void sofia_reg_auth_challenge(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_regtype_t regtype, const char *realm, int stale);
+auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, sip_authorization_t const *authorization, 
+								sip_t const *sip, const char *regstr, char *np, size_t nplen, char *ip, switch_event_t **v_event, 
+								long exptime, sofia_regtype_t regtype, const char *to_user, switch_event_t **auth_params);
+								
 
 void sofia_reg_handle_sip_r_challenge(int status,
 									  char const *phrase,
-									  nua_t *nua, sofia_profile_t *profile, 
-									  nua_handle_t *nh, switch_core_session_t *session, sofia_gateway_t *gateway, sip_t const *sip, tagi_t tags[]);
+									  nua_t *nua, sofia_profile_t *profile,
+									  nua_handle_t *nh, sofia_private_t *sofia_private,
+									  switch_core_session_t *session, sofia_gateway_t *gateway, sip_t const *sip, tagi_t tags[]);
 void sofia_reg_handle_sip_r_register(int status,
 					char const *phrase,
 					nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
@@ -523,17 +756,18 @@
 
 void sofia_glue_execute_sql(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic);
 void sofia_glue_actually_execute_sql(sofia_profile_t *profile, switch_bool_t master, char *sql, switch_mutex_t *mutex);
-void sofia_reg_check_expire(sofia_profile_t *profile, time_t now);
+void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot);
 void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now);
+void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now);
 void sofia_reg_unregister(sofia_profile_t *profile);
-switch_status_t sofia_glue_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool);
+switch_status_t sofia_glue_ext_address_lookup(sofia_profile_t *profile, private_object_t *tech_pvt, char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool);
 
 void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp);
 int sofia_glue_get_user_host(char *in, char **user, char **host);
 switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status);
 void sofia_glue_do_xfer_invite(switch_core_session_t *session);
 uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, 
-								  sofia_regtype_t regtype, char *key, uint32_t keylen, switch_event_t **v_event);
+								  sofia_regtype_t regtype, char *key, uint32_t keylen, switch_event_t **v_event, const char *is_nat);
 extern switch_endpoint_interface_t *sofia_endpoint_interface;
 void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip);
 switch_status_t sofia_on_hangup(switch_core_session_t *session);
@@ -556,13 +790,15 @@
 void sofia_glue_release_profile__(const char *file, const char *func, int line, sofia_profile_t *profile);
 #define sofia_glue_release_profile(x) sofia_glue_release_profile__(__FILE__, __SWITCH_FUNC__, __LINE__,  x)
 
-sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, char *key);
+sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, const char *key);
 #define sofia_glue_find_profile(x) sofia_glue_find_profile__(__FILE__, __SWITCH_FUNC__, __LINE__,  x)
 
 switch_status_t sofia_reg_add_gateway(char *key, sofia_gateway_t *gateway);
-sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, int line, char *key);
+sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, int line, const char *key);
 #define sofia_reg_find_gateway(x) sofia_reg_find_gateway__(__FILE__, __SWITCH_FUNC__, __LINE__,  x)
 
+sofia_gateway_subscription_t *sofia_find_gateway_subscription(sofia_gateway_t *gateway_ptr, const char *event);
+
 void sofia_reg_release_gateway__(const char *file, const char *func, int line, sofia_gateway_t *gateway);
 #define sofia_reg_release_gateway(x) sofia_reg_release_gateway__(__FILE__, __SWITCH_FUNC__, __LINE__, x);
 
@@ -591,7 +827,7 @@
 			}															\
 		}																\
 																		\
-		if(_session) break;												\
+		if (_session) break;											\
 	} while(!_session)
 
 
@@ -604,11 +840,64 @@
 
 const char *sofia_glue_transport2str(const sofia_transport_t tp);
 char * sofia_glue_find_parameter(const char *str, const char *param);
-
+char *sofia_glue_create_via(switch_core_session_t *session, const char *ip, switch_port_t port, sofia_transport_t transport);
+char *sofia_glue_create_external_via(switch_core_session_t *session, sofia_profile_t *profile, sofia_transport_t transport);
+char *sofia_glue_strip_uri(const char *str);
+int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip);
 int sofia_glue_transport_has_tls(const sofia_transport_t tp);
 const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name);
 switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction);
 void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt);
 switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt);
 void sofia_presence_event_thread_start(void);
-void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id);
+void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id, int reboot);
+switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, int force);
+switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force);
+const char *sofia_glue_strip_proto(const char *uri);
+switch_status_t reconfig_sofia(sofia_profile_t *profile);
+void sofia_glue_del_gateway(sofia_gateway_t *gp);
+void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent, const char *network_ip);
+void sofia_glue_restart_all_profiles(void);
+void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly);
+const char * sofia_state_string(int state);
+switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force);
+void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout);
+void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options);
+
+/*
+ * SLA (shared line appearance) entrypoints
+ */
+
+void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip, long exptime, const char *full_contact);
+void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
+void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
+void sofia_sla_handle_sip_r_subscribe(int status,
+									  char const *phrase,
+									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
+void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]);
+
+/* 
+ * Logging control functions
+ */
+
+/*!
+ * \brief Changes the loglevel of a sofia component
+ * \param name the sofia component on which to change the loglevel, or "all" to change them all
+ * \note Valid components are "all", "default" (sofia's default logger), "tport", "iptsec", "nea", "nta", "nth_client", "nth_server", "nua", "soa", "sresolv", "stun"
+ * \return SWITCH_STATUS_SUCCESS or SWITCH_STATUS_FALSE if the component isnt valid, or the level is out of range
+ */
+switch_status_t sofia_set_loglevel(const char *name, int level);
+
+/*!
+ * \brief Gets the loglevel of a sofia component
+ * \param name the sofia component on which to change the loglevel
+ * \note Valid components are "default" (sofia's default logger), "tport", "iptsec", "nea", "nta", "nth_client", "nth_server", "nua", "soa", "sresolv", "stun"
+ * \return the component's loglevel, or -1 if the component isn't valid
+ */
+int sofia_get_loglevel(const char *name);
+sofia_cid_type_t sofia_cid_name2type(const char *name);
+void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup);
+void sofia_glue_set_rtp_stats(private_object_t *tech_pvt);
+void sofia_glue_get_addr(msg_t *msg, char *buf, size_t buflen, int *port);
+sofia_destination_t* sofia_glue_get_destination(char *data);
+void sofia_glue_free_destination(sofia_destination_t *dst);

Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj (14389 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj	2009-07-27 19:05:59 UTC (rev 14389)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj	2009-07-27 20:18:20 UTC (rev 14390)
@@ -17,15 +17,12 @@
 	<Configurations>
 		<Configuration
 			Name="Debug|Win32"
-			OutputDirectory="$(ConfigurationName)"
-			IntermediateDirectory="$(ConfigurationName)"
 			ConfigurationType="2"
-			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
 			CharacterSet="2"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
-				CommandLine=""
 			/>
 			<Tool
 				Name="VCCustomBuildTool"
@@ -41,17 +38,9 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				Optimization="0"
-				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&quot;"
+				PreprocessorDefinitions="LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
 				UsePrecompiledHeader="0"
-				WarningLevel="4"
-				WarnAsError="true"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
 				DisableSpecificWarnings="4201"
 			/>
 			<Tool
@@ -66,14 +55,7 @@
 			<Tool
 				Name="VCLinkerTool"
 				AdditionalDependencies="ws2_32.lib advapi32.lib iphlpapi.lib"
-				OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
-				LinkIncremental="1"
-				AdditionalLibraryDirectories="&quot;..\..\..\..\w32\vsnet\$(OutDir)&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
-				GenerateDebugInformation="true"
-				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
-				SubSystem="2"
-				ImportLibrary="$(OutDir)/mod_sofia.lib"
-				TargetMachine="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
 			/>
 			<Tool
 				Name="VCALinkTool"
@@ -102,15 +84,12 @@
 		</Configuration>
 		<Configuration
 			Name="Release|Win32"
-			OutputDirectory="$(ConfigurationName)"
-			IntermediateDirectory="$(ConfigurationName)"
 			ConfigurationType="2"
-			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
 			CharacterSet="2"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
-				CommandLine=""
 			/>
 			<Tool
 				Name="VCCustomBuildTool"
@@ -126,14 +105,10 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;"
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
-				RuntimeLibrary="2"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&quot;"
+				PreprocessorDefinitions="LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB"
 				UsePrecompiledHeader="0"
-				WarningLevel="4"
-				WarnAsError="true"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
 				DisableSpecificWarnings="4201"
 			/>
 			<Tool
@@ -148,17 +123,7 @@
 			<Tool
 				Name="VCLinkerTool"
 				AdditionalDependencies="ws2_32.lib advapi32.lib iphlpapi.lib"
-				OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
-				LinkIncremental="1"
-				AdditionalLibraryDirectories="&quot;..\..\..\..\w32\vsnet\$(OutDir)&quot;;&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
-				GenerateDebugInformation="true"
-				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
-				SubSystem="2"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				LinkTimeCodeGeneration="1"
-				ImportLibrary="$(OutDir)/mod_sofia.lib"
-				TargetMachine="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&quot;"
 			/>
 			<Tool
 				Name="VCALinkTool"
@@ -189,28 +154,34 @@
 	<References>
 	</References>
 	<Files>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+		<File
+			RelativePath=".\mod_sofia.c"
 			>
-			<File
-				RelativePath=".\mod_sofia.c"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+		</File>
+		<File
+			RelativePath=".\mod_sofia.h"
 			>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+		</File>
+		<File
+			RelativePath=".\sofia.c"
 			>
-		</Filter>
+		</File>
+		<File
+			RelativePath=".\sofia_glue.c"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia_presence.c"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia_reg.c"
+			>
+		</File>
+		<File
+			RelativePath=".\sofia_sla.c"
+			>
+		</File>
 	</Files>
 	<Globals>
 	</Globals>
Property changes on: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj
___________________________________________________________________
Name: svn:eol-style
   + CRLF

Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c (14389 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c	2009-07-27 19:05:59 UTC (rev 14389)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c	2009-07-27 20:18:20 UTC (rev 14390)
@@ -1,6 +1,6 @@
 /* 
  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
  *
  * Version: MPL 1.1
  *
@@ -17,13 +17,13 @@
  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
  *
  * The Initial Developer of the Original Code is
- * Anthony Minessale II <anthmct@yahoo.com>
+ * Anthony Minessale II <anthm@freeswitch.org>
  * Portions created by the Initial Developer are Copyright (C)
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  * 
- * Anthony Minessale II <anthmct@yahoo.com>
+ * Anthony Minessale II <anthm@freeswitch.org>
  * Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
  * Paul D. Tinsley <pdt at jackhammer.org>
  * Bret McDanel <trixter AT 0xdecafbad.com>
@@ -35,10 +35,8 @@
  *
  */
 #include "mod_sofia.h"
-#include "sofia-sip/msg_parser.h"
-#include "sofia-sip/sip_extra.h"
-#include "sofia-sip/tport_tag.h"
 
+
 extern su_log_t tport_log[];
 extern su_log_t iptsec_log[];
 extern su_log_t nea_log[];
@@ -49,6 +47,7 @@
 extern su_log_t soa_log[];
 extern su_log_t sresolv_log[];
 extern su_log_t stun_log[];
+extern su_log_t su_log_default[];
 
 static void set_variable_sip_param(switch_channel_t *channel, char *header_type, sip_param_t const *params);
 
@@ -56,145 +55,340 @@
 
 static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 									 char const *phrase,
-									 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
+									 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+									 tagi_t tags[]);
 
 static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status,
-									 char const *phrase,
-									 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
-static void sofia_handle_sip_r_options(switch_core_session_t *session, int status,
-									 char const *phrase,
-									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
+									  char const *phrase,
+									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+									  tagi_t tags[]);
+static void sofia_handle_sip_r_options(switch_core_session_t *session, int status, char const *phrase, nua_t *nua, sofia_profile_t *profile,
+									   nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
 
 void sofia_handle_sip_r_notify(switch_core_session_t *session, int status,
 							   char const *phrase,
 							   nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
 {
-	if (status >= 300 && sip) {
-		const char *call_id = sip->sip_call_id->i_id;
+#if 0
+	if (status >= 300 && sip && sip->sip_call_id) {
 		char *sql;
-		switch_core_hash_delete(profile->sub_hash, call_id);
-		
-		sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id);
+		sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", sip->sip_call_id->i_id);
 		switch_assert(sql != NULL);
 		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
-		nua_handle_destroy(nh);
 	}
+#endif
 }
 
 void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
-							  char const *phrase,
-							  nua_t *nua,
-							  sofia_profile_t *profile,
-							  nua_handle_t *nh,
-							  sofia_private_t *sofia_private,
-							  sip_t const *sip,
-							  tagi_t tags[])
+							   char const *phrase,
+							   nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
 {
 	switch_channel_t *channel = NULL;
-	
+	private_object_t *tech_pvt = NULL;
+	switch_event_t *s_event = NULL;
+	sofia_gateway_subscription_t *gw_sub_ptr;
+	int sub_state;
+
+	tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END());
+
 	/* make sure we have a proper event */
 	if (!sip || !sip->sip_event) {
 		goto error;
 	}
 
+	/* the following could be refactored back to the calling event handler here in sofia.c XXX MTK */
+	/* potentially interesting note: for Linksys shared appearance, we'll probably have to set up to get bare notifies
+	 * and pass them inward to the sla handler. we'll have to set NUTAG_APPL_METHOD("NOTIFY") when creating
+	 * nua, and also pick them off special elsewhere here in sofia.c - MTK
+	 * *and* for Linksys, I believe they use "sa" as their magic appearance agent name for those blind notifies, so
+	 * we'll probably have to change to match
+	*/
+	if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
+		
+		if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
+			sofia_sla_handle_sip_i_notify(nua, profile, nh, sip, tags);
+			goto end;
+		}
+	}
+
 	/* Automatically return a 200 OK for Event: keep-alive */
 	if (!strcasecmp(sip->sip_event->o_type, "keep-alive")) {
+		/* XXX MTK - is this right? in this case isn't sofia is already sending a 200 itself also? */
 		nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
-		return;
+		goto end;
 	}
 
-	/* make sure we have a proper "talk" event */
-	if (!session || strcasecmp(sip->sip_event->o_type, "talk")) {
-		goto error;
+	if (session) {
+		channel = switch_core_session_get_channel(session);
+		switch_assert(channel != NULL);
+		tech_pvt = switch_core_session_get_private(session);
+		switch_assert(tech_pvt != NULL);
 	}
 
-	channel = switch_core_session_get_channel(session);
-	switch_assert(channel != NULL);
-	if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
-		switch_channel_answer(channel);
-		switch_channel_set_variable(channel, "auto_answer_destination", switch_channel_get_variable(channel, "destination_number"));
-		switch_ivr_session_transfer(session, "auto_answer", NULL , NULL);
+	/* For additional NOTIFY event packages see http://www.iana.org/assignments/sip-events. */
+	if (sip->sip_content_type &&
+		sip->sip_content_type->c_type &&
+		sip->sip_payload &&
+		sip->sip_payload->pl_data &&
+		!strcasecmp(sip->sip_event->o_type, "refer")) {
+		if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_NOTIFY_REFER) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "content-type", sip->sip_content_type->c_type);
+			switch_event_add_body(s_event, "%s", sip->sip_payload->pl_data);
+		}
+	}
+
+	/* add common headers for the NOTIFY to the switch_event and fire if it exists */
+	if (s_event != NULL) {
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event-package", sip->sip_event->o_type);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event-id", sip->sip_event->o_id);
+
+		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s@%s", 
+								sip->sip_contact->m_url->url_user, sip->sip_contact->m_url->url_host);
+		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", 
+								sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-tag", sip->sip_from->a_tag);
+		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", 
+								sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-tag", sip->sip_to->a_tag);
+
+		if (sip->sip_call_id && sip->sip_call_id->i_id) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", sip->sip_call_id->i_id);
+		}
+		if (sip->sip_subscription_state && sip->sip_subscription_state->ss_substate) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-substate", sip->sip_subscription_state->ss_substate);
+		}
+		if (sip->sip_subscription_state && sip->sip_subscription_state->ss_reason) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-reason", sip->sip_subscription_state->ss_reason);
+		}
+		if (sip->sip_subscription_state && sip->sip_subscription_state->ss_retry_after) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-retry-after", sip->sip_subscription_state->ss_retry_after);
+		}
+		if (sip->sip_subscription_state && sip->sip_subscription_state->ss_expires) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-expires", sip->sip_subscription_state->ss_expires);
+		}
+		if (session) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "UniqueID", switch_core_session_get_uuid(session));
+		}
+		switch_event_fire(&s_event);
+	}
+
+	if (!strcasecmp(sip->sip_event->o_type, "refer")) {
+		if (session && channel && tech_pvt) {
+			if (sip->sip_payload && sip->sip_payload->pl_data) {
+				char *p;
+				int status_val = 0;
+				if ((p = strchr(sip->sip_payload->pl_data, ' '))) {
+					p++;
+					if (p) {
+						status_val = atoi(p);
+					}
+				}
+				if (!status_val || status_val >= 200) {
+					switch_channel_set_variable(channel, "sip_refer_reply", sip->sip_payload->pl_data);
+					if (status_val == 200) {
+						switch_channel_hangup(channel, SWITCH_CAUSE_BLIND_TRANSFER);
+					}
+					if (tech_pvt->want_event == 9999) {
+						tech_pvt->want_event = 0;
+					}
+				}
+			}
+		}
 		nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
-		return;
 	}
 
-error:
-	nua_respond(nh, 481, "Subscription Does Not Exist", NUTAG_WITH_THIS(nua), TAG_END());
-	return;
+	/* if no session, assume it could be an incoming notify from a gateway subscription */
+	if (session) {
+		/* make sure we have a proper "talk" event */
+		if (strcasecmp(sip->sip_event->o_type, "talk")) {
+			goto error;
+		}
+
+		if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			switch_channel_answer(channel);
+			switch_channel_set_variable(channel, "auto_answer_destination", switch_channel_get_variable(channel, "destination_number"));
+			switch_ivr_session_transfer(session, "auto_answer", NULL, NULL);
+			nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+			goto end;
+		}
+	}
+	
+	if (!sofia_private || !sofia_private->gateway) {
+		if (profile->debug) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Gateway information missing Subscription Event: %s\n", sip->sip_event->o_type);
+		}
+		goto error;	
+	}
+				
+	/* find the corresponding gateway subscription (if any) */
+	if (!(gw_sub_ptr = sofia_find_gateway_subscription(sofia_private->gateway, sip->sip_event->o_type))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+						  "Could not find gateway subscription.  Gateway: %s.  Subscription Event: %s\n",
+						  sofia_private->gateway->name, sip->sip_event->o_type);
+		goto error;	
+	}
+
+	if (!(gw_sub_ptr->state == SUB_STATE_SUBED || gw_sub_ptr->state == SUB_STATE_SUBSCRIBE)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+						  "Ignoring notify due to subscription state: %d\n",
+						  gw_sub_ptr->state);
+		goto error;	
+	}
+
+	/* dispatch freeswitch event */
+	if (switch_event_create(&s_event, SWITCH_EVENT_NOTIFY_IN) == SWITCH_STATUS_SUCCESS) {
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event", sip->sip_event->o_type);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "pl_data", sip->sip_payload->pl_data);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "sip_content_type", sip->sip_content_type->c_type);
+		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", sofia_private->gateway->profile->sip_port);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", sofia_private->gateway->profile->name);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", sofia_private->gateway->profile->url);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "gateway_name", sofia_private->gateway->name);
+		switch_event_fire(&s_event);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dispatched freeswitch event for message-summary NOTIFY\n");
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create event\n");
+		goto error;	
+	}
+
+	goto end;
+
+  error:
+
+
+	if (sip && sip->sip_event && sip->sip_event->o_type && !strcasecmp(sip->sip_event->o_type, "message-summary")) {
+		/* unsolicited mwi, just say ok */
+		nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+	} else {
+		nua_respond(nh, 481, "Subscription Does Not Exist", NUTAG_WITH_THIS(nua), TAG_END());
+	}
+	
+ end:
+	
+	if (sub_state == nua_substate_terminated && sofia_private && sofia_private != &mod_sofia_globals.destroy_private && 
+		sofia_private != &mod_sofia_globals.keep_private) {
+		sofia_private->destroy_nh = 1;
+		sofia_private->destroy_me = 1;
+	}
+
 }
 
 void sofia_handle_sip_i_bye(switch_core_session_t *session, int status,
-							  char const *phrase,
-							  nua_t *nua,
-							  sofia_profile_t *profile,
-							  nua_handle_t *nh,
-							  sofia_private_t *sofia_private,
-							  sip_t const *sip,
-							  tagi_t tags[])
+							char const *phrase,
+							nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
 {
 	const char *tmp;
 	switch_channel_t *channel;
+	private_object_t *tech_pvt;
+#ifdef MANUAL_BYE
+	int cause;
+	char st[80] = "";
+#endif
 
-	if (!session) return;
+	if (!session)
+		return;
 
-	channel = switch_core_session_get_channel(session); 
+	channel = switch_core_session_get_channel(session);
+	tech_pvt = switch_core_session_get_private(session);
 
 
-    if (sip->sip_reason && sip->sip_reason->re_protocol && 
-        (!strcasecmp(sip->sip_reason->re_protocol, "Q.850") || !strcasecmp(sip->sip_reason->re_protocol, "FreeSWITCH")) &&
-        sip->sip_reason->re_cause) {
-        private_object_t *tech_pvt = switch_core_session_get_private(session);
-        tech_pvt->q850_cause = atoi(sip->sip_reason->re_cause);
+#ifdef MANUAL_BYE
+	status = 200;
+	phrase = "OK";
+	
+	sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+
+	if (sip->sip_reason && sip->sip_reason->re_protocol &&
+		(!strcasecmp(sip->sip_reason->re_protocol, "Q.850") 
+			|| !strcasecmp(sip->sip_reason->re_protocol, "FreeSWITCH")
+			|| !strcasecmp(sip->sip_reason->re_protocol, profile->username)) && sip->sip_reason->re_cause) {
+		tech_pvt->q850_cause = atoi(sip->sip_reason->re_cause);
+		cause = tech_pvt->q850_cause;
+	} else {
+		cause = sofia_glue_sip_cause_to_freeswitch(status);
+	}
+
+	switch_snprintf(st, sizeof(st), "%d", status);
+	switch_channel_set_variable(channel, "sip_term_status", st);
+	switch_snprintf(st, sizeof(st), "sip:%d", status);
+
+	if (phrase) {
+		switch_channel_set_variable_partner(channel, "sip_hangup_phrase", phrase);
+	}
+
+	switch_snprintf(st, sizeof(st), "%d", cause);
+	switch_channel_set_variable(channel, "sip_term_cause", st);
+	switch_channel_hangup(channel, cause);
+	nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+
+	if (sofia_private) {
+        sofia_private->destroy_me = 1;
+        sofia_private->destroy_nh = 1;
     }
+#endif
 
-	if (sip->sip_user_agent && !switch_strlen_zero(sip->sip_user_agent->g_string)){
+
+	if (sip->sip_user_agent && !switch_strlen_zero(sip->sip_user_agent->g_string)) {
 		switch_channel_set_variable(channel, "sip_user_agent", sip->sip_user_agent->g_string);
+	} else if (sip->sip_server && !switch_strlen_zero(sip->sip_server->g_string)) {
+		switch_channel_set_variable(channel, "sip_user_agent", sip->sip_server->g_string);
 	}
+
 	if ((tmp = sofia_glue_get_unknown_header(sip, "rtp-txstat"))) {
 		switch_channel_set_variable(channel, "sip_rtp_txstat", tmp);
 	}
 	if ((tmp = sofia_glue_get_unknown_header(sip, "rtp-rxstat"))) {
 		switch_channel_set_variable(channel, "sip_rtp_rxstat", tmp);
 	}
+	if ((tmp = sofia_glue_get_unknown_header(sip, "P-RTP-Stat"))) {
+		switch_channel_set_variable(channel, "sip_p_rtp_stat", tmp);
+	}
+	
+	tech_pvt->got_bye = 1;
+	switch_channel_set_variable(channel, "sip_hangup_disposition", "recv_bye");	
+
 	return;
 }
 
 void sofia_handle_sip_r_message(int status, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip)
 {
-	if (status == 503) {
-		const char *user = NULL, *host = NULL;
-		char *sql;
+}
 
-		if (sip->sip_to && sip->sip_to->a_url) {
-			user = sip->sip_to->a_url->url_user;
-			host = sip->sip_to->a_url->url_host;
+void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout)
+{
+	time_t exp = switch_epoch_time_now(NULL) + timeout;
+	
+	tech_pvt->want_event = event;
 
-			sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", user, host);
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Deleting registration for %s@%s\n", user, host);
-			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
-		}
+	while(switch_channel_ready(tech_pvt->channel) && tech_pvt->want_event && switch_epoch_time_now(NULL) < exp) {
+		switch_yield(100000);
 	}
-
-	nua_handle_destroy(nh);
+	
 }
 
 void sofia_event_callback(nua_event_t event,
 						  int status,
 						  char const *phrase,
-						  nua_t *nua,
-						  sofia_profile_t *profile,
-						  nua_handle_t *nh,
-						  sofia_private_t *sofia_private,
-						  sip_t const *sip,
-						  tagi_t tags[])
+						  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
 {
 	struct private_object *tech_pvt = NULL;
 	auth_res_t auth_res = AUTH_FORBIDDEN;
 	switch_core_session_t *session = NULL;
 	switch_channel_t *channel = NULL;
 	sofia_gateway_t *gateway = NULL;
+	int locked = 0;
+	int check_destroy = 1;
 
-	if (sofia_private) {
+	if (nh && sofia_private == &mod_sofia_globals.keep_private) {
+		if (status >= 300) {
+			nua_handle_bind(nh, NULL);
+			nua_handle_destroy(nh);
+			return;
+		}
+	}
+
+	if (sofia_private && sofia_private != &mod_sofia_globals.destroy_private && sofia_private != &mod_sofia_globals.keep_private) {
 		if ((gateway = sofia_private->gateway)) {
 			if (switch_thread_rwlock_tryrdlock(gateway->profile->rwlock) != SWITCH_STATUS_SUCCESS) {
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile %s is locked\n", gateway->profile->name);
@@ -203,38 +397,44 @@
 		} else if (!switch_strlen_zero(sofia_private->uuid)) {
 			if ((session = switch_core_session_locate(sofia_private->uuid))) {
 				tech_pvt = switch_core_session_get_private(session);
-				channel = switch_core_session_get_channel(tech_pvt->session);
+				channel = switch_core_session_get_channel(session);
+				if (tech_pvt) {
+					switch_mutex_lock(tech_pvt->sofia_mutex);
+					locked = 1;										
+				} else {
+					switch_core_session_rwunlock(session);
+					return;
+				}
+
+				if (status >= 180 && !*sofia_private->auth_gateway_name) {
+					const char *gwname = switch_channel_get_variable(channel, "sip_use_gateway");
+					if (!switch_strlen_zero(gwname)) {
+						switch_set_string(sofia_private->auth_gateway_name, gwname);
+					}
+				}
 				if (!tech_pvt->call_id && sip && sip->sip_call_id && sip->sip_call_id->i_id) {
 					tech_pvt->call_id = switch_core_session_strdup(session, sip->sip_call_id->i_id);
 					switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id);
 				}
+
 				if (tech_pvt->gateway_name) {
 					gateway = sofia_reg_find_gateway(tech_pvt->gateway_name);
 				}
+
+				if (channel && switch_channel_down(channel)) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel is already hungup.\n");
+					goto done;
+				}
 			} else {
-				/* too late */
+				/* we can't find the session it must be hanging up or something else, its too late to do anything with it. */
 				return;
 			}
 		}
 	}
-	
-	if (status != 100 && status != 200) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n",
-						  nua_event_name(event), status, phrase, session ? switch_channel_get_name(channel) : "n/a");
-	}
 
-	if (session) {
-		switch_core_session_signal_lock(session);
+	if (sofia_test_pflag(profile, PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
+		sip_authorization_t const *authorization = NULL;
 
-		if (channel && switch_channel_get_state(channel) >= CS_HANGUP) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel is already hungup.\n");
-			goto done;
-		}
-	}
-
-	if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
-		sip_authorization_t const *authorization = NULL;
-		
 		if (sip->sip_authorization) {
 			authorization = sip->sip_authorization;
 		} else if (sip->sip_proxy_authorization) {
@@ -243,13 +443,14 @@
 
 		if (authorization) {
 			char network_ip[80];
-			get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_addr);
-			auth_res = sofia_reg_parse_auth(profile, authorization, sip, 
-											(char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key), network_ip, NULL, 0, REG_INVITE, NULL);
+			sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), NULL);
+			auth_res = sofia_reg_parse_auth(profile, authorization, sip,
+											(char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key), network_ip, NULL, 0,
+											REG_INVITE, NULL, NULL);
 		}
-
+		
 		if (auth_res != AUTH_OK) {
-			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+			//switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
 			nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
 			goto done;
 		}
@@ -260,17 +461,31 @@
 	}
 
 	if (sip && (status == 401 || status == 407)) {
-		sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, session, gateway, sip, tags);
+		sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, sofia_private, session, gateway, sip, tags);
 		goto done;
 	}
 
 	switch (event) {
+	case nua_r_get_params:
+	case nua_i_fork:
+	case nua_r_info:
+	case nua_r_bye:
+	case nua_r_unregister:
+	case nua_r_unsubscribe:
+	case nua_r_publish:
+	case nua_i_cancel:
+	case nua_r_cancel:
+	case nua_i_error:
+	case nua_i_active:
+	case nua_i_ack:
+	case nua_i_terminated:
+	case nua_r_set_params:
+	case nua_i_prack:
+	case nua_r_prack:
+		break;
 	case nua_r_shutdown:
-		if (status >= 200) {
-			su_root_break(profile->s_root);
-		}
+		if (status >= 200) su_root_break(profile->s_root);
 		break;
-
 	case nua_r_message:
 		sofia_handle_sip_r_message(status, profile, nh, sip);
 		break;
@@ -280,24 +495,9 @@
 	case nua_r_options:
 		sofia_handle_sip_r_options(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
 		break;
-	case nua_r_get_params:
-	case nua_r_unregister:
-	case nua_i_fork:
-	case nua_r_info:
-	case nua_r_bye:
-		break;
 	case nua_i_bye:
 		sofia_handle_sip_i_bye(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
 		break;
-	case nua_r_unsubscribe:
-	case nua_r_publish:
-	case nua_i_cancel:
-	case nua_i_error:
-	case nua_i_active:
-	case nua_i_ack:
-	case nua_i_terminated:
-	case nua_r_set_params:
-		break;
 	case nua_r_notify:
 		sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
 		break;
@@ -311,18 +511,16 @@
 		sofia_handle_sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, tags);
 		break;
 	case nua_i_invite:
-		if (!session) {
-			sofia_handle_sip_i_invite(nua, profile, nh, sofia_private, sip, tags);
-		}
+		if (!session) sofia_handle_sip_i_invite(nua, profile, nh, sofia_private, sip, tags);
 		break;
 	case nua_i_publish:
 		sofia_presence_handle_sip_i_publish(nua, profile, nh, sofia_private, sip, tags);
 		break;
 	case nua_i_register:
+		//nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip->sip_contact), NUTAG_WITH_THIS(nua), TAG_END());
+		//nua_handle_destroy(nh);
 		sofia_reg_handle_sip_i_register(nua, profile, nh, sofia_private, sip, tags);
 		break;
-	case nua_i_prack:
-		break;
 	case nua_i_state:
 		sofia_handle_sip_i_state(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
 		break;
@@ -332,12 +530,12 @@
 	case nua_i_info:
 		sofia_handle_sip_i_info(nua, profile, nh, session, sip, tags);
 		break;
+	case nua_r_update:
+		break;
 	case nua_r_refer:
 		break;
 	case nua_i_refer:
-		if (session) {
-			sofia_handle_sip_i_refer(nua, profile, nh, session, sip, tags);
-		}
+		if (session) sofia_handle_sip_i_refer(nua, profile, nh, session, sip, tags);
 		break;
 	case nua_r_subscribe:
 		sofia_presence_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
@@ -356,12 +554,64 @@
 
   done:
 
+	if (tech_pvt && tech_pvt->want_event && event == tech_pvt->want_event) {
+		tech_pvt->want_event = 0;
+	}
+
+	switch (event) {
+	case nua_i_subscribe:
+	case nua_r_notify:
+		check_destroy = 0;
+		break;
+
+	case nua_i_notify:
+		
+		if (sip && sip->sip_event && !strcmp(sip->sip_event->o_type, "dialog") && sip->sip_event->o_params && !strcmp(sip->sip_event->o_params[0], "sla")) {
+			check_destroy = 0;
+		}
+
+		break;
+	default:
+		break;
+	}
+
+	if ((sofia_private && sofia_private == &mod_sofia_globals.destroy_private)) {
+		nua_handle_bind(nh, NULL);
+		nua_handle_destroy(nh);
+		nh = NULL;
+	}
+
+	if (check_destroy) {
+		if (nh && ((sofia_private && sofia_private->destroy_nh) || !nua_handle_magic(nh))) {
+			if (sofia_private) {
+				nua_handle_bind(nh, NULL);
+			}
+			nua_handle_destroy(nh);
+			nh = NULL;
+		}
+	}
+	
+	if (sofia_private && sofia_private->destroy_me) {
+		if (tech_pvt) {
+            tech_pvt->sofia_private = NULL;
+        }
+
+		if (nh) {
+			nua_handle_bind(nh, NULL);
+		}
+		sofia_private->destroy_me = 12;
+		sofia_private_free(sofia_private);
+	}
+
 	if (gateway) {
 		sofia_reg_release_gateway(gateway);
 	}
 
+	if (locked && tech_pvt) {
+		switch_mutex_unlock(tech_pvt->sofia_mutex);
+	}
+	
 	if (session) {
-		switch_core_session_signal_unlock(session);
 		switch_core_session_rwunlock(session);
 	}
 }
@@ -373,15 +623,26 @@
 	if ((subclass = switch_event_get_header(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_REGISTER)) {
 		char *from_user = switch_event_get_header(event, "orig-from-user");
 		char *from_host = switch_event_get_header(event, "orig-from-host");
+		char *to_host = switch_event_get_header(event, "orig-to-host");
 		char *contact_str = switch_event_get_header(event, "orig-contact");
 		char *exp_str = switch_event_get_header(event, "orig-expires");
 		char *rpid = switch_event_get_header(event, "orig-rpid");
 		char *call_id = switch_event_get_header(event, "orig-call-id");
-		char *user_agent = switch_event_get_header(event, "user-agent");
-		long expires = (long) switch_timestamp(NULL);
+		char *user_agent = switch_event_get_header(event, "orig-user-agent");
+		long expires = (long) switch_epoch_time_now(NULL);
 		char *profile_name = switch_event_get_header(event, "orig-profile-name");
+		char *to_user = switch_event_get_header(event, "orig-to-user");
+		char *presence_hosts = switch_event_get_header(event, "orig-presence-hosts");
+		char *network_ip = switch_event_get_header(event, "orig-network-ip");
+		char *network_port = switch_event_get_header(event, "orig-network-port");
+		char *username = switch_event_get_header(event, "orig-username");
+		char *realm = switch_event_get_header(event, "orig-realm");
+		char *fixed_contact_str = NULL;
+
 		sofia_profile_t *profile = NULL;
 
+		char guess_ip4[256];
+
 		if (exp_str) {
 			expires += atol(exp_str);
 		}
@@ -400,11 +661,38 @@
 			sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", from_user, from_host);
 		}
 
+		if (mod_sofia_globals.rewrite_multicasted_fs_path && contact_str) {
+			const char *needle = ";fs_path=";
+			char *sptr, *eptr = NULL;
+			/* allocate enough room for worst-case scenario */
+			size_t len = strlen(contact_str) + strlen(to_host) + 14;
+			fixed_contact_str = malloc(len);
+			switch_assert(fixed_contact_str);
+			switch_copy_string(fixed_contact_str, contact_str, len);
+	
+			if ((sptr = strstr(fixed_contact_str, needle))) {
+				char *origsptr = strstr(contact_str, needle);
+				eptr = strchr(++origsptr, ';');
+			} else {
+				sptr = strchr(fixed_contact_str, '\0') - 1;
+			}
+
+			switch_snprintf(sptr, len - (sptr - fixed_contact_str), ";fs_path=sip:%s%s", to_host, eptr ? eptr : ">");
+
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Rewrote contact string from '%s' to '%s'\n", contact_str, fixed_contact_str);
+			contact_str = fixed_contact_str;
+		}
+
 		switch_mutex_lock(profile->ireg_mutex);
 		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 		
-		sql = switch_mprintf("insert into sip_registrations values ('%q', '%q','%q','%q','Registered', '%q', %ld, '%q')",
-							  call_id, from_user, from_host, contact_str, rpid, expires, user_agent);
+		switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET);
+		sql = switch_mprintf("insert into sip_registrations "
+							 "(call_id, sip_user, sip_host, presence_hosts, contact, status, rpid, expires,"
+							 "user_agent, server_user, server_host, profile_name, hostname, network_ip, network_port, sip_username, sip_realm) "
+							 "values ('%q','%q','%q','%q','%q','Registered','%q',%ld, '%q','%q','%q','%q','%q','%q','%q','%q','%q')",
+							 call_id, from_user, from_host, presence_hosts, contact_str, rpid, expires, user_agent, to_user, guess_ip4, 
+							 profile_name, mod_sofia_globals.hostname, network_ip, network_port, username, realm);
 
 		if (sql) {
 			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
@@ -412,10 +700,11 @@
 		}
 		switch_mutex_unlock(profile->ireg_mutex);
 
-
 		if (profile) {
 			sofia_glue_release_profile(profile);
 		}
+
+		switch_safe_free(fixed_contact_str);
 	}
 }
 
@@ -426,19 +715,19 @@
 	uint32_t gateway_loops = 0;
 	int loops = 0;
 	uint32_t qsize;
-
+	void *pop;
+	
 	ireg_loops = IREG_SECONDS;
 	gateway_loops = GATEWAY_SECONDS;
 
 	sofia_set_pflag_locked(profile, PFLAG_WORKER_RUNNING);
-	
-	switch_queue_create(&profile->sql_queue, 500000, profile->pool);
-	
+
+	switch_queue_create(&profile->sql_queue, SOFIA_QUEUE_SIZE, profile->pool);
+
 	qsize = switch_queue_size(profile->sql_queue);
 
 	while ((mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING)) || qsize) {
 		if (qsize) {
-			void *pop;
 			switch_mutex_lock(profile->ireg_mutex);
 			while (switch_queue_trypop(profile->sql_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
 				sofia_glue_actually_execute_sql(profile, SWITCH_TRUE, (char *) pop, NULL);
@@ -449,45 +738,53 @@
 
 		if (++loops >= 100) {
 			if (++ireg_loops >= IREG_SECONDS) {
-				sofia_reg_check_expire(profile, switch_timestamp(NULL));
+				sofia_reg_check_expire(profile, switch_epoch_time_now(NULL), 0);
 				ireg_loops = 0;
 			}
 
 			if (++gateway_loops >= GATEWAY_SECONDS) {
-				sofia_reg_check_gateway(profile, switch_timestamp(NULL));
+				sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
 				gateway_loops = 0;
 			}
+			sofia_sub_check_gateway(profile, time(NULL));
 			loops = 0;
 		}
 
-		switch_yield(10000);
+		switch_cond_next();
 		qsize = switch_queue_size(profile->sql_queue);
 	}
-	
+
+	switch_mutex_lock(profile->ireg_mutex);
+	while (switch_queue_trypop(profile->sql_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
+		sofia_glue_actually_execute_sql(profile, SWITCH_TRUE, (char *) pop, NULL);
+		free(pop);
+	}
+	switch_mutex_unlock(profile->ireg_mutex);
+
 	sofia_clear_pflag_locked(profile, PFLAG_WORKER_RUNNING);
-	
+
 	return NULL;
 }
 
-
-void launch_sofia_worker_thread(sofia_profile_t *profile)
+switch_thread_t *launch_sofia_worker_thread(sofia_profile_t *profile)
 {
 	switch_thread_t *thread;
 	switch_threadattr_t *thd_attr = NULL;
 	int x = 0;
 
 	switch_threadattr_create(&thd_attr, profile->pool);
-	switch_threadattr_detach_set(thd_attr, 1);
 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
 	switch_threadattr_priority_increase(thd_attr);
 	switch_thread_create(&thread, thd_attr, sofia_profile_worker_thread_run, profile, profile->pool);
 
-	while(!sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
+	while (!sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
 		switch_yield(100000);
 		if (++x >= 100) {
 			break;
 		}
 	}
+
+	return thread;
 }
 
 void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void *obj)
@@ -496,8 +793,15 @@
 	switch_memory_pool_t *pool;
 	sip_alias_node_t *node;
 	switch_event_t *s_event;
-	int tportlog = 0;
+	int use_100rel = !sofia_test_pflag(profile, PFLAG_DISABLE_100REL);
+	int use_timer = !sofia_test_pflag(profile, PFLAG_DISABLE_TIMER);
+	const char *supported = NULL;
+	int sanity;
+	switch_thread_t *worker_thread;
+	switch_status_t st;
 
+	
+
 	switch_mutex_lock(mod_sofia_globals.mutex);
 	mod_sofia_globals.threads++;
 	switch_mutex_unlock(mod_sofia_globals.mutex);
@@ -513,20 +817,46 @@
 		goto end;
 	}
 
-	if (switch_test_flag(profile, TFLAG_TPORT_LOG)) {
-		tportlog = 1;
+	supported = switch_core_sprintf(profile->pool, "%s%sprecondition, path, replaces", 
+									use_100rel ? "100rel, " : "",
+									use_timer ? "timer, " : ""
+									);
+
+	if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_core_get_variable("nat_type")) {
+		if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_UDP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created UDP nat mapping for %s port %d\n", profile->name, profile->sip_port);
+		}
+		if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created TCP nat mapping for %s port %d\n", profile->name, profile->sip_port);
+		}
+		if(sofia_test_pflag(profile, PFLAG_TLS) && switch_nat_add_mapping(profile->tls_sip_port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created TCP/TLS nat mapping for %s port %d\n", profile->name, profile->tls_sip_port);
+		}
 	}
 
 	profile->nua = nua_create(profile->s_root,	/* Event loop */
-							sofia_event_callback,	/* Callback for processing events */
-							profile,	/* Additional data to pass to callback */
-							NUTAG_URL(profile->bindurl),
-							TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_SIPS_URL(profile->tls_bindurl)),
-							TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_CERTIFICATE_DIR(profile->tls_cert_dir)),
-							TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), TPTAG_TLS_VERSION(profile->tls_version)),
-							NTATAG_UDP_MTU(65536),
-							TAG_IF(tportlog, TPTAG_LOG(1)),
-							TAG_END());	/* Last tag should always finish the sequence */
+							  sofia_event_callback,	/* Callback for processing events */
+							  profile,	/* Additional data to pass to callback */
+							  NUTAG_URL(profile->bindurl),
+							  NTATAG_USER_VIA(1),
+							  TAG_IF(!strchr(profile->sipip, ':'), SOATAG_AF(SOA_AF_IP4_ONLY)),
+							  TAG_IF(strchr(profile->sipip, ':'), SOATAG_AF(SOA_AF_IP6_ONLY)),
+							  TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_SIPS_URL(profile->tls_bindurl)), 
+							  TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_CERTIFICATE_DIR(profile->tls_cert_dir)), 
+							  TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), TPTAG_TLS_VERIFY_POLICY(0)),
+							  TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), TPTAG_TLS_VERSION(profile->tls_version)), 
+							  TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), TPTAG_KEEPALIVE(20000)),
+							  TAG_IF(!strchr(profile->sipip, ':'), NTATAG_UDP_MTU(65535)), 
+ 							  TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_SRV), NTATAG_USE_SRV(0)),
+ 							  TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_NAPTR), NTATAG_USE_NAPTR(0)),
+							  NTATAG_DEFAULT_PROXY(profile->outbound_proxy),
+							  NTATAG_SERVER_RPORT(profile->rport_level),
+							  TPTAG_LOG(sofia_test_flag(profile, TFLAG_TPORT_LOG)), 
+							  TAG_IF(profile->timer_t1, NTATAG_SIP_T1(profile->timer_t1)),
+							  TAG_IF(profile->timer_t1x64, NTATAG_SIP_T1X64(profile->timer_t1x64)),
+							  TAG_IF(profile->timer_t2, NTATAG_SIP_T2(profile->timer_t2)),
+							  TAG_IF(profile->timer_t4, NTATAG_SIP_T4(profile->timer_t4)),
+							  TAG_END());	/* Last tag should always finish the sequence */
 
 	if (!profile->nua) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Creating SIP UA for profile: %s\n", profile->name);
@@ -540,49 +870,54 @@
 				   NUTAG_APPL_METHOD("OPTIONS"),
 				   NUTAG_APPL_METHOD("NOTIFY"),
 				   NUTAG_APPL_METHOD("INFO"),
+#ifdef MANUAL_BYE
+				   NUTAG_APPL_METHOD("BYE"),
+#endif
 				   NUTAG_AUTOANSWER(0),
 				   NUTAG_AUTOALERT(0),
+				   NUTAG_ENABLEMESSENGER(1),
 				   TAG_IF((profile->mflags & MFLAG_REGISTER), NUTAG_ALLOW("REGISTER")),
 				   TAG_IF((profile->mflags & MFLAG_REFER), NUTAG_ALLOW("REFER")),
 				   NUTAG_ALLOW("INFO"),
 				   NUTAG_ALLOW("NOTIFY"),
 				   NUTAG_ALLOW_EVENTS("talk"),
 				   NUTAG_SESSION_TIMER(profile->session_timeout),
+				   TAG_IF(profile->minimum_session_expires, NUTAG_MIN_SE(profile->minimum_session_expires)),
 				   NTATAG_MAX_PROCEEDING(profile->max_proceeding),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("SUBSCRIBE")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("dialog")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("call-info")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("sla")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("include-session-description")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence.winfo")),
-				   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("message-summary")),
-				   SIPTAG_SUPPORTED_STR("100rel, precondition, timer"), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END());
+				   TAG_IF(profile->pres_type, NUTAG_ALLOW("PUBLISH")),
+				   TAG_IF(profile->pres_type, NUTAG_ALLOW("SUBSCRIBE")),
+				   TAG_IF(profile->pres_type, NUTAG_ENABLEMESSAGE(1)),
+				   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("presence")),
+				   TAG_IF((profile->pres_type || sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)), NUTAG_ALLOW_EVENTS("dialog")),
+				   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("call-info")),
+				   TAG_IF((profile->pres_type || sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)), NUTAG_ALLOW_EVENTS("sla")),
+				   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("include-session-description")),
+				   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("presence.winfo")),
+				   TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("message-summary")),
+				   NUTAG_ALLOW_EVENTS("refer"),
+				   SIPTAG_SUPPORTED_STR(supported), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END());
 
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set params for %s\n", profile->name);
 
 	for (node = profile->aliases; node; node = node->next) {
 		node->nua = nua_create(profile->s_root,	/* Event loop */
-								sofia_event_callback,	/* Callback for processing events */
-								profile,	/* Additional data to pass to callback */
-								NUTAG_URL(node->url), TAG_END());	/* Last tag should always finish the sequence */
+							   sofia_event_callback,	/* Callback for processing events */
+							   profile,	/* Additional data to pass to callback */
+							   NTATAG_SERVER_RPORT(profile->rport_level), NUTAG_URL(node->url), TAG_END());	/* Last tag should always finish the sequence */
 
 		nua_set_params(node->nua,
 					   NUTAG_APPL_METHOD("OPTIONS"),
-					   NUTAG_EARLY_MEDIA(1),
 					   NUTAG_AUTOANSWER(0),
 					   NUTAG_AUTOALERT(0),
 					   TAG_IF((profile->mflags & MFLAG_REGISTER), NUTAG_ALLOW("REGISTER")),
 					   TAG_IF((profile->mflags & MFLAG_REFER), NUTAG_ALLOW("REFER")),
 					   NUTAG_ALLOW("INFO"),
-					   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
-					   TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-					   SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END());
+					   TAG_IF(profile->pres_type, NUTAG_ALLOW("PUBLISH")),
+					   TAG_IF(profile->pres_type, NUTAG_ENABLEMESSAGE(1)),
+					   SIPTAG_SUPPORTED_STR(supported), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END());
 	}
 
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "activated db for %s\n", profile->name);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Activated db for %s\n", profile->name);
 
 	switch_mutex_init(&profile->ireg_mutex, SWITCH_MUTEX_NESTED, profile->pool);
 	switch_mutex_init(&profile->gateway_mutex, SWITCH_MUTEX_NESTED, profile->pool);
@@ -592,29 +927,29 @@
 								(sofia_test_pflag(profile, PFLAG_TLS)) ? ",_sips._tcp" : "");
 
 		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "module_name", "%s", "mod_sofia");
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_name", "%s", profile->name);
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_uri", "%s", profile->url);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", profile->url);
 
 		if (sofia_test_pflag(profile, PFLAG_TLS)) {
 			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "tls_port", "%d", profile->tls_sip_port);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", "%s", profile->tls_url);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", profile->tls_url);
 		}
 		switch_event_fire(&s_event);
 	}
 
 	sofia_glue_add_profile(profile->name, profile);
 
-	if (profile->pflags & PFLAG_PRESENCE) {
+	if (profile->pres_type) {
 		sofia_presence_establish_presence(profile);
 	}
 
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Starting thread for %s\n", profile->name);
 
-	profile->started = switch_timestamp(NULL);
+	profile->started = switch_epoch_time_now(NULL);
 
 	sofia_set_pflag_locked(profile, PFLAG_RUNNING);
-	launch_sofia_worker_thread(profile);
+	worker_thread = launch_sofia_worker_thread(profile);
 
 	switch_yield(1000000);
 
@@ -622,25 +957,42 @@
 		su_root_step(profile->s_root, 1000);
 	}
 
+	sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+
+	switch_core_session_hupall_matching_var("sofia_profile_name", profile->name, SWITCH_CAUSE_MANAGER_REQUEST);
+	sanity = 10;
+	while (profile->inuse) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Waiting for %d session(s)\n", profile->inuse);
+		su_root_step(profile->s_root, 1000);
+		if (!--sanity) {
+			break;
+		} else if (sanity == 5) {
+			switch_core_session_hupall_matching_var("sofia_profile_name", profile->name, SWITCH_CAUSE_MANAGER_REQUEST);
+		}
+	}
+
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock %s\n", profile->name);
 	switch_thread_rwlock_wrlock(profile->rwlock);
 	sofia_reg_unregister(profile);
 	nua_shutdown(profile->nua);
 	su_root_run(profile->s_root);
-
+	
 	sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "waiting for worker thread\n");
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Waiting for worker thread\n");
 
-	while(sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
-		switch_yield(100000);
+	switch_thread_join(&st, worker_thread);
+	
+	sanity = 4;
+	while (profile->inuse) {
+		switch_core_session_hupall_matching_var("sofia_profile_name", profile->name, SWITCH_CAUSE_MANAGER_REQUEST);
+		switch_yield(5000000);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Waiting for %d session(s)\n", profile->inuse);
+		if (!--sanity) {
+			break;
+		}
 	}
-
-	while(profile->inuse) {
-		switch_yield(100000);
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "waiting for %d session(s)\n", profile->inuse);
-	}
 	nua_destroy(profile->nua);
-
+	
 	switch_mutex_lock(profile->ireg_mutex);
 	switch_mutex_unlock(profile->ireg_mutex);
 
@@ -649,20 +1001,32 @@
 
 	if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
 		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp,_sip._tcp,_sip._sctp%s",
-							(sofia_test_pflag(profile, PFLAG_TLS)) ? ",_sips._tcp" : "");
+								(sofia_test_pflag(profile, PFLAG_TLS)) ? ",_sips._tcp" : "");
 
 		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "module_name", "%s", "mod_sofia");
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_name", "%s", profile->name);
-		switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_uri", "%s", profile->url);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", profile->url);
 
 		if (sofia_test_pflag(profile, PFLAG_TLS)) {
 			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "tls_port", "%d", profile->tls_sip_port);
-			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", "%s", profile->tls_url);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", profile->tls_url);
 		}
 		switch_event_fire(&s_event);
 	}
 
+	if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_core_get_variable("nat_type")) {
+		if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted UDP nat mapping for %s port %d\n", profile->name, profile->sip_port);
+		}
+		if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted TCP nat mapping for %s port %d\n", profile->name, profile->sip_port);
+		}
+		if(sofia_test_pflag(profile, PFLAG_TLS) && switch_nat_del_mapping(profile->tls_sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted TCP/TLS nat mapping for %s port %d\n", profile->name, profile->tls_sip_port);
+		}
+	}
+
 	sofia_glue_sql_close(profile);
 	su_home_unref(profile->home);
 	su_root_destroy(profile->s_root);
@@ -670,7 +1034,6 @@
 
 	sofia_glue_del_profile(profile);
 	switch_core_hash_destroy(&profile->chat_hash);
-	switch_core_hash_destroy(&profile->sub_hash);
 
 	switch_thread_rwlock_unlock(profile->rwlock);
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write unlock %s\n", profile->name);
@@ -701,37 +1064,135 @@
 	switch_thread_create(&thread, thd_attr, sofia_profile_thread_run, profile, profile->pool);
 }
 
+static void logger(void *logarg, char const *fmt, va_list ap)
+{
+	if (fmt && ap) {
+		switch_log_vprintf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, fmt, ap);
+	} else if (fmt && !ap) {
+		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, "%s", fmt);
+	}
+}
 
+static su_log_t *sofia_get_logger(const char *name) 
+{
+	if (!strcasecmp(name, "tport")) {
+		return tport_log;
+	} else if (!strcasecmp(name, "iptsec")) {
+		return iptsec_log;
+	} else if (!strcasecmp(name, "nea")) {
+		return nea_log;
+	} else if (!strcasecmp(name, "nta")) {
+		return nta_log;
+	} else if (!strcasecmp(name, "nth_client")) {
+		return nth_client_log;
+	} else if (!strcasecmp(name, "nth_server")) {
+		return nth_server_log;
+	} else if (!strcasecmp(name, "nua")) {
+		return nua_log;
+	} else if (!strcasecmp(name, "sresolv")) {
+		return sresolv_log;
+	} else if (!strcasecmp(name, "stun")) {
+		return stun_log;
+	} else if (!strcasecmp(name, "default")) {
+		return su_log_default;
+	} else {
+		return NULL;
+	}
+}
 
-static void logger(void *logarg, char const *fmt, va_list ap)
+switch_status_t sofia_set_loglevel(const char *name, int level)
 {
-	char *data = NULL;
+	su_log_t *log = NULL;
+	
+	if (level < 0 || level > 9) {
+		return SWITCH_STATUS_FALSE;
+	}
+		
+	if (!strcasecmp(name, "all")) {
+		su_log_set_level(su_log_default, level);
+		su_log_set_level(tport_log, level);
+		su_log_set_level(iptsec_log, level);
+		su_log_set_level(nea_log, level);
+		su_log_set_level(nta_log, level);
+		su_log_set_level(nth_client_log, level);
+		su_log_set_level(nth_server_log, level);
+		su_log_set_level(nua_log, level);
+		su_log_set_level(soa_log, level);
+		su_log_set_level(sresolv_log, level);
+		su_log_set_level(stun_log, level);
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
+	if (!(log = sofia_get_logger(name))) {
+		return SWITCH_STATUS_FALSE;
+	}
+	
+	su_log_set_level(log, level);
+		
+	return SWITCH_STATUS_SUCCESS;
+}
 
-	if (fmt) {
-#ifdef HAVE_VASPRINTF
-		int ret;
-		ret = vasprintf(&data, fmt, ap);
-		if ((ret == -1) || !data) {
-			return;
+int sofia_get_loglevel(const char *name)
+{
+	su_log_t *log = NULL;
+	
+	if ((log = sofia_get_logger(name))) {
+		return log->log_level;
+	} else {
+		return -1;
+	}
+}
+
+static void parse_gateway_subscriptions(sofia_profile_t *profile, sofia_gateway_t *gateway, switch_xml_t gw_subs_tag)
+{
+	switch_xml_t subscription_tag, param;
+
+	for (subscription_tag = switch_xml_child(gw_subs_tag, "subscription"); subscription_tag; subscription_tag = subscription_tag->next) {
+		sofia_gateway_subscription_t *gw_sub;
+
+		if ((gw_sub = switch_core_alloc(profile->pool, sizeof(*gw_sub)))) {
+			char *expire_seconds = "3600", *retry_seconds = "30", *content_type = "NO_CONTENT_TYPE";
+			char *event = (char *) switch_xml_attr_soft(subscription_tag, "event");
+			gw_sub->event = switch_core_strdup(gateway->pool, event);			
+			gw_sub->gateway = gateway;
+			gw_sub->next = NULL;
+			
+			for (param = switch_xml_child(subscription_tag, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+				if (!strcmp(var, "expire-seconds")) {
+					expire_seconds = val;
+				} else if (!strcmp(var, "retry-seconds")) {
+					retry_seconds = val;
+				} else if (!strcmp(var, "content-type")) {
+					content_type = val;
+				}
+			}
+			
+			gw_sub->retry_seconds = atoi(retry_seconds);
+			if (gw_sub->retry_seconds < 10) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "INVALID: retry_seconds correcting the value to 30\n");
+				gw_sub->retry_seconds = 30;
+			}
+			
+			gw_sub->expires_str = switch_core_strdup(gateway->pool, expire_seconds);  
+			
+			if ((gw_sub->freq = atoi(gw_sub->expires_str)) < 5) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+				"Invalid Freq: %d.  Setting Register-Frequency to 3600\n", gw_sub->freq);
+				gw_sub->freq = 3600;
+			}
+			gw_sub->freq -= 2;
+			gw_sub->content_type = switch_core_strdup(gateway->pool, content_type);
+			gw_sub->next = gateway->subscriptions;		
 		}
-#else
-		data = (char *) malloc(2048);
-		if (data) {
-			vsnprintf(data, 2048, fmt, ap);
-		} else {
-			return;
-		}
-#endif
+		gateway->subscriptions = gw_sub;
 	}
-	if (data) {
-		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, (char *) "%s", data);
-		free(data);
-	}
 }
 
 static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag)
 {
-	switch_xml_t gateway_tag, param;
+	switch_xml_t gateway_tag, param = NULL, x_params, gw_subs_tag;
 	sofia_gateway_t *gp;
 
 	for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) {
@@ -751,34 +1212,90 @@
 		switch_mutex_unlock(mod_sofia_globals.hash_mutex);
 
 		if ((gateway = switch_core_alloc(profile->pool, sizeof(*gateway)))) {
+			const char *sipip, *format;
+			switch_uuid_t uuid;
+			uint32_t ping_freq = 0, extension_in_contact = 0;
 			char *register_str = "true", *scheme = "Digest",
 				*realm = NULL,
 				*username = NULL,
+				*auth_username = NULL,
 				*password = NULL,
 				*caller_id_in_from = "false",
 				*extension = NULL,
 				*proxy = NULL,
-				*context = "default",
+				*context = profile->context,
 				*expire_seconds = "3600",
 				*retry_seconds = "30",
-				*from_user = "",
-				*from_domain = "",
-				*register_proxy = NULL,
-				*contact_params = NULL,
-				*params = NULL,
-				*register_transport = NULL;
-
+				*from_user = "", *from_domain = NULL, *outbound_proxy = NULL, *register_proxy = NULL, *contact_host = NULL,
+				*contact_params = NULL, *params = NULL, *register_transport = NULL;
+			
+			if (!context) {
+				context = "default";
+			}
+			
+			switch_uuid_get(&uuid);
+			switch_uuid_format(gateway->uuid_str, &uuid);
+			
 			gateway->register_transport = SOFIA_TRANSPORT_UDP;
 			gateway->pool = profile->pool;
 			gateway->profile = profile;
 			gateway->name = switch_core_strdup(gateway->pool, name);
 			gateway->freq = 0;
 			gateway->next = NULL;
+			gateway->ping = 0;
+			gateway->ping_freq = 0;
+			
+			
+			if ((x_params = switch_xml_child(gateway_tag, "variables"))) {
+				param = switch_xml_child(x_params, "variable");
+			} else {
+				param = switch_xml_child(gateway_tag, "variable");
+			}
+			
+			
+			for (; param; param = param->next) {
+				const char *var = switch_xml_attr(param, "name");
+				const char *val = switch_xml_attr(param, "value");
+				const char *direction = switch_xml_attr(param, "direction");
+				int in = 0, out = 0;
+				
+				if (var && val) {
+					if (direction) {
+						if (!strcasecmp(direction, "inbound")) {
+							in = 1;
+						} else if (!strcasecmp(direction, "outbound")) {
+							out = 1;
+						}
+					} else {
+						in = out = 1;
+					}
 
-			for (param = switch_xml_child(gateway_tag, "param"); param; param = param->next) {
+					if (in) {
+						if (!gateway->ib_vars) {
+							switch_event_create_plain(&gateway->ib_vars, SWITCH_EVENT_GENERAL);
+						}
+						switch_event_add_header_string(gateway->ib_vars, SWITCH_STACK_BOTTOM, var, val);
+					}
+
+					if (out) {
+						if (!gateway->ob_vars) {
+							switch_event_create_plain(&gateway->ob_vars, SWITCH_EVENT_GENERAL);
+						}
+						switch_event_add_header_string(gateway->ob_vars, SWITCH_STACK_BOTTOM, var, val);
+					}
+				}
+			}
+
+			if ((x_params = switch_xml_child(gateway_tag, "params"))) {
+				param = switch_xml_child(x_params, "param");
+			} else {
+				param = switch_xml_child(gateway_tag, "param");
+			}
+			
+			for (; param; param = param->next) {
 				char *var = (char *) switch_xml_attr_soft(param, "name");
 				char *val = (char *) switch_xml_attr_soft(param, "value");
-
+				
 				if (!strcmp(var, "register")) {
 					register_str = val;
 				} else if (!strcmp(var, "scheme")) {
@@ -787,12 +1304,18 @@
 					realm = val;
 				} else if (!strcmp(var, "username")) {
 					username = val;
+				} else if (!strcmp(var, "extension-in-contact")) {
+					extension_in_contact = switch_true(val);
+				} else if (!strcmp(var, "auth-username")) {
+					auth_username = val;
 				} else if (!strcmp(var, "password")) {
 					password = val;
 				} else if (!strcmp(var, "caller-id-in-from")) {
 					caller_id_in_from = val;
 				} else if (!strcmp(var, "extension")) {
 					extension = val;
+				} else if (!strcmp(var, "ping")) {
+					ping_freq = atoi(val);
 				} else if (!strcmp(var, "proxy")) {
 					proxy = val;
 				} else if (!strcmp(var, "context")) {
@@ -801,12 +1324,18 @@
 					expire_seconds = val;
 				} else if (!strcmp(var, "retry-seconds")) {
 					retry_seconds = val;
+				} else if (!strcmp(var, "retry_seconds")) { // support typo for back compat
+					retry_seconds = val;
 				} else if (!strcmp(var, "from-user")) {
 					from_user = val;
 				} else if (!strcmp(var, "from-domain")) {
 					from_domain = val;
+				} else if (!strcmp(var, "contact-host")) {
+					contact_host = val;
 				} else if (!strcmp(var, "register-proxy")) {
 					register_proxy = val;
+				} else if (!strcmp(var, "outbound-proxy")) {
+					outbound_proxy = val;
 				} else if (!strcmp(var, "contact-params")) {
 					contact_params = val;
 				} else if (!strcmp(var, "register-transport")) {
@@ -821,8 +1350,25 @@
 				}
 			}
 
+			if (ping_freq) {
+				if (ping_freq >= 5) {
+					gateway->ping_freq = ping_freq;
+					gateway->ping = switch_epoch_time_now(NULL) + ping_freq;
+				} else {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: invalid ping!\n");
+				}
+			}
+
+			if ((gw_subs_tag = switch_xml_child(gateway_tag, "subscriptions"))) {
+				parse_gateway_subscriptions(profile, gateway, gw_subs_tag);
+			}
+			
 			if (switch_strlen_zero(realm)) {
-				realm = name;
+				if (switch_strlen_zero(proxy)) {
+					realm = name;
+				} else {
+					realm = proxy;
+				}
 			}
 
 			if (switch_strlen_zero(username)) {
@@ -849,46 +1395,86 @@
 
 			if (!switch_true(register_str)) {
 				gateway->state = REG_STATE_NOREG;
+				gateway->status = SOFIA_GATEWAY_UP;
 			}
 
-			if (switch_strlen_zero(from_domain)) {
-				from_domain = realm;
+			if (switch_strlen_zero(auth_username)) {
+				auth_username = username;
 			}
+			
+			if (!switch_strlen_zero(register_proxy)) {
+				if (strncasecmp(register_proxy, "sip:", 4) && strncasecmp(register_proxy, "sips:", 5)) {
+					gateway->register_sticky_proxy = switch_core_sprintf(gateway->pool, "sip:%s", register_proxy);
+				} else {
+					gateway->register_sticky_proxy = switch_core_strdup(gateway->pool, register_proxy);
+				}
+			}
 
-			if (switch_strlen_zero(register_proxy)) {
-				register_proxy = proxy;
+			if (!switch_strlen_zero(outbound_proxy)) {
+				if (strncasecmp(outbound_proxy, "sip:", 4) && strncasecmp(outbound_proxy, "sips:", 5)) {
+					gateway->outbound_sticky_proxy = switch_core_sprintf(gateway->pool, "sip:%s", outbound_proxy);
+				} else {
+					gateway->outbound_sticky_proxy = switch_core_strdup(gateway->pool, outbound_proxy);
+				}
 			}
 
 			gateway->retry_seconds = atoi(retry_seconds);
-			if (gateway->retry_seconds < 10) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "INVALID: retry_seconds correcting the value to 30\n");
+
+			if (gateway->retry_seconds < 5) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid retry-seconds of %d on gateway %s, using the value of 30 instead.\n",
+								  gateway->retry_seconds, name);
 				gateway->retry_seconds = 30;
 			}
+
 			gateway->register_scheme = switch_core_strdup(gateway->pool, scheme);
 			gateway->register_context = switch_core_strdup(gateway->pool, context);
 			gateway->register_realm = switch_core_strdup(gateway->pool, realm);
 			gateway->register_username = switch_core_strdup(gateway->pool, username);
+			gateway->auth_username = switch_core_strdup(gateway->pool, auth_username);
 			gateway->register_password = switch_core_strdup(gateway->pool, password);
+
 			if (switch_true(caller_id_in_from)) {
-				switch_set_flag(gateway, REG_FLAG_CALLERID);
+				sofia_set_flag(gateway, REG_FLAG_CALLERID);
 			}
-			register_transport = (char *)sofia_glue_transport2str(gateway->register_transport);
+
+			register_transport = (char *) sofia_glue_transport2str(gateway->register_transport);
+
 			if (contact_params) {
 				if (*contact_params == ';') {
-					params = switch_core_sprintf(gateway->pool, "%s&transport=%s", contact_params, register_transport);
+					params = switch_core_sprintf(gateway->pool, "%s;transport=%s", contact_params, register_transport);
 				} else {
-					params = switch_core_sprintf(gateway->pool, ";%s&transport=%s", contact_params, register_transport);
+					params = switch_core_sprintf(gateway->pool, ";%s;transport=%s", contact_params, register_transport);
 				}
 			} else {
 				params = switch_core_sprintf(gateway->pool, ";transport=%s", register_transport);
 			}
 
-			gateway->register_url = switch_core_sprintf(gateway->pool, "sip:%s;transport=%s", register_proxy, register_transport);
-			gateway->register_from = switch_core_sprintf(gateway->pool, "<sip:%s@%s;transport=%s>", from_user, from_domain, register_transport);
-			gateway->register_contact = switch_core_sprintf(gateway->pool, "<sip:%s@%s:%d%s>", extension,
-												 profile->extsipip ? profile->extsipip : profile->sipip,
-												 sofia_glue_transport_has_tls(gateway->register_transport) ? profile->tls_sip_port : profile->sip_port, params);
+			if (!switch_strlen_zero(from_domain)) {
+				gateway->from_domain = switch_core_strdup(gateway->pool, from_domain);
+			}
 
+			gateway->register_url = switch_core_sprintf(gateway->pool, "sip:%s", proxy);
+			gateway->register_from = switch_core_sprintf(gateway->pool, "<sip:%s@%s;transport=%s>", 
+														 from_user, from_domain ? from_domain : proxy, register_transport);
+
+			sipip = contact_host ? contact_host : profile->extsipip ?  profile->extsipip : profile->sipip;
+
+			if (extension_in_contact) {
+				format = strchr(sipip, ':') ? "<sip:%s@[%s]:%d%s>" : "<sip:%s@%s:%d%s>";
+				gateway->register_contact = switch_core_sprintf(gateway->pool, format, extension,
+																sipip,
+																sofia_glue_transport_has_tls(gateway->register_transport) ?
+																profile->tls_sip_port : profile->sip_port, params);
+			} else {
+				format = strchr(sipip, ':') ? "<sip:gw+%s@[%s]:%d%s>" : "<sip:gw+%s@%s:%d%s>";
+				gateway->register_contact = switch_core_sprintf(gateway->pool, format, gateway->name,
+																sipip,
+																sofia_glue_transport_has_tls(gateway->register_transport) ?
+																profile->tls_sip_port : profile->sip_port, params);
+			}
+
+			gateway->extension = switch_core_strdup(gateway->pool, extension);
+			
 			if (!strncasecmp(proxy, "sip:", 4)) {
 				gateway->register_proxy = switch_core_strdup(gateway->pool, proxy);
 				gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4);
@@ -900,46 +1486,530 @@
 			gateway->expires_str = switch_core_strdup(gateway->pool, expire_seconds);
 
 			if ((gateway->freq = atoi(gateway->expires_str)) < 5) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-								   "Invalid Freq: %d.  Setting Register-Frequency to 3600\n", gateway->freq);
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid register-frequency of %d on gateway %s, using the value of 3600 instead\n",
+								  gateway->freq, name);
 				gateway->freq = 3600;
 			}
-			gateway->freq -= 2;
 
 			gateway->next = profile->gateways;
 			profile->gateways = gateway;
 			sofia_reg_add_gateway(gateway->name, gateway);
 		}
 
-	skip:
+	  skip:
 		switch_assert(gateway_tag);
 	}
 }
 
-
 static void parse_domain_tag(sofia_profile_t *profile, switch_xml_t x_domain_tag, const char *dname, const char *parse, const char *alias)
 {
-
 	if (switch_true(alias)) {
 		if (sofia_glue_add_profile(switch_core_strdup(profile->pool, dname), profile) == SWITCH_STATUS_SUCCESS) {
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Alias [%s] for profile [%s]\n", dname, profile->name);
 		} else {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding Alias [%s] for profile [%s] (name in use)\n", 
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Alias [%s] for profile [%s] (already exists)\n",                         
 							  dname, profile->name);
 		}
 	}
-	
+
 	if (switch_true(parse)) {
-		switch_xml_t ut, gateways_tag;
+		switch_xml_t gts, gt, uts, ut, gateways_tag;
+		/* Backwards Compatibility */
 		for (ut = switch_xml_child(x_domain_tag, "user"); ut; ut = ut->next) {
 			if (((gateways_tag = switch_xml_child(ut, "gateways")))) {
 				parse_gateways(profile, gateways_tag);
 			}
 		}
+		/* New Method with <groups> tags and users are now inside a <users> tag */
+		for (gts = switch_xml_child(x_domain_tag, "groups"); gts; gts = gts->next) {
+			for (gt = switch_xml_child(gts, "group"); gt; gt = gt->next) {
+				for (uts = switch_xml_child(gt, "users"); uts; uts = uts->next) {
+					for (ut = switch_xml_child(uts, "user"); ut; ut = ut->next) {
+						if (((gateways_tag = switch_xml_child(ut, "gateways")))) {
+							parse_gateways(profile, gateways_tag);
+						}
+					}
+				}
+			}
+		}
 	}
 }
 
+static void parse_rtp_bugs(sofia_profile_t *profile, const char *str)
+{
+	if (switch_stristr("clear", str)) {
+		profile->auto_rtp_bugs = 0;
+	}
 
+	if (switch_stristr("CISCO_SKIP_MARK_BIT_2833", str)) {
+		profile->auto_rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
+	}
+
+	if (switch_stristr("~CISCO_SKIP_MARK_BIT_2833", str)) {
+		profile->auto_rtp_bugs &= ~RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
+	}
+	
+	if (switch_stristr("SONUS_SEND_INVALID_TIMESTAMP_2833", str)) {
+		profile->auto_rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+	}
+
+	if (switch_stristr("~SONUS_SEND_INVALID_TIMESTAMP_2833", str)) {
+		profile->auto_rtp_bugs &= ~RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+	}
+
+
+}
+
+switch_status_t reconfig_sofia(sofia_profile_t *profile)
+{
+	switch_xml_t cfg, xml = NULL, xprofile, profiles, gateways_tag, domain_tag, domains_tag, aliases_tag, alias_tag, settings, param;
+	char *cf = "sofia.conf";
+	switch_event_t *params = NULL;
+	switch_status_t status = SWITCH_STATUS_FALSE;
+
+	switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
+	switch_assert(params);
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", profile->name);
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "reconfig", "true");
+
+	if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
+		status = SWITCH_STATUS_FALSE;
+		goto done;
+	}
+	
+	if ((profiles = switch_xml_child(cfg, "profiles"))) {
+		for (xprofile = switch_xml_child(profiles, "profile"); xprofile; xprofile = xprofile->next) {
+			char *xprofilename = (char *) switch_xml_attr_soft(xprofile, "name");
+			char *xprofiledomain = (char *) switch_xml_attr(xprofile, "domain");
+
+			if (strcasecmp(profile->name, xprofilename)) {
+				continue;
+			}
+
+			/* you could change profile->foo here if it was a minor change like context or dialplan ... */
+			profile->rport_level = 1; /* default setting */
+			profile->acl_count = 0;
+			sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+			profile->ib_calls = 0;
+			profile->ob_calls = 0;
+			profile->ib_failed_calls = 0;
+			profile->ob_failed_calls = 0;
+
+			if (xprofiledomain) {
+				profile->domain_name = switch_core_strdup(profile->pool, xprofiledomain);
+			}
+
+			if ((settings = switch_xml_child(xprofile, "settings"))) {
+				for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+					char *var = (char *) switch_xml_attr_soft(param, "name");
+					char *val = (char *) switch_xml_attr_soft(param, "value");
+					if (!strcasecmp(var, "debug")) {
+						profile->debug = atoi(val);
+					} else if (!strcasecmp(var, "tracelevel")) {
+						mod_sofia_globals.tracelevel = switch_log_str2level(val);
+					} else if (!strcasecmp(var, "sip-trace")) {
+						if (switch_true(val)) {
+							sofia_set_flag(profile, TFLAG_TPORT_LOG);
+						} else {
+							sofia_clear_flag(profile, TFLAG_TPORT_LOG);
+						}
+						nua_set_params(profile->nua, TPTAG_LOG(sofia_test_flag(profile, TFLAG_TPORT_LOG)), TAG_END());
+					} else if (!strcasecmp(var, "send-message-query-on-register")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
+						}
+					} else if (!strcasecmp(var, "auto-rtp-bugs")) {
+						parse_rtp_bugs(profile, val);
+					} else if (!strcasecmp(var, "user-agent-string")) { 
+						profile->user_agent = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "auto-restart")) {
+						profile->auto_restart = switch_true(val);
+					} else if (!strcasecmp(var, "dtmf-type")) {
+						if (!strcasecmp(val, "rfc2833")) {
+							profile->dtmf_type = DTMF_2833;
+						} else if (!strcasecmp(val, "info")) {
+							profile->dtmf_type = DTMF_INFO;
+						} else {
+							profile->dtmf_type = DTMF_NONE;
+						}
+					} else if (!strcasecmp(var, "NDLB-force-rport")) {
+						if (switch_true(val)) {
+							profile->rport_level = 2;
+						}
+					} else if (!strcasecmp(var, "caller-id-type")) {
+						profile->cid_type = sofia_cid_name2type(val);
+					} else if (!strcasecmp(var, "record-template")) {
+						profile->record_template = switch_core_strdup(profile->pool, val);;
+					} else if ((!strcasecmp(var, "inbound-no-media") || !strcasecmp(var, "inbound-bypass-media"))) {
+						if (switch_true(val)) {
+							sofia_set_flag(profile, TFLAG_INB_NOMEDIA);
+						} else {
+							sofia_clear_flag(profile, TFLAG_INB_NOMEDIA);
+						}
+					} else if (!strcasecmp(var, "force-subscription-expires")) {
+						int tmp = atoi(val);
+						if (tmp > 0) {
+							profile->force_subscription_expires = tmp;
+						}
+					} else if (!strcasecmp(var, "inbound-late-negotiation")) {
+						if (switch_true(val)) {
+							sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION);
+						} else {
+							sofia_clear_flag(profile, TFLAG_LATE_NEGOTIATION);
+						}
+					} else if (!strcasecmp(var, "inbound-proxy-media")) {
+						if (switch_true(val)) { 
+							sofia_set_flag(profile, TFLAG_PROXY_MEDIA);
+						} else {
+							sofia_clear_flag(profile, TFLAG_PROXY_MEDIA);
+						}
+					} else if (!strcasecmp(var, "inbound-use-callid-as-uuid")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_CALLID_AS_UUID);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_CALLID_AS_UUID);
+						}
+					} else if (!strcasecmp(var, "rtp-autoflush-during-bridge")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
+						}
+					} else if (!strcasecmp(var, "manual-redirect")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_MANUAL_REDIRECT);
+						}
+					} else if (!strcasecmp(var, "outbound-use-uuid-as-callid")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_UUID_AS_CALLID);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_UUID_AS_CALLID);
+						}
+					} else if (!strcasecmp(var, "NDLB-received-in-nat-reg-contact")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT);
+						}
+					} else if (!strcasecmp(var, "aggressive-nat-detection")) {
+						if (switch_true(val)) { 
+							sofia_set_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION);
+						}
+					} else if (!strcasecmp(var, "disable-rtp-auto-adjust")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DISABLE_RTP_AUTOADJ);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_DISABLE_RTP_AUTOADJ);
+						}
+					} else if (!strcasecmp(var, "NDLB-support-asterisk-missing-srtp-auth")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DISABLE_SRTP_AUTH); 
+						} else {
+							sofia_clear_pflag(profile, PFLAG_DISABLE_SRTP_AUTH); 
+						}
+					} else if (!strcasecmp(var, "NDLB-funny-stun")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_FUNNY_STUN); 
+						} else {
+							sofia_clear_pflag(profile, PFLAG_FUNNY_STUN); 
+						}
+					} else if (!strcasecmp(var, "stun-enabled")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_STUN_ENABLED);
+						}
+					} else if (!strcasecmp(var, "stun-auto-disable")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_STUN_AUTO_DISABLE);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_STUN_AUTO_DISABLE); 
+						}
+					} else if (!strcasecmp(var, "apply-nat-acl")) {
+						if (profile->acl_count < SOFIA_MAX_ACL) {
+							if (!profile->extsipip && switch_check_network_list_ip(profile->sipip, val)) {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Not adding acl %s because it's the local network\n", val);
+							} else {
+								profile->nat_acl[profile->nat_acl_count++] = switch_core_strdup(profile->pool, val);
+							}
+						} else {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL);
+						}
+					} else if (!strcasecmp(var, "apply-inbound-acl")) {
+						if (profile->acl_count < SOFIA_MAX_ACL) {
+							profile->acl[profile->acl_count++] = switch_core_strdup(profile->pool, val);
+						} else {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL);
+						}
+					} else if (!strcasecmp(var, "apply-register-acl")) {
+						if (profile->reg_acl_count < SOFIA_MAX_ACL) {
+							profile->reg_acl[profile->reg_acl_count++] = switch_core_strdup(profile->pool, val);
+						} else {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL);
+						}
+					} else if (!strcasecmp(var, "rfc2833-pt")) {
+						profile->te = (switch_payload_t) atoi(val);
+					} else if (!strcasecmp(var, "cng-pt") && !(sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG))) {
+						profile->cng_pt = (switch_payload_t) atoi(val);
+					} else if (!strcasecmp(var, "vad")) {
+						if (!strcasecmp(val, "in")) {
+							sofia_set_flag(profile, TFLAG_VAD_IN);
+						} else if (!strcasecmp(val, "out")) {
+							sofia_set_flag(profile, TFLAG_VAD_OUT);
+						} else if (!strcasecmp(val, "both")) {
+							sofia_set_flag(profile, TFLAG_VAD_IN);
+							sofia_set_flag(profile, TFLAG_VAD_OUT);
+						} else if (strcasecmp(val, "none")) {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid option %s for VAD\n", val);
+						}
+					} else if (!strcasecmp(var, "unregister-on-options-fail")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
+						}
+					} else if (!strcasecmp(var, "require-secure-rtp")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_SECURE);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_SECURE);
+						}
+					} else if (!strcasecmp(var, "multiple-registrations")) {
+						if (!strcasecmp(val, "call-id")) {
+							sofia_set_pflag(profile, PFLAG_MULTIREG);
+						} else if (!strcasecmp(val, "contact") || switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_MULTIREG);
+							sofia_set_pflag(profile, PFLAG_MULTIREG_CONTACT);
+						} else if (switch_true(val)) {
+							sofia_clear_pflag(profile, PFLAG_MULTIREG);
+							//sofia_clear_pflag(profile, PFLAG_MULTIREG_CONTACT);
+						}
+					} else if (!strcasecmp(var, "supress-cng") || !strcasecmp(var, "suppress-cng")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_SUPPRESS_CNG);
+							profile->cng_pt = 0;
+						} else {
+							sofia_clear_pflag(profile, PFLAG_SUPPRESS_CNG);
+						}
+					} else if (!strcasecmp(var, "NDLB-broken-auth-hash")) {
+						if (switch_true(val)) {
+							profile->ndlb |= PFLAG_NDLB_BROKEN_AUTH_HASH;
+						} else {
+							profile->ndlb &= ~PFLAG_NDLB_BROKEN_AUTH_HASH;
+						}
+					} else if (!strcasecmp(var, "NDLB-sendrecv-in-session")) {
+						if (switch_true(val)) {
+							profile->ndlb |= PFLAG_NDLB_SENDRECV_IN_SESSION;
+						} else {
+							profile->ndlb &= ~PFLAG_NDLB_SENDRECV_IN_SESSION;
+						}
+					} else if (!strcasecmp(var, "pass-rfc2833")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_PASS_RFC2833);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_PASS_RFC2833);
+						}
+					} else if (!strcasecmp(var, "rtp-autoflush")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_AUTOFLUSH);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_AUTOFLUSH);
+						}
+					} else if (!strcasecmp(var, "rtp-autofix-timing")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_AUTOFIX_TIMING);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_AUTOFIX_TIMING);
+						}
+					} else if (!strcasecmp(var, "nat-options-ping")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_NAT_OPTIONS_PING);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_NAT_OPTIONS_PING);
+						}
+					} else if (!strcasecmp(var, "inbound-codec-negotiation")) {
+						if (!strcasecmp(val, "greedy")) {
+							sofia_set_pflag(profile, PFLAG_GREEDY);
+						} else if (!strcasecmp(val, "scrooge")) {
+							sofia_set_pflag(profile, PFLAG_GREEDY);
+							sofia_set_pflag(profile, PFLAG_SCROOGE);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_SCROOGE);
+							sofia_clear_pflag(profile, PFLAG_GREEDY);
+						}
+					} else if (!strcasecmp(var, "disable-transcoding")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DISABLE_TRANSCODING);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_DISABLE_TRANSCODING);
+						}
+					} else if (!strcasecmp(var, "rtp-rewrite-timestamps")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_REWRITE_TIMESTAMPS);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_REWRITE_TIMESTAMPS);
+						}
+					} else if (!strcasecmp(var, "auth-calls")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_AUTH_CALLS);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_AUTH_CALLS);
+						}
+					} else if (!strcasecmp(var, "context")) {
+						profile->context = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "local-network-acl")) {
+						profile->local_network = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "force-register-domain")) {
+						profile->reg_domain = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "force-register-db-domain")) {
+						profile->reg_db_domain = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "hold-music")) {
+						profile->hold_music = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "outbound-proxy")) {
+						profile->outbound_proxy = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "session-timeout")) {
+						int v_session_timeout = atoi(val);
+						if (v_session_timeout >= 0) {
+							profile->session_timeout = v_session_timeout;
+						}
+					} else if (!strcasecmp(var, "rtp-timeout-sec")) {
+						int v = atoi(val);
+						if (v >= 0) {
+							profile->rtp_timeout_sec = v;
+						}
+					} else if (!strcasecmp(var, "rtp-hold-timeout-sec")) {
+						int v = atoi(val);
+						if (v >= 0) {
+							profile->rtp_hold_timeout_sec = v;
+						}
+					} else if (!strcasecmp(var, "nonce-ttl")) {
+						profile->nonce_ttl = atoi(val);
+					} else if (!strcasecmp(var, "dialplan")) {
+						profile->dialplan = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "max-calls")) {
+						profile->max_calls = atoi(val);
+					} else if (!strcasecmp(var, "codec-prefs")) {
+						profile->codec_string = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "challenge-realm")) {
+						profile->challenge_realm = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "dtmf-duration")) {
+						int dur = atoi(val);
+						if (dur > 10 && dur < 8000) {
+							profile->dtmf_duration = dur;
+						} else {
+							profile->dtmf_duration = SWITCH_DEFAULT_DTMF_DURATION;
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds, using default of %d!\n", SWITCH_DEFAULT_DTMF_DURATION);
+						}
+					} else if (!strcasecmp(var, "timer-T1")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t1 = v;
+						} else {
+							profile->timer_t1 = 500;
+						}
+						nua_set_params(profile->nua, NTATAG_SIP_T1(profile->timer_t1), TAG_END());
+					} else if (!strcasecmp(var, "timer-T1X64")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t1x64 = v;
+						} else {
+							profile->timer_t1x64 = 32000;
+						}
+						nua_set_params(profile->nua, NTATAG_SIP_T1X64(profile->timer_t1x64), TAG_END());
+					} else if (!strcasecmp(var, "timer-T2")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t2 = v;
+						} else {
+							profile->timer_t2 = 4000;
+						}
+						nua_set_params(profile->nua, NTATAG_SIP_T2(profile->timer_t2), TAG_END());
+					} else if (!strcasecmp(var, "timer-T4")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t4 = v;
+						} else {
+							profile->timer_t4 = 4000;
+						}
+						nua_set_params(profile->nua, NTATAG_SIP_T4(profile->timer_t4), TAG_END());
+					}
+				}
+			}
+
+			if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) {
+				parse_gateways(profile, gateways_tag);
+			}
+			
+			status = SWITCH_STATUS_SUCCESS;
+
+			if ((domains_tag = switch_xml_child(xprofile, "domains"))) {
+				switch_event_t *xml_params;
+				switch_event_create(&xml_params, SWITCH_EVENT_REQUEST_PARAMS);
+				switch_assert(xml_params);
+				switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "purpose", "gateways");
+				switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "profile", profile->name);
+				
+				for (domain_tag = switch_xml_child(domains_tag, "domain"); domain_tag; domain_tag = domain_tag->next) {
+					switch_xml_t droot, x_domain_tag;
+					const char *dname = switch_xml_attr_soft(domain_tag, "name");
+					const char *parse = switch_xml_attr_soft(domain_tag, "parse");
+					const char *alias = switch_xml_attr_soft(domain_tag, "alias");
+
+					if (!switch_strlen_zero(dname)) {
+						if (!strcasecmp(dname, "all")) {
+							switch_xml_t xml_root, x_domains;
+							if (switch_xml_locate("directory", NULL, NULL, NULL, &xml_root, &x_domains, xml_params, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+								for (x_domain_tag = switch_xml_child(x_domains, "domain"); x_domain_tag; x_domain_tag = x_domain_tag->next) {
+									dname = switch_xml_attr_soft(x_domain_tag, "name");
+									parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
+								}
+								switch_xml_free(xml_root);
+							}
+						} else if (switch_xml_locate_domain(dname, xml_params, &droot, &x_domain_tag) == SWITCH_STATUS_SUCCESS) {
+							parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
+							switch_xml_free(droot);
+						}
+					}
+				}
+				
+				switch_event_destroy(&xml_params);
+			}
+
+			if ((aliases_tag = switch_xml_child(xprofile, "aliases"))) {
+				for (alias_tag = switch_xml_child(aliases_tag, "alias"); alias_tag; alias_tag = alias_tag->next) {
+					char *aname = (char *) switch_xml_attr_soft(alias_tag, "name");
+					if (!switch_strlen_zero(aname)) {
+						
+						if (sofia_glue_add_profile(switch_core_strdup(profile->pool, aname), profile) == SWITCH_STATUS_SUCCESS) {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Alias [%s] for profile [%s]\n", aname, profile->name);
+						} else {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Alias [%s] for profile [%s] (already exists)\n",
+											  aname, profile->name);
+						}
+					}
+				}
+			}
+		}
+	}
+
+ done:
+
+	if (xml) {
+        switch_xml_free(xml);
+    }
+
+	switch_event_destroy(&params);
+
+	return status;
+}
+
 switch_status_t config_sofia(int reload, char *profile_name)
 {
 	char *cf = "sofia.conf";
@@ -949,41 +2019,60 @@
 	char url[512] = "";
 	int profile_found = 0;
 	switch_event_t *params = NULL;;
-	
+
 	if (!reload) {
 		su_init();
 		if (sip_update_default_mclass(sip_extend_mclass(NULL)) < 0) {
 			su_deinit();
 			return SWITCH_STATUS_FALSE;
 		}
-
-		su_log_redirect(NULL, logger, NULL);
+		
+		/* Redirect loggers in sofia */
+		su_log_redirect(su_log_default, logger, NULL);
 		su_log_redirect(tport_log, logger, NULL);
+		su_log_redirect(iptsec_log, logger, NULL);
+		su_log_redirect(nea_log, logger, NULL);
+		su_log_redirect(nta_log, logger, NULL);
+		su_log_redirect(nth_client_log, logger, NULL);
+		su_log_redirect(nth_server_log, logger, NULL);
+		su_log_redirect(nua_log, logger, NULL);
+		su_log_redirect(soa_log, logger, NULL);
+		su_log_redirect(sresolv_log, logger, NULL);
+		su_log_redirect(stun_log, logger, NULL);
 	}
 
 	if (!switch_strlen_zero(profile_name) && (profile = sofia_glue_find_profile(profile_name))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile [%s] Already exists.\n", switch_str_nil(profile_name));
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile [%s] Already exists.\n", switch_str_nil(profile_name));
 		status = SWITCH_STATUS_FALSE;
 		sofia_glue_release_profile(profile);
 		return status;
 	}
 
-	switch_event_create(&params, SWITCH_EVENT_MESSAGE);
+	switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
 	switch_assert(params);
 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", profile_name);
-	
+
 	if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
 		status = SWITCH_STATUS_FALSE;
 		goto done;
 	}
 
+	mod_sofia_globals.auto_restart = SWITCH_TRUE;
+	mod_sofia_globals.rewrite_multicasted_fs_path = SWITCH_FALSE;
+
 	if ((settings = switch_xml_child(cfg, "global_settings"))) {
 		for (param = switch_xml_child(settings, "param"); param; param = param->next) {
 			char *var = (char *) switch_xml_attr_soft(param, "name");
 			char *val = (char *) switch_xml_attr_soft(param, "value");
 			if (!strcasecmp(var, "log-level")) {
 				su_log_set_level(NULL, atoi(val));
+			} else if (!strcasecmp(var, "debug-presence")) {
+				mod_sofia_globals.debug_presence = atoi(val);
+			} else if (!strcasecmp(var, "auto-restart")) {
+				mod_sofia_globals.auto_restart = switch_true(val);
+			} else if (!strcasecmp(var, "rewrite-multicasted-fs-path")) {
+				mod_sofia_globals.rewrite_multicasted_fs_path = switch_true(val);
 			}
 		}
 	}
@@ -1020,6 +2109,8 @@
 					goto done;
 				}
 
+				profile->auto_rtp_bugs = RTP_BUG_CISCO_SKIP_MARK_BIT_2833 | RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+
 				profile->pool = pool;
 				profile->user_agent = SOFIA_USER_AGENT;
 
@@ -1028,44 +2119,48 @@
 
 				if (xprofiledomain) {
 					profile->domain_name = switch_core_strdup(profile->pool, xprofiledomain);
-				} else {
-					profile->domain_name = profile->name;
 				}
 
 				profile->dbname = switch_core_strdup(profile->pool, url);
 				switch_core_hash_init(&profile->chat_hash, profile->pool);
-				switch_core_hash_init(&profile->sub_hash, profile->pool);
 				switch_thread_rwlock_create(&profile->rwlock, profile->pool);
 				switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool);
 				profile->dtmf_duration = 100;
 				profile->tls_version = 0;
 				profile->mflags = MFLAG_REFER | MFLAG_REGISTER;
-				
+				profile->rport_level = 1;
+				sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+				sofia_set_pflag(profile, PFLAG_DISABLE_100REL);
+				profile->auto_restart = 1;
+				sofia_set_pflag(profile, PFLAG_AUTOFIX_TIMING);
+				sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
+				sofia_set_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
+				profile->contact_user = SOFIA_DEFAULT_CONTACT_USER;
+
 				for (param = switch_xml_child(settings, "param"); param; param = param->next) {
 					char *var = (char *) switch_xml_attr_soft(param, "name");
 					char *val = (char *) switch_xml_attr_soft(param, "value");
 
 					if (!strcasecmp(var, "debug")) {
 						profile->debug = atoi(val);
-					} else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_TIMER);
 					} else if (!strcasecmp(var, "sip-trace") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_TPORT_LOG);
+						sofia_set_flag(profile, TFLAG_TPORT_LOG);
 					} else if (!strcasecmp(var, "odbc-dsn") && !switch_strlen_zero(val)) {
-#ifdef SWITCH_HAVE_ODBC
-						profile->odbc_dsn = switch_core_strdup(profile->pool, val);
-						if ((profile->odbc_user = strchr(profile->odbc_dsn, ':'))) {
-							*profile->odbc_user++ = '\0';
-							if ((profile->odbc_pass = strchr(profile->odbc_user, ':'))) {
-								*profile->odbc_pass++ = '\0';
+						if (switch_odbc_available()) {
+							profile->odbc_dsn = switch_core_strdup(profile->pool, val);
+							if ((profile->odbc_user = strchr(profile->odbc_dsn, ':'))) {
+								*profile->odbc_user++ = '\0';
+								if ((profile->odbc_pass = strchr(profile->odbc_user, ':'))) {
+									*profile->odbc_pass++ = '\0';
+								}
 							}
+						} else {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
 						}
-
-#else
-						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
-#endif
 					} else if (!strcasecmp(var, "user-agent-string")) {
-						profile->user_agent = switch_core_strdup(profile->pool, val);;
+						profile->user_agent = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "auto-restart")) {
+						profile->auto_restart = switch_true(val);
 					} else if (!strcasecmp(var, "dtmf-type")) {
 						if (!strcasecmp(val, "rfc2833")) {
 							profile->dtmf_type = DTMF_2833;
@@ -1074,53 +2169,169 @@
 						} else {
 							profile->dtmf_type = DTMF_NONE;
 						}
+					} else if (!strcasecmp(var, "NDLB-force-rport")) {
+						if (switch_true(val)) {
+							profile->rport_level = 2;
+						}
+					} else if (!strcasecmp(var, "auto-rtp-bugs")) {
+						parse_rtp_bugs(profile, val);
+					} else if (!strcasecmp(var, "dbname")) {
+						profile->dbname = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "presence-hosts")) {
+						profile->presence_hosts = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "caller-id-type")) {
+						profile->cid_type = sofia_cid_name2type(val);
 					} else if (!strcasecmp(var, "record-template")) {
-						profile->record_template = switch_core_strdup(profile->pool, val);;
-					} else if (!strcasecmp(var, "inbound-no-media") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_INB_NOMEDIA);
-					} else if (!strcasecmp(var, "inbound-bypass-media") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_INB_NOMEDIA);
+						profile->record_template = switch_core_strdup(profile->pool, val);
+					} else if ((!strcasecmp(var, "inbound-no-media") || !strcasecmp(var, "inbound-bypass-media")) && switch_true(val)) {
+						sofia_set_flag(profile, TFLAG_INB_NOMEDIA);
 					} else if (!strcasecmp(var, "inbound-late-negotiation") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_LATE_NEGOTIATION);
+						sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION);
+					} else if (!strcasecmp(var, "rtp-autoflush-during-bridge")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
+						}
+					} else if (!strcasecmp(var, "manual-redirect")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_MANUAL_REDIRECT);
+						}
 					} else if (!strcasecmp(var, "inbound-proxy-media") && switch_true(val)) {
-						switch_set_flag(profile, TFLAG_PROXY_MEDIA);
+						sofia_set_flag(profile, TFLAG_PROXY_MEDIA);
+					} else if (!strcasecmp(var, "force-subscription-expires")) {
+						int tmp = atoi(val);
+						if (tmp > 0) {
+							profile->force_subscription_expires = tmp;
+						}
+					} else if (!strcasecmp(var, "send-message-query-on-register")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
+						}
+					} else if (!strcasecmp(var, "inbound-use-callid-as-uuid")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_CALLID_AS_UUID);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_CALLID_AS_UUID);
+						}
+					} else if (!strcasecmp(var, "outbound-use-uuid-as-callid")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_UUID_AS_CALLID);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_UUID_AS_CALLID);
+						}
+					} else if (!strcasecmp(var, "NDLB-received-in-nat-reg-contact") && switch_true(val)) {
+						sofia_set_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT);
+					} else if (!strcasecmp(var, "aggressive-nat-detection") && switch_true(val)) {
+						sofia_set_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION);
+					} else if (!strcasecmp(var, "disable-rtp-auto-adjust") && switch_true(val)) {
+						sofia_set_pflag(profile, PFLAG_DISABLE_RTP_AUTOADJ);
+					} else if (!strcasecmp(var, "NDLB-support-asterisk-missing-srtp-auth") && switch_true(val)) {
+						sofia_set_pflag(profile, PFLAG_DISABLE_SRTP_AUTH);
+					} else if (!strcasecmp(var, "NDLB-funny-stun")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_FUNNY_STUN); 
+						} else {
+							sofia_clear_pflag(profile, PFLAG_FUNNY_STUN); 
+						}
+					} else if (!strcasecmp(var, "stun-enabled")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_STUN_ENABLED); 
+						}
+					} else if (!strcasecmp(var, "stun-auto-disable")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_STUN_AUTO_DISABLE);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_STUN_AUTO_DISABLE); 
+						}
 					} else if (!strcasecmp(var, "rfc2833-pt")) {
 						profile->te = (switch_payload_t) atoi(val);
-					} else if (!strcasecmp(var, "cng-pt")) {
+					} else if (!strcasecmp(var, "cng-pt") && !sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG)) {
 						profile->cng_pt = (switch_payload_t) atoi(val);
 					} else if (!strcasecmp(var, "sip-port")) {
-						profile->sip_port = strcasecmp(val, "auto") ? atoi(val) : SOFIA_AUTO_PORT;
+						profile->sip_port = (switch_port_t)atoi(val);
 					} else if (!strcasecmp(var, "vad")) {
 						if (!strcasecmp(val, "in")) {
-							switch_set_flag(profile, TFLAG_VAD_IN);
+							sofia_set_flag(profile, TFLAG_VAD_IN);
 						} else if (!strcasecmp(val, "out")) {
-							switch_set_flag(profile, TFLAG_VAD_OUT);
+							sofia_set_flag(profile, TFLAG_VAD_OUT);
 						} else if (!strcasecmp(val, "both")) {
-							switch_set_flag(profile, TFLAG_VAD_IN);
-							switch_set_flag(profile, TFLAG_VAD_OUT);
+							sofia_set_flag(profile, TFLAG_VAD_IN);
+							sofia_set_flag(profile, TFLAG_VAD_OUT);
+						} else if (strcasecmp(val, "none")) {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid option %s for VAD\n", val);
+						}
+					} else if (!strcasecmp(var, "ext-rtp-ip")) {
+						if (!switch_strlen_zero(val)) {
+							char *ip = mod_sofia_globals.guess_ip;
+							
+							if (!strcmp(val, "0.0.0.0")) {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
+							} else if (!strcasecmp(val, "auto-nat")) {
+								ip = mod_sofia_globals.auto_nat ? switch_core_get_variable("nat_public_addr") : mod_sofia_globals.guess_ip; 
+							} else {
+								ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
+							}
+							sofia_set_pflag(profile, PFLAG_AUTO_NAT);
+							profile->extrtpip = switch_core_strdup(profile->pool, ip);
 						} else {
-							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invald option %s for VAD\n", val);
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-rtp-ip\n");
 						}
-					} else if (!strcasecmp(var, "ext-rtp-ip")) {
-						profile->extrtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip);
 					} else if (!strcasecmp(var, "rtp-ip")) {
-						profile->rtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip);
+						char *ip = mod_sofia_globals.guess_ip;
+
+						if (!strcmp(val, "0.0.0.0")) {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
+						} else {
+							ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
+						}
+						profile->rtpip = switch_core_strdup(profile->pool, ip);
 					} else if (!strcasecmp(var, "sip-ip")) {
-						profile->sipip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip);
+						char *ip = mod_sofia_globals.guess_ip;
+
+						if (!strcmp(val, "0.0.0.0")) {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
+						} else {
+							ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
+						}
+						profile->sipip = switch_core_strdup(profile->pool, ip);
 					} else if (!strcasecmp(var, "ext-sip-ip")) {
-						if (!strcasecmp(val, "auto")) {
-							profile->extsipip = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
-						} else {
+						if (!switch_strlen_zero(val)) {
 							char *ip = mod_sofia_globals.guess_ip;
-							switch_port_t port = 0;
-							if (sofia_glue_ext_address_lookup(&ip, &port, val, profile->pool) == SWITCH_STATUS_SUCCESS) {
-								profile->extsipip = switch_core_strdup(profile->pool, ip);
-							} else {
-								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get external ip.\n");
+							char stun_ip[50] = "";
+							char *myip = stun_ip;
+							
+							switch_copy_string(stun_ip, ip, sizeof(stun_ip));
+							
+							if (!strcasecmp(val, "0.0.0.0")) {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
+							} else if (!strcasecmp(val, "auto-nat")) {
+								ip = mod_sofia_globals.auto_nat ? switch_core_get_variable("nat_public_addr") : mod_sofia_globals.guess_ip;
+							} else if (strcasecmp(val, "auto")) {
+								switch_port_t port = 0;
+								if (sofia_glue_ext_address_lookup(profile, NULL, &myip, &port, val, profile->pool) == SWITCH_STATUS_SUCCESS) {
+									ip = myip;
+								} else {
+									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get external ip.\n");
+								}
 							}
+							sofia_set_pflag(profile, PFLAG_AUTO_NAT);
+							profile->extsipip = switch_core_strdup(profile->pool, ip);
+						} else {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-sip-ip\n");
 						}
+					} else if (!strcasecmp(var, "local-network-acl")) {
+						profile->local_network = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "force-register-domain")) {
 						profile->reg_domain = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "force-register-db-domain")) {
+						profile->reg_db_domain = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "bind-params")) {
 						profile->bind_params = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "sip-domain")) {
@@ -1129,6 +2340,8 @@
 						profile->timer_name = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "hold-music")) {
 						profile->hold_music = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "outbound-proxy")) {
+						profile->outbound_proxy = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "session-timeout")) {
 						int v_session_timeout = atoi(val);
 						if (v_session_timeout >= 0) {
@@ -1153,76 +2366,154 @@
 						profile->mflags &= ~MFLAG_REFER;
 					} else if (!strcasecmp(var, "disable-register") && switch_true(val)) {
 						profile->mflags &= ~MFLAG_REGISTER;
+					} else if (!strcasecmp(var, "media-option")) {
+						if (!strcasecmp(val, "resume-media-on-hold")) {
+							profile->media_options |= MEDIA_OPT_MEDIA_ON_HOLD;
+						} else if (!strcasecmp(val, "bypass-media-after-att-xfer")) {
+							profile->media_options |= MEDIA_OPT_BYPASS_AFTER_ATT_XFER;
+						}
 					} else if (!strcasecmp(var, "manage-presence")) {
+						if (!strcasecmp(val, "passive")) {
+							profile->pres_type = PRES_TYPE_PASSIVE;
+						
+						} else if (switch_true(val)) {
+							profile->pres_type = PRES_TYPE_FULL;
+						} 
+					} else if (!strcasecmp(var, "manage-shared-appearance")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_PRESENCE;
+							sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE);
+							profile->sla_contact = switch_core_sprintf(profile->pool, "sla-agent");
 						}
+					} else if (!strcasecmp(var, "disable-srv")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DISABLE_SRV);
+						}
+					} else if (!strcasecmp(var, "disable-naptr")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DISABLE_NAPTR);
+						}
 					} else if (!strcasecmp(var, "unregister-on-options-fail")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_UNREG_OPTIONS_FAIL;
+							sofia_set_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
 						}
 					} else if (!strcasecmp(var, "require-secure-rtp")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_SECURE;
+							sofia_set_pflag(profile, PFLAG_SECURE);
 						}
 					} else if (!strcasecmp(var, "multiple-registrations")) {
-						if (switch_true(val)) {
-							profile->pflags |= PFLAG_MULTIREG;
+						if (!strcasecmp(val, "call-id")) {
+							sofia_set_pflag(profile, PFLAG_MULTIREG);
+						} else if (!strcasecmp(val, "contact") || switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_MULTIREG);
+							sofia_set_pflag(profile, PFLAG_MULTIREG_CONTACT);
+						} else if (switch_true(val)) {
+							sofia_clear_pflag(profile, PFLAG_MULTIREG);
+							//sofia_clear_pflag(profile, PFLAG_MULTIREG_CONTACT);
 						}
-					} else if (!strcasecmp(var, "supress-cng")) {
+					} else if (!strcasecmp(var, "supress-cng") || !strcasecmp(var, "suppress-cng")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_SUPRESS_CNG;
+							sofia_set_pflag(profile, PFLAG_SUPPRESS_CNG);
+							profile->cng_pt = 0;
 						}
-					} else if (!strcasecmp(var, "NDLB-to-in-200-contact")) {
-						if (switch_true(val)) {
-							profile->ndlb |= PFLAG_NDLB_TO_IN_200_CONTACT;
-						}
 					} else if (!strcasecmp(var, "NDLB-broken-auth-hash")) {
 						if (switch_true(val)) {
 							profile->ndlb |= PFLAG_NDLB_BROKEN_AUTH_HASH;
 						}
+					} else if (!strcasecmp(var, "NDLB-sendrecv-in-session")) {
+						if (switch_true(val)) {
+							profile->ndlb |= PFLAG_NDLB_SENDRECV_IN_SESSION;
+						} else {
+							profile->ndlb &= ~PFLAG_NDLB_SENDRECV_IN_SESSION;
+						}
 					} else if (!strcasecmp(var, "pass-rfc2833")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_PASS_RFC2833;
+							sofia_set_pflag(profile, PFLAG_PASS_RFC2833);
 						}
+					} else if (!strcasecmp(var, "rtp-autoflush")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_AUTOFLUSH);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_AUTOFLUSH);
+						}
+					} else if (!strcasecmp(var, "rtp-autofix-timing")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_AUTOFIX_TIMING);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_AUTOFIX_TIMING);
+						}
+					} else if (!strcasecmp(var, "contact-user")) {
+						profile->contact_user = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "nat-options-ping")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_NAT_OPTIONS_PING);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_NAT_OPTIONS_PING);
+						}
 					} else if (!strcasecmp(var, "inbound-codec-negotiation")) {
 						if (!strcasecmp(val, "greedy")) {
-							profile->pflags |= PFLAG_GREEDY;
+							sofia_set_pflag(profile, PFLAG_GREEDY);
+						} else if (!strcasecmp(val, "scrooge")) {
+							sofia_set_pflag(profile, PFLAG_GREEDY);
+							sofia_set_pflag(profile, PFLAG_SCROOGE);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_SCROOGE);
+							sofia_clear_pflag(profile, PFLAG_GREEDY);
 						}
 					} else if (!strcasecmp(var, "disable-transcoding")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_DISABLE_TRANSCODING;
+							sofia_set_pflag(profile, PFLAG_DISABLE_TRANSCODING);
 						}
 					} else if (!strcasecmp(var, "rtp-rewrite-timestamps")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_REWRITE_TIMESTAMPS;
+							sofia_set_pflag(profile, PFLAG_REWRITE_TIMESTAMPS);
 						}
 					} else if (!strcasecmp(var, "auth-calls")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_AUTH_CALLS;
+							sofia_set_pflag(profile, PFLAG_AUTH_CALLS);
 						}
 					} else if (!strcasecmp(var, "nonce-ttl")) {
 						profile->nonce_ttl = atoi(val);
 					} else if (!strcasecmp(var, "accept-blind-reg")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_BLIND_REG;
+							sofia_set_pflag(profile, PFLAG_BLIND_REG);
 						}
+					} else if (!strcasecmp(var, "enable-3pcc")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_3PCC);
+						}
+						else if (!strcasecmp(val, "proxy")){
+							sofia_set_pflag(profile, PFLAG_3PCC_PROXY);
+						}
 					} else if (!strcasecmp(var, "accept-blind-auth")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_BLIND_AUTH;
+							sofia_set_pflag(profile, PFLAG_BLIND_AUTH);
 						}
 					} else if (!strcasecmp(var, "auth-all-packets")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_AUTH_ALL;
+							sofia_set_pflag(profile, PFLAG_AUTH_ALL);
 						}
 					} else if (!strcasecmp(var, "full-id-in-dialplan")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_FULL_ID;
+							sofia_set_pflag(profile, PFLAG_FULL_ID);
 						}
 					} else if (!strcasecmp(var, "inbound-reg-force-matching-username")) {
 						if (switch_true(val)) {
-							profile->pflags |= PFLAG_CHECKUSER;
+							sofia_set_pflag(profile, PFLAG_CHECKUSER);
 						}
+					} else if (!strcasecmp(var, "enable-timer")) {
+						if (!switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DISABLE_TIMER);
+						}
+					} else if (!strcasecmp(var, "minimum-session-expires")) {
+						profile->minimum_session_expires = atoi(val);
+						/* per RFC 4028: minimum_session_expires must be > 90 */
+						if (profile->minimum_session_expires < 90) {
+							profile->minimum_session_expires = 90;
+						}
+					} else if (!strcasecmp(var, "enable-100rel")) {
+						if (switch_true(val)) {
+							sofia_clear_pflag(profile, PFLAG_DISABLE_100REL);
+						}
 					} else if (!strcasecmp(var, "bitpacking")) {
 						if (!strcasecmp(val, "aal2")) {
 							profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
@@ -1231,6 +2522,16 @@
 						profile->username = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "context")) {
 						profile->context = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "apply-nat-acl")) {
+						if (profile->acl_count < SOFIA_MAX_ACL) {
+							if (!profile->extsipip && profile->sipip && switch_check_network_list_ip(profile->sipip, val)) {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Not adding acl %s because it's the local network\n", val);
+							} else {
+								profile->nat_acl[profile->nat_acl_count++] = switch_core_strdup(profile->pool, val);
+							}
+						} else {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL);
+						}
 					} else if (!strcasecmp(var, "apply-inbound-acl")) {
 						if (profile->acl_count < SOFIA_MAX_ACL) {
 							profile->acl[profile->acl_count++] = switch_core_strdup(profile->pool, val);
@@ -1257,17 +2558,21 @@
 						profile->max_calls = atoi(val);
 					} else if (!strcasecmp(var, "codec-prefs")) {
 						profile->codec_string = switch_core_strdup(profile->pool, val);
+					} else if (!strcasecmp(var, "challenge-realm")) {
+						profile->challenge_realm = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "dtmf-duration")) {
 						int dur = atoi(val);
 						if (dur > 10 && dur < 8000) {
 							profile->dtmf_duration = dur;
 						} else {
-							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds!\n");
+							profile->dtmf_duration = SWITCH_DEFAULT_DTMF_DURATION;
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds, using default of %d!\n", 
+											  SWITCH_DEFAULT_DTMF_DURATION);
 						}
 
-					/*
-					 * handle TLS params #1
-					 */
+						/*
+						 * handle TLS params #1
+						 */
 					} else if (!strcasecmp(var, "tls")) {
 						if (switch_true(val)) {
 							sofia_set_pflag(profile, PFLAG_TLS);
@@ -1275,7 +2580,7 @@
 					} else if (!strcasecmp(var, "tls-bind-params")) {
 						profile->tls_bind_params = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "tls-sip-port")) {
-						profile->tls_sip_port = strcasecmp(val, "auto") ? atoi(val) : SOFIA_AUTO_PORT;
+						profile->tls_sip_port = (switch_port_t)atoi(val);
 					} else if (!strcasecmp(var, "tls-cert-dir")) {
 						profile->tls_cert_dir = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "tls-version")) {
@@ -1285,10 +2590,38 @@
 						} else {
 							profile->tls_version = 0;
 						}
- 					}
+					} else if (!strcasecmp(var, "timer-T1")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t1 = v;
+						} else {
+							profile->timer_t1 = 500;
+						}
+					} else if (!strcasecmp(var, "timer-T1X64")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t1x64 = v;
+						} else {
+							profile->timer_t1x64 = 32000;
+						}
+					} else if (!strcasecmp(var, "timer-T2")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t2 = v;
+						} else {
+							profile->timer_t2 = 4000;
+						}
+					} else if (!strcasecmp(var, "timer-T4")) {
+						int v = atoi(val);
+						if (v > 0) {
+							profile->timer_t4 = v;
+						} else {
+							profile->timer_t4 = 4000;
+						}
+					}
 				}
 
-				if (!profile->cng_pt) {
+				if ((!profile->cng_pt) && (!sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG))) {
 					profile->cng_pt = SWITCH_RTP_CNG_PAYLOAD;
 				}
 
@@ -1305,10 +2638,6 @@
 					profile->nonce_ttl = 60;
 				}
 
-				if (switch_test_flag(profile, TFLAG_TIMER) && !profile->timer_name) {
-					profile->timer_name = switch_core_strdup(profile->pool, "soft");
-				}
-
 				if (!profile->username) {
 					profile->username = switch_core_strdup(profile->pool, "FreeSWITCH");
 				}
@@ -1319,61 +2648,119 @@
 				}
 
 				if (!profile->sip_port) {
-					profile->sip_port = atoi(SOFIA_DEFAULT_PORT);
+					profile->sip_port = (switch_port_t)atoi(SOFIA_DEFAULT_PORT);
 				}
 
 				if (!profile->dialplan) {
 					profile->dialplan = switch_core_strdup(profile->pool, "XML");
 				}
 
+				if (!profile->context) {
+					profile->context = switch_core_strdup(profile->pool, "default");
+				}
+
 				if (!profile->sipdomain) {
 					profile->sipdomain = switch_core_strdup(profile->pool, profile->sipip);
 				}
-				if (profile->extsipip) {
-					if (profile->sip_port == SOFIA_AUTO_PORT) {
-						profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:*", profile->extsipip);
-					} else {
-						profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->extsipip, profile->sip_port);
-					}
+				if (profile->extsipip && sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+					char *ipv6 = strchr(profile->extsipip, ':');
+					profile->public_url = switch_core_sprintf(profile->pool,
+															  "sip:%s@%s%s%s:%d",
+															  profile->contact_user,
+															  ipv6 ? "[" : "",
+															  profile->extsipip,
+															  ipv6 ? "]" : "",
+															  profile->sip_port);
+				}
+
+				if (profile->extsipip && !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+					char *ipv6 = strchr(profile->extsipip, ':');
+					profile->url = switch_core_sprintf(profile->pool,
+														"sip:%s@%s%s%s:%d",
+														profile->contact_user,
+														ipv6 ? "[" : "",
+														profile->extsipip,
+														ipv6 ? "]" : "",
+														profile->sip_port);
 					profile->bindurl = switch_core_sprintf(profile->pool, "%s;maddr=%s", profile->url, profile->sipip);
 				} else {
-					if (profile->sip_port == SOFIA_AUTO_PORT) {
-						profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:*", profile->sipip);
-					} else {
-						profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->sipip, profile->sip_port);
-					}
+					char *ipv6 = strchr(profile->sipip, ':');
+					profile->url = switch_core_sprintf(profile->pool,
+														"sip:%s@%s%s%s:%d",
+														profile->contact_user,
+														ipv6 ? "[" : "",
+														profile->sipip,
+														ipv6 ? "]" : "",
+														profile->sip_port);
 					profile->bindurl = profile->url;
 				}
 
+				profile->tcp_contact = switch_core_sprintf(profile->pool, "%s;transport=tcp", profile->url);
+
+				if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+					profile->tcp_public_contact = switch_core_sprintf(profile->pool, "%s;transport=tcp", profile->public_url);
+				}
+
 				if (profile->bind_params) {
 					char *bindurl = profile->bindurl;
 					profile->bindurl = switch_core_sprintf(profile->pool, "%s;%s", bindurl, profile->bind_params);
 				}
-
+				
 				/*
 				 * handle TLS params #2
 				 */
 				if (sofia_test_pflag(profile, PFLAG_TLS)) {
 					if (!profile->tls_sip_port) {
-						profile->tls_sip_port = atoi(SOFIA_DEFAULT_TLS_PORT);
+						profile->tls_sip_port = (switch_port_t)atoi(SOFIA_DEFAULT_TLS_PORT);
 					}
 
-					if (profile->extsipip) {
-						if (profile->tls_sip_port == SOFIA_AUTO_PORT) {
-							profile->tls_url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:*", profile->extsipip);
-							profile->tls_bindurl = switch_core_sprintf(profile->pool, "sips:mod_sofia@%s:*;maddr=%s", profile->extsipip, profile->sipip);
-						} else {
-							profile->tls_url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->extsipip, profile->tls_sip_port);
-							profile->tls_bindurl = switch_core_sprintf(profile->pool, "sips:mod_sofia@%s:%d;maddr=%s", profile->extsipip, profile->tls_sip_port, profile->sipip);
-						}
+					if (profile->extsipip && sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+						char *ipv6 = strchr(profile->extsipip, ':');
+						profile->tls_public_url = switch_core_sprintf(profile->pool,
+																  "sip:%s@%s%s%s:%d",
+																  profile->contact_user,
+																  ipv6 ? "[" : "",
+																  profile->extsipip,
+																  ipv6 ? "]" : "",
+																  profile->tls_sip_port);
+					}
+					
+					if (profile->extsipip && !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+						char *ipv6 = strchr(profile->extsipip, ':');
+						profile->tls_url = 
+							switch_core_sprintf(profile->pool,
+												"sip:%s@%s%s%s:%d",
+												profile->contact_user,
+												ipv6 ? "[" : "",
+												profile->extsipip, ipv6 ? "]" : "",
+												profile->tls_sip_port);
+						profile->tls_bindurl =
+							switch_core_sprintf(profile->pool,
+												"sips:%s@%s%s%s:%d;maddr=%s",
+												profile->contact_user,
+												ipv6 ? "[" : "",
+												profile->extsipip,
+												ipv6 ? "]" : "",
+												profile->tls_sip_port,
+												profile->sipip);
 					} else {
-						if (profile->tls_sip_port == SOFIA_AUTO_PORT) {
-							profile->tls_url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:*", profile->sipip);
-							profile->tls_bindurl = switch_core_sprintf(profile->pool, "sips:mod_sofia@%s:*", profile->sipip);
-						} else {
-							profile->tls_url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->sipip, profile->tls_sip_port);
-							profile->tls_bindurl = switch_core_sprintf(profile->pool, "sips:mod_sofia@%s:%d", profile->sipip, profile->tls_sip_port);
-						}
+						char *ipv6 = strchr(profile->sipip, ':');
+						profile->tls_url = 
+							switch_core_sprintf(profile->pool,
+												"sip:%s@%s%s%s:%d",
+												profile->contact_user,
+												ipv6 ? "[" : "",
+												profile->sipip,
+												ipv6 ? "]" : "",
+												profile->tls_sip_port);
+						profile->tls_bindurl =
+							switch_core_sprintf(profile->pool,
+												"sips:%s@%s%s%s:%d",
+												profile->contact_user,
+												ipv6 ? "[" : "",
+												profile->sipip,
+												ipv6 ? "]" : "",
+												profile->tls_sip_port);
 					}
 
 					if (profile->tls_bind_params) {
@@ -1384,41 +2771,50 @@
 					if (!profile->tls_cert_dir) {
 						profile->tls_cert_dir = switch_core_sprintf(profile->pool, "%s/ssl", SWITCH_GLOBAL_dirs.conf_dir);
 					}
+					profile->tls_contact = switch_core_sprintf(profile->pool, "%s;transport=tls", profile->tls_url);
+					if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+						profile->tls_public_contact = switch_core_sprintf(profile->pool, "%s;transport=tls", profile->tls_public_url);
+					}
 				}
 			}
 			if (profile) {
 				switch_xml_t aliases_tag, alias_tag;
 
-				if ((gateways_tag = switch_xml_child(xprofile, "registrations"))) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
-									  "The <registrations> syntax has been discontinued, please see the new syntax in the default configuration examples\n");
-				} else if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) {
+				if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) {
 					parse_gateways(profile, gateways_tag);
 				}
 
 				if ((domains_tag = switch_xml_child(xprofile, "domains"))) {
+					switch_event_t *xml_params;
+					switch_event_create(&xml_params, SWITCH_EVENT_REQUEST_PARAMS);
+					switch_assert(xml_params);
+					switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "purpose", "gateways");
+					switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "profile", profile->name);
+					
 					for (domain_tag = switch_xml_child(domains_tag, "domain"); domain_tag; domain_tag = domain_tag->next) {
 						switch_xml_t droot, x_domain_tag;
 						const char *dname = switch_xml_attr_soft(domain_tag, "name");
 						const char *parse = switch_xml_attr_soft(domain_tag, "parse");
 						const char *alias = switch_xml_attr_soft(domain_tag, "alias");
-						
-						if (!switch_strlen_zero(dname)) { 
+
+						if (!switch_strlen_zero(dname)) {
 							if (!strcasecmp(dname, "all")) {
 								switch_xml_t xml_root, x_domains;
-								if (switch_xml_locate("directory", NULL, NULL, NULL, &xml_root, &x_domains, NULL) == SWITCH_STATUS_SUCCESS) {
-									for(x_domain_tag = switch_xml_child(x_domains, "domain"); x_domain_tag; x_domain_tag = x_domain_tag->next) {
+								if (switch_xml_locate("directory", NULL, NULL, NULL, &xml_root, &x_domains, xml_params, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+									for (x_domain_tag = switch_xml_child(x_domains, "domain"); x_domain_tag; x_domain_tag = x_domain_tag->next) {
 										dname = switch_xml_attr_soft(x_domain_tag, "name");
 										parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
 									}
 									switch_xml_free(xml_root);
 								}
-							} else if (switch_xml_locate_domain(dname, NULL, &droot, &x_domain_tag) == SWITCH_STATUS_SUCCESS) {
+							} else if (switch_xml_locate_domain(dname, xml_params, &droot, &x_domain_tag) == SWITCH_STATUS_SUCCESS) {
 								parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
-								switch_xml_free(droot);									
+								switch_xml_free(droot);
 							}
 						}
 					}
+					
+					switch_event_destroy(&xml_params);
 				}
 
 				if ((aliases_tag = switch_xml_child(xprofile, "aliases"))) {
@@ -1429,16 +2825,21 @@
 							if (sofia_glue_add_profile(switch_core_strdup(profile->pool, aname), profile) == SWITCH_STATUS_SUCCESS) {
 								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Alias [%s] for profile [%s]\n", aname, profile->name);
 							} else {
-								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding Alias [%s] for profile [%s] (name in use)\n", 
-												   aname, profile->name);
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding Alias [%s] for profile [%s] (name in use)\n",
+												  aname, profile->name);
 							}
 						}
 					}
 				}
 
 				if (profile->sipip) {
-					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url);
 					launch_sofia_profile_thread(profile);
+					if (profile->odbc_dsn) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Connecting ODBC Profile %s [%s]\n", profile->name, url);
+						switch_yield(1000000);
+					} else {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url);
+					}
 				} else {
 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to start Profile %s due to no configured sip-ip\n", profile->name);
 				}
@@ -1466,58 +2867,100 @@
 }
 
 static void sofia_handle_sip_r_options(switch_core_session_t *session, int status,
-									  char const *phrase,
-									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
+									   char const *phrase,
+									   nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+									   tagi_t tags[])
 {
-	if ((profile->pflags & PFLAG_UNREG_OPTIONS_FAIL) && status != 200 && sip && sip->sip_to) {
+	sofia_gateway_t *gateway = NULL;
+
+	if (sofia_private && !switch_strlen_zero(sofia_private->gateway_name)) {
+		gateway = sofia_reg_find_gateway(sofia_private->gateway_name);
+		sofia_private->destroy_me = 1;
+	}
+
+	if (gateway) {
+		if (status >= 200 && status < 600) {
+			if (gateway->state == REG_STATE_FAILED) {
+				gateway->state = REG_STATE_UNREGED;
+			}
+			gateway->status = SOFIA_GATEWAY_UP;
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ping failed %s\n", gateway->name);
+			gateway->status = SOFIA_GATEWAY_DOWN;
+			if (gateway->state == REG_STATE_REGED) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unregister %s\n", gateway->name);
+				gateway->state = REG_STATE_FAILED;
+			}
+		}
+		gateway->ping = switch_epoch_time_now(NULL) + gateway->ping_freq;
+		sofia_reg_release_gateway(gateway);
+		gateway->pinging = 0;
+	} else if (sofia_test_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL) && status != 200 && sip && sip->sip_to) {
 		char *sql;
-		time_t now = switch_timestamp(NULL);
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Expire registration '%s@%s' due to options failure\n", 
-						  sip->sip_to->a_url->url_user,
-						  sip->sip_to->a_url->url_host
-						  );
+		time_t now = switch_epoch_time_now(NULL);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Expire registration '%s@%s' due to options failure\n",
+						  sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
 
-		sql = switch_mprintf("update sip_registrations set expired=%ld where sip_user='%s' and sip_host='%s'", 
-								   (long)now,
-								   sip->sip_to->a_url->url_user,
-								   sip->sip_to->a_url->url_host
-								   );
+		sql = switch_mprintf("update sip_registrations set expires=%ld where sip_user='%s' and sip_host='%s'",
+							 (long) now, sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
 		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 	}
 }
 
-
 static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status,
 									  char const *phrase,
-									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
+									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+									  tagi_t tags[])
 {
 	if (sip && session) {
 		switch_channel_t *channel = switch_core_session_get_channel(session);
 		const char *uuid;
 		switch_core_session_t *other_session;
 		private_object_t *tech_pvt = switch_core_session_get_private(session);
+		char network_ip[80];
+		int network_port = 0;
+		switch_caller_profile_t *caller_profile = NULL;
+
+		sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &network_port);
+
+		switch_channel_set_variable(channel, "sip_reply_host", network_ip);
+		switch_channel_set_variable_printf(channel, "sip_reply_port", "%d", network_port);
 		
+		if ((caller_profile = switch_channel_get_caller_profile(channel))) {
+			caller_profile->network_addr = switch_core_strdup(caller_profile->pool, network_ip);
+		}
+
 		switch_channel_clear_flag(channel, CF_REQ_MEDIA);
+		
+		if ((status == 180 || status == 183 || status == 200)) { 
+			if (sip->sip_user_agent && sip->sip_user_agent->g_string) {
+				switch_channel_set_variable(channel, "sip_user_agent", sip->sip_user_agent->g_string);
+			} else if (sip->sip_server && sip->sip_server->g_string) {
+				switch_channel_set_variable(channel, "sip_user_agent", sip->sip_server->g_string);
+			}
+		}
 
 		if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
 
-			if (!switch_test_flag(tech_pvt, TFLAG_SENT_UPDATE)) {
+			if (!sofia_test_flag(tech_pvt, TFLAG_SENT_UPDATE)) {
 				return;
 			}
 
-			switch_clear_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
+			sofia_clear_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
 
 			if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
 				const char *r_sdp = NULL;
 				switch_core_session_message_t msg = { 0 };
-			
-				if (sip->sip_payload && sip->sip_payload->pl_data && 
+
+				if (sip->sip_payload && sip->sip_payload->pl_data &&
 					sip->sip_content_type && sip->sip_content_type->c_subtype && switch_stristr("sdp", sip->sip_content_type->c_subtype)) {
-					r_sdp = sip->sip_payload->pl_data;
+					tech_pvt->remote_sdp_str = switch_core_session_strdup(tech_pvt->session, sip->sip_payload->pl_data);
+					r_sdp = tech_pvt->remote_sdp_str;
+					sofia_glue_tech_proxy_remote_addr(tech_pvt);
 				}
 
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Passing %d %s to other leg\n", status, phrase);
-				
+
 				msg.message_id = SWITCH_MESSAGE_INDICATE_RESPOND;
 				msg.from = __FILE__;
 				msg.numeric_arg = status;
@@ -1553,7 +2996,7 @@
 				astate = "confirmed";
 			}
 
-			if (!switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED) && 
+			if (!switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED) &&
 				!switch_channel_test_flag(channel, CF_RING_READY)) {
 				const char *from_user = "", *from_host = "", *to_user = "", *to_host = "", *contact_user = "", *contact_host = "";
 				const char *user_agent = "", *call_id = "";
@@ -1582,39 +3025,217 @@
 					contact_host = switch_str_nil(contact->url_host);
 				}
 
-				if (profile->pflags & PFLAG_PRESENCE) {
-					sql = switch_mprintf(
-										 "insert into sip_dialogs values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
+				if (profile->pres_type) {
+					sql = switch_mprintf("insert into sip_dialogs "
+										 "(call_id,uuid,sip_to_user,sip_to_host,sip_from_user,sip_from_host,contact_user,"
+										 "contact_host,state,direction,user_agent,profile_name,hostname) "
+										 "values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
 										 call_id,
 										 switch_core_session_get_uuid(session),
-										 to_user,
-										 to_host,
-										 from_user,
-										 from_host,
-										 contact_user,
-										 contact_host,
-										 astate,
-										 "outbound",
-										 user_agent
-										 );
+										 to_user, to_host, from_user, from_host, contact_user, 
+										 contact_host, astate, "outbound", user_agent,
+										 profile->name, mod_sofia_globals.hostname);
 
 					switch_assert(sql);
-					
+
 					sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 				}
-			} else if (status == 200 && (profile->pflags & PFLAG_PRESENCE)) { 
+			} else if (status == 200 && (profile->pres_type)) {
 				char *sql = NULL;
 				sql = switch_mprintf("update sip_dialogs set state='%s' where uuid='%s';\n", astate, switch_core_session_get_uuid(session));
-				switch_assert(sql); 
-				sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); 
+				switch_assert(sql);
+				sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 			}
 		}
+
+		if (channel && sip && (status == 300 || status == 302 || status == 305) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			sip_contact_t * p_contact = sip->sip_contact;
+			int i = 0;
+			char var_name[80];	
+			const char *diversion_header;
+			char *full_contact = NULL;
+			char *invite_contact;
+			const char *br;
+			
+			if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
+				switch_xml_t root = NULL, domain = NULL;
+				switch_core_session_t *a_session;
+				switch_channel_t *a_channel;
+
+				const char *sip_redirect_profile, *sip_redirect_context, *sip_redirect_dialplan, *sip_redirect_fork;
+
+				if ((a_session = switch_core_session_locate(br)) && (a_channel = switch_core_session_get_channel(a_session))) { 
+					switch_stream_handle_t stream = { 0 };
+					char separator[2] = "|";
+					char *redirect_dialstring;
+					su_home_t *home = su_home_new(sizeof(*home));
+					switch_assert(home != NULL);
+
+					SWITCH_STANDARD_STREAM(stream);
+
+					if (!(sip_redirect_profile = switch_channel_get_variable(channel, "sip_redirect_profile"))) {
+						sip_redirect_profile = profile->name;
+					}
+					if (!(sip_redirect_context = switch_channel_get_variable(channel, "sip_redirect_context"))) {
+						sip_redirect_context = "redirected";
+					}
+					if (!(sip_redirect_dialplan = switch_channel_get_variable(channel, "sip_redirect_dialplan"))) {
+						sip_redirect_dialplan = "XML";
+					}
+
+					sip_redirect_fork = switch_channel_get_variable(channel, "sip_redirect_fork");
+					
+					if (switch_true(sip_redirect_fork)) {
+						*separator = ',';
+					}
+
+					for (p_contact = sip->sip_contact; p_contact; p_contact = p_contact->m_next) {
+						if (p_contact->m_url) {
+							full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
+							invite_contact = sofia_glue_strip_uri(full_contact);
+							
+							switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_%d", i);
+							switch_channel_set_variable(a_channel, var_name, full_contact);
+							
+							if (i == 0) {
+								switch_channel_set_variable(channel, "sip_redirected_to", full_contact);
+								switch_channel_set_variable(a_channel, "sip_redirected_to", full_contact);
+							}
+							
+							if (p_contact->m_url->url_user) {
+								switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_user_%d", i);
+								switch_channel_set_variable(channel, var_name, p_contact->m_url->url_user);
+								switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_user);
+							}
+							if (p_contact->m_url->url_host) {
+								switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_host_%d", i);
+								switch_channel_set_variable(channel, var_name, p_contact->m_url->url_host);
+								switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_host);
+							}
+							if (p_contact->m_url->url_params) {
+								switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_params_%d", i);
+								switch_channel_set_variable(channel, var_name, p_contact->m_url->url_params);
+								switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_params);
+							}
+							
+							switch_snprintf(var_name, sizeof(var_name), "sip_redirect_dialstring_%d", i);
+							switch_channel_set_variable_printf(channel, var_name, "sofia/%s/%s", sip_redirect_profile, invite_contact);
+							switch_channel_set_variable_printf(a_channel, var_name, "sofia/%s/%s", sip_redirect_profile, invite_contact);
+							stream.write_function(&stream, "%ssofia/%s/%s", i ? separator : "", sip_redirect_profile, invite_contact);
+							free(invite_contact);
+							i++;
+						}
+					}
+					
+					redirect_dialstring = stream.data;
+					
+					switch_channel_set_variable(channel, "sip_redirect_dialstring", redirect_dialstring);
+					switch_channel_set_variable(a_channel, "sip_redirect_dialstring", redirect_dialstring);
+					
+					p_contact = sip->sip_contact;
+					full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
+					
+					if ((diversion_header = sofia_glue_get_unknown_header(sip, "diversion"))) {
+						switch_channel_set_variable(channel, "sip_redirected_by", diversion_header);
+						switch_channel_set_variable(a_channel, "sip_redirected_by", diversion_header);
+					}
+					
+					if (sofia_test_pflag(profile, PFLAG_MANUAL_REDIRECT)) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Redirect: Transfering to %s %s %s\n", 
+										  p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context);
+						switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context);					
+					} else if ((!strcmp(profile->sipip, p_contact->m_url->url_host))
+							   || (profile->extsipip && !strcmp(profile->extsipip, p_contact->m_url->url_host))
+							   || (switch_xml_locate_domain(p_contact->m_url->url_host, NULL, &root, &domain) == SWITCH_STATUS_SUCCESS)) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Redirect: Transfering to %s\n", p_contact->m_url->url_user);
+						switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, NULL, NULL);
+						switch_xml_free(root);
+					} else {
+						invite_contact = sofia_glue_strip_uri(full_contact);
+						tech_pvt->redirected = switch_core_session_strdup(session, invite_contact);
+						free(invite_contact);
+					}
+					
+					if (home) {
+						su_home_unref(home);
+						home = NULL;
+					}
+
+					free(stream.data);
+					switch_core_session_rwunlock(a_session);
+				}
+			} else {
+				su_home_t *home = su_home_new(sizeof(*home));
+				switch_assert(home != NULL);
+				full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
+				invite_contact = sofia_glue_strip_uri(full_contact);
+
+				tech_pvt->redirected = switch_core_session_strdup(session, invite_contact);
+
+				free(invite_contact);
+
+				if (home) {
+					su_home_unref(home);
+					home = NULL;
+				}
+			}
+		}
 	}
+
+	if (!session && (status == 180 || status == 183 || status == 200)) {
+		/* nevermind */
+		nua_handle_bind(nh, NULL);
+		nua_handle_destroy(nh);
+	}
 }
 
+
+/* Pure black magic, if you can't understand this code you are lucky.........*/
+void *SWITCH_THREAD_FUNC media_on_hold_thread_run(switch_thread_t *thread, void *obj)
+{
+	switch_core_session_t *other_session = NULL, *session = (switch_core_session_t *) obj;
+	const char *uuid;
+	
+	if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
+		switch_channel_t *channel = switch_core_session_get_channel(session);
+		private_object_t *tech_pvt = switch_core_session_get_private(session);
+		
+		if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+			if (switch_core_session_compare(session, other_session)) {
+				sofia_set_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
+				switch_ivr_media(switch_core_session_get_uuid(other_session), SMF_REBRIDGE);
+			
+				if (tech_pvt->rtp_session) {
+					switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+				}
+
+				sofia_glue_toggle_hold(tech_pvt, 1);
+			}
+			switch_core_session_rwunlock(other_session);
+		}
+
+		switch_core_session_rwunlock(session);
+	}
+	
+	return NULL;
+}
+
+static void launch_media_on_hold(switch_core_session_t *session)
+{
+	switch_thread_t *thread;
+	switch_threadattr_t *thd_attr = NULL;
+
+	switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session));
+	switch_threadattr_detach_set(thd_attr, 1);
+	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+	switch_threadattr_priority_increase(thd_attr);
+	switch_thread_create(&thread, thd_attr, media_on_hold_thread_run, session, switch_core_session_get_pool(session));
+}
+
 static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 									 char const *phrase,
-									 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
+									 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+									 tagi_t tags[])
 {
 	const char *l_sdp = NULL, *r_sdp = NULL;
 	int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
@@ -1634,20 +3255,54 @@
 			NUTAG_OFFER_SENT_REF(offer_sent),
 			NUTAG_ANSWER_SENT_REF(answer_sent),
 			SIPTAG_REPLACES_STR_REF(replaces_str), SOATAG_LOCAL_SDP_STR_REF(l_sdp), SOATAG_REMOTE_SDP_STR_REF(r_sdp), TAG_END());
+	
+	if (ss_state == nua_callstate_terminated) {
 
+		if ((status == 300 || status == 302 || status == 305) && session) {
+			channel = switch_core_session_get_channel(session);
+			tech_pvt = switch_core_session_get_private(session);
+			
+			if (!tech_pvt || !tech_pvt->nh) {
+				goto done;
+			}
+			
+
+			if (tech_pvt->redirected) {
+				sofia_glue_do_invite(session);
+				goto done;
+			}
+		}
+
+		if (sofia_private) {
+			sofia_private->destroy_me = 1;
+		}
+	}
+
 	if (session) {
 		channel = switch_core_session_get_channel(session);
 		tech_pvt = switch_core_session_get_private(session);
-		switch_assert(tech_pvt != NULL);
-		switch_assert(tech_pvt->nh != NULL);
 
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s]\n",
-						  switch_channel_get_name(channel), nua_callstate_name(ss_state));
+		if (!tech_pvt || !tech_pvt->nh) {
+			goto done;
+		}
 
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s][%d]\n",
+						  switch_channel_get_name(channel), nua_callstate_name(ss_state), status);
+		
 		if (r_sdp) {
+			sdp_parser_t *parser;
+			sdp_session_t *sdp;
+
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp);
 			tech_pvt->remote_sdp_str = switch_core_session_strdup(session, r_sdp);
 			switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
+
+			if ( sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && (parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+				if ((sdp = sdp_session(parser))) {
+					sofia_glue_set_r_sdp_codec_string(channel, (tech_pvt->profile?tech_pvt->profile->codec_string:NULL), sdp);
+				}
+				sdp_parser_free(parser);
+			}
 			sofia_glue_pass_sdp(tech_pvt, (char *) r_sdp);
 		}
 	}
@@ -1658,8 +3313,12 @@
 
 	if (status == 183 && !r_sdp) {
 		status = 180;
+	} 
+	
+	if (status == 180 && r_sdp) {
+		status = 183;
 	}
-
+	
 	if (channel && (status == 180 || status == 183) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
 		const char *val;
 		if ((val = switch_channel_get_variable(channel, "sip_auto_answer")) && switch_true(val)) {
@@ -1667,9 +3326,22 @@
 		}
 	}
 
- state_process:
-	
+  state_process:
+
 	switch ((enum nua_callstate) ss_state) {
+	case nua_callstate_terminated:
+	case nua_callstate_terminating:
+	case nua_callstate_ready:
+	case nua_callstate_completed:
+	case nua_callstate_received:
+	case nua_callstate_proceeding:
+		if (!(session && channel && tech_pvt)) goto done;
+		break;
+	default:
+		break;
+	}
+
+	switch ((enum nua_callstate) ss_state) {
 	case nua_callstate_init:
 		break;
 	case nua_callstate_authenticating:
@@ -1677,61 +3349,59 @@
 	case nua_callstate_calling:
 		break;
 	case nua_callstate_proceeding:
-		if (channel) {
-			if (status == 180) {
-				switch_channel_mark_ring_ready(channel);
-				if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK)) {
-					if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
-						if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
-							&& (other_session = switch_core_session_locate(uuid))) {
-							switch_core_session_message_t msg;
-							msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING;
-							msg.from = __FILE__;
-							switch_core_session_receive_message(other_session, &msg);
-							switch_core_session_rwunlock(other_session);
-						}
+		if (status == 180) {
+			switch_channel_mark_ring_ready(channel);
+			if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK)) {
+				if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
+					if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+						&& (other_session = switch_core_session_locate(uuid))) {
+						switch_core_session_message_t msg;
+						msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING;
+						msg.from = __FILE__;
+						switch_core_session_receive_message(other_session, &msg);
+						switch_core_session_rwunlock(other_session);
+					}
 
-					} else {
-						switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
-					}
+				} else {
+					switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
 				}
 			}
-
-			if (r_sdp) {
-				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
-					switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
-					switch_channel_mark_pre_answered(channel);
-					switch_set_flag(tech_pvt, TFLAG_SDP);
-					if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
-						if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
-							goto done;
-						}
+		}
+			
+		if (r_sdp) {
+			if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+				if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
+					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
+				}
+				sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+				switch_channel_mark_pre_answered(channel);
+				sofia_set_flag(tech_pvt, TFLAG_SDP);
+				if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+					if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+						goto done;
 					}
-					if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) && (uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
-						&& (other_session = switch_core_session_locate(uuid))) {
-						other_channel = switch_core_session_get_channel(other_session);
-						if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
-							switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
-						}
-
-						switch_channel_pre_answer(other_channel);
-						switch_core_session_rwunlock(other_session);
+				}
+				if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) && (uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+					&& (other_session = switch_core_session_locate(uuid))) {
+					other_channel = switch_core_session_get_channel(other_session);
+					if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
+						switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
 					}
-					goto done;
+					switch_channel_pre_answer(other_channel);
+					switch_core_session_rwunlock(other_session);
+				}
+				goto done;
+			} else {
+				if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
+					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
 				} else {
-					if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
-						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
-					} else if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
-						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
-					} else {
-						if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
-							switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
-							nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
-							switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
-						}
+					if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
+						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+						nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+						switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
 					}
-					goto done;
 				}
+				goto done;
 			}
 		}
 		break;
@@ -1739,29 +3409,29 @@
 		nua_ack(nh, TAG_END());
 		break;
 	case nua_callstate_received:
-		if (tech_pvt && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
-			if (r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
+		if (!sofia_test_flag(tech_pvt, TFLAG_SDP)) {
+			if (r_sdp && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
 				if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
 					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA");
-					switch_set_flag_locked(tech_pvt, TFLAG_READY);
+					sofia_set_flag_locked(tech_pvt, TFLAG_READY);
 					if (switch_channel_get_state(channel) == CS_NEW) {
 						switch_channel_set_state(channel, CS_INIT);
 					}
-					switch_set_flag(tech_pvt, TFLAG_SDP);
+					sofia_set_flag(tech_pvt, TFLAG_SDP);
 					goto done;
 				} else if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
-                    switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
-                    switch_set_flag_locked(tech_pvt, TFLAG_READY);
-                    if (switch_channel_get_state(channel) == CS_NEW) {
-                        switch_channel_set_state(channel, CS_INIT);
-                    }
-				} else if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
-                    switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
-                    switch_set_flag_locked(tech_pvt, TFLAG_READY);
-                    if (switch_channel_get_state(channel) == CS_NEW) {
-                        switch_channel_set_state(channel, CS_INIT);
-                    }
-                } else {
+					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
+					sofia_set_flag_locked(tech_pvt, TFLAG_READY);
+					if (switch_channel_get_state(channel) == CS_NEW) {
+						switch_channel_set_state(channel, CS_INIT);
+					}
+				} else if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
+					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
+					sofia_set_flag_locked(tech_pvt, TFLAG_READY);
+					if (switch_channel_get_state(channel) == CS_NEW) {
+						switch_channel_set_state(channel, CS_INIT);
+					}
+				} else {
 					sdp_parser_t *parser;
 					sdp_session_t *sdp;
 					uint8_t match = 0;
@@ -1774,17 +3444,17 @@
 							sdp_parser_free(parser);
 						}
 					}
-					
+
 					if (match) {
 						nua_handle_t *bnh;
 						sip_replaces_t *replaces;
 						su_home_t *home = NULL;
 						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED");
-						switch_set_flag_locked(tech_pvt, TFLAG_READY);
+						sofia_set_flag_locked(tech_pvt, TFLAG_READY);
 						if (switch_channel_get_state(channel) == CS_NEW) {
 							switch_channel_set_state(channel, CS_INIT);
 						}
-						switch_set_flag(tech_pvt, TFLAG_SDP);
+						sofia_set_flag(tech_pvt, TFLAG_SDP);
 						if (replaces_str) {
 							home = su_home_new(sizeof(*home));
 							switch_assert(home != NULL);
@@ -1796,15 +3466,16 @@
 								while (switch_channel_get_state(channel) < CS_EXECUTE) {
 									switch_yield(10000);
 								}
-								
+
 								if ((b_private = nua_handle_magic(bnh))) {
 									const char *br_b = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
 									char *br_a = b_private->uuid;
-									
+
 									if (br_b) {
 										switch_ivr_uuid_bridge(br_a, br_b);
 										switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
-										switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+										sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+										sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
 										switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
 									} else {
 										switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
@@ -1830,22 +3501,39 @@
 				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
 					goto done;
 				} else {
-					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
-					sofia_glue_tech_choose_port(tech_pvt, 0);
-					sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
-					switch_channel_set_state(channel, CS_HIBERNATE);
-					nua_respond(tech_pvt->nh, SIP_200_OK,
-								SIPTAG_CONTACT_STR(tech_pvt->profile->url),
-								SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-								SOATAG_REUSE_REJECTED(1),
-								SOATAG_ORDERED_USER(1),
-								SOATAG_AUDIO_AUX("cn telephone-event"),
-								NUTAG_INCLUDE_EXTRA_SDP(1),
-								TAG_END());
+					if (sofia_test_pflag(profile, PFLAG_3PCC)) {
+						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
+						sofia_glue_tech_choose_port(tech_pvt, 0);
+						sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+						sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);
+						switch_channel_set_state(channel, CS_HIBERNATE);
+						nua_respond(tech_pvt->nh, SIP_200_OK,
+									SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+									SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+									SOATAG_REUSE_REJECTED(1),
+									SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), 
+									TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
+					} else if (sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
+						//3PCC proxy mode delays the 200 OK until the call is answered
+						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
+						sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);
+						sofia_glue_tech_choose_port(tech_pvt, 0);
+						sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+						switch_channel_set_flag(channel, TFLAG_LATE_NEGOTIATION);
+						//Moves into CS_INIT so call moves forward into the dialplan
+						switch_channel_set_state(channel, CS_INIT);
+					} else {
+						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "3PCC DISABLED");
+						switch_channel_hangup(channel, SWITCH_CAUSE_MANDATORY_IE_MISSING);
+					}
 					goto done;
 				}
 			}
 
+		} else if (tech_pvt && sofia_test_flag(tech_pvt, TFLAG_SDP) && !r_sdp) {
+			nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END());
+			sofia_set_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE);
+			goto done;
 		} else {
 			ss_state = nua_callstate_completed;
 			goto state_process;
@@ -1855,28 +3543,92 @@
 	case nua_callstate_early:
 		break;
 	case nua_callstate_completed:
-		if (tech_pvt && r_sdp) {
-			sdp_parser_t *parser; 
+		if (r_sdp) {
+			sdp_parser_t *parser;
 			sdp_session_t *sdp;
-			uint8_t match = 0;
+			uint8_t match = 0, is_ok = 1;
+			tech_pvt->hold_laps = 0;
 
-			if (r_sdp) { 
+			if (r_sdp) {
+				const char *var;
+				
+				if ((var = switch_channel_get_variable(channel, "sip_ignore_reinvites")) && switch_true(var)) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring Re-invite\n");
+					nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END());
+					goto done;
+				}
+
 				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+					
 					if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
 						&& (other_session = switch_core_session_locate(uuid))) {
 						switch_core_session_message_t msg = { 0 };
+						
+						if (profile->media_options & MEDIA_OPT_MEDIA_ON_HOLD) {
+							tech_pvt->hold_laps = 1;
+							switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
+							switch_channel_clear_flag(channel, CF_PROXY_MODE);
+							sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE);
+							
+							if (!switch_channel_media_ready(channel)) {
+								if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
+									//const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
 
+									tech_pvt->num_codecs = 0;
+									sofia_glue_tech_prepare_codecs(tech_pvt);
+									if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
+										switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+										status = SWITCH_STATUS_FALSE;
+										goto done;
+									}
+								}
+							}
+
+							if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+								sofia_glue_tech_prepare_codecs(tech_pvt);
+								if ((status = sofia_glue_tech_choose_port(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+									switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+									goto done;
+								}
+							}
+							sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 1);
+							
+							nua_respond(tech_pvt->nh, SIP_200_OK,
+										SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+										SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+										SOATAG_REUSE_REJECTED(1),
+										SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), 
+										TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
+							launch_media_on_hold(session);
+
+							switch_core_session_rwunlock(other_session);
+							goto done;
+						}
+						
 						msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT;
 						msg.from = __FILE__;
 						msg.string_arg = (char *) r_sdp;
 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Passing SDP to other leg.\n%s\n", r_sdp);
+						
+						if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+							if (!switch_stristr("sendonly", r_sdp)) {
+								sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+								switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL);
+							}
+						} else if (switch_stristr("sendonly", r_sdp)) {
+							sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+							switch_channel_presence(tech_pvt->channel, "unknown", "hold", NULL);
+						}
+					
+
 						if (switch_core_session_receive_message(other_session, &msg) != SWITCH_STATUS_SUCCESS) {
 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Other leg is not available\n");
 							nua_respond(tech_pvt->nh, 403, "Hangup in progress", TAG_END());
-						}					
+						}
 						switch_core_session_rwunlock(other_session);
 					} else {
 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Re-INVITE to a no-media channel that is not in a bridge.\n");
+						is_ok = 0;
 						switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
 					}
 					goto done;
@@ -1894,37 +3646,81 @@
 							goto done;
 						}
 						sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
-						switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+						sofia_set_flag_locked(tech_pvt, TFLAG_REINVITE);
 						if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Reinvite RTP Error!\n");
+							is_ok = 0;
 							switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
 						}
 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n");
 					} else {
 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Reinvite Codec Error!\n");
-						switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+						is_ok = 0;
 					}
 				}
+				
+				if (is_ok) {
+					if (tech_pvt->local_crypto_key) {
+						sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+					}
+					nua_respond(tech_pvt->nh, SIP_200_OK,
+								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+								SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+								SOATAG_REUSE_REJECTED(1),
+								SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), 
+								TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
+				} else {
+					nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+				}
+			}
+		}
+		break;
+	case nua_callstate_ready:
 
+		if (r_sdp && sofia_test_flag(tech_pvt, TFLAG_NOSDP_REINVITE)) {
+			sdp_parser_t *parser;
+			sdp_session_t *sdp;
+			uint8_t match = 0;
+			int is_ok = 1;
 
-				nua_respond(tech_pvt->nh, SIP_200_OK,
-							SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
-							SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-							SOATAG_REUSE_REJECTED(1),
-							SOATAG_ORDERED_USER(1),
-							SOATAG_AUDIO_AUX("cn telephone-event"),
-							NUTAG_INCLUDE_EXTRA_SDP(1),
-							TAG_END());
+			sofia_clear_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE);
+
+			if (tech_pvt->num_codecs) {
+				if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+					if ((sdp = sdp_session(parser))) {
+						match = sofia_glue_negotiate_sdp(session, sdp);
+					}
+					sdp_parser_free(parser);
+				}
 			}
+
+			if (match) {
+				sofia_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+				if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error!\n");
+					switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RTP ERROR");
+					is_ok = 0;
+				}
+				sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+			} else {
+				switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+				is_ok = 0;
+			}
+
+			if (!is_ok) {
+				nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+				switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
+			}
+
+			goto done;
 		}
-		break;
-	case nua_callstate_ready:
+
 		if (channel) {
 			switch_channel_clear_flag(channel, CF_REQ_MEDIA);
 		}
 		if (tech_pvt && nh == tech_pvt->nh2) {
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cheater Reinvite!\n");
-			switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+			sofia_set_flag_locked(tech_pvt, TFLAG_REINVITE);
 			tech_pvt->nh = tech_pvt->nh2;
 			tech_pvt->nh2 = NULL;
 			if (sofia_glue_tech_choose_port(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
@@ -1935,34 +3731,38 @@
 			}
 			goto done;
 		}
-
+		
 		if (channel) {
-			if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
-				switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-                switch_set_flag(tech_pvt, TFLAG_SDP);
-				switch_channel_mark_answered(channel);
-				if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
-					&& (other_session = switch_core_session_locate(uuid))) {
-					other_channel = switch_core_session_get_channel(other_session);
-					switch_channel_answer(other_channel);
-					switch_core_session_rwunlock(other_session);
+            if (sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
+                sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
+                sofia_set_flag(tech_pvt, TFLAG_SDP);
+                switch_channel_mark_answered(channel);
+				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+					if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+						&& (other_session = switch_core_session_locate(uuid))) {
+						other_channel = switch_core_session_get_channel(other_session);
+						switch_channel_answer(other_channel);
+						switch_core_session_rwunlock(other_session);
+					}
 				}
-				goto done;
+                goto done;
+            }
+			
+			if (!r_sdp && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
+				r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
 			}
 
-			if (!r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
-				r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
-			}
-			if (r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
+			if (r_sdp && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
 				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
-					switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-					switch_set_flag_locked(tech_pvt, TFLAG_SDP);
+					sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
+					sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
 					switch_channel_mark_answered(channel);
 					if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
 						if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
 							goto done;
 						}
 					}
+
 					if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
 						&& (other_session = switch_core_session_locate(uuid))) {
 						other_channel = switch_core_session_get_channel(other_session);
@@ -1988,7 +3788,7 @@
 					}
 
 					if (match) {
-						switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+						sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
 						if (sofia_glue_tech_choose_port(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
 							if (sofia_glue_activate_rtp(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
 								switch_channel_mark_answered(channel);
@@ -1996,12 +3796,17 @@
 								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error!\n");
 								switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
 							}
-							if (switch_channel_get_state(channel) == CS_HIBERNATE) {
-								switch_set_flag_locked(tech_pvt, TFLAG_READY);
-								if (switch_channel_get_state(channel) == CS_NEW) {
+
+							if (sofia_test_flag(tech_pvt, TFLAG_3PCC)) {
+								/* Check if we are in 3PCC proxy mode, if so then set the flag to indicate we received the ack */
+								if (sofia_test_pflag(profile, PFLAG_3PCC_PROXY )) {
+									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
+									sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
+								} else if (switch_channel_get_state(channel) == CS_HIBERNATE) {
+									sofia_set_flag_locked(tech_pvt, TFLAG_READY);
 									switch_channel_set_state(channel, CS_INIT);
+									sofia_set_flag(tech_pvt, TFLAG_SDP);
 								}
-								switch_set_flag(tech_pvt, TFLAG_SDP);
 							}
 							goto done;
 						}
@@ -2015,58 +3820,127 @@
 
 		break;
 	case nua_callstate_terminating:
-		if (session) {
-			if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
-				switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-			}
+		if (status == 488 || switch_channel_get_state(channel) == CS_HIBERNATE) {
+			tech_pvt->q850_cause = SWITCH_CAUSE_MANDATORY_IE_MISSING;
 		}
-		break;
 	case nua_callstate_terminated:
-		if (session) {
-			if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
-				switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-				if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) {
-					switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
-				} else {
-                    int cause;
-                    if (tech_pvt->q850_cause) {
-                        cause = tech_pvt->q850_cause;
-                    } else {
-                        cause = sofia_glue_sip_cause_to_freeswitch(status);
-                    }
-					switch_snprintf(st, sizeof(st), "%d", status);
-					switch_channel_set_variable(channel, "sip_term_status", st);
-					switch_snprintf(st, sizeof(st), "%d", cause);
-					switch_channel_set_variable(channel, "sip_term_cause", st);
-					switch_channel_hangup(channel, cause);
+		sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+		if (sofia_test_flag(tech_pvt, TFLAG_NOHUP)) {
+			sofia_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
+		} else if (switch_channel_up(channel)) {
+			int cause;
+			if (tech_pvt->q850_cause) {
+				cause = tech_pvt->q850_cause;
+			} else {
+				cause = sofia_glue_sip_cause_to_freeswitch(status);
+			}
+			if (status) {
+				switch_snprintf(st, sizeof(st), "%d", status);
+				switch_channel_set_variable(channel, "sip_term_status", st);
+				switch_snprintf(st, sizeof(st), "sip:%d", status);
+				switch_channel_set_variable_partner(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st);
+				switch_channel_set_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st);
+				if (phrase) {
+					switch_channel_set_variable_partner(channel, "sip_hangup_phrase", phrase);
 				}
 			}
-			
+			switch_snprintf(st, sizeof(st), "%d", cause);
+			switch_channel_set_variable(channel, "sip_term_cause", st);
+			switch_channel_hangup(channel, cause);
+		}
+		
+
+		if (ss_state == nua_callstate_terminated) {
 			if (tech_pvt->sofia_private) {
-				sofia_private = tech_pvt->sofia_private;
 				tech_pvt->sofia_private = NULL;
-				free(sofia_private);
 			}
+			
+			tech_pvt->nh = NULL;
+	
+			if (nh) {
+				nua_handle_bind(nh, NULL);
+				nua_handle_destroy(nh);
+			}
+		}
+		
+		break;
+	}
 
-			tech_pvt->nh = NULL;		
+  done:
+	return;
+}
 
+typedef struct {
+	char *exten;
+	char *event;
+	char *reply_uuid;
+	char *bridge_to_uuid;
+	switch_memory_pool_t *pool;
+} nightmare_xfer_helper_t;
 
-		} else if (sofia_private) {
-			free(sofia_private);
+void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void *obj)
+{
+	nightmare_xfer_helper_t *nhelper = (nightmare_xfer_helper_t *) obj;
+	switch_memory_pool_t *pool;
+	switch_status_t status;
+	switch_core_session_t *session, *a_session;
+	
+	if ((a_session = switch_core_session_locate(nhelper->bridge_to_uuid))) {
+		switch_core_session_t *tsession;
+		switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
+		uint32_t timeout = 60;
+		char *tuuid_str;
+
+		if ((session = switch_core_session_locate(nhelper->reply_uuid))) {
+			private_object_t *tech_pvt = switch_core_session_get_private(session);
+			switch_channel_t *channel_a = switch_core_session_get_channel(session);
+
+			status = switch_ivr_originate(a_session, &tsession, &cause, nhelper->exten, timeout, NULL, NULL, NULL, NULL, NULL, SOF_NONE);
+							
+			if ((switch_channel_up(channel_a))) {
+				
+				if (status != SWITCH_STATUS_SUCCESS || cause != SWITCH_CAUSE_SUCCESS) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", nhelper->exten);
+					nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("messsage/sipfrag"),
+							   NUTAG_SUBSTATE(nua_substate_terminated),
+							   SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(nhelper->event), TAG_END());
+					status = SWITCH_STATUS_FALSE;
+				} else {
+					tuuid_str = switch_core_session_get_uuid(tsession);
+					switch_ivr_uuid_bridge(nhelper->bridge_to_uuid, tuuid_str);
+					switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
+					sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+					nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+							   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(nhelper->event), TAG_END());
+					switch_core_session_rwunlock(tsession);
+				}
+			}
+			switch_core_session_rwunlock(session);
 		}
 
-		if (nh) {
-			nua_handle_bind(nh, NULL);
-			nua_handle_destroy(nh);
-		}
-		break;
+		switch_core_session_rwunlock(a_session);
 	}
 
-  done:
-	return;
+	pool = nhelper->pool;
+	switch_core_destroy_memory_pool(&pool);
+
+	return NULL;
 }
 
+static void launch_nightmare_xfer(nightmare_xfer_helper_t *nhelper)
+{
+	switch_thread_t *thread;
+	switch_threadattr_t *thd_attr = NULL;
+
+	switch_threadattr_create(&thd_attr, nhelper->pool);
+	switch_threadattr_detach_set(thd_attr, 1);
+	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+	switch_threadattr_priority_increase(thd_attr);
+	switch_thread_create(&thread, thd_attr, nightmare_xfer_thread_run, nhelper, nhelper->pool);
+}
+
 /*---------------------------------------*/
+
 void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
 {
 	/* Incoming refer */
@@ -2080,6 +3954,8 @@
 	su_home_t *home = NULL;
 	char *full_ref_by = NULL;
 	char *full_ref_to = NULL;
+	nightmare_xfer_helper_t *nightmare_xfer_helper;
+	switch_memory_pool_t *npool;
 
 	if (!(profile->mflags & MFLAG_REFER)) {
 		nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
@@ -2091,45 +3967,51 @@
 		goto done;
 	}
 
-	if (switch_channel_test_flag(channel_a, CF_PROXY_MODE)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Transfer on bypass media not allowed.\n");
-		nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-				   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
-		goto done;
-	}
-
 	from = sip->sip_from;
 	to = sip->sip_to;
-	
+
 	home = su_home_new(sizeof(*home));
 	switch_assert(home != NULL);
 
-	if (sip->sip_referred_by) {		
+	if (sip->sip_referred_by) {
 		full_ref_by = sip_header_as_string(home, (void *) sip->sip_referred_by);
 	}
 
 	if ((refer_to = sip->sip_refer_to)) {
+		char *rep;
 		full_ref_to = sip_header_as_string(home, (void *) sip->sip_refer_to);
 
-		if (profile->pflags & PFLAG_FULL_ID) {
-			exten = switch_mprintf("%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host);
+		if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
+			exten = switch_core_session_sprintf(session, "%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host);
 		} else {
 			exten = (char *) refer_to->r_url->url_user;
 		}
 
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host);
 
-		if (refer_to->r_url->url_headers) {
+		if (refer_to->r_url->url_headers && (rep = (char *)switch_stristr("Replaces=", refer_to->r_url->url_headers))) {
 			sip_replaces_t *replaces;
 			nua_handle_t *bnh;
-			char *rep;
 
-			if ((rep = strchr(refer_to->r_url->url_headers, '='))) {
+			if (switch_channel_test_flag(channel_a, CF_PROXY_MODE)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Attended Transfer BYPASS MEDIA CALLS!\n");
+				switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
+				nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+						   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
+				goto done;
+			}
+			
+			if (rep) {
 				const char *br_a = NULL, *br_b = NULL;
 				char *buf;
+				char *p;
 
-				rep++;
+				rep = switch_core_session_strdup(session, rep + 9);
 
+				if ((p = strchr(rep, ';'))) {
+					*p = '\0';
+				}
+				
 				if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
 					rep = url_unescape(buf, (const char *) rep);
 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Replaces: [%s]\n", rep);
@@ -2144,6 +4026,7 @@
 					private_object_t *b_tech_pvt = NULL;
 					switch_core_session_t *b_session = NULL;
 
+
 					switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep);
 					if ((b_private = nua_handle_magic(bnh))) {
 						if (!(b_session = switch_core_session_locate(b_private->uuid))) {
@@ -2154,42 +4037,47 @@
 
 						br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
 						br_b = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
+
+						if (br_a && br_b) {
+							switch_core_session_t *new_b_session = NULL, *a_session = NULL, *tmp = NULL;
 						
-						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", switch_str_nil(br_a), switch_str_nil(br_b));
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", 
+											  switch_str_nil(br_a),
+											  switch_str_nil(br_b));
 
-						if (br_a && br_b) {
-							switch_core_session_t *new_b_session = NULL, *a_session = NULL;
-								
+							if ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER) && (tmp = switch_core_session_locate(br_b))) {
+								switch_channel_t *tchannel = switch_core_session_get_channel(tmp);
+								switch_channel_set_variable(tchannel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE, "true");
+								switch_core_session_rwunlock(tmp);
+							}
+							
 							switch_ivr_uuid_bridge(br_b, br_a);
 							switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
 							nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
 									   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
 
-							switch_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
-							switch_ivr_park_session(b_session);
+							sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
+							sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
+							switch_channel_set_variable(switch_core_session_get_channel(b_session), "park_timeout", "2");
+							switch_channel_set_state(switch_core_session_get_channel(b_session), CS_PARK);
+
 							new_b_session = switch_core_session_locate(br_b);
 							a_session = switch_core_session_locate(br_a);
 							sofia_info_send_sipfrag(a_session, new_b_session);
+
 							if (new_b_session) {
 								switch_core_session_rwunlock(new_b_session);
 							}
+
 							if (a_session) {
 								switch_core_session_rwunlock(a_session);
 							}
-							//switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
 						} else {
 							if (!br_a && !br_b) {
-								switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-								switch_set_flag_locked(b_tech_pvt, TFLAG_XFER);
-								b_tech_pvt->xferto = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session));
-								switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-								nua_notify(tech_pvt->nh,
-											NUTAG_NEWSUB(1),
-											SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-											NUTAG_SUBSTATE(nua_substate_terminated),
-											SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-											SIPTAG_EVENT_STR(etmp),
-											TAG_END());
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot transfer channels that are not in a bridge.\n");
+								nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+										   NUTAG_SUBSTATE(nua_substate_terminated),
+										   SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
 							} else {
 								switch_core_session_t *t_session;
 								switch_channel_t *hup_channel;
@@ -2202,8 +4090,8 @@
 									private_object_t *h_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session);
 									t_session = switch_core_session_locate(br_b);
 									hup_channel = channel_a;
-									switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-									switch_clear_flag_locked(h_tech_pvt, TFLAG_SIP_HOLD);
+									sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+									sofia_clear_flag_locked(h_tech_pvt, TFLAG_SIP_HOLD);
 									switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
 								}
 
@@ -2218,15 +4106,13 @@
 									if (!switch_strlen_zero(full_ref_to)) {
 										switch_channel_set_variable(t_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
 									}
-									
+
 									switch_ivr_session_transfer(t_session, ext, NULL, NULL);
 									nua_notify(tech_pvt->nh,
-												NUTAG_NEWSUB(1),
-												SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-												NUTAG_SUBSTATE(nua_substate_terminated),
-												SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-												SIPTAG_EVENT_STR(etmp),
-												TAG_END());
+											   NUTAG_NEWSUB(1),
+											   SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+											   NUTAG_SUBSTATE(nua_substate_terminated),
+											   SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
 									switch_core_session_rwunlock(t_session);
 									switch_channel_hangup(hup_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
 								} else {
@@ -2248,12 +4134,9 @@
 						switch_channel_t *channel = switch_core_session_get_channel(session);
 
 						if ((a_session = switch_core_session_locate(br_a))) {
-							switch_core_session_t *tsession;
-							switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
-							uint32_t timeout = 60;
-							char *tuuid_str;
 							const char *port = NULL;
-							switch_status_t status;
+							char *param_string = "";
+							int count = 0, bytes = 0;
 
 							if (refer_to && refer_to->r_url && refer_to->r_url->url_port) {
 								port = refer_to->r_url->url_port;
@@ -2262,42 +4145,56 @@
 							if (switch_strlen_zero(port)) {
 								port = "5060";
 							}
+							
 							channel = switch_core_session_get_channel(a_session);
 							
-							exten = switch_mprintf("sofia/%s/%s@%s:%s",
-												   profile->name,
-												   refer_to->r_url->url_user,
-												   refer_to->r_url->url_host,
-												   port);
-							
+							if (refer_to->r_params) {
+								for (count = 0; refer_to->r_params[count] ; count++) {
+									bytes += strlen(refer_to->r_params[count]) + 1;
+								}
+
+								if (bytes) {
+									bytes += 2;
+
+									param_string = switch_core_session_alloc(session, bytes);
+									*param_string = ';';
+									for (count = 0; refer_to->r_params[count] ; count++) {
+										switch_snprintf(param_string + strlen(param_string), bytes - strlen(param_string), "%s;", refer_to->r_params[count]);
+									}
+								
+									if (end_of(param_string) == ';') {
+										end_of(param_string) = '\0';
+									}
+								}
+							}
+
+							exten = switch_core_session_sprintf(session, "sofia/%s/sip:%s@%s", 
+																profile->name, refer_to->r_url->url_user, 
+																refer_to->r_url->url_host);
+
+							switch_core_new_memory_pool(&npool);
+							nightmare_xfer_helper = switch_core_alloc(npool, sizeof(*nightmare_xfer_helper));
+							nightmare_xfer_helper->exten = switch_core_strdup(npool, exten);
+							nightmare_xfer_helper->event = switch_core_strdup(npool, etmp);
+							nightmare_xfer_helper->reply_uuid = switch_core_strdup(npool, switch_core_session_get_uuid(session));
+							nightmare_xfer_helper->bridge_to_uuid = switch_core_strdup(npool, br_a);
+							nightmare_xfer_helper->pool = npool;
+
 							switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
+
 							if (!switch_strlen_zero(full_ref_by)) {
 								switch_channel_set_variable(channel, SOFIA_SIP_HEADER_PREFIX "Referred-By", full_ref_by);
 							}
+
 							if (!switch_strlen_zero(full_ref_to)) {
 								switch_channel_set_variable(channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
 							}
-							status = switch_ivr_originate(a_session,
-														  &tsession, &cause, exten, timeout, &noop_state_handler, NULL, NULL, NULL, SOF_NONE);
 
-							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", exten);
-							nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-									   NUTAG_SUBSTATE(nua_substate_terminated),
-									   SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Good Luck, you'll need it......\n");
+							launch_nightmare_xfer(nightmare_xfer_helper);
 							
 							switch_core_session_rwunlock(a_session);
 
-							if (status != SWITCH_STATUS_SUCCESS) {
-								goto done;
-							}
-							
-							tuuid_str = switch_core_session_get_uuid(tsession);
-							switch_ivr_uuid_bridge(br_a, tuuid_str);
-							switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
-							switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-							nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-									   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
-							switch_core_session_rwunlock(tsession);
 						} else {
 							goto error;
 						}
@@ -2328,7 +4225,7 @@
 
 		if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
 			switch_core_session_t *b_session;
-			
+
 			if ((b_session = switch_core_session_locate(br))) {
 				switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
 				switch_channel_set_variable(channel, "transfer_fallback_extension", from->a_user);
@@ -2338,23 +4235,20 @@
 				if (!switch_strlen_zero(full_ref_to)) {
 					switch_channel_set_variable(b_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
 				}
+
 				switch_ivr_session_transfer(b_session, exten, NULL, NULL);
 				switch_core_session_rwunlock(b_session);
 			}
 
 			switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "BLIND_TRANSFER");
 			nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-			   NUTAG_SUBSTATE(nua_substate_terminated),
-			   SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
-			   SIPTAG_EVENT_STR(etmp),
-			   TAG_END());
-			 
+					   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
+
 		} else {
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Blind Transfer 1 Legged calls\n");
 			switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
 			nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
-					   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp),
-					   TAG_END());
+					   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
 		}
 	}
 
@@ -2364,9 +4258,6 @@
 		home = NULL;
 	}
 
-	if (exten && strchr(exten, '@')) {
-		switch_safe_free(exten);
-	}
 	if (etmp) {
 		switch_safe_free(etmp);
 	}
@@ -2378,8 +4269,9 @@
 	const char *signal_ptr;
 	const char *rec_header;
 	const char *clientcode_header;
-	switch_dtmf_t dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
-	
+	switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0) };
+	switch_event_t *event;
+
 	if (session) {
 		/* Get the channel */
 		switch_channel_t *channel = switch_core_session_get_channel(session);
@@ -2387,47 +4279,75 @@
 		/* Barf if we didn't get our private */
 		assert(switch_core_session_get_private(session));
 
-		if (sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype && 
+		if (sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype &&
 			sip->sip_payload && sip->sip_payload->pl_data) {
 			if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "dtmf-relay")) {
 				/* Try and find signal information in the payload */
 				if ((signal_ptr = switch_stristr("Signal=", sip->sip_payload->pl_data))) {
+					int tmp;
 					/* move signal_ptr where we need it (right past Signal=) */
 					signal_ptr = signal_ptr + 7;
-					dtmf.digit = *signal_ptr;
+
+					/* handle broken devices with spaces after the = (cough) VegaStream (cough) */
+					while (*signal_ptr && *signal_ptr == ' ') signal_ptr++;
+
+					if (*signal_ptr && (*signal_ptr == '*' || *signal_ptr == '#' || *signal_ptr == 'A' || *signal_ptr == 'B' || *signal_ptr == 'C' || *signal_ptr == 'D')) {
+						dtmf.digit = *signal_ptr;
+					} else {
+						tmp = atoi(signal_ptr);
+						dtmf.digit = switch_rfc2833_to_char(tmp);
+					}
 				} else {
 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Bad signal\n");
-					goto fail;
+					goto end;
 				}
 
 				if ((signal_ptr = switch_stristr("Duration=", sip->sip_payload->pl_data))) {
 					int tmp;
 					signal_ptr += 9;
+
+					/* handle broken devices with spaces after the = (cough) VegaStream (cough) */
+					while (*signal_ptr && *signal_ptr == ' ') signal_ptr++;
+					
 					if ((tmp = atoi(signal_ptr)) <= 0) {
-						tmp = SWITCH_DEFAULT_DTMF_DURATION;
-					} 
+						tmp = switch_core_default_dtmf_duration(0);
+					}
 					dtmf.duration = tmp * 8;
 				}
 			} else if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "dtmf")) {
-				dtmf.digit = *sip->sip_payload->pl_data;
+				int tmp = atoi(sip->sip_payload->pl_data);
+				dtmf.digit = switch_rfc2833_to_char(tmp);
 			} else {
-				goto fail;
+				goto end;
 			}
-		
+
 			if (dtmf.digit) {
 				/* queue it up */
 				switch_channel_queue_dtmf(channel, &dtmf);
 
 				/* print debug info */
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INFO DTMF(%c)\n", dtmf.digit);
+				
+				if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
+					const char *uuid;
+					switch_core_session_t *session_b;
+					
+					if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (session_b = switch_core_session_locate(uuid))) {
+						while (switch_channel_has_dtmf(channel)) {
+							switch_dtmf_t idtmf = { 0, 0 };
+							if (switch_channel_dequeue_dtmf(channel, &idtmf) == SWITCH_STATUS_SUCCESS) {
+								switch_core_session_send_dtmf(session_b, &idtmf);
+							}
+						}
 
+						switch_core_session_rwunlock(session_b);
+					}
+				}
+
 				/* Send 200 OK response */
 				nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
-	
-				return;
-			} else {
-				goto fail;
 			}
+			goto end;
 		}
 
 		if ((clientcode_header = sofia_glue_get_unknown_header(sip, "x-clientcode"))) {
@@ -2435,10 +4355,8 @@
 				switch_channel_set_variable(channel, "call_clientcode", clientcode_header);
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Setting CMC to %s\n", clientcode_header);
 				nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
-			} else {
-				goto fail;
 			}
-			return;
+			goto end;
 		}
 
 		if ((rec_header = sofia_glue_get_unknown_header(sip, "record"))) {
@@ -2470,16 +4388,74 @@
 					}
 				}
 			}
-			return;
 		}
 	}
+
+ end:
+
+
+	if (sip && switch_event_create(&event, SWITCH_EVENT_RECV_INFO) == SWITCH_STATUS_SUCCESS) {
+		sip_alert_info_t *alert_info = sip_alert_info(sip);
+
+		if (sip && sip->sip_content_type) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Content-Type", sip->sip_content_type->c_type);
+		}
+
+		if (sip->sip_from && sip->sip_from->a_url) {
+			if (sip->sip_from->a_url->url_user) {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-From-User", sip->sip_from->a_url->url_user);
+			}
+
+			if (sip->sip_from->a_url->url_host) {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-From-Host", sip->sip_from->a_url->url_host);
+			}
+		}
+
+		if (sip->sip_to && sip->sip_to->a_url) {
+			if (sip->sip_to->a_url->url_user) {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-To-User", sip->sip_to->a_url->url_user);
+			}
+
+			if (sip->sip_to->a_url->url_host) {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-To-Host", sip->sip_to->a_url->url_host);
+			}
+		}
+
+
+		if (sip->sip_contact && sip->sip_contact->m_url) {
+			if (sip->sip_contact->m_url->url_user) {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Contact-User", sip->sip_contact->m_url->url_user);
+			}
+
+			if (sip->sip_contact->m_url->url_host) {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Contact-Host", sip->sip_contact->m_url->url_host);
+			}
+		}
+
+
+		if (sip->sip_call_info) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Call-Info", sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_call_info));
+		}
+
+		if (alert_info) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Alert-Info", sip_header_as_string(nua_handle_home(nh), (void *) alert_info));
+		}
+
+
+		if (sip->sip_payload && sip->sip_payload->pl_data) {
+			switch_event_add_body(event, "%s", sip->sip_payload->pl_data);
+		}
+
+		switch_event_fire(&event);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dispatched freeswitch event for INFO\n");
+	}
+
+	nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+
 	return;
 
- fail:
-	nua_respond(nh, 488, "Unsupported Request", NUTAG_WITH_THIS(nua), TAG_END());
 }
 
-
 #define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri", #varprefix "_params")
 const char *_url_set_chanvars(switch_core_session_t *session, url_t *url, const char *user_var,
 							  const char *host_var, const char *port_var, const char *uri_var, const char *params_var)
@@ -2539,7 +4515,9 @@
 	sip_remote_party_id_t *rpid = NULL;
 	sip_p_asserted_identity_t *passerted = NULL;
 	sip_p_preferred_identity_t *ppreferred = NULL;
+	sip_privacy_t *privacy = NULL;
 	sip_alert_info_t *alert_info = NULL;
+	sip_call_info_t *call_info = NULL;
 	private_object_t *tech_pvt = NULL;
 	switch_channel_t *channel = NULL;
 	const char *channel_name = NULL;
@@ -2554,76 +4532,195 @@
 	uint32_t sess_count = switch_core_session_count();
 	uint32_t sess_max = switch_core_session_limit(0);
 	int is_auth = 0, calling_myself = 0;
-	su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua));
-	
+	int network_port = 0;
+	char *is_nat = NULL;
+	char acl_token[512] = "";
+	sofia_transport_t transport;
 
-	if (sess_count >= sess_max || !(profile->pflags & PFLAG_RUNNING)) {
+	profile->ib_calls++;
+
+	if (sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING)) {
 		nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
-		return;
+		goto fail;
 	}
 
 	if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
 		nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
-		return;
+		goto fail;
 	}
 
+	if (!(sip->sip_contact && sip->sip_contact->m_url)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
+		nua_respond(nh, 400, "Missing Contact Header", TAG_END());
+		goto fail;
+	}
+
+	sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &network_port);
+
+	if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
+		if (sip && sip->sip_via) {
+			const char *port = sip->sip_via->v_port;
+			const char *host = sip->sip_via->v_host;
+
+			if (host && sip->sip_via->v_received) {
+				is_nat = "via received";
+			} else if (host && strcmp(network_ip, host)) {
+				is_nat = "via host";
+			} else if (port && atoi(port) != network_port) {
+				is_nat = "via port";
+			}
+		}
+	}
+
+	if (!is_nat && profile->nat_acl_count) {
+		uint32_t x = 0;
+		int ok = 1;
+		char *last_acl = NULL;
+		const char *contact_host = NULL;
+
+		if (sip && sip->sip_contact && sip->sip_contact->m_url) {
+			contact_host = sip->sip_contact->m_url->url_host;
+		}
+
+		if (!switch_strlen_zero(contact_host)) {
+			for (x = 0; x < profile->nat_acl_count; x++) {
+				last_acl = profile->nat_acl[x];
+				if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
+					break;
+				}
+			}
+
+			if (ok) {
+				is_nat = last_acl;
+			}
+		}
+	}
 	
-	get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) my_addrinfo->ai_addr)->sin_addr);
-
 	if (profile->acl_count) {
 		uint32_t x = 0;
-		for (x = 0 ; x < profile->acl_count; x++) {
-			if (!switch_check_network_list_ip(network_ip, profile->acl[x])) {
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl %s\n", network_ip,  profile->acl[x]);
+		int ok = 1;
+		char *last_acl = NULL;
+		const char *token = NULL;
+
+		for (x = 0; x < profile->acl_count; x++) {
+			last_acl = profile->acl[x];
+			if (!(ok = switch_check_network_list_ip_token(network_ip, last_acl, &token))) {
+				break;
+			}
+		}
+
+		if (ok) {
+			if (token) {
+				switch_set_string(acl_token, token);
+			}
+			if (sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Approved by acl \"%s[%s]\". Access Granted.\n",
+								  network_ip, switch_str_nil(last_acl), acl_token);
+				is_auth = 1;
+			}
+		} else {
+			if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", network_ip, switch_str_nil(last_acl));
 				nua_respond(nh, SIP_403_FORBIDDEN, TAG_END());
-				return;
+				goto fail;
+			} else {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n",
+								  network_ip, switch_str_nil(last_acl));
 			}
 		}
 	}
 
-
-	if ((profile->pflags & PFLAG_AUTH_CALLS) || (!(profile->pflags & PFLAG_BLIND_AUTH) && (sip->sip_proxy_authorization || sip->sip_authorization))) {
-		if (strcmp(network_ip, profile->sipip)) {
-			if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &v_event)) {
+	if (!is_auth &&
+		(sofia_test_pflag(profile, PFLAG_AUTH_CALLS) || (!sofia_test_pflag(profile, PFLAG_BLIND_AUTH) && (sip->sip_proxy_authorization || sip->sip_authorization)))) {
+		if (!strcmp(network_ip, profile->sipip) && network_port == profile->sip_port) {
+			calling_myself++;
+		} else {
+			if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &v_event, NULL)) {
 				if (v_event) {
 					switch_event_destroy(&v_event);
 				}
+				
+				if (sip->sip_authorization || sip->sip_proxy_authorization) {
+					goto fail;
+				}
+
 				return;
 			}
-		} else {
-			calling_myself++;
 		}
 		is_auth++;
 	}
 
-	
-	if (!(sip->sip_contact && sip->sip_contact->m_url)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
-		nua_respond(nh, 400, "Missing Contact Header", TAG_END());
-		return;
+	if (sofia_endpoint_interface) {
+		if (sofia_test_pflag(profile, PFLAG_CALLID_AS_UUID)) {
+			session = switch_core_session_request_uuid(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL, sip->sip_call_id->i_id);
+		} else {
+			session = switch_core_session_request(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL);
+		}
 	}
 
-	
-	if (!sofia_endpoint_interface || !(session = switch_core_session_request(sofia_endpoint_interface, NULL))) {
+	if (!session) {
 		nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
-		return;
+		goto fail;
 	}
 
 	if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
 		nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
 		switch_core_session_destroy(&session);
-		return;
+		goto fail;
 	}
+
+
 	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_mutex_init(&tech_pvt->sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
 
+	tech_pvt->remote_ip = switch_core_session_strdup(session, network_ip);
+	tech_pvt->remote_port = network_port;
+
+	channel = tech_pvt->channel = switch_core_session_get_channel(session);
+
+	if (*acl_token) {
+		switch_channel_set_variable(channel, "acl_token", acl_token);
+		if (strchr(acl_token, '@')) {
+			if (switch_ivr_set_user(session, acl_token) == SWITCH_STATUS_SUCCESS) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authenticating user %s\n", acl_token);
+			} else {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error Authenticating user %s\n", acl_token);
+			}
+		}
+	}
+
+	if (sip->sip_contact && sip->sip_contact->m_url) {
+		char tmp[35] = "";
+		const char *ipv6 = strchr(tech_pvt->remote_ip, ':');
+
+		transport = sofia_glue_url2transport(sip->sip_contact->m_url);
+
+		tech_pvt->record_route =
+			switch_core_session_sprintf(session,
+			"sip:%s@%s%s%s:%d;transport=%s",
+			sip->sip_contact->m_url->url_user,
+			ipv6 ? "[" : "",
+			tech_pvt->remote_ip,
+			ipv6 ? "]" : "",
+			tech_pvt->remote_port,
+			sofia_glue_transport2str(transport));
+
+		switch_channel_set_variable(channel, "sip_received_ip", tech_pvt->remote_ip);
+		snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_port);
+		switch_channel_set_variable(channel, "sip_received_port", tmp);
+	}
+
+	if (sip->sip_via) {
+		switch_channel_set_variable(channel, "sip_via_protocol", sofia_glue_transport2str(sofia_glue_via2transport(sip->sip_via)));
+	}
+
 	if (*key != '\0') {
 		tech_pvt->key = switch_core_session_strdup(session, key);
 	}
 
-	channel = tech_pvt->channel = switch_core_session_get_channel(session);
-	
+
 	if (is_auth) {
 		switch_channel_set_variable(channel, "sip_authorized", "true");
 	}
@@ -2634,8 +4731,8 @@
 
 	if (v_event) {
 		switch_event_header_t *hp;
-		
-		for(hp = v_event->headers; hp; hp = hp->next) {
+
+		for (hp = v_event->headers; hp; hp = hp->next) {
 			switch_channel_set_variable(channel, hp->name, hp->value);
 		}
 		switch_event_destroy(&v_event);
@@ -2672,29 +4769,46 @@
 
 	if ((rpid = sip_remote_party_id(sip))) {
 		if (rpid->rpid_url && rpid->rpid_url->url_user) {
+			char *full_rpid_header = sip_header_as_string(nh->nh_home, (void *) rpid); 
 			from_user = rpid->rpid_url->url_user;
+			if (!switch_strlen_zero(full_rpid_header)) {
+				switch_channel_set_variable(channel, "sip_Remote-Party-ID", full_rpid_header);
+			}
+
 		}
 		if (!switch_strlen_zero(rpid->rpid_display)) {
 			displayname = rpid->rpid_display;
 		}
+		switch_channel_set_variable(channel, "sip_cid_type", "rpid");
 	}
 
 	if ((passerted = sip_p_asserted_identity(sip))) {
 		if (passerted->paid_url && passerted->paid_url->url_user) {
+			char *full_paid_header = sip_header_as_string(nh->nh_home, (void *) passerted);
 			from_user = passerted->paid_url->url_user;
+			if (!switch_strlen_zero(full_paid_header)) {
+				switch_channel_set_variable(channel, "sip_P-Asserted-Identity", from_user);
+			}
 		}
 		if (!switch_strlen_zero(passerted->paid_display)) {
 			displayname = passerted->paid_display;
 		}
+		switch_channel_set_variable(channel, "sip_cid_type", "pid");
 	}
 
 	if ((ppreferred = sip_p_preferred_identity(sip))) {
 		if (ppreferred->ppid_url && ppreferred->ppid_url->url_user) {
+			char *full_ppid_header = sip_header_as_string(nh->nh_home, (void *) ppreferred);
 			from_user = ppreferred->ppid_url->url_user;
+			if (!switch_strlen_zero(full_ppid_header)) {
+				switch_channel_set_variable(channel, "sip_P-Preferred-Identity", full_ppid_header);
+			}
+			
 		}
 		if (!switch_strlen_zero(ppreferred->ppid_display)) {
 			displayname = ppreferred->ppid_display;
 		}
+		switch_channel_set_variable(channel, "sip_cid_type", "pid");
 	}
 
 	if (from_user) {
@@ -2703,18 +4817,29 @@
 
 	if (sip->sip_request->rq_url) {
 		const char *req_uri = url_set_chanvars(session, sip->sip_request->rq_url, sip_req);
-		if (profile->pflags & PFLAG_FULL_ID) {
+		if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
 			destination_number = req_uri;
 		} else {
 			destination_number = sip->sip_request->rq_url->url_user;
 		}
+		if (sip->sip_request->rq_url->url_params && (sofia_glue_find_parameter(sip->sip_request->rq_url->url_params, "intercom=true"))) {
+			switch_channel_set_variable(channel, "sip_auto_answer_detected", "true");
+		}
+	}
+
+	if (!destination_number && sip->sip_to && sip->sip_to->a_url) {
+		destination_number = sip->sip_to->a_url->url_user;
+	}
+	
+	if (destination_number) {
 		check_decode(destination_number, session);
+	} else {
+		destination_number = "service";
 	}
-
+	
 	if (sip->sip_to && sip->sip_to->a_url) {
 		const char *host, *user;
 		int port;
-		sofia_transport_t transport;
 		url_t *transport_url;
 
 		if (sip->sip_record_route && sip->sip_record_route->r_url) {
@@ -2728,10 +4853,12 @@
 
 		url_set_chanvars(session, sip->sip_to->a_url, sip_to);
 		if (switch_channel_get_variable(channel, "sip_to_uri")) {
-
+			const char *ipv6;
+			const char *tmp, *at, *url = NULL;
+			
 			host = switch_channel_get_variable(channel, "sip_to_host");
 			user = switch_channel_get_variable(channel, "sip_to_user");
-		
+
 			switch_channel_set_variable(channel, "sip_to_comment", sip->sip_to->a_comment);
 
 			if (sip->sip_to->a_params) {
@@ -2744,42 +4871,70 @@
 				port = sofia_glue_transport_has_tls(transport) ? profile->tls_sip_port : profile->sip_port;
 			}
 
-			tech_pvt->to_uri = switch_core_session_sprintf(session, "sip:%s@%s:%d;transport=%s",
-						 user, host, port, sofia_glue_transport2str(transport));
+			ipv6 = strchr(host, ':');
+			tech_pvt->to_uri =
+				switch_core_session_sprintf(session,
+					"sip:%s@%s%s%s:%d;transport=%s",
+					user, ipv6 ? "[" : "",
+					host, ipv6 ? "]" : "",
+					port,
+					sofia_glue_transport2str(transport));
 
-			if (profile->ndlb & PFLAG_NDLB_TO_IN_200_CONTACT) {
-				if (strchr(tech_pvt->to_uri, '>')) {
-					tech_pvt->reply_contact = tech_pvt->to_uri;
-				} else {
-					tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s>", tech_pvt->to_uri);
-				}
+			if (sofia_glue_check_nat(profile, tech_pvt->remote_ip)) {
+				url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url;
+			} else { 
+				url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url;
+			}			
+			
+			tmp = sofia_overcome_sip_uri_weakness(session, url, transport, SWITCH_TRUE, NULL);
+	
+			if ((at = strchr(tmp, '@'))) {
+				url = switch_core_session_sprintf(session, "sip:%s%s", user, at);
+			}
+
+			if (url) {
+				const char *brackets = NULL;
+				const char *proto = NULL;
+				
+				brackets = strchr(url, '>');
+				proto = switch_stristr("transport=", url);
+				tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s%s%s%s%s",
+																	  brackets ? "" : "<", url,
+																	  proto ? "" : ";transport=",
+																	  proto ? "" : sofia_glue_transport2str(transport),
+																	  brackets ? "" : ">");
 			} else {
-				const char *url;
-
-				if ((url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url)) {
-					if (strchr(url, '>')) {
-						tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, sofia_glue_transport2str(transport));
-					} else {
-						tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", url, sofia_glue_transport2str(transport));
-					}
-				} else {
-					switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-				}
+				switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
 			}
+			
 		} else {
-			const char *url;
-
-			if ((url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url)) {
-				if (strchr(url, '>')) {
-					tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, sofia_glue_transport2str(transport));
-				} else {
-					tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", url, sofia_glue_transport2str(transport));
-				}
+			const char *url = NULL;
+			if (sofia_glue_check_nat(profile, tech_pvt->remote_ip)) {
+			url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url;
+			} else { 
+				url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url;
+			}			
+			
+			if (url) {
+				const char *brackets = NULL;
+				const char *proto = NULL;
+				
+				brackets = strchr(url, '>');
+				proto = switch_stristr("transport=", url);
+				tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s%s%s%s%s",
+																	  brackets ? "" : "<", url,
+																	  proto ? "" : ";transport=",
+																	  proto ? "" : sofia_glue_transport2str(transport),
+																	  brackets ? "" : ">");
 			} else {
 				switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
 			}
 		}
 	}
+	
+	if (sofia_glue_check_nat(profile, tech_pvt->remote_ip)) {
+		tech_pvt->user_via = sofia_glue_create_external_via(session, profile, tech_pvt->transport);
+	}
 
 	if (sip->sip_contact && sip->sip_contact->m_url) {
 		const char *contact_uri = url_set_chanvars(session, sip->sip_contact->m_url, sip_contact);
@@ -2815,11 +4970,11 @@
 
 	switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "INBOUND CALL");
 
-	if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
+	if (sofia_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
 		switch_channel_set_flag(channel, CF_PROXY_MODE);
 	}
 
-	if (switch_test_flag(tech_pvt, TFLAG_PROXY_MEDIA)) {
+	if (sofia_test_flag(tech_pvt, TFLAG_PROXY_MEDIA)) {
 		switch_channel_set_flag(channel, CF_PROXY_MEDIA);
 	}
 
@@ -2831,8 +4986,8 @@
 	if (sip->sip_subject && sip->sip_subject->g_string) {
 		switch_channel_set_variable(channel, "sip_subject", sip->sip_subject->g_string);
 	}
-	
-	if (sip->sip_user_agent && !switch_strlen_zero(sip->sip_user_agent->g_string)){
+
+	if (sip->sip_user_agent && !switch_strlen_zero(sip->sip_user_agent->g_string)) {
 		switch_channel_set_variable(channel, "sip_user_agent", sip->sip_user_agent->g_string);
 	}
 
@@ -2854,20 +5009,6 @@
 		switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
 	}
 
-	if (sip->sip_request->rq_url) {
-		sofia_gateway_t *gateway;
-		char *from_key;
-		char *user = (char *) sip->sip_request->rq_url->url_user;
-		check_decode(user, session);
-		from_key = switch_core_session_sprintf(session, "sip:%s@%s", user, sip->sip_request->rq_url->url_host);
-
-		if ((gateway = sofia_reg_find_gateway(from_key))) {
-			context = gateway->register_context;
-			switch_channel_set_variable(channel, "sip_gateway", gateway->name);
-			sofia_reg_release_gateway(gateway);
-		}
-	}
-
 	if (!context) {
 		context = switch_channel_get_variable(channel, "user_context");
 	}
@@ -2890,7 +5031,16 @@
 		su_free(profile->home, tmp);
 	}
 
-	if (sofia_test_pflag(profile, PFLAG_PRESENCE)) {
+	if ((call_info = sip_call_info(sip))) {
+		char *tmp = sip_header_as_string(profile->home, (void *) call_info);
+		if (call_info->ci_params && (msg_params_find(call_info->ci_params , "answer-after=0"))) {
+			switch_channel_set_variable(channel, "sip_auto_answer_detected", "true");
+		}
+		switch_channel_set_variable(channel, "sip_call_info", tmp);
+		su_free(profile->home, tmp);
+	}
+
+	if (profile->pres_type) {
 		const char *user = switch_str_nil(sip->sip_from->a_url->url_user);
 		const char *host = switch_str_nil(sip->sip_from->a_url->url_host);
 
@@ -2900,14 +5050,111 @@
 		free(tmp);
 	}
 
+
+	if (strstr(destination_number, "gw+")) {
+		const char *gw_name = destination_number + 3;
+		sofia_gateway_t *gateway;
+		if (gw_name && (gateway = sofia_reg_find_gateway(gw_name))) {
+			context = switch_core_session_strdup(session, gateway->register_context);
+			switch_channel_set_variable(channel, "sip_gateway", gateway->name);
+
+			if (gateway->extension) {
+				destination_number = switch_core_session_strdup(session, gateway->extension);
+			}
+
+			gateway->ib_calls++;
+
+			if (gateway->ib_vars) {
+				switch_event_header_t *hp;
+				for(hp = gateway->ib_vars->headers; hp; hp = hp->next) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s setting variable [%s]=[%s]\n",
+									  switch_channel_get_name(channel), hp->name, hp->value);
+					switch_channel_set_variable(channel, hp->name, hp->value);
+				}
+			}
+
+			sofia_reg_release_gateway(gateway);
+		}
+	}
+
+	if (sip->sip_replaces) {
+		nua_handle_t *bnh;
+		if ((bnh = nua_handle_by_replaces(nua, sip->sip_replaces))) {
+			sofia_private_t *b_private = NULL;
+			if ((b_private = nua_handle_magic(bnh))) {
+				switch_core_session_t *b_session = NULL;
+				if ((b_session = switch_core_session_locate(b_private->uuid))) {
+					switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
+					const char *uuid;
+					int one_leg = 1;
+					private_object_t *b_tech_pvt = NULL;
+					const char *app = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_VARIABLE);
+					const char *data = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_DATA_VARIABLE);
+					
+					if (app && data && !strcasecmp(app, "conference")) {
+						destination_number = switch_core_session_sprintf(b_session, "answer,conference:%s", data);
+						dialplan = "inline";
+					} else {
+						if (switch_core_session_check_interface(b_session, sofia_endpoint_interface)) {
+							b_tech_pvt = switch_core_session_get_private(b_session);
+						}
+
+						if ((uuid = switch_channel_get_variable(b_channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
+							one_leg = 0;
+						} else {
+							uuid = switch_core_session_get_uuid(b_session);
+						}
+					
+						if (uuid) {
+							switch_core_session_t *c_session = NULL;
+							int do_conf = 0;					
+						
+							uuid = switch_core_session_strdup(b_session, uuid);
+
+							if ((c_session = switch_core_session_locate(uuid))) {
+								switch_channel_t *c_channel = switch_core_session_get_channel(c_session);
+								private_object_t *c_tech_pvt = NULL;
+					
+								if (switch_core_session_check_interface(c_session, sofia_endpoint_interface)) {
+									c_tech_pvt = switch_core_session_get_private(c_session);
+								}
+								
+
+								if (!one_leg && 
+									(!b_tech_pvt || !sofia_test_flag(b_tech_pvt, TFLAG_SIP_HOLD)) && 
+									(!c_tech_pvt || !sofia_test_flag(c_tech_pvt, TFLAG_SIP_HOLD))) {
+									char *ext = switch_core_session_sprintf(b_session, "conference:%s@sla+flags{mintwo}", uuid);
+								
+									switch_channel_set_flag(c_channel, CF_REDIRECT);
+									switch_ivr_session_transfer(b_session, ext, "inline", NULL);
+									switch_ivr_session_transfer(c_session, ext, "inline", NULL);
+									switch_channel_clear_flag(c_channel, CF_REDIRECT);
+									do_conf = 1;
+								}
+								switch_core_session_rwunlock(c_session);
+							}
+						
+							if (do_conf) {
+								destination_number = switch_core_session_sprintf(b_session, "answer,conference:%s@sla+flags{mintwo}", uuid);
+							} else {
+								destination_number = switch_core_session_sprintf(b_session, "answer,intercept:%s", uuid);
+							}
+
+							dialplan = "inline";
+						}
+					}
+					switch_core_session_rwunlock(b_session);
+				}
+			}
+			nua_handle_unref(bnh);
+		}
+	}
+
 	check_decode(displayname, session);
 	tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
 														 from_user,
 														 dialplan,
-														 displayname,
-														 from_user,
-														 network_ip,
-														 NULL, NULL, NULL, MODNAME, context, destination_number);
+														 displayname, from_user, network_ip, NULL, NULL, NULL, MODNAME, context, destination_number);
 
 	if (tech_pvt->caller_profile) {
 
@@ -2925,13 +5172,23 @@
 					switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
 					switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER);
 				}
-			} 
-			
+			}
+
 			if (rpid->rpid_screen && !strcasecmp(rpid->rpid_screen, "no")) {
 				switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
 			}
 		}
 
+		if ((privacy = sip_privacy(sip))) {
+			char *full_priv_header = sip_header_as_string(nh->nh_home, (void *) privacy); 
+			if (!switch_strlen_zero(full_priv_header)) {
+				switch_channel_set_variable(channel, "sip_Privacy", full_priv_header);
+			}
+			if (msg_params_find(privacy->priv_values, "id")) {
+				switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+			}
+		}
+
 		/* Loop thru unknown Headers Here so we can do something with them */
 		for (un = sip->sip_unknown; un; un = un->un_next) {
 			if (!strncasecmp(un->un_name, "Diversion", 9)) {
@@ -2944,27 +5201,43 @@
 						free(tmp_name);
 					}
 				}
+			} else if (!strncasecmp(un->un_name, "History-Info", 12)) {
+				switch_channel_set_variable(channel, "sip_history_info", un->un_value);
 			} else if (!strncasecmp(un->un_name, "X-", 2) || !strncasecmp(un->un_name, "P-", 2)) {
 				if (!switch_strlen_zero(un->un_value)) {
-					char *new_name;
-					if ((new_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) {
+					char new_name[512] = "";
+					int reps  = 0;
+					for(;;) {
+						char postfix[25] = "";
+						if (reps > 0) {
+							switch_snprintf(postfix, sizeof(postfix), "-%d", reps);
+						}
+						reps++;
+						switch_snprintf(new_name, sizeof(new_name), "%s%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name, postfix);
+
+						if (switch_channel_get_variable(channel, new_name)) {
+							continue;
+						}
+
 						switch_channel_set_variable(channel, new_name, un->un_value);
-						free(new_name);
+						break;
 					}
 				}
 			}
 		}
-
+		
 		switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
 	}
-
+	
 	if (!(sofia_private = malloc(sizeof(*sofia_private)))) {
 		abort();
 	}
+
 	memset(sofia_private, 0, sizeof(*sofia_private));
+	sofia_private->is_call++;
 	tech_pvt->sofia_private = sofia_private;
 	
-	if ((profile->pflags & PFLAG_PRESENCE)) {
+	if ((profile->pres_type)) {
 		sofia_presence_set_chat_hash(tech_pvt, sip);
 	}
 	switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
@@ -3010,28 +5283,25 @@
 			contact_host = switch_str_nil(contact->url_host);
 		}
 
-
-		if (profile->pflags & PFLAG_PRESENCE) {
-
-			sql = switch_mprintf(
-								 "insert into sip_dialogs values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
+		if (profile->pres_type) {
+			sql = switch_mprintf("insert into sip_dialogs "
+								 "(call_id,uuid,sip_to_user,sip_to_host,sip_from_user,sip_from_host,contact_user,"
+								 "contact_host,state,direction,user_agent,profile_name,hostname) "
+								 "values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
 								 call_id,
 								 tech_pvt->sofia_private->uuid,
-								 to_user,
-								 to_host,
-								 dialog_from_user,
-								 dialog_from_host,
-								 contact_user,
-								 contact_host,
-								 "confirmed",
-								 "inbound",
-								 user_agent
-								 );
-			
+								 to_user, to_host, dialog_from_user, dialog_from_host, 
+								 contact_user, contact_host, "confirmed", "inbound", user_agent,
+								 profile->name, mod_sofia_globals.hostname);
 			switch_assert(sql);
 			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 		}
-		
+
+		if (is_nat) {
+			sofia_set_flag(tech_pvt, TFLAG_NAT);
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting NAT mode based on %s\n", is_nat);
+			switch_channel_set_variable(channel, "sip_nat_detected", "true");
+		}
 		return;
 	}
 
@@ -3042,30 +5312,33 @@
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "LUKE'S VOICE: Artoo, see what you can do with it. Hang on back there....\n"
 						  "Green laserfire moves past the beeping little robot as his head turns.  "
 						  "After a few beeps and a twist of his mechanical arm,\n"
-						  "Artoo reduces the max sessions to %d thus, saving the switch from certian doom.\n", 
-						  sess_count - 10);
-
+						  "Artoo reduces the max sessions to %d thus, saving the switch from certain doom.\n", sess_count - 10);
 		switch_mutex_unlock(profile->flag_mutex);
 	}
 
 	if (tech_pvt->hash_key) {
+		switch_mutex_lock(tech_pvt->profile->flag_mutex);
 		switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key);
+		switch_mutex_unlock(tech_pvt->profile->flag_mutex);
 	}
 
 	nua_handle_bind(nh, NULL);
-	free(tech_pvt->sofia_private);
+	sofia_private_free(sofia_private);
 	switch_core_session_destroy(&session);
 	nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
+	return;
+
+ fail:
+	profile->ib_failed_calls++;
+	return;
+
 }
 
 void sofia_handle_sip_i_options(int status,
-						  char const *phrase,
-						  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
+								char const *phrase,
+								nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
 {
-	nua_respond(nh, SIP_200_OK,
-				NUTAG_WITH_THIS(nua),
-				TAG_END());
-	nua_handle_destroy(nh);
+	nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
 }
 
 static void sofia_info_send_sipfrag(switch_core_session_t *aleg, switch_core_session_t *bleg)
@@ -3073,19 +5346,33 @@
 	private_object_t *b_tech_pvt = NULL, *a_tech_pvt = NULL;
 	char message[256] = "";
 
-	if (aleg && bleg) {
+	if (aleg && bleg && switch_core_session_compare(aleg, bleg)) {
+		switch_channel_t *channel = switch_core_session_get_channel(bleg);
+		const char *ua = switch_channel_get_variable(channel, "sip_user_agent");
+		
 		a_tech_pvt = (private_object_t *) switch_core_session_get_private(aleg);
 		b_tech_pvt = (private_object_t *) switch_core_session_get_private(bleg);
-		
+
 		if (b_tech_pvt && a_tech_pvt && a_tech_pvt->caller_profile) {
 			switch_caller_profile_t *acp = a_tech_pvt->caller_profile;
-
-			if (switch_strlen_zero(acp->caller_id_name)) {
-				snprintf(message, sizeof(message), "From:\r\nTo: %s\r\n", acp->caller_id_number);
-			} else {
-				snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", acp->caller_id_name, acp->caller_id_number);
+			
+			if (ua && switch_stristr("snom", ua)) {
+				if (switch_strlen_zero(acp->caller_id_name)) {
+					snprintf(message, sizeof(message), "From:\r\nTo: %s\r\n", acp->caller_id_number);
+				} else {
+					snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", acp->caller_id_name, acp->caller_id_number);
+				}
+				nua_info(b_tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR(message), TAG_END());
+			} else if (ua && switch_stristr("polycom", ua)) {
+				if (switch_strlen_zero(acp->caller_id_name)) {
+					snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", acp->caller_id_number, acp->caller_id_number);
+				} else {
+					snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", acp->caller_id_name, acp->caller_id_number);
+				}
+				nua_update(b_tech_pvt->nh,
+						   TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)),
+						   TAG_END());
 			}
-			nua_info(b_tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR(message), TAG_END());
 		}
 	}
 }
@@ -3119,49 +5406,49 @@
 	char var1[] = "sip_";
 	char *cp, *sh, *sh_end, *sh_save;
 
-	/* Build the static part of the sip_header_name variable from	*/
-	/* the header_type. If the header type is "referred_by" then	*/
-	/* sip_header_name = "sip_referred_by_".			*/
+	/* Build the static part of the sip_header_name variable from   */
+	/* the header_type. If the header type is "referred_by" then    */
+	/* sip_header_name = "sip_referred_by_".                        */
 	sh = sip_header_name;
 	sh_end = sh + sizeof(sip_header_name) - 1;
-	for (cp=var1; *cp; cp++, sh++) {
+	for (cp = var1; *cp; cp++, sh++) {
 		*sh = *cp;
 	}
 	*sh = '\0';
 
-	/* Copy the header_type to the sip_header_name. Before copying 	*/
+	/* Copy the header_type to the sip_header_name. Before copying  */
 	/* each character, check that we aren't going to overflow the   */
-	/* the sip_header_name buffer.  We have to account for the 	*/
-	/* trailing underscore and NULL that will be added to the end.	*/
-	for (cp=header_type; (*cp && (sh < (sh_end-1))); cp++, sh++) {
+	/* the sip_header_name buffer.  We have to account for the      */
+	/* trailing underscore and NULL that will be added to the end.  */
+	for (cp = header_type; (*cp && (sh < (sh_end - 1))); cp++, sh++) {
 		*sh = *cp;
 	}
 	*sh++ = '_';
 	*sh = '\0';
 
-	/* sh now points to the NULL at the end of the partially built	*/
+	/* sh now points to the NULL at the end of the partially built  */
 	/* sip_header_name variable.  This is also the start of the     */
 	/* variable part of the sip_header_name built from the lvalue   */
-	/* of the parms data.                                           */
+	/* of the params data.                                          */
 	sh_save = sh;
 
 	while (params && params[0]) {
 
-		/* Copy the params data to the sip_header_name variable until	*/
-		/* the end of the params string is reached, an '=' is detected	*/
-		/* or until the sip_header_name buffer has been exhausted.	*/
-		for (cp=(char *)(*params); ((*cp != '=') && *cp && (sh < sh_end)); cp++, sh++) {
+		/* Copy the params data to the sip_header_name variable until   */
+		/* the end of the params string is reached, an '=' is detected  */
+		/* or until the sip_header_name buffer has been exhausted.      */
+		for (cp = (char *) (*params); ((*cp != '=') && *cp && (sh < sh_end)); cp++, sh++) {
 			*sh = *cp;
 		}
 
-		/* cp now points to either the end of the parms data or the	*/
-		/* equal (=) sign spearating the lvalue and rvalue.		*/
+		/* cp now points to either the end of the params data or the */
+		/* equal (=) sign separating the lvalue and rvalue.          */
 		if (*cp == '=')
-			cp++;	
+			cp++;
 		*sh = '\0';
 		switch_channel_set_variable(channel, sip_header_name, cp);
 
-		/* Bump pointer to next param in the list.  Also reset the	*/
+		/* Bump pointer to next param in the list.  Also reset the      */
 		/* sip_header_name pointer to the beginning of the dynamic area */
 		params++;
 		sh = sh_save;
@@ -3176,5 +5463,5 @@
  * c-basic-offset:4
  * End:
  * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
  */
Property changes on: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c
___________________________________________________________________
Name: svn:eol-style
   + native

Copied: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_glue.c (from rev 14389, freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c) (0 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_glue.c	                        (rev 0)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_glue.c	2009-07-27 20:18:20 UTC (rev 14390)
@@ -0,0 +1,4225 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
+ * Paul D. Tinsley <pdt at jackhammer.org>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ * Eliot Gable <egable AT.AT broadvox.com>
+ *
+ *
+ * sofia_glue.c -- SOFIA SIP Endpoint (code to tie sofia to freeswitch)
+ *
+ */
+#include "mod_sofia.h"
+#include <switch_stun.h>
+
+
+void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options)
+{
+	char buf[2048];
+	const char *ip = t38_options->ip;
+	uint32_t port = t38_options->port;
+	const char *family = "IP4";
+	const char *username = tech_pvt->profile->username;
+
+	if (!ip) {
+		if (!(ip = tech_pvt->adv_sdp_audio_ip)) {
+			ip = tech_pvt->proxy_sdp_audio_ip;
+		}
+	}
+
+	if (!port) {
+		if (!(port = tech_pvt->adv_sdp_audio_port)) {
+			port = tech_pvt->proxy_sdp_audio_port;
+		}
+	}
+
+	if (!tech_pvt->owner_id) {
+		tech_pvt->owner_id = (uint32_t) switch_epoch_time_now(NULL) - port;
+	}
+
+	if (!tech_pvt->session_id) {
+		tech_pvt->session_id = tech_pvt->owner_id;
+	}
+
+	tech_pvt->session_id++;
+
+	family = strchr(ip, ':') ? "IP6" : "IP4";
+	switch_snprintf(buf, sizeof(buf),
+					"v=0\n"
+					"o=%s %010u %010u IN %s %s\n"
+					"s=%s\n"
+					"c=IN %s %s\n" 
+					"t=0 0\n"
+					"m=image %d udptl t38\n"
+					"a=T38MaxBitRate:%d\n"
+					"%s"
+					"%s"
+					"%s"
+					"a=T38FaxRateManagement:%s\n"
+					"a=T38FaxMaxBuffer:%d\n"
+					"a=T38FaxMaxDatagram:%d\n"
+					"a=T38FaxUdpEC:%s\n"
+					"a=T38VendorInfo:%s\n",
+					
+					username,
+					tech_pvt->owner_id, 
+					tech_pvt->session_id,
+					family,
+					ip,
+					username,
+					family,
+					ip,
+					port,
+					
+					t38_options->T38MaxBitRate,
+					t38_options->T38FaxFillBitRemoval ? "a=T38FaxFillBitRemoval\n" : "",
+					t38_options->T38FaxTranscodingMMR ? "a=T38FaxTranscodingMMR\n" : "",
+					t38_options->T38FaxTranscodingJBIG ? "a=T38FaxTranscodingJBIG\n" : "",
+					t38_options->T38FaxRateManagement,
+					t38_options->T38FaxMaxBuffer,
+					t38_options->T38FaxMaxDatagram,
+					t38_options->T38FaxUdpEC,
+					t38_options->T38VendorInfo
+					);
+	
+	sofia_glue_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE);
+}
+
+void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32_t port, const char *sr, int force)
+{
+	char buf[2048];
+	int ptime = 0;
+	uint32_t rate = 0;
+	uint32_t v_port;
+	int use_cng = 1;
+	const char *val;
+	const char *family;
+	const char *pass_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_video_fmtp");
+	const char *ov_fmtp = switch_channel_get_variable(tech_pvt->channel, "sip_force_video_fmtp");
+	char srbuf[128] = "";
+	const char *var_val;
+	const char *username = tech_pvt->profile->username;
+
+	if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) ||
+		((val = switch_channel_get_variable(tech_pvt->channel, "supress_cng")) && switch_true(val)) ||
+		((val = switch_channel_get_variable(tech_pvt->channel, "suppress_cng")) && switch_true(val))) {
+		use_cng = 0;
+		tech_pvt->cng_pt = 0;
+	}
+
+	if (!force && !ip && !sr
+		&& (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA))) {
+		return;
+	}
+
+	if (!ip) {
+		if (!(ip = tech_pvt->adv_sdp_audio_ip)) {
+			ip = tech_pvt->proxy_sdp_audio_ip;
+		}
+	}
+	if (!port) {
+		if (!(port = tech_pvt->adv_sdp_audio_port)) {
+			port = tech_pvt->proxy_sdp_audio_port;
+		}
+	}
+
+	if (!sr) {
+		sr = "sendrecv";
+	}
+
+	if (!tech_pvt->owner_id) {
+		tech_pvt->owner_id = (uint32_t) switch_epoch_time_now(NULL) - port;
+	}
+
+	if (!tech_pvt->session_id) {
+		tech_pvt->session_id = tech_pvt->owner_id;
+	}
+
+	tech_pvt->session_id++;
+
+	if ((tech_pvt->profile->ndlb & PFLAG_NDLB_SENDRECV_IN_SESSION) || 
+		((var_val=switch_channel_get_variable(tech_pvt->channel, "ndlb_sendrecv_in_session")) && switch_true(var_val))) {
+		switch_snprintf(srbuf, sizeof(srbuf), "a=%s\n", sr);
+		sr = NULL;
+	}
+	
+	family = strchr(ip, ':') ? "IP6" : "IP4";
+	switch_snprintf(buf, sizeof(buf),
+					"v=0\n"
+					"o=%s %010u %010u IN %s %s\n"
+					"s=%s\n"
+					"c=IN %s %s\n" "t=0 0\n"
+					"%sm=audio %d RTP/%sAVP",
+					username,
+					tech_pvt->owner_id, tech_pvt->session_id, family, ip, username, family, ip, 
+					srbuf,
+					port,
+					(!switch_strlen_zero(tech_pvt->local_crypto_key) 
+					&& sofia_test_flag(tech_pvt,TFLAG_SECURE)) ? "S" : "");
+
+	if (tech_pvt->rm_encoding) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
+	} else if (tech_pvt->num_codecs) {
+		int i;
+		int already_did[128] = { 0 };
+		for (i = 0; i < tech_pvt->num_codecs; i++) {
+			const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+			if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+				continue;
+			}
+
+			if (imp->ianacode < 128) {
+				if (already_did[imp->ianacode]) {
+					continue;
+				}
+
+				already_did[imp->ianacode] = 1;
+			}
+
+			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
+			if (!ptime) {
+				ptime = imp->microseconds_per_packet / 1000;
+			}
+		}
+	}
+
+	if (tech_pvt->dtmf_type == DTMF_2833 && tech_pvt->te > 95) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->te);
+	}
+
+	if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->cng_pt);
+	}
+
+	switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
+
+
+	if (tech_pvt->rm_encoding) {
+		rate = tech_pvt->rm_rate;
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->agreed_pt, tech_pvt->rm_encoding, rate);
+		if (tech_pvt->fmtp_out) {
+			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->agreed_pt, tech_pvt->fmtp_out);
+		}
+		if (tech_pvt->read_codec.implementation && !ptime) {
+			ptime = tech_pvt->read_codec.implementation->microseconds_per_packet / 1000;
+		}
+
+	} else if (tech_pvt->num_codecs) {
+		int i;
+		int already_did[128] = { 0 };
+		for (i = 0; i < tech_pvt->num_codecs; i++) {
+			const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+			if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+				continue;
+			}
+
+			if (imp->ianacode < 128) {
+				if (already_did[imp->ianacode]) {
+					continue;
+				}
+
+				already_did[imp->ianacode] = 1;
+			}
+
+			rate = imp->samples_per_second;
+
+			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, rate);
+			if (imp->fmtp) {
+				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
+			}
+		}
+	}
+
+	if (tech_pvt->dtmf_type == DTMF_2833 && tech_pvt->te > 95) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te);
+	}
+	if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d CN/8000\n", tech_pvt->cng_pt);
+		if (!tech_pvt->rm_encoding) {
+			tech_pvt->cng_pt = 0;
+		}
+	} else {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=silenceSupp:off - - - -\n");
+	}
+
+	if (ptime) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
+	}
+
+	if (sr) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=%s\n", sr);
+	} 
+
+	if (!switch_strlen_zero(tech_pvt->local_crypto_key) && sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=crypto:%s\n", tech_pvt->local_crypto_key);
+		//switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n");
+#if 0
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "m=audio %d RTP/AVP", port);
+
+		if (tech_pvt->rm_encoding) {
+			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
+		} else if (tech_pvt->num_codecs) {
+			int i;
+			int already_did[128] = { 0 };
+			for (i = 0; i < tech_pvt->num_codecs; i++) {
+				const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+				if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+					continue;
+				}
+
+				if (imp->ianacode < 128) {
+					if (already_did[imp->ianacode]) {
+						continue;
+					}
+
+					already_did[imp->ianacode] = 1;
+				}
+
+				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
+			}
+		}
+
+		switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\na=crypto:%s\n", tech_pvt->local_crypto_key);
+#endif
+	}
+
+	if (sofia_test_flag(tech_pvt, TFLAG_VIDEO)) {
+		if (!switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) && !switch_channel_test_flag(tech_pvt->channel, CF_EARLY_MEDIA) &&
+			!tech_pvt->local_sdp_video_port) {
+			sofia_glue_tech_choose_video_port(tech_pvt, 0);
+		}
+
+		if ((v_port = tech_pvt->adv_sdp_video_port)) {
+			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "m=video %d RTP/AVP", v_port);
+			
+			/*****************************/
+			if (tech_pvt->video_rm_encoding) {
+				sofia_glue_tech_set_video_codec(tech_pvt, 0);
+				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->video_agreed_pt);
+			} else if (tech_pvt->num_codecs) {
+				int i;
+				int already_did[128] = { 0 };
+				for (i = 0; i < tech_pvt->num_codecs; i++) {
+					const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+					if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+						continue;
+					}
+
+					if (imp->ianacode < 128) {
+						if (already_did[imp->ianacode]) {
+							continue;
+						}
+						already_did[imp->ianacode] = 1;
+					}
+
+					switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
+					if (!ptime) {
+						ptime = imp->microseconds_per_packet / 1000;
+					}
+				}
+			}
+
+			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
+
+			if (tech_pvt->video_rm_encoding) {
+				const char *of;
+				rate = tech_pvt->video_rm_rate;
+				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->video_pt, tech_pvt->video_rm_encoding,
+								tech_pvt->video_rm_rate);
+
+				pass_fmtp = NULL;
+
+				if (switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE)) {
+					if ((of = switch_channel_get_variable_partner(tech_pvt->channel, "sip_video_fmtp"))) {
+						pass_fmtp = of;
+					}
+				}
+
+				if (ov_fmtp) {
+					pass_fmtp = ov_fmtp;
+				}
+
+				if (pass_fmtp) {
+					switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->video_pt, pass_fmtp);
+				}
+
+			} else if (tech_pvt->num_codecs) {
+				int i;
+				int already_did[128] = { 0 };
+
+				for (i = 0; i < tech_pvt->num_codecs; i++) {
+					const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+					if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+						continue;
+					}
+
+					if (imp->ianacode < 128) {
+						if (already_did[imp->ianacode]) {
+							continue;
+						}
+						already_did[imp->ianacode] = 1;
+					}
+
+					if (!rate) {
+						rate = imp->samples_per_second;
+					}
+
+					switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame,
+									imp->samples_per_second);
+					if (imp->fmtp) {
+						switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
+					} else {
+						if (pass_fmtp) {
+							switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, pass_fmtp);
+						}
+					}
+				}
+			}
+		}
+	}
+	sofia_glue_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE);
+}
+
+void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt)
+{
+	const char *abs, *codec_string = NULL;
+	const char *ocodec = NULL;
+
+	if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+		return;
+	}
+
+	if (tech_pvt->num_codecs) {
+		return;
+	}
+
+	switch_assert(tech_pvt->session != NULL);
+
+	if ((abs = switch_channel_get_variable(tech_pvt->channel, "absolute_codec_string"))) {
+		codec_string = abs;
+	} else {
+		if (!(codec_string = switch_channel_get_variable(tech_pvt->channel, "codec_string"))) {
+			if (tech_pvt->profile->codec_string) {
+				codec_string = tech_pvt->profile->codec_string;
+			}
+		}
+
+		if ((ocodec = switch_channel_get_variable(tech_pvt->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
+			if (!codec_string || sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_TRANSCODING)) {
+				codec_string = ocodec;
+			} else {
+				if (!(codec_string = switch_core_session_sprintf(tech_pvt->session, "%s,%s", ocodec, codec_string))) {
+					codec_string = ocodec;
+				}
+			}
+		}
+	}
+
+	if (codec_string) {
+		char *tmp_codec_string;
+		if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) {
+			tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS);
+			tech_pvt->num_codecs =
+				switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last);
+		}
+	} else {
+		tech_pvt->num_codecs = switch_loadable_module_get_codecs(tech_pvt->codecs, sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0]));
+	}
+
+
+}
+
+void sofia_glue_check_video_codecs(private_object_t *tech_pvt)
+{
+	if (tech_pvt->num_codecs && !sofia_test_flag(tech_pvt, TFLAG_VIDEO)) {
+		int i;
+		tech_pvt->video_count = 0;
+		for (i = 0; i < tech_pvt->num_codecs; i++) {
+			if (tech_pvt->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) {
+				tech_pvt->video_count++;
+			}
+		}
+		if (tech_pvt->video_count) {
+			sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO);
+		}
+	}
+}
+
+
+void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t *profile, private_object_t *tech_pvt, const char *channame)
+{
+	char name[256];
+	unsigned int x;
+	char *p;
+
+	switch_assert(session != NULL);
+	switch_assert(profile != NULL);
+	switch_assert(tech_pvt != NULL);
+
+	switch_core_session_add_stream(session, NULL);
+
+	switch_mutex_lock(tech_pvt->flag_mutex);
+	switch_mutex_lock(profile->flag_mutex);
+
+	/* copy flags from profile to the sofia private */
+	for(x = 0; x < TFLAG_MAX; x++ ) {
+		tech_pvt->flags[x] = profile->flags[x];
+	}
+
+	tech_pvt->profile = profile;
+	profile->inuse++;
+	switch_mutex_unlock(profile->flag_mutex);
+	switch_mutex_unlock(tech_pvt->flag_mutex);
+
+	if (tech_pvt->bte) {
+		tech_pvt->te = tech_pvt->bte;
+	} else if (!tech_pvt->te) {
+		tech_pvt->te = profile->te;
+	}
+
+	tech_pvt->dtmf_type = profile->dtmf_type;
+
+	if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
+		if (tech_pvt->bcng_pt) {
+			tech_pvt->cng_pt = tech_pvt->bcng_pt;
+		} else if (!tech_pvt->cng_pt) {
+			tech_pvt->cng_pt = profile->cng_pt;
+		}
+	}
+
+	tech_pvt->session = session;
+	tech_pvt->channel = switch_core_session_get_channel(session);
+	switch_core_session_set_private(session, tech_pvt);
+
+	switch_snprintf(name, sizeof(name), "sofia/%s/%s", profile->name, channame);
+	if ((p = strchr(name, ';'))) {
+		*p = '\0';
+	}
+	switch_channel_set_name(tech_pvt->channel, name);
+}
+
+switch_status_t sofia_glue_ext_address_lookup(sofia_profile_t *profile, private_object_t *tech_pvt, char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool)
+{
+	char *error = "";
+	switch_status_t status = SWITCH_STATUS_FALSE;
+	int x;
+	switch_port_t myport = *port;
+	const char *var;
+	int funny = 0;
+	switch_port_t stun_port = SWITCH_STUN_DEFAULT_PORT;
+	char *stun_ip = NULL;
+
+	if (!sourceip) {
+		return status;
+	}
+
+	if (!strncasecmp(sourceip, "host:", 5)) {
+		status = (*ip = switch_stun_host_lookup(sourceip + 5, pool)) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+	} else if (!strncasecmp(sourceip, "stun:", 5)) {
+		char *p;
+
+		if (!sofia_test_pflag(profile, PFLAG_STUN_ENABLED)) {
+			*ip = switch_core_strdup(pool, profile->rtpip);
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Trying to use STUN but its disabled!\n");
+			return SWITCH_STATUS_SUCCESS;
+		}
+		
+		stun_ip = strdup(sourceip + 5);
+
+		if ((p = strchr(stun_ip, ':'))) {
+			int iport;
+			*p++ = '\0';
+			iport = atoi(p);
+			if (iport > 0 && iport < 0xFFFF) {
+				stun_port = (switch_port_t) iport;
+			}
+		}
+
+		if (switch_strlen_zero(stun_ip)) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! NO STUN SERVER\n");
+			goto out;
+		}
+
+		for (x = 0; x < 5; x++) {
+			if (sofia_test_pflag(profile, PFLAG_FUNNY_STUN) || 
+				(tech_pvt && (var = switch_channel_get_variable(tech_pvt->channel, "funny_stun")) && switch_true(var))) {
+				error = "funny";
+				funny++;
+			}
+			if ((status = switch_stun_lookup(ip, port, stun_ip, stun_port, &error, pool)) != SWITCH_STATUS_SUCCESS) {
+				switch_yield(100000);
+			} else {
+				break;
+			}
+		}
+		if (status != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! %s:%d [%s]\n", stun_ip, stun_port, error);
+			goto out;
+		}
+		if (!*ip) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! No IP returned\n");
+			goto out;
+		}
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "STUN Success [%s]:[%d]\n", *ip, *port);
+		status = SWITCH_STATUS_SUCCESS;
+		if (tech_pvt) {
+			if (myport == *port && !strcmp(*ip, tech_pvt->profile->rtpip)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "STUN Not Required ip and port match. [%s]:[%d]\n", *ip, *port);
+				if (sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE)) {
+					sofia_clear_pflag(profile, PFLAG_STUN_ENABLED);
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "STUN completely disabled.\n");
+				}
+			} else {
+				tech_pvt->stun_ip = switch_core_session_strdup(tech_pvt->session, stun_ip);
+				tech_pvt->stun_port = stun_port;
+				tech_pvt->stun_flags |= STUN_FLAG_SET;
+				if (funny) {
+					tech_pvt->stun_flags |= STUN_FLAG_FUNNY;
+				}
+			}
+		}
+	} else {
+		*ip = sourceip;
+		status = SWITCH_STATUS_SUCCESS;
+	}
+
+ out:
+
+	switch_safe_free(stun_ip);
+
+	return status;
+}
+
+
+const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name)
+{
+	sip_unknown_t *un;
+	for (un = sip->sip_unknown; un; un = un->un_next) {
+		if (!strcasecmp(un->un_name, name)) {
+			if (!switch_strlen_zero(un->un_value)) {
+				return un->un_value;
+			}
+		}
+	}
+	return NULL;
+}
+
+switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int force)
+{
+	char *ip = tech_pvt->profile->rtpip;
+	switch_port_t sdp_port;
+	char tmp[50];
+	const char *use_ip = NULL;
+	switch_port_t external_port = 0;
+
+	if (!force) {
+		if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) ||
+			switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) || tech_pvt->adv_sdp_audio_port) {
+			return SWITCH_STATUS_SUCCESS;
+		}
+	}
+
+	if (tech_pvt->local_sdp_audio_port) {
+		switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_audio_port);
+	}
+
+
+	tech_pvt->local_sdp_audio_ip = ip;
+
+	if (!(tech_pvt->local_sdp_audio_port = switch_rtp_request_port(tech_pvt->profile->rtpip))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No RTP ports available!\n");
+		return SWITCH_STATUS_FALSE;
+	}
+	sdp_port = tech_pvt->local_sdp_audio_port;
+
+	if (!(use_ip = switch_channel_get_variable(tech_pvt->channel, "rtp_adv_audio_ip")) && !sofia_test_pflag(tech_pvt->profile, PFLAG_AUTO_NAT)) {
+		if (tech_pvt->profile->extrtpip) {
+			use_ip = tech_pvt->profile->extrtpip;
+		}
+	}
+
+	if (use_ip) {
+		tech_pvt->extrtpip = switch_core_session_strdup(tech_pvt->session, use_ip);
+		if (sofia_glue_ext_address_lookup(tech_pvt->profile, tech_pvt, &ip, &sdp_port, 
+										  tech_pvt->extrtpip, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			return SWITCH_STATUS_FALSE;
+		}
+	}
+
+	if (!use_ip && tech_pvt->profile->extrtpip && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
+		tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip ? ip : tech_pvt->profile->extrtpip);
+		switch_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP, &external_port, SWITCH_FALSE);
+	} else {
+		tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip);
+	}
+	
+	tech_pvt->adv_sdp_audio_port = external_port != 0 ? external_port : sdp_port;
+
+	switch_snprintf(tmp, sizeof(tmp), "%d", sdp_port);
+	switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+	switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, int force)
+{
+	char *ip = tech_pvt->profile->rtpip;
+	switch_port_t sdp_port;
+	char tmp[50];
+	switch_port_t external_port = 0;
+
+	if (!force) {
+		if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)
+			|| tech_pvt->local_sdp_video_port) {
+			return SWITCH_STATUS_SUCCESS;
+		}
+	}
+
+	if (tech_pvt->local_sdp_video_port) {
+		switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_video_port);
+	}
+
+	if (!(tech_pvt->local_sdp_video_port = switch_rtp_request_port(tech_pvt->profile->rtpip))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No RTP ports available!\n");
+		return SWITCH_STATUS_FALSE;
+	}
+	sdp_port = tech_pvt->local_sdp_video_port;
+
+
+	if (tech_pvt->profile->extrtpip) {
+		if (sofia_glue_ext_address_lookup(tech_pvt->profile, tech_pvt, &ip, &sdp_port, tech_pvt->profile->extrtpip,
+										  switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			return SWITCH_STATUS_FALSE;
+		}
+	}
+
+	if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
+		switch_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP, &external_port, SWITCH_FALSE);
+	}
+	
+	tech_pvt->adv_sdp_video_port = external_port != 0 ? external_port : sdp_port;
+
+	switch_snprintf(tmp, sizeof(tmp), "%d", sdp_port);
+	switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+	switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+sofia_transport_t sofia_glue_str2transport(const char *str)
+{
+	if (!strncasecmp(str, "udp", 3)) {
+		return SOFIA_TRANSPORT_UDP;
+	} else if (!strncasecmp(str, "tcp", 3)) {
+		return SOFIA_TRANSPORT_TCP;
+	} else if (!strncasecmp(str, "sctp", 4)) {
+		return SOFIA_TRANSPORT_SCTP;
+	} else if (!strncasecmp(str, "tls", 3)) {
+		return SOFIA_TRANSPORT_TCP_TLS;
+	}
+
+	return SOFIA_TRANSPORT_UNKNOWN;
+}
+
+char *sofia_glue_find_parameter(const char *str, const char *param)
+{
+	char *ptr = NULL;
+
+	ptr = (char *) str;
+	while (ptr) {
+		if (!strncasecmp(ptr, param, strlen(param)))
+			return ptr;
+
+		if ((ptr = strchr(ptr, ';')))
+			ptr++;
+	}
+
+	return NULL;
+}
+
+sofia_transport_t sofia_glue_url2transport(const url_t *url)
+{
+	char *ptr = NULL;
+	int tls = 0;
+
+	if (!url)
+		return SOFIA_TRANSPORT_UNKNOWN;
+
+	if (url->url_scheme && !strcasecmp(url->url_scheme, "sips")) {
+		tls++;
+	}
+
+	if ((ptr = sofia_glue_find_parameter(url->url_params, "transport="))) {
+		return sofia_glue_str2transport(ptr + 10);
+	}
+
+	return (tls) ? SOFIA_TRANSPORT_TCP_TLS : SOFIA_TRANSPORT_UDP;
+}
+
+sofia_transport_t sofia_glue_via2transport(const sip_via_t *via)
+{
+	char *ptr = NULL;
+
+	if (!via || !via->v_protocol)
+		return SOFIA_TRANSPORT_UNKNOWN;
+
+	if ((ptr = strrchr(via->v_protocol, '/'))) {
+		ptr++;
+
+		if (!strncasecmp(ptr, "udp", 3)) {
+			return SOFIA_TRANSPORT_UDP;
+		} else if (!strncasecmp(ptr, "tcp", 3)) {
+			return SOFIA_TRANSPORT_TCP;
+		} else if (!strncasecmp(ptr, "tls", 3)) {
+			return SOFIA_TRANSPORT_TCP_TLS;
+		} else if (!strncasecmp(ptr, "sctp", 4)) {
+			return SOFIA_TRANSPORT_SCTP;
+		}
+	}
+
+	return SOFIA_TRANSPORT_UNKNOWN;
+}
+
+const char *sofia_glue_transport2str(const sofia_transport_t tp)
+{
+	switch (tp) {
+	case SOFIA_TRANSPORT_TCP:
+		return "tcp";
+
+	case SOFIA_TRANSPORT_TCP_TLS:
+		return "tls";
+
+	case SOFIA_TRANSPORT_SCTP:
+		return "sctp";
+
+	default:
+		return "udp";
+	}
+}
+
+char *sofia_glue_create_external_via(switch_core_session_t *session, sofia_profile_t *profile, sofia_transport_t transport) 
+{
+	return sofia_glue_create_via(session,
+								 profile->extsipip,
+								 (sofia_glue_transport_has_tls(transport))
+								 ? profile->tls_sip_port : profile->sip_port,
+								 transport);
+}
+
+char *sofia_glue_create_via(switch_core_session_t *session, const char *ip, switch_port_t port, sofia_transport_t transport) 
+{
+	if (port && port != 5060) {
+		if (session) {
+			return switch_core_session_sprintf(session, "SIP/2.0/%s %s:%d;rport", sofia_glue_transport2str(transport), ip, port);		
+		} else {
+			return switch_mprintf("SIP/2.0/%s %s:%d;rport", sofia_glue_transport2str(transport), ip, port);		
+		}
+	} else {
+		if (session) {
+			return switch_core_session_sprintf(session, "SIP/2.0/%s %s;rport", sofia_glue_transport2str(transport), ip);
+		} else {
+			return switch_mprintf("SIP/2.0/%s %s;rport", sofia_glue_transport2str(transport), ip);
+		}
+	}
+}
+
+char *sofia_glue_strip_uri(const char *str)
+{
+	char *p;
+	char *r;
+
+	if ((p = strchr(str, '<'))) {
+		p++;
+		r = strdup(p);
+		if ((p = strchr(r, '>'))) {
+			*p = '\0';
+		}
+	} else {
+		r = strdup(str);
+	}
+
+	return r;
+}
+
+int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip)
+{
+	return (network_ip && 
+			profile->local_network && 
+			sofia_test_pflag(profile, PFLAG_AUTO_NAT) && 
+			!switch_check_network_list_ip(network_ip, profile->local_network));
+}
+
+int sofia_glue_transport_has_tls(const sofia_transport_t tp)
+{
+	switch (tp) {
+	case SOFIA_TRANSPORT_TCP_TLS:
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+void sofia_glue_get_addr(msg_t *msg, char *buf, size_t buflen, int *port) {
+	su_addrinfo_t *addrinfo = msg_addrinfo(msg);
+
+	if (buf) {
+		get_addr(buf, buflen, addrinfo->ai_addr, addrinfo->ai_addrlen);
+	}
+
+	if (port) {
+		*port = get_port(addrinfo->ai_addr); 
+	}
+}
+
+char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char *uri, const sofia_transport_t transport, switch_bool_t uri_only,
+									  const char *params)
+{
+	char *stripped = switch_core_session_strdup(session, uri);
+	char *new_uri = NULL;
+	char *p;
+
+	stripped = sofia_glue_get_url_from_contact(stripped, 0);
+
+	/* remove our params so we don't make any whiny moronic device piss it's pants and forget who it is for a half-hour */
+	if ((p = (char *)switch_stristr(";fs_", stripped))) {
+		*p = '\0'; 
+	}
+
+	if (transport && transport != SOFIA_TRANSPORT_UDP) {
+
+		if (switch_stristr("port=", stripped)) {
+			new_uri = switch_core_session_sprintf(session, "%s%s%s", uri_only ? "" : "<", stripped, uri_only ? "" : ">");
+		} else {
+
+			if (strchr(stripped, ';')) {
+				if (params) {
+					new_uri = switch_core_session_sprintf(session, "%s%s;transport=%s;%s%s",
+														  uri_only ? "" : "<", stripped, sofia_glue_transport2str(transport), params, uri_only ? "" : ">");
+				} else {
+					new_uri = switch_core_session_sprintf(session, "%s%s;transport=%s%s",
+														  uri_only ? "" : "<", stripped, sofia_glue_transport2str(transport), uri_only ? "" : ">");
+				}
+			} else {
+				if (params) {
+					new_uri = switch_core_session_sprintf(session, "%s%s;transport=%s;%s%s",
+														  uri_only ? "" : "<", stripped, sofia_glue_transport2str(transport), params, uri_only ? "" : ">");
+				} else {
+					new_uri = switch_core_session_sprintf(session, "%s%s;transport=%s%s",
+														  uri_only ? "" : "<", stripped, sofia_glue_transport2str(transport), uri_only ? "" : ">");
+				}
+			}
+		}
+	} else {
+		if (params) {
+			new_uri = switch_core_session_sprintf(session, "%s%s;%s%s", uri_only ? "" : "<", stripped, params, uri_only ? "" : ">");
+		} else {
+			if (uri_only) {
+				new_uri = stripped;
+			} else {
+				new_uri = switch_core_session_sprintf(session, "<%s>", stripped);
+			}
+		}
+	}
+
+	return new_uri;
+}
+
+#define RA_PTR_LEN 512
+switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt)
+{
+	const char *err;
+	char rip[RA_PTR_LEN] = "";
+	char rp[RA_PTR_LEN] = "";
+	char rvp[RA_PTR_LEN] = "";
+	char *p, *ip_ptr = NULL, *port_ptr = NULL, *vid_port_ptr = NULL, *pe;
+	int x;
+	const char *val;
+	
+	if (switch_strlen_zero(tech_pvt->remote_sdp_str)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if ((p = (char *) switch_stristr("c=IN IP4 ", tech_pvt->remote_sdp_str)) ||
+		(p = (char *) switch_stristr("c=IN IP6 ", tech_pvt->remote_sdp_str))) {
+		ip_ptr = p + 9;
+	}
+
+	if ((p = (char *) switch_stristr("m=audio ", tech_pvt->remote_sdp_str))) {
+		port_ptr = p + 8;
+	}
+
+	if ((p = (char *) switch_stristr("m=image ", tech_pvt->remote_sdp_str))) {
+		port_ptr = p + 8;
+	}
+
+	if ((p = (char *) switch_stristr("m=video ", tech_pvt->remote_sdp_str))) {
+		vid_port_ptr = p + 8;
+	}
+
+	if (!(ip_ptr && port_ptr)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	p = ip_ptr;
+	pe = p + strlen(p);
+	x = 0;
+	while (x < sizeof(rip) - 1 && p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) {
+		rip[x++] = *p;
+		p++;
+		if (p >= pe) {
+			return SWITCH_STATUS_FALSE;
+		}
+	}
+
+	p = port_ptr;
+	x = 0;
+	while (x < sizeof(rp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
+		rp[x++] = *p;
+		p++;
+		if (p >= pe) {
+			return SWITCH_STATUS_FALSE;
+		}
+	}
+
+	p = vid_port_ptr;
+	x = 0;
+	while (x < sizeof(rvp) - 1 && p && *p && (*p >= '0' && *p <= '9')) {
+		rvp[x++] = *p;
+		p++;
+		if (p >= pe) {
+			return SWITCH_STATUS_FALSE;
+		}
+	}
+
+	if (!(*rip && *rp)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid SDP\n");
+		return SWITCH_STATUS_FALSE;
+	}
+
+	tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, rip);
+	tech_pvt->remote_sdp_audio_port = (switch_port_t) atoi(rp);
+	
+	if (*rvp) {
+		tech_pvt->remote_sdp_video_ip = switch_core_session_strdup(tech_pvt->session, rip);
+		tech_pvt->remote_sdp_video_port = (switch_port_t) atoi(rvp);
+	}
+
+	if (tech_pvt->remote_sdp_video_ip && tech_pvt->remote_sdp_video_port) {
+		if (!strcmp(tech_pvt->remote_sdp_video_ip, rip) && atoi(rvp) == tech_pvt->remote_sdp_video_port) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote video address:port [%s:%d] has not changed.\n",
+							  tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+		} else {
+			sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO);
+			switch_channel_set_flag(tech_pvt->channel, CF_VIDEO);
+			if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+				if (switch_rtp_set_remote_address(tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, 
+												  tech_pvt->remote_sdp_video_port, SWITCH_TRUE, &err) !=
+					SWITCH_STATUS_SUCCESS) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err);
+				} else {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n",
+									  tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port);
+					if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) &&
+						!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+						/* Reactivate the NAT buster flag. */
+						switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+					}
+				}
+			}
+		}
+	}
+
+	if (switch_rtp_ready(tech_pvt->rtp_session)) {
+		char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
+		switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+		
+		if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote address:port [%s:%d] has not changed.\n",
+							  tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+			return SWITCH_STATUS_SUCCESS;
+		}
+		
+		if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, 
+										  tech_pvt->remote_sdp_audio_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
+							  tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+			if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+				!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+				/* Reactivate the NAT buster flag. */
+				switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);	
+			}
+		}
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt)
+{
+	switch_size_t len;
+	char *p, *q, *pe , *qe;
+	int has_video=0,has_audio=0,has_ip=0;
+	char port_buf[25] = "";
+	char vport_buf[25] = "";
+	char *new_sdp;
+	int bad = 0;
+
+	if (switch_strlen_zero(tech_pvt->local_sdp_str)) {
+		return;
+	}
+
+	len = strlen(tech_pvt->local_sdp_str) * 2;
+	
+	if (switch_stristr("sendonly", tech_pvt->local_sdp_str) || switch_stristr("0.0.0.0", tech_pvt->local_sdp_str)) {
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Skip patch on hold SDP\n");
+	    return;
+	}
+	
+	if (switch_strlen_zero(tech_pvt->adv_sdp_audio_ip) || !tech_pvt->adv_sdp_audio_port) {
+	    if (sofia_glue_tech_choose_port(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s I/O Error\n", switch_channel_get_name(tech_pvt->channel));
+			return;
+		}
+		tech_pvt->iananame = switch_core_session_strdup(tech_pvt->session, "PROXY");
+		tech_pvt->rm_rate = 8000;
+		tech_pvt->codec_ms = 20;
+	}
+	
+	new_sdp = switch_core_session_alloc(tech_pvt->session, len);
+	switch_snprintf(port_buf, sizeof(port_buf), "%u", tech_pvt->adv_sdp_audio_port);
+	
+
+	p = tech_pvt->local_sdp_str;
+	q = new_sdp;
+	pe = p + strlen(p);
+	qe = q + len - 1;
+
+	while(p && *p) {
+		if (p >= pe) {
+			bad = 1;
+			goto end;
+		}
+		
+		if (q >= qe) {
+			bad = 2;
+			goto end;
+		}
+
+	    if (tech_pvt->adv_sdp_audio_ip && !strncmp("c=IN IP", p, 7)) {
+			strncpy(q, p, 9);
+			p += 9;
+			q += 9;
+			strncpy(q, tech_pvt->adv_sdp_audio_ip, strlen(tech_pvt->adv_sdp_audio_ip));
+			q += strlen(tech_pvt->adv_sdp_audio_ip);
+
+			while(p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f'))) {
+				if (p >= pe) {
+					bad = 3;
+					goto end;
+				}
+				p++;
+			}
+
+	    	has_ip++;
+
+		} else if (!strncmp("m=audio ", p, 8) || (!strncmp("m=image ", p, 8))) {
+			strncpy(q, p, 8);
+			p += 8;
+
+			if (p >= pe) {
+				bad = 4;
+				goto end;
+			}
+
+
+			q += 8;
+			
+			if (q >= qe) {
+				bad = 5;
+				goto end;
+			}
+
+
+			strncpy(q, port_buf, strlen(port_buf));
+			q += strlen(port_buf);
+
+			if (q >= qe) {
+				bad = 6;
+				goto end;
+			}
+
+			while (p && *p && (*p >= '0' && *p <= '9')) {
+				if (p >= pe) {
+					bad = 7;
+					goto end;
+				}
+				p++;
+			}
+
+			has_audio++;		
+
+	    } else if (!strncmp("m=video ", p, 8)) {
+			if (!has_video) {
+				sofia_glue_tech_choose_video_port(tech_pvt, 1);
+				tech_pvt->video_rm_encoding = "PROXY-VID";
+				tech_pvt->video_rm_rate = 90000;
+				tech_pvt->video_codec_ms = 0;
+				switch_snprintf(vport_buf, sizeof(vport_buf), "%u", tech_pvt->adv_sdp_video_port);
+			}
+
+			strncpy(q, p, 8);
+			p += 8;
+
+			if (p >= pe) {
+				bad = 8;
+				goto end;
+			}
+
+			q += 8;
+
+			if (q >= qe) {
+				bad = 9;
+				goto end;
+			}
+
+			strncpy(q, vport_buf, strlen(vport_buf));
+			q += strlen(vport_buf);
+
+			if (q >= qe) {
+				bad = 10;
+				goto end;
+			}
+
+			while (p && *p && (*p >= '0' && *p <= '9')) {
+
+				if (p >= pe) {
+					bad = 11;
+					goto end;
+				}
+
+				p++;
+			}
+			
+			has_video++;
+	    }
+	    
+	    while (p && *p && *p != '\n') {
+
+			if (p >= pe) {
+				bad = 12;
+				goto end;
+			}
+
+			if (q >= qe) {
+				bad = 13;
+				goto end;
+			}
+
+			*q++ = *p++;
+	    }
+		
+		if (p >= pe) {
+            bad = 14;
+            goto end;
+        }
+		
+		if (q >= qe) {
+			bad = 15;
+			goto end;
+		}
+
+	    *q++ = *p++;
+
+	}
+
+ end:
+
+	if (bad) {
+		return;
+	}
+
+
+	if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s too late.\n", switch_channel_get_name(tech_pvt->channel));
+		return;
+	}
+
+
+	if (!has_ip && !has_audio) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SDP has no audio in it.\n%s\n",
+						  switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str);
+		return;
+	}
+	
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Patched SDP\n---\n%s\n+++\n%s\n",
+					  switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str, new_sdp);
+
+	sofia_glue_tech_set_local_sdp(tech_pvt, new_sdp, SWITCH_FALSE);
+
+}
+
+
+void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup)
+{
+	switch_mutex_lock(tech_pvt->sofia_mutex);
+	tech_pvt->local_sdp_str = dup ? switch_core_session_strdup(tech_pvt->session, sdp_str) : (char *)sdp_str;
+	switch_mutex_unlock(tech_pvt->sofia_mutex);	
+}
+
+
+switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
+{
+	char *alert_info = NULL;
+	const char *max_forwards = NULL;
+	const char *alertbuf;
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	switch_caller_profile_t *caller_profile;
+	const char *cid_name, *cid_num;
+	char *e_dest = NULL;
+	const char *holdstr = "";
+	switch_stream_handle_t stream = { 0 };
+	switch_event_header_t *hi;
+	char *extra_headers = NULL;
+	switch_status_t status = SWITCH_STATUS_FALSE;
+	uint32_t session_timeout = 0;
+	const char *val;
+	const char *rep;
+	const char *call_id = NULL;
+	char *route = NULL;
+	char *route_uri = NULL;
+	sofia_destination_t *dst = NULL;
+	sofia_cid_type_t cid_type = tech_pvt->profile->cid_type;
+
+	rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
+
+	switch_assert(tech_pvt != NULL);
+
+	sofia_clear_flag_locked(tech_pvt, TFLAG_SDP);
+
+	caller_profile = switch_channel_get_caller_profile(channel);
+
+	cid_name = caller_profile->caller_id_name;
+	cid_num = caller_profile->caller_id_number;
+	sofia_glue_tech_prepare_codecs(tech_pvt);
+	sofia_glue_check_video_codecs(tech_pvt);
+	check_decode(cid_name, session);
+	check_decode(cid_num, session);
+
+	if (!tech_pvt->from_str) {
+		const char* sipip;
+		const char* format;
+		const char *alt = NULL;
+
+		if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
+			sipip = tech_pvt->profile->extsipip;
+		} else {
+			sipip = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip;
+		}
+
+		format = strchr(sipip, ':') ? "\"%s\" <sip:%s%s[%s]>" : "\"%s\" <sip:%s%s%s>";
+
+		if ((alt = switch_channel_get_variable(channel, "sip_invite_domain"))) {
+			sipip = alt;
+		}
+			
+		tech_pvt->from_str = 
+			switch_core_session_sprintf(tech_pvt->session,
+										format,
+										cid_name,
+										cid_num,
+										!switch_strlen_zero(cid_num) ? "@" : "",
+										sipip);
+	}
+
+	if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) {
+		alert_info = switch_core_session_sprintf(tech_pvt->session, "Alert-Info: %s", alertbuf);
+	}
+
+	max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE);
+
+	if ((status = sofia_glue_tech_choose_port(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+		return status;
+	}
+
+	sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+
+	sofia_set_flag_locked(tech_pvt, TFLAG_READY);
+
+	if (!tech_pvt->nh) {
+		char *d_url = NULL, *url = NULL;
+		sofia_private_t *sofia_private;
+		char *invite_contact = NULL, *to_str, *use_from_str, *from_str, *url_str;
+		const char *t_var;
+		char *rpid_domain = "cluecon.com", *p;
+		const char *priv = "off";
+		const char *screen = "no";
+		const char *invite_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_params");
+		const char *invite_to_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_to_params");
+		const char *invite_to_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_to_uri");
+		const char *invite_contact_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_contact_params");
+		const char *invite_from_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_from_params");
+		const char *from_var = switch_channel_get_variable(tech_pvt->channel, "sip_from_uri");
+		const char *from_display = switch_channel_get_variable(tech_pvt->channel, "sip_from_display");
+		
+		if (switch_strlen_zero(tech_pvt->dest)) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "URL Error!\n");
+			return SWITCH_STATUS_FALSE;
+		}
+
+		if ((d_url = sofia_glue_get_url_from_contact(tech_pvt->dest, 1))) {
+			url = d_url;
+		} else {
+			url = tech_pvt->dest;
+		}
+
+		url_str = url;
+
+		if (from_var) {
+			if (strncasecmp(from_var, "sip:", 4) || strncasecmp(from_var, "sips:", 5)) {
+				use_from_str = switch_core_session_strdup(tech_pvt->session, from_var);
+			} else {
+				use_from_str = switch_core_session_sprintf(tech_pvt->session, "sip:%s", from_var);
+			}
+		} else if (!switch_strlen_zero(tech_pvt->gateway_from_str)) {
+			use_from_str = tech_pvt->gateway_from_str;
+		} else {
+			use_from_str = tech_pvt->from_str;
+		}
+
+		if (!switch_strlen_zero(tech_pvt->gateway_from_str)) {
+			rpid_domain = switch_core_session_strdup(session, tech_pvt->gateway_from_str);
+		} else if (!switch_strlen_zero(tech_pvt->from_str)) {
+			rpid_domain = switch_core_session_strdup(session, tech_pvt->from_str);
+		} 
+
+		sofia_glue_get_url_from_contact(rpid_domain, 0);
+		if ((rpid_domain = strrchr(rpid_domain, '@'))) {
+			rpid_domain++;
+			if ((p = strchr(rpid_domain, ';'))) {
+				*p = '\0';
+			}
+		}
+
+		if (!rpid_domain) {
+			rpid_domain = "cluecon.com";
+		}
+
+		/*
+		 * Ignore transport chanvar and uri parameter for gateway connections
+		 * since all of them have been already taken care of in mod_sofia.c:sofia_outgoing_channel()
+		 */
+		if (tech_pvt->transport == SOFIA_TRANSPORT_UNKNOWN && switch_strlen_zero(tech_pvt->gateway_name)) {
+			if ((p = (char *) switch_stristr("port=", url))) {
+				p += 5;
+				tech_pvt->transport = sofia_glue_str2transport(p);
+			} else {
+				if ((t_var = switch_channel_get_variable(channel, "sip_transport"))) {
+					tech_pvt->transport = sofia_glue_str2transport(t_var);
+				}
+			}
+
+			if (tech_pvt->transport == SOFIA_TRANSPORT_UNKNOWN) {
+				tech_pvt->transport = SOFIA_TRANSPORT_UDP;
+			}
+		}
+
+		if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
+			tech_pvt->user_via = sofia_glue_create_external_via(session, tech_pvt->profile, tech_pvt->transport);
+		}
+
+		if (!sofia_test_pflag(tech_pvt->profile, PFLAG_TLS) && sofia_glue_transport_has_tls(tech_pvt->transport)) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "TLS not supported by profile\n");
+			return SWITCH_STATUS_FALSE;
+		}
+
+		if (switch_strlen_zero(tech_pvt->invite_contact)) {
+			const char * contact;
+			if ((contact = switch_channel_get_variable(channel, "sip_contact_user"))) {
+				char *ip_addr;
+				char *ipv6;
+				
+				if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { 
+					ip_addr = (switch_check_network_list_ip(tech_pvt->remote_ip, tech_pvt->profile->local_network)) 
+						? tech_pvt->profile->sipip : tech_pvt->profile->extsipip;
+				} else {
+					ip_addr = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip;
+				}
+				
+				ipv6 = strchr(ip_addr, ':');
+
+				if (sofia_glue_transport_has_tls(tech_pvt->transport)) {
+					tech_pvt->invite_contact = switch_core_session_sprintf(session, "sip:%s@%s%s%s:%d", contact, 
+																		   ipv6 ? "[" : "", ip_addr, ipv6 ? "]" : "", 
+																		   tech_pvt->profile->tls_sip_port);
+				} else {
+					tech_pvt->invite_contact = switch_core_session_sprintf(session, "sip:%s@%s%s%s:%d", contact, 
+																		   ipv6 ? "[" : "", ip_addr, ipv6 ? "]" : "", tech_pvt->profile->sip_port);
+				}
+			} else {
+				if (sofia_glue_transport_has_tls(tech_pvt->transport)) {
+					tech_pvt->invite_contact = tech_pvt->profile->tls_url;
+				} else {
+					if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { 
+						tech_pvt->invite_contact = tech_pvt->profile->public_url;
+					} else {
+						tech_pvt->invite_contact = tech_pvt->profile->url;
+					}
+				}
+			}
+		}
+
+		url_str = sofia_overcome_sip_uri_weakness(session, url, tech_pvt->transport, SWITCH_TRUE, invite_params);
+		invite_contact = sofia_overcome_sip_uri_weakness(session, tech_pvt->invite_contact, tech_pvt->transport, SWITCH_FALSE, invite_contact_params);
+		from_str = sofia_overcome_sip_uri_weakness(session, use_from_str, 0, SWITCH_TRUE, invite_from_params);
+		to_str = sofia_overcome_sip_uri_weakness(session, invite_to_uri ? invite_to_uri : tech_pvt->dest_to, 0, SWITCH_FALSE, invite_to_params ? invite_to_params : invite_params);
+
+
+		/*
+		   Does the "genius" who wanted SIP to be "text-based" so it was "easier to read" even use it now,
+		   or did he just suggest it to make our lives miserable?
+		 */
+		use_from_str = from_str;
+		if (!from_display && !strcasecmp(tech_pvt->caller_profile->caller_id_name, "_undef_")) {
+			from_str = switch_core_session_sprintf(session, "<%s>", use_from_str);
+		} else {
+			from_str = switch_core_session_sprintf(session, "\"%s\" <%s>", from_display ? from_display : 
+												   tech_pvt->caller_profile->caller_id_name, use_from_str);
+		}
+		
+		if (!(call_id = switch_channel_get_variable(channel, "sip_outgoing_call_id"))) {
+			if (sofia_test_pflag(tech_pvt->profile, PFLAG_UUID_AS_CALLID)) {
+				call_id = switch_core_session_get_uuid(session);
+			}
+		}
+		
+		tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
+								  NUTAG_URL(url_str),
+								  TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
+								  SIPTAG_TO_STR(to_str), 
+								  SIPTAG_FROM_STR(from_str),
+								  SIPTAG_CONTACT_STR(invite_contact),
+								  TAG_END());
+
+		if (tech_pvt->dest && (strstr(tech_pvt->dest, ";fs_nat") || strstr(tech_pvt->dest, ";received") 
+							   || ((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val)))) {
+			sofia_set_flag(tech_pvt, TFLAG_NAT);
+			tech_pvt->record_route = switch_core_session_strdup(tech_pvt->session, url_str);
+			route_uri = tech_pvt->record_route;
+			session_timeout = SOFIA_NAT_SESSION_TIMEOUT;
+			switch_channel_set_variable(channel, "sip_nat_detected", "true");
+		}
+		
+		if ((val = switch_channel_get_variable(channel, "sip_cid_type"))) {
+			cid_type = sofia_cid_name2type(val);
+		}
+		switch (cid_type) {
+		case CID_TYPE_PID:
+			if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
+				tech_pvt->asserted_id = switch_core_session_sprintf(tech_pvt->session, "\"%s\"<sip:%s@%s>",
+																	tech_pvt->caller_profile->caller_id_name,
+																	tech_pvt->caller_profile->caller_id_number, 
+																	rpid_domain);
+			} else {
+				tech_pvt->preferred_id = switch_core_session_sprintf(tech_pvt->session, "\"%s\"<sip:%s@%s>",
+																	 tech_pvt->caller_profile->caller_id_name,
+																	 tech_pvt->caller_profile->caller_id_number, 
+																	 rpid_domain);
+			}
+			
+			if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+				tech_pvt->privacy = "id";
+			} else {
+				tech_pvt->privacy = "none";
+			}
+
+			break;
+		case CID_TYPE_RPID:
+			{
+				if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) {
+					priv = "name";
+					if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+						priv = "full";
+					}
+				} else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+					priv = "full";
+				}
+				
+				if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
+					screen = "yes";
+				}
+				
+				tech_pvt->rpid = switch_core_session_sprintf(tech_pvt->session, "\"%s\"<sip:%s@%s>;party=calling;screen=%s;privacy=%s",
+															 tech_pvt->caller_profile->caller_id_name,
+															 tech_pvt->caller_profile->caller_id_number, rpid_domain, screen, priv);
+			}
+			break;
+		default:
+			break;
+		}
+
+
+		switch_safe_free(d_url);
+
+		if (!(sofia_private = malloc(sizeof(*sofia_private)))) {
+			abort();
+		}
+
+		memset(sofia_private, 0, sizeof(*sofia_private));
+		sofia_private->is_call++;
+
+		tech_pvt->sofia_private = sofia_private;
+		switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
+		nua_handle_bind(tech_pvt->nh, tech_pvt->sofia_private);
+	}
+
+	if (tech_pvt->e_dest) {
+		char *user = NULL, *host = NULL;
+		char hash_key[256] = "";
+
+		e_dest = strdup(tech_pvt->e_dest);
+		switch_assert(e_dest != NULL);
+		user = e_dest;
+
+		if ((host = strchr(user, '@'))) {
+			*host++ = '\0';
+		}
+		switch_snprintf(hash_key, sizeof(hash_key), "%s%s%s", user, host, cid_num);
+
+		tech_pvt->chat_from = tech_pvt->from_str;
+		tech_pvt->chat_to = tech_pvt->dest;
+		if (tech_pvt->profile->pres_type) {
+			tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
+			switch_mutex_lock(tech_pvt->profile->flag_mutex);
+			switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
+			switch_mutex_unlock(tech_pvt->profile->flag_mutex);
+		}
+		free(e_dest);
+	}
+
+	holdstr = sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? "*" : "";
+
+	if (!switch_channel_get_variable(channel, "sofia_profile_name")) {
+		switch_channel_set_variable(channel, "sofia_profile_name", tech_pvt->profile->name);
+	}
+
+	SWITCH_STANDARD_STREAM(stream);
+	if ((hi = switch_channel_variable_first(channel))) {
+		for (; hi; hi = hi->next) {
+			const char *name = (char *) hi->name;
+			char *value = (char *) hi->value;
+
+			if (!strncasecmp(name, SOFIA_SIP_HEADER_PREFIX, strlen(SOFIA_SIP_HEADER_PREFIX))) {
+				const char *hname = name + strlen(SOFIA_SIP_HEADER_PREFIX);
+				stream.write_function(&stream, "%s: %s\r\n", hname, value);
+			}
+		}
+		switch_channel_variable_last(channel);
+	}
+
+	if (stream.data) {
+		extra_headers = stream.data;
+	}
+
+	session_timeout = tech_pvt->profile->session_timeout;
+	if ((val = switch_channel_get_variable(channel, SOFIA_SESSION_TIMEOUT))) {
+		int v_session_timeout = atoi(val);
+		if (v_session_timeout >= 0) {
+			session_timeout = v_session_timeout;
+		}
+	}
+
+	if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			sofia_glue_tech_proxy_remote_addr(tech_pvt);
+		}
+		sofia_glue_tech_patch_sdp(tech_pvt);
+	}
+
+	if (!switch_strlen_zero(tech_pvt->dest)) {
+		dst = sofia_glue_get_destination(tech_pvt->dest);
+
+		if (dst->route_uri) {
+			route_uri = sofia_overcome_sip_uri_weakness(tech_pvt->session, dst->route_uri, tech_pvt->transport, SWITCH_TRUE, NULL);
+		}
+	
+		if (dst->route) {
+			route = dst->route;
+		}
+	}
+
+	if ((val = switch_channel_get_variable(channel, "sip_route_uri"))) {
+		route_uri = switch_core_session_strdup(session, val);
+		route = NULL;
+	}
+	
+	if (route_uri) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Setting proxy route to %s\n", route_uri, switch_channel_get_name(channel));
+		tech_pvt->route_uri = switch_core_session_strdup(tech_pvt->session, route_uri);
+	}
+
+	nua_invite(tech_pvt->nh,
+			   NUTAG_AUTOANSWER(0),
+			   NUTAG_SESSION_TIMER(session_timeout),
+			   TAG_IF(tech_pvt->redirected, NUTAG_URL(tech_pvt->redirected)),
+			   TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
+			   TAG_IF(!switch_strlen_zero(tech_pvt->rpid), SIPTAG_REMOTE_PARTY_ID_STR(tech_pvt->rpid)),
+			   TAG_IF(!switch_strlen_zero(tech_pvt->preferred_id), SIPTAG_P_PREFERRED_IDENTITY_STR(tech_pvt->preferred_id)),
+			   TAG_IF(!switch_strlen_zero(tech_pvt->asserted_id), SIPTAG_P_ASSERTED_IDENTITY_STR(tech_pvt->asserted_id)),
+			   TAG_IF(!switch_strlen_zero(tech_pvt->privacy), SIPTAG_PRIVACY_STR(tech_pvt->privacy)),
+			   TAG_IF(!switch_strlen_zero(alert_info), SIPTAG_HEADER_STR(alert_info)),
+			   TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
+			   TAG_IF(!switch_strlen_zero(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)),
+			   TAG_IF(!switch_strlen_zero(route_uri), NUTAG_PROXY(route_uri)),
+			   TAG_IF(!switch_strlen_zero(route), SIPTAG_ROUTE_STR(route)),
+			   SOATAG_ADDRESS(tech_pvt->adv_sdp_audio_ip),
+			   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+			   SOATAG_REUSE_REJECTED(1),
+			   SOATAG_ORDERED_USER(1),
+			   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
+			   SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), SOATAG_HOLD(holdstr), TAG_END());
+
+	switch_safe_free(stream.data);
+	sofia_glue_free_destination(dst);
+	tech_pvt->redirected = NULL;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+void sofia_glue_do_xfer_invite(switch_core_session_t *session)
+{
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	switch_caller_profile_t *caller_profile;
+	const char *sipip, *format, *contact_url; 
+
+	switch_assert(tech_pvt != NULL);
+	switch_mutex_lock(tech_pvt->sofia_mutex);
+	caller_profile = switch_channel_get_caller_profile(channel);
+
+	if (sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { 
+		sipip = tech_pvt->profile->extsipip;
+		contact_url = tech_pvt->profile->public_url;
+	} else {
+		sipip = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip;
+		contact_url = tech_pvt->profile->url;
+	}
+
+	format = strchr(sipip, ':') ? "\"%s\" <sip:%s@[%s]>" : "\"%s\" <sip:%s@%s>";
+
+	if ((tech_pvt->from_str = switch_core_session_sprintf(session, format,
+															caller_profile->caller_id_name,
+															caller_profile->caller_id_number, sipip))) {
+
+		const char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
+
+		tech_pvt->nh2 = nua_handle(tech_pvt->profile->nua, NULL,
+								   SIPTAG_TO_STR(tech_pvt->dest),
+								   SIPTAG_FROM_STR(tech_pvt->from_str),
+								   SIPTAG_CONTACT_STR(contact_url),
+								   TAG_END());
+
+		nua_handle_bind(tech_pvt->nh2, tech_pvt->sofia_private);
+
+		nua_invite(tech_pvt->nh2,
+				   SIPTAG_CONTACT_STR(contact_url),
+				   TAG_IF(!switch_strlen_zero(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
+				   SOATAG_ADDRESS(tech_pvt->adv_sdp_audio_ip),
+				   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+				   SOATAG_REUSE_REJECTED(1),
+				   SOATAG_ORDERED_USER(1),
+				   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), TAG_END());
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+	}
+	switch_mutex_unlock(tech_pvt->sofia_mutex);
+}
+
+void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt)
+{
+	const char *sdp_str;
+
+	if ((sdp_str = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) {
+		sdp_parser_t *parser;
+		sdp_session_t *sdp;
+		sdp_media_t *m;
+		sdp_connection_t *connection;
+
+		if ((parser = sdp_parse(NULL, sdp_str, (int) strlen(sdp_str), 0))) {
+			if ((sdp = sdp_session(parser))) {
+				for (m = sdp->sdp_media; m; m = m->m_next) {
+					if (m->m_type != sdp_media_audio || !m->m_port) {
+						continue;
+					}
+
+					connection = sdp->sdp_connection;
+					if (m->m_connections) {
+						connection = m->m_connections;
+					}
+
+					if (connection) {
+						tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address);
+					}
+					tech_pvt->proxy_sdp_audio_port = (switch_port_t) m->m_port;
+					if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) {
+						break;
+					}
+				}
+			}
+			sdp_parser_free(parser);
+		}
+		sofia_glue_tech_set_local_sdp(tech_pvt, sdp_str, SWITCH_TRUE);
+	}
+}
+
+
+#define add_stat(_i, _s) \
+	switch_snprintf(var_name, sizeof(var_name), "rtp_%s_%s", switch_str_nil(prefix), _s) ; \
+	switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_SIZE_T_FMT, _i); \
+	switch_channel_set_variable(tech_pvt->channel, var_name, var_val)
+
+static void set_stats(switch_rtp_t *rtp_session, private_object_t *tech_pvt, const char *prefix)
+{
+	switch_rtp_stats_t *stats = switch_rtp_get_stats(rtp_session, NULL);
+	char var_name[256] = "", var_val[35] = "";
+
+	if (stats) {
+
+		add_stat(stats->inbound.raw_bytes, "in_raw_bytes");
+		add_stat(stats->inbound.media_bytes, "in_media_bytes");
+		add_stat(stats->inbound.packet_count, "in_packet_count");
+		add_stat(stats->inbound.media_packet_count, "in_media_packet_count");
+		add_stat(stats->inbound.skip_packet_count, "in_skip_packet_count");
+		add_stat(stats->inbound.jb_packet_count, "in_jb_packet_count");
+		add_stat(stats->inbound.dtmf_packet_count, "in_dtmf_packet_count");
+		add_stat(stats->inbound.cng_packet_count, "in_cng_packet_count");
+		add_stat(stats->inbound.cng_packet_count, "in_flush_packet_count");
+
+		add_stat(stats->outbound.raw_bytes, "out_raw_bytes");
+		add_stat(stats->outbound.media_bytes, "out_media_bytes");
+		add_stat(stats->outbound.packet_count, "out_packet_count");
+		add_stat(stats->outbound.media_packet_count, "out_media_packet_count");
+		add_stat(stats->outbound.skip_packet_count, "out_skip_packet_count");
+		add_stat(stats->outbound.dtmf_packet_count, "out_dtmf_packet_count");
+		add_stat(stats->outbound.cng_packet_count, "out_cng_packet_count");
+		
+	}
+}
+
+void sofia_glue_set_rtp_stats(private_object_t *tech_pvt)
+{
+	if (tech_pvt->rtp_session) {
+        set_stats(tech_pvt->rtp_session, tech_pvt, "audio");
+	}
+
+	if (tech_pvt->video_rtp_session) {
+        set_stats(tech_pvt->video_rtp_session, tech_pvt, "video");
+	}
+}
+
+void sofia_glue_deactivate_rtp(private_object_t *tech_pvt)
+{
+	int loops = 0;
+	if (switch_rtp_ready(tech_pvt->rtp_session)) {
+		while (loops < 10 && (sofia_test_flag(tech_pvt, TFLAG_READING) || sofia_test_flag(tech_pvt, TFLAG_WRITING))) {
+			switch_yield(10000);
+			loops++;
+		}
+	}
+
+	if (tech_pvt->rtp_session) {
+		switch_rtp_destroy(&tech_pvt->rtp_session);
+	} else if (tech_pvt->local_sdp_audio_port) {
+		switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_audio_port);
+	}
+
+	if (tech_pvt->local_sdp_audio_port > 0 && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { 
+		switch_nat_del_mapping((switch_port_t)tech_pvt->local_sdp_audio_port, SWITCH_NAT_UDP);
+	}
+	
+	if (tech_pvt->video_rtp_session) {
+		switch_rtp_destroy(&tech_pvt->video_rtp_session);
+	} else if (tech_pvt->local_sdp_video_port) {
+		switch_rtp_release_port(tech_pvt->profile->rtpip, tech_pvt->local_sdp_video_port);
+	}
+
+		
+	if (tech_pvt->local_sdp_video_port > 0 && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) { 
+		switch_nat_del_mapping((switch_port_t)tech_pvt->local_sdp_video_port, SWITCH_NAT_UDP);
+	}
+}
+
+switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force)
+{
+
+	if (tech_pvt->video_read_codec.implementation && switch_core_codec_ready(&tech_pvt->video_read_codec)) {
+		if (!force) {
+			return SWITCH_STATUS_SUCCESS;
+		}
+		if (strcasecmp(tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding) ||
+			tech_pvt->video_read_codec.implementation->samples_per_second != tech_pvt->video_rm_rate) {
+
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n",
+							  tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding);
+			switch_core_codec_destroy(&tech_pvt->video_read_codec);
+			switch_core_codec_destroy(&tech_pvt->video_write_codec);
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->video_read_codec.implementation->iananame);
+			return SWITCH_STATUS_SUCCESS;
+		}
+	}
+
+	if (!tech_pvt->video_rm_encoding) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec with no name?\n");
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (switch_core_codec_init(&tech_pvt->video_read_codec,
+							   tech_pvt->video_rm_encoding,
+							   tech_pvt->video_rm_fmtp,
+							   tech_pvt->video_rm_rate,
+							   0,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+		return SWITCH_STATUS_FALSE;
+	} else {
+		if (switch_core_codec_init(&tech_pvt->video_write_codec,
+								   tech_pvt->video_rm_encoding,
+								   tech_pvt->video_rm_fmtp,
+								   tech_pvt->video_rm_rate,
+								   0,
+								   1,
+								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+								   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+			return SWITCH_STATUS_FALSE;
+		} else {
+			int ms;
+			tech_pvt->video_read_frame.rate = tech_pvt->video_rm_rate;
+			ms = tech_pvt->video_write_codec.implementation->microseconds_per_packet / 1000;
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set VIDEO Codec %s %s/%ld %d ms\n",
+							  switch_channel_get_name(tech_pvt->channel), tech_pvt->video_rm_encoding, tech_pvt->video_rm_rate, tech_pvt->video_codec_ms);
+			tech_pvt->video_read_frame.codec = &tech_pvt->video_read_codec;
+
+			tech_pvt->video_fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->video_write_codec.fmtp_out);
+
+			tech_pvt->video_write_codec.agreed_pt = tech_pvt->video_agreed_pt;
+			tech_pvt->video_read_codec.agreed_pt = tech_pvt->video_agreed_pt;
+			switch_core_session_set_video_read_codec(tech_pvt->session, &tech_pvt->video_read_codec);
+			switch_core_session_set_video_write_codec(tech_pvt->session, &tech_pvt->video_write_codec);
+		}
+	}
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
+{
+	int ms;
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	int resetting = 0;
+	
+	if (!tech_pvt->iananame) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No audio codec available\n");
+		switch_goto_status(SWITCH_STATUS_FALSE, end);
+	}
+
+	if (tech_pvt->read_codec.implementation && switch_core_codec_ready(&tech_pvt->read_codec)) {
+		if (!force) {
+			switch_goto_status(SWITCH_STATUS_SUCCESS, end);
+		}
+		if (strcasecmp(tech_pvt->read_codec.implementation->iananame, tech_pvt->iananame) ||
+			tech_pvt->read_codec.implementation->samples_per_second != tech_pvt->rm_rate) {
+
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n",
+							  tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding);
+			switch_core_session_lock_codec_write(tech_pvt->session);
+			switch_core_session_lock_codec_read(tech_pvt->session);
+			resetting = 1;
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+			switch_core_session_reset(tech_pvt->session, SWITCH_TRUE, SWITCH_TRUE);
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_codec.implementation->iananame);
+			switch_goto_status(SWITCH_STATUS_SUCCESS, end);
+		}
+	}
+	
+	if (switch_core_codec_init(&tech_pvt->read_codec,
+							   tech_pvt->iananame,
+							   tech_pvt->rm_fmtp,
+							   tech_pvt->rm_rate,
+							   tech_pvt->codec_ms,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
+							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+		switch_goto_status(SWITCH_STATUS_FALSE, end);
+	}
+
+	if (switch_core_codec_init(&tech_pvt->write_codec,
+							   tech_pvt->iananame,
+							   tech_pvt->rm_fmtp,
+							   tech_pvt->rm_rate,
+							   tech_pvt->codec_ms,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
+							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+		switch_goto_status(SWITCH_STATUS_FALSE, end);
+	}
+
+	switch_assert(tech_pvt->read_codec.implementation);
+	switch_assert(tech_pvt->write_codec.implementation);
+
+	tech_pvt->read_impl = *tech_pvt->read_codec.implementation;
+	tech_pvt->write_impl = *tech_pvt->write_codec.implementation;
+
+
+	if (switch_rtp_ready(tech_pvt->rtp_session)) {
+		switch_assert(tech_pvt->read_codec.implementation);
+		switch_rtp_set_default_samples_per_interval(tech_pvt->rtp_session, tech_pvt->read_impl.samples_per_packet);
+	}
+
+	tech_pvt->read_frame.rate = tech_pvt->rm_rate;
+	ms = tech_pvt->write_codec.implementation->microseconds_per_packet / 1000;
+
+	if (!switch_core_codec_ready(&tech_pvt->read_codec)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+		switch_goto_status(SWITCH_STATUS_FALSE, end);
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples\n",
+					  switch_channel_get_name(tech_pvt->channel), tech_pvt->iananame, tech_pvt->rm_rate, tech_pvt->codec_ms,
+					  tech_pvt->read_impl.samples_per_packet);
+	tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+
+	tech_pvt->write_codec.agreed_pt = tech_pvt->agreed_pt;
+	tech_pvt->read_codec.agreed_pt = tech_pvt->agreed_pt;
+
+	if (force != 2) {
+		switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+		switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+	}
+
+	tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out);
+
+	if (switch_rtp_ready(tech_pvt->rtp_session)) {
+		switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->pt);
+	}
+
+ end:
+	if (resetting) {
+		switch_core_session_unlock_codec_write(tech_pvt->session);
+		switch_core_session_unlock_codec_read(tech_pvt->session);
+	}
+
+	return status;
+}
+
+
+switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction)
+{
+	unsigned char b64_key[512] = "";
+	const char *type_str;
+	unsigned char *key;
+	const char *val;
+
+	char *p;
+
+	if (type == AES_CM_128_HMAC_SHA1_80) {
+		type_str = SWITCH_RTP_CRYPTO_KEY_80;
+	} else {
+		type_str = SWITCH_RTP_CRYPTO_KEY_32;
+	}
+
+	if (direction == SWITCH_RTP_CRYPTO_SEND) {
+		key = tech_pvt->local_raw_key;
+	} else {
+		key = tech_pvt->remote_raw_key;
+
+	}
+
+	switch_rtp_get_random(key, SWITCH_RTP_KEY_LEN);
+	switch_b64_encode(key, SWITCH_RTP_KEY_LEN, b64_key, sizeof(b64_key));
+	p = strrchr((char *) b64_key, '=');
+
+	while (p && *p && *p == '=') {
+		*p-- = '\0';
+	}
+
+	tech_pvt->local_crypto_key = switch_core_session_sprintf(tech_pvt->session, "%d %s inline:%s", index, type_str, b64_key);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Local Key [%s]\n", tech_pvt->local_crypto_key);
+
+	if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_SRTP_AUTH) &&
+		!((val = switch_channel_get_variable(tech_pvt->channel, "NDLB_support_asterisk_missing_srtp_auth")) && switch_true(val))) {
+		tech_pvt->crypto_type = type;
+	} else {
+		tech_pvt->crypto_type = AES_CM_128_NULL_AUTH;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t sofia_glue_add_crypto(private_object_t *tech_pvt, const char *key_str, switch_rtp_crypto_direction_t direction)
+{
+	unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
+	int index;
+	switch_rtp_crypto_key_type_t type;
+	char *p;
+
+
+	if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+		goto bad;
+	}
+
+	index = atoi(key_str);
+
+	p = strchr(key_str, ' ');
+
+	if (p && *p && *(p + 1)) {
+		p++;
+		if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_32, strlen(SWITCH_RTP_CRYPTO_KEY_32))) {
+			type = AES_CM_128_HMAC_SHA1_32;
+		} else if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_80, strlen(SWITCH_RTP_CRYPTO_KEY_80))) {
+			type = AES_CM_128_HMAC_SHA1_80;
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
+			goto bad;
+		}
+
+		p = strchr(p, ' ');
+		if (p && *p && *(p + 1)) {
+			p++;
+			if (strncasecmp(p, "inline:", 7)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
+				goto bad;
+			}
+
+			p += 7;
+			switch_b64_decode(p, (char *) key, sizeof(key));
+
+			if (direction == SWITCH_RTP_CRYPTO_SEND) {
+				tech_pvt->crypto_send_type = type;
+				memcpy(tech_pvt->local_raw_key, key, SWITCH_RTP_KEY_LEN);
+			} else {
+				tech_pvt->crypto_recv_type = type;
+				memcpy(tech_pvt->remote_raw_key, key, SWITCH_RTP_KEY_LEN);
+			}
+			return SWITCH_STATUS_SUCCESS;
+		}
+
+	}
+
+  bad:
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error!\n");
+	return SWITCH_STATUS_FALSE;
+
+}
+
+
+switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_flag_t myflags)
+{
+	int bw, ms;
+	const char *err = NULL;
+	const char *val = NULL;
+	switch_rtp_flag_t flags;
+	switch_status_t status;
+	char tmp[50];
+	uint32_t rtp_timeout_sec = tech_pvt->profile->rtp_timeout_sec;
+	uint32_t rtp_hold_timeout_sec = tech_pvt->profile->rtp_hold_timeout_sec;
+	char *timer_name = NULL;
+	const char *var;
+
+	switch_assert(tech_pvt != NULL);
+
+	if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	switch_mutex_lock(tech_pvt->sofia_mutex);
+
+	if (switch_rtp_ready(tech_pvt->rtp_session)) {
+		switch_rtp_reset_media_timer(tech_pvt->rtp_session);
+	}
+
+	if ((var = switch_channel_get_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) {
+		sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
+	}
+
+	if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
+		status = SWITCH_STATUS_SUCCESS;
+		goto end;
+	}
+
+	if (switch_rtp_ready(tech_pvt->rtp_session) && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+		status = SWITCH_STATUS_SUCCESS;
+		goto end;
+	}
+
+	if ((status = sofia_glue_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+		goto end;
+	}
+
+	bw = tech_pvt->read_impl.bits_per_second;
+	ms = tech_pvt->read_impl.microseconds_per_packet;
+
+	if (myflags) {
+		flags = myflags;
+	} else if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+				!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+		flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+    } else {
+		flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT);
+	}
+
+	if ((val = switch_channel_get_variable(tech_pvt->channel, "dtmf_type"))) {
+		if (!strcasecmp(val, "rfc2833")) {
+			tech_pvt->dtmf_type = DTMF_2833;
+		} else if (!strcasecmp(val, "info")) {
+			tech_pvt->dtmf_type = DTMF_INFO;
+		} else {
+			tech_pvt->dtmf_type = tech_pvt->profile->dtmf_type;
+		}
+	}
+
+	if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_RFC2833)
+		|| ((val = switch_channel_get_variable(tech_pvt->channel, "pass_rfc2833")) && switch_true(val))) {
+		sofia_set_flag(tech_pvt, TFLAG_PASS_RFC2833);
+	}
+
+
+	if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFLUSH)
+		|| ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_autoflush")) && switch_true(val))) {
+		flags |= SWITCH_RTP_FLAG_AUTOFLUSH;
+	}
+
+	if (!(sofia_test_pflag(tech_pvt->profile, PFLAG_REWRITE_TIMESTAMPS) ||
+		  ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_rewrite_timestamps")) && !switch_true(val)))) {
+		flags |= SWITCH_RTP_FLAG_RAW_WRITE;
+	}
+
+	if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
+		tech_pvt->cng_pt = 0;
+	} else if (tech_pvt->cng_pt) {
+		flags |= SWITCH_RTP_FLAG_AUTO_CNG;
+	}
+
+	if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+		//const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
+		//const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
+		char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
+		switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+		
+		if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n", switch_channel_get_name(tech_pvt->channel));
+			goto video;
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n", 
+							  switch_channel_get_name(tech_pvt->channel),
+							  remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+		}
+	}
+
+	if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AUDIO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n",
+						  switch_channel_get_name(tech_pvt->channel),
+						  tech_pvt->local_sdp_audio_ip,
+						  tech_pvt->local_sdp_audio_port,
+						  tech_pvt->remote_sdp_audio_ip,
+						  tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+	}
+
+	switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_audio_port);
+	switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+	switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+
+	if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+		sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+		
+		if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, SWITCH_TRUE, &err) !=
+			SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n",
+							  tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+			if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+				!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+				/* Reactivate the NAT buster flag. */
+				switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+			}
+		}
+		goto video;
+	}
+
+	if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+		if ((status = sofia_glue_tech_proxy_remote_addr(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
+			goto end;
+		}
+
+		if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) &&
+			!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+			flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+		} else {
+			flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_DATAWAIT);
+		}
+		timer_name = NULL;
+
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+						  "PROXY AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
+						  switch_channel_get_name(tech_pvt->channel),
+						  tech_pvt->local_sdp_audio_ip,
+						  tech_pvt->local_sdp_audio_port,
+						  tech_pvt->remote_sdp_audio_ip,
+						  tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+	} else {
+		timer_name = tech_pvt->profile->timer_name;
+
+		if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) {
+			timer_name = (char *) var;
+		}
+	}
+
+	if (switch_channel_up(tech_pvt->channel) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+		tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
+											   tech_pvt->local_sdp_audio_port,
+											   tech_pvt->remote_sdp_audio_ip,
+											   tech_pvt->remote_sdp_audio_port,
+											   tech_pvt->agreed_pt,
+											   tech_pvt->read_impl.samples_per_packet,
+											   tech_pvt->codec_ms * 1000,
+											   (switch_rtp_flag_t) flags, timer_name, &err,
+											   switch_core_session_get_pool(tech_pvt->session));
+	}
+
+	if (switch_rtp_ready(tech_pvt->rtp_session)) {
+		uint8_t vad_in = sofia_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
+		uint8_t vad_out = sofia_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
+		uint8_t inb = sofia_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1;
+		uint32_t stun_ping = 0;
+
+		switch_channel_set_flag(tech_pvt->channel, CF_FS_RTP);
+		
+		if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_in")) && switch_true(val)) {
+			vad_in = 1;
+		}
+		if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_enable_vad_out")) && switch_true(val)) {
+			vad_out = 1;
+		}
+
+		if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_in")) && switch_true(val)) {
+			vad_in = 0;
+		}
+		if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_vad_out")) && switch_true(val)) {
+			vad_out = 0;
+		}
+
+		if ((tech_pvt->stun_flags & STUN_FLAG_SET) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_stun_ping"))) {
+			int ival = atoi(val);
+			
+			if (ival <= 0) {
+				if (switch_true(val)) {
+					ival = 6;
+				}
+			}
+
+			stun_ping = (ival * tech_pvt->read_impl.samples_per_second) / tech_pvt->read_impl.samples_per_packet;
+		}
+
+		tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
+		sofia_set_flag(tech_pvt, TFLAG_RTP);
+		sofia_set_flag(tech_pvt, TFLAG_IO);
+		
+		switch_rtp_intentional_bugs(tech_pvt->rtp_session, tech_pvt->rtp_bugs);
+		
+		if ((vad_in && inb) || (vad_out && !inb)) {
+			switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING);
+			sofia_set_flag(tech_pvt, TFLAG_VAD);
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AUDIO RTP Engage VAD for %s ( %s %s )\n",
+							  switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : "");
+		}
+
+		if (stun_ping) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting stun ping to %s:%d\n", tech_pvt->stun_ip, stun_ping);
+			switch_rtp_activate_stun_ping(tech_pvt->rtp_session, tech_pvt->stun_ip, tech_pvt->stun_port, 
+										  stun_ping, (tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0);
+		}
+
+		if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) {
+			int len = atoi(val);
+
+			if (len < 100 || len > 1000) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Jitterbuffer spec [%d] must be between 100 and 1000\n", len);
+			} else {
+				int qlen;
+
+				qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", len, qlen);
+				switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen);
+			}
+		}
+
+		if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_timeout_sec"))) {
+			int v = atoi(val);
+			if (v >= 0) {
+				rtp_timeout_sec = v;
+			}
+		}
+
+		if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_hold_timeout_sec"))) {
+			int v = atoi(val);
+			if (v >= 0) {
+				rtp_hold_timeout_sec = v;
+			}
+		}
+
+		if (rtp_timeout_sec) {
+			tech_pvt->max_missed_packets = (tech_pvt->read_impl.samples_per_second * rtp_timeout_sec) /
+				tech_pvt->read_impl.samples_per_packet;
+
+			switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
+			if (!rtp_hold_timeout_sec) {
+				rtp_hold_timeout_sec = rtp_timeout_sec * 10;
+			}
+		}
+
+		if (rtp_hold_timeout_sec) {
+			tech_pvt->max_missed_hold_packets = (tech_pvt->read_impl.samples_per_second * rtp_hold_timeout_sec) /
+				tech_pvt->read_impl.samples_per_packet;
+		}
+
+		if (tech_pvt->te) {
+			switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
+		}
+
+		if (sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) ||
+			((val = switch_channel_get_variable(tech_pvt->channel, "supress_cng")) && switch_true(val)) ||
+			((val = switch_channel_get_variable(tech_pvt->channel, "suppress_cng")) && switch_true(val))) {
+			tech_pvt->cng_pt = 0;
+		}
+
+		if (tech_pvt->cng_pt && !sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG)) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", tech_pvt->cng_pt);
+			switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
+		}
+
+		if (tech_pvt->remote_crypto_key && sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+			sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
+			switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, tech_pvt->crypto_type, tech_pvt->local_raw_key,
+									  SWITCH_RTP_KEY_LEN);
+			switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt->crypto_tag, tech_pvt->crypto_type, tech_pvt->remote_raw_key,
+									  SWITCH_RTP_KEY_LEN);
+			switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE, "true");
+		}
+
+	  video:
+
+		sofia_glue_check_video_codecs(tech_pvt);
+
+		if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) {
+			if (!tech_pvt->local_sdp_video_port) {
+				sofia_glue_tech_choose_video_port(tech_pvt, 1);
+			}
+
+			if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) &&
+				!((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
+				flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_AUTOADJ |
+		 									 SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_NOBLOCK | SWITCH_RTP_FLAG_RAW_WRITE);
+			} else {
+				flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_NOBLOCK | SWITCH_RTP_FLAG_RAW_WRITE);
+			}
+
+			if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+				flags |= SWITCH_RTP_FLAG_PROXY_MEDIA;
+			}
+			sofia_glue_tech_set_video_codec(tech_pvt, 0);
+
+			/* set video timer to 10ms so it can co-exist with audio */
+			tech_pvt->video_rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
+														 tech_pvt->local_sdp_video_port,
+														 tech_pvt->remote_sdp_video_ip,
+														 tech_pvt->remote_sdp_video_port,
+														 tech_pvt->video_agreed_pt,
+														 1, 10000, (switch_rtp_flag_t) flags, NULL, &err, switch_core_session_get_pool(tech_pvt->session));
+
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
+							  switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
+							  switch_channel_get_name(tech_pvt->channel),
+							  tech_pvt->local_sdp_audio_ip,
+							  tech_pvt->local_sdp_video_port,
+							  tech_pvt->remote_sdp_video_ip,
+							  tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt,
+							  0, switch_rtp_ready(tech_pvt->video_rtp_session) ? "SUCCESS" : err);
+
+			if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+				switch_channel_set_flag(tech_pvt->channel, CF_VIDEO);
+			} else {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
+				switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+				goto end;
+			}
+		}
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
+		switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+		sofia_clear_flag_locked(tech_pvt, TFLAG_IO);
+		status = SWITCH_STATUS_FALSE;
+		goto end;
+	}
+
+	sofia_set_flag(tech_pvt, TFLAG_IO);
+	status = SWITCH_STATUS_SUCCESS;
+
+  end:
+
+	switch_mutex_unlock(tech_pvt->sofia_mutex);
+
+	return status;
+
+}
+
+void sofia_glue_set_r_sdp_codec_string(switch_channel_t *channel,const char *codec_string, sdp_session_t *sdp)
+{
+	char buf[1024] = {0};
+	sdp_media_t *m;
+	sdp_attribute_t *attr;
+	int ptime = 0, dptime = 0;
+	sdp_connection_t *connection;
+	sdp_rtpmap_t *map;
+	short int match = 0;
+	int i;
+	int already_did[128] = { 0 };
+	int num_codecs = 0;
+	char *codec_order[SWITCH_MAX_CODECS];
+	const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 };
+
+	if (!switch_strlen_zero(codec_string)) {
+		char *tmp_codec_string;
+		if ((tmp_codec_string = strdup(codec_string))) {
+			num_codecs = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS);
+			num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, num_codecs);
+			switch_safe_free(tmp_codec_string);
+		}
+	} else {
+		num_codecs = switch_loadable_module_get_codecs(codecs, SWITCH_MAX_CODECS);
+	}
+
+	if (!channel || !num_codecs) {
+		return;
+	}
+
+	for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
+		if (switch_strlen_zero(attr->a_name)) {
+			continue;
+		}
+
+		if (!strcasecmp(attr->a_name, "ptime")) {
+			dptime = atoi(attr->a_value);
+			break;
+		}
+	}
+
+	for (m = sdp->sdp_media; m; m = m->m_next) {
+		ptime = dptime;
+		if ( m->m_type == sdp_media_image && m->m_port) {
+			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",t38");
+		} else if (m->m_type == sdp_media_audio && m->m_port) {
+			for (attr = m->m_attributes; attr; attr = attr->a_next) {
+				if (switch_strlen_zero(attr->a_name)) {
+					continue;
+				}
+				if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
+					ptime = atoi(attr->a_value);
+					break;
+				}
+			}
+			connection = sdp->sdp_connection;
+			if (m->m_connections) {
+				connection = m->m_connections;
+			}
+
+			if (!connection) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+				break;
+			}
+
+			for (i = 0; i < num_codecs; i++) {
+				const switch_codec_implementation_t *imp = codecs[i];
+				if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO || imp->ianacode > 127 || already_did[imp->ianacode]) {
+					continue;
+				}
+				for (map = m->m_rtpmaps; map; map = map->rm_next) {
+					if ( map->rm_pt > 127 ||  already_did[map->rm_pt]) {
+						continue;
+					}
+
+					if (map->rm_pt < 96) {
+						match = (map->rm_pt == imp->ianacode) ? 1 : 0;
+					} else {
+						if (map->rm_encoding) {
+							match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
+						} else {
+							match = 0;
+						}
+					}
+
+					if (match) {
+						if (ptime > 0) {
+							switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate, ptime);
+						} else {
+							switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate);
+						}
+						already_did[imp->ianacode] = 1;
+						break;
+					}
+				}
+			}
+		} else if (m->m_type == sdp_media_video && m->m_port) {
+			connection = sdp->sdp_connection;
+			if (m->m_connections) {
+				connection = m->m_connections;
+			}
+
+			if (!connection) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+				break;
+			}
+			for (i = 0; i < num_codecs; i++) {
+				const switch_codec_implementation_t *imp = codecs[i];
+				if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
+					continue;
+				}
+				for (map = m->m_rtpmaps; map; map = map->rm_next) {
+					if ( map->rm_pt > 127 || already_did[map->rm_pt]) {
+						continue;
+					}
+
+					if (map->rm_pt < 96) {
+						match = (map->rm_pt == imp->ianacode) ? 1 : 0;
+					} else {
+						if(map->rm_encoding) {
+							match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
+						} else {
+							match = 0;
+						}
+					}
+
+					if (match) {
+						if(ptime > 0) {
+							switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate, ptime);
+						} else {
+							switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate);
+						}
+						already_did[imp->ianacode] = 1;
+						break;
+					}
+				}
+			}
+		}
+	}
+	if (buf[0] == ',') {
+		switch_channel_set_variable(channel, "ep_codec_string", buf + 1);
+	}
+}
+
+switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_sdp)
+{
+	sdp_parser_t *parser = NULL;
+	sdp_session_t *sdp;
+	uint8_t match = 0;
+
+	switch_assert(tech_pvt != NULL);
+	switch_assert(r_sdp != NULL);
+
+	if (switch_strlen_zero(r_sdp)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+		
+		if (tech_pvt->num_codecs) {
+			if ((sdp = sdp_session(parser))) {
+				match = sofia_glue_negotiate_sdp(tech_pvt->session, sdp);
+			}
+		}
+		
+		sdp_parser_free(parser);
+	}
+
+	if (match) {
+		if (sofia_glue_tech_choose_port(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+			return SWITCH_STATUS_FALSE;
+		}
+		if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+			return SWITCH_STATUS_FALSE;
+		}
+		switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA");
+		sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+		switch_channel_mark_pre_answered(tech_pvt->channel);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+
+	return SWITCH_STATUS_FALSE;
+}
+
+void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
+{
+	if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) {
+		if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+			const char *stream;
+
+			sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+			switch_channel_presence(tech_pvt->channel, "unknown", "hold", NULL);
+
+			if (tech_pvt->max_missed_hold_packets) {
+				switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets);
+			}
+
+			if (!(stream = switch_channel_get_variable(tech_pvt->channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+				stream = tech_pvt->profile->hold_music;
+			}
+
+			if (stream && strcasecmp(stream, "silence")) {
+				if (!strcasecmp(stream, "indicate_hold")) {
+					switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND);
+					switch_channel_set_flag(tech_pvt->channel, CF_HOLD);
+					switch_ivr_hold_uuid(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), NULL, 0);
+				} else {
+					switch_ivr_broadcast(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), stream, SMF_ECHO_ALEG | SMF_LOOP);
+					switch_yield(250000);
+				}
+			}
+		}
+	} else {
+		if (sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+			sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD);
+		}
+
+		sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
+		
+		if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+			const char *uuid;
+			switch_core_session_t *b_session;
+
+			switch_yield(250000);
+
+			if (tech_pvt->max_missed_packets) {
+				switch_rtp_reset_media_timer(tech_pvt->rtp_session);
+				switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
+			}
+
+			if ((uuid = switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (b_session = switch_core_session_locate(uuid))) {
+				switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
+
+				if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) {
+					switch_ivr_unhold(b_session);
+					switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND);
+					switch_channel_clear_flag(tech_pvt->channel, CF_HOLD);
+				} else {
+					switch_channel_stop_broadcast(b_channel);
+					switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
+				}
+				switch_core_session_rwunlock(b_session);
+			}
+
+			sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+			switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL);
+		}
+	}
+}
+
+uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
+{
+	uint8_t match = 0;
+	switch_payload_t te = 0, cng_pt = 0;
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	sdp_media_t *m;
+	sdp_attribute_t *attr;
+	int first = 0, last = 0;
+	int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
+	int sendonly = 0;
+	int greedy = 0, x = 0, skip = 0, mine = 0;
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	const char *val;
+	const char *crypto = NULL;
+	int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0;
+	int scrooge = 0;
+
+	switch_assert(tech_pvt != NULL);
+
+	greedy = !!sofia_test_pflag(tech_pvt->profile, PFLAG_GREEDY);
+	scrooge = !!sofia_test_pflag(tech_pvt->profile, PFLAG_SCROOGE);
+	
+	if (!greedy || !scrooge) {
+		if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) {
+			if (!strcasecmp(val, "greedy")) {
+				greedy = 1;
+			} else if (!strcasecmp(val, "scrooge")) {
+				scrooge = 1;
+				greedy = 1;
+			}
+		}
+	}
+
+	if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
+
+		if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833) {
+
+			if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
+				tech_pvt->rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
+			}
+		}
+		
+		if (tech_pvt->profile->auto_rtp_bugs & RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833) {
+			if (strstr(tech_pvt->origin, "Sonus_UAC")) {
+				tech_pvt->rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+								  "Hello,\nI see you have a Sonus!\n"
+								  "FYI, Sonus cannot follow the RFC on the proper way to send DTMF.\n"
+								  "Sadly, my creator had to spend several hours figuring this out so I thought you'd like to know that!\n"
+								  "Don't worry, DTMF will work but you may want to ask them to fix it......\n"
+								  );
+			}
+		}
+	}
+
+	if ((m = sdp->sdp_media) && (m->m_mode == sdp_sendonly || m->m_mode == sdp_inactive)) {
+		sendonly = 2;			/* global sendonly always wins */
+	}
+
+	for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
+		if (switch_strlen_zero(attr->a_name)) {
+			continue;
+		}
+
+		if (!strcasecmp(attr->a_name, "sendonly") || !strcasecmp(attr->a_name, "inactive")) {
+			sendonly = 1;
+		} else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendrecv")) {
+			sendonly = 0;
+		} else if (!strcasecmp(attr->a_name, "ptime")) {
+			dptime = atoi(attr->a_value);
+		} else if (!strcasecmp(attr->a_name, "maxptime")) {
+			dmaxptime = atoi(attr->a_value);
+		}
+	}
+
+	if (!tech_pvt->hold_laps) {
+		tech_pvt->hold_laps++;
+		sofia_glue_toggle_hold(tech_pvt, sendonly);
+	}
+
+	for (m = sdp->sdp_media; m; m = m->m_next) {
+		sdp_connection_t *connection;
+
+		ptime = dptime;
+		maxptime = dmaxptime;
+
+		if (m->m_proto == sdp_proto_srtp) {
+			got_savp++;
+		} else if (m->m_proto == sdp_proto_rtp) {
+			got_avp++;
+		} else if (m->m_proto == sdp_proto_udptl) {
+			got_udptl++;
+		}
+
+		if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
+			switch_t38_options_t *t38_options = switch_core_session_alloc(tech_pvt->session, sizeof(switch_t38_options_t));
+			
+			for (attr = m->m_attributes; attr; attr = attr->a_next) {
+				if (!strcasecmp(attr->a_name, "T38MaxBitRate") && attr->a_value) { 
+					t38_options->T38MaxBitRate = (uint32_t) atoi(attr->a_value);
+				} else  if (!strcasecmp(attr->a_name, "T38FaxFillBitRemoval")) {
+					t38_options->T38FaxFillBitRemoval = SWITCH_TRUE;
+				} else  if (!strcasecmp(attr->a_name, "T38FaxTranscodingMMR")) {
+					t38_options->T38FaxTranscodingMMR = SWITCH_TRUE;
+				} else  if (!strcasecmp(attr->a_name, "T38FaxTranscodingJBIG")) {
+					t38_options->T38FaxTranscodingJBIG = SWITCH_TRUE;
+				} else  if (!strcasecmp(attr->a_name, "T38FaxRateManagement") && attr->a_value) {
+					t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+				} else  if (!strcasecmp(attr->a_name, "T38FaxMaxBuffer") && attr->a_value) {
+					t38_options->T38FaxMaxBuffer = (uint32_t) atoi(attr->a_value);
+				} else  if (!strcasecmp(attr->a_name, "T38FaxMaxDatagram") && attr->a_value) {
+					t38_options->T38FaxMaxDatagram = (uint32_t) atoi(attr->a_value);
+				} else  if (!strcasecmp(attr->a_name, "T38FaxUdpEC") && attr->a_value) {
+					t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+				} else  if (!strcasecmp(attr->a_name, "T38VendorInfo") && attr->a_value) {
+					t38_options->T38VendorInfo = switch_core_session_strdup(tech_pvt->session, attr->a_value);
+				}
+			}
+
+			switch_channel_set_variable(tech_pvt->channel, "has_t38", "true");
+			switch_channel_set_private(tech_pvt->channel, "t38_options", t38_options);
+
+			//switch_channel_set_flag(tech_pvt->channel, CF_PROXY_MEDIA);
+			//switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA);
+
+		} else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
+			sdp_rtpmap_t *map;
+
+			for (attr = m->m_attributes; attr; attr = attr->a_next) {
+				if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
+					ptime = atoi(attr->a_value);
+				} else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
+					maxptime = atoi(attr->a_value);
+				} else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !switch_strlen_zero(attr->a_value)) {
+					int crypto_tag;
+
+					if (m->m_proto != sdp_proto_srtp) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "a=crypto in RTP/AVP, refer to rfc3711\n");
+						match = 0;
+						goto done;
+					}
+
+					crypto = attr->a_value;
+					crypto_tag = atoi(crypto);
+
+					if (tech_pvt->remote_crypto_key && switch_rtp_ready(tech_pvt->rtp_session)) {
+						if (crypto_tag && crypto_tag == tech_pvt->crypto_tag) {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Existing key is still valid.\n");
+						} else {
+							const char *a = switch_stristr("AES", tech_pvt->remote_crypto_key);
+							const char *b = switch_stristr("AES", crypto);
+
+							/* Change our key every time we can */
+							if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
+								switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
+								sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
+								switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type,
+														  tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
+							} else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
+								switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
+								sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
+								switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type,
+														  tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
+							} else {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
+							}
+														
+							if (a && b && !strncasecmp(a, b, 23)) {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto);
+								tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
+								tech_pvt->crypto_tag = crypto_tag;
+								
+								if (switch_rtp_ready(tech_pvt->rtp_session) && sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+									sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
+									switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt->crypto_tag,
+															  tech_pvt->crypto_type, tech_pvt->remote_raw_key, SWITCH_RTP_KEY_LEN);
+								}
+								got_crypto++;
+							} else {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring unacceptable key\n");
+							}
+						}
+					} else if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+						tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", tech_pvt->remote_crypto_key);
+						tech_pvt->crypto_tag = crypto_tag;
+						got_crypto++;
+
+						if (switch_strlen_zero(tech_pvt->local_crypto_key)) {
+							if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
+								switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
+								sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
+							} else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
+								switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
+								sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
+							} else {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
+							}
+						}
+					}
+				}
+			}
+
+			if (got_crypto && !got_avp) {
+				switch_channel_set_variable(tech_pvt->channel, SOFIA_CRYPTO_MANDATORY_VARIABLE, "true");
+				switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE, "true");
+			}
+
+			connection = sdp->sdp_connection;
+			if (m->m_connections) {
+				connection = m->m_connections;
+			}
+
+			if (!connection) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+				match = 0;
+				break;
+			}
+
+		  greed:
+			x = 0;
+
+			if (tech_pvt->rm_encoding) {
+				for (map = m->m_rtpmaps; map; map = map->rm_next) {
+					if (map->rm_pt < 96) {
+						match = (map->rm_pt == tech_pvt->pt) ? 1 : 0;
+					} else {
+						match = strcasecmp(switch_str_nil(map->rm_encoding), tech_pvt->iananame) ? 0 : 1;
+					}
+
+					if (match && connection->c_address && tech_pvt->remote_sdp_audio_ip && 
+						!strcmp(connection->c_address, tech_pvt->remote_sdp_audio_ip) && m->m_port == tech_pvt->remote_sdp_audio_port) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Our existing sdp is still good [%s %s:%d], let's keep it.\n",
+										  tech_pvt->rm_encoding, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+						got_audio = 1;
+						break;
+					}
+				}
+			}
+
+
+
+			for (map = m->m_rtpmaps; map; map = map->rm_next) {
+				int32_t i;
+				uint32_t near_rate = 0;
+				const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
+				const char *rm_encoding;
+
+				if (x++ < skip) {
+					continue;
+				}
+
+				if (!(rm_encoding = map->rm_encoding)) {
+					rm_encoding = "";
+				}
+
+				if (!te && !strcasecmp(rm_encoding, "telephone-event")) {
+					te = tech_pvt->te = (switch_payload_t) map->rm_pt;
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set 2833 dtmf payload to %u\n", te);
+					if (tech_pvt->rtp_session) {
+						switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
+					}
+				}
+
+				if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && !cng_pt && !strcasecmp(rm_encoding, "CN")) {
+					cng_pt = (switch_payload_t) map->rm_pt;
+					if (tech_pvt->rtp_session) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
+						switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
+					}
+				}
+
+				if (match) {
+					if (te && cng_pt) {
+						break;
+					}
+					continue;
+				}
+
+				if (greedy) {
+					first = mine;
+					last = first + 1;
+				} else {
+					first = 0;
+					last = tech_pvt->num_codecs;
+				}
+				
+				if (maxptime && (!ptime || ptime > maxptime)) {
+					ptime = maxptime;
+				}
+
+				for (i = first; i < last && i < tech_pvt->num_codecs; i++) {
+					const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+					uint32_t codec_rate = imp->samples_per_second;
+					if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+						continue;
+					}
+
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d]/[%s:%d:%u:%d]\n",
+									  rm_encoding, map->rm_pt, (int) map->rm_rate, ptime,
+									  imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000);
+					if (map->rm_pt < 96) {
+						match = (map->rm_pt == imp->ianacode) ? 1 : 0;
+					} else {
+						match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
+					}
+
+					if (match) {
+						if (scrooge) {
+							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
+											  "Bah HUMBUG! Sticking with %s@%uh@%ui\n", 
+											  imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000);
+						} else {
+							if ((ptime && ptime * 1000 != imp->microseconds_per_packet) || 
+								map->rm_rate != codec_rate) {
+								near_rate = map->rm_rate;
+								near_match = imp;
+								match = 0;
+								continue;
+							}
+						}
+						mimp = imp;
+						break;
+					} else {
+						match = 0;
+					}
+				}
+
+				if (!match && near_match) {
+					const switch_codec_implementation_t *search[1];
+					char *prefs[1];
+					char tmp[80];
+					int num;
+					
+					switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui", near_match->iananame, near_rate ? near_rate : near_match->samples_per_second, ptime);
+					
+					prefs[0] = tmp;
+					num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
+					
+					if (num) {
+						mimp = search[0];
+					} else {
+						mimp = near_match;
+					}
+					
+					if (!maxptime || mimp->microseconds_per_packet / 1000 <= maxptime) {
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Substituting codec %s@%ui@%uh\n",
+										  mimp->iananame, mimp->microseconds_per_packet / 1000, mimp->samples_per_second);
+						match = 1;
+					} else {
+						mimp = NULL;
+						match = 0;
+					}
+					
+				}
+
+				if (!match && greedy) {
+					skip++;
+					continue;
+				}
+
+				if (mimp) {
+					char tmp[50];
+					tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) map->rm_encoding);
+					tech_pvt->iananame = switch_core_session_strdup(session, (char *) mimp->iananame);
+					tech_pvt->pt = (switch_payload_t) map->rm_pt;
+					tech_pvt->rm_rate = map->rm_rate;
+					if (!strcasecmp((char *) mimp->iananame, "ilbc") && switch_strlen_zero((char*)map->rm_fmtp)) {
+						/* default to 30 when no mode is defined for ilbc ONLY */
+						tech_pvt->codec_ms = 30;
+					} else {
+						tech_pvt->codec_ms = mimp->microseconds_per_packet / 1000;
+					}
+					tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address);
+					tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
+					tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
+					tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt;
+					switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+					switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+					switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+
+				}
+
+				if (match) {
+					if (sofia_glue_tech_set_codec(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) {
+						match = 0;
+					}
+				}
+			}
+
+			if (!match && greedy && mine < tech_pvt->num_codecs) {
+				mine++;
+				skip = 0;
+				goto greed;
+			}
+
+		} else if (m->m_type == sdp_media_video && m->m_port) {
+			sdp_rtpmap_t *map;
+			const char *rm_encoding;
+			int framerate = 0;
+			const switch_codec_implementation_t *mimp = NULL;
+			int vmatch = 0, i;
+			switch_channel_set_variable(tech_pvt->channel, "video_possible", "true");
+
+			connection = sdp->sdp_connection;
+			if (m->m_connections) {
+				connection = m->m_connections;
+			}
+
+			if (!connection) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+				match = 0;
+				break;
+			}
+
+			for (map = m->m_rtpmaps; map; map = map->rm_next) {
+
+				for (attr = m->m_attributes; attr; attr = attr->a_next) {
+					if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) {
+						framerate = atoi(attr->a_value);
+					}
+				}
+				if (!(rm_encoding = map->rm_encoding)) {
+					rm_encoding = "";
+				}
+
+				for (i = 0; i < tech_pvt->num_codecs; i++) {
+					const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+					if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+						continue;
+					}
+
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n",
+									  rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
+					if (map->rm_pt < 96) {
+						vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0;
+					} else {
+						vmatch = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
+					}
+
+
+					if (vmatch && (map->rm_rate == imp->samples_per_second)) {
+						mimp = imp;
+						break;
+					} else {
+						vmatch = 0;
+					}
+				}
+
+
+				if (mimp) {
+					if ((tech_pvt->video_rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
+						char tmp[50];
+						tech_pvt->video_pt = (switch_payload_t) map->rm_pt;
+						tech_pvt->video_rm_rate = map->rm_rate;
+						tech_pvt->video_codec_ms = mimp->microseconds_per_packet / 1000;
+						tech_pvt->remote_sdp_video_ip = switch_core_session_strdup(session, (char *) connection->c_address);
+						tech_pvt->video_rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
+						tech_pvt->remote_sdp_video_port = (switch_port_t) m->m_port;
+						tech_pvt->video_agreed_pt = (switch_payload_t) map->rm_pt;
+						switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_video_port);
+						switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+						switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
+						switch_channel_set_variable(tech_pvt->channel, "sip_video_fmtp", tech_pvt->video_rm_fmtp);
+						switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->video_agreed_pt);
+						switch_channel_set_variable(tech_pvt->channel, "sip_video_pt", tmp);
+						sofia_glue_check_video_codecs(tech_pvt);
+						break;
+					} else {
+						vmatch = 0;
+					}
+				}
+			}
+		}
+	}
+	
+ done:
+	tech_pvt->cng_pt = cng_pt;
+	sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
+
+	return match;
+}
+
+/* map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 */
+switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status)
+{
+	switch (status) {
+	case 200:
+		return SWITCH_CAUSE_NORMAL_CLEARING;
+	case 401:
+	case 402:
+	case 403:
+	case 407:
+	case 603:
+		return SWITCH_CAUSE_CALL_REJECTED;
+	case 404:
+	case 485:
+	case 604:
+		return SWITCH_CAUSE_NO_ROUTE_DESTINATION;
+	case 408:
+	case 504:
+		return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
+	case 410:
+		return SWITCH_CAUSE_NUMBER_CHANGED;
+	case 413:
+	case 414:
+	case 416:
+	case 420:
+	case 421:
+	case 423:
+	case 505:
+	case 513:
+		return SWITCH_CAUSE_INTERWORKING;
+	case 480:
+		return SWITCH_CAUSE_NO_USER_RESPONSE;
+	case 400:
+	case 481:
+	case 500:
+	case 503:
+		return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE;
+	case 486:
+	case 600:
+		return SWITCH_CAUSE_USER_BUSY;
+	case 484:
+		return SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+	case 488:
+	case 606:
+		return SWITCH_CAUSE_INCOMPATIBLE_DESTINATION;
+	case 502:
+		return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
+	case 405:
+		return SWITCH_CAUSE_SERVICE_UNAVAILABLE;
+	case 406:
+	case 415:
+	case 501:
+		return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED;
+	case 482:
+	case 483:
+		return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR;
+	case 487:
+		return SWITCH_CAUSE_ORIGINATOR_CANCEL;
+	default:
+		return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
+	}
+}
+
+void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp)
+{
+	const char *val;
+	switch_core_session_t *other_session;
+	switch_channel_t *other_channel;
+
+	if ((val = switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE))
+		&& (other_session = switch_core_session_locate(val))) {
+		other_channel = switch_core_session_get_channel(other_session);
+		switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
+
+		if (!sofia_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && (switch_channel_test_flag(other_channel, CF_OUTBOUND) &&
+																switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND) &&
+																switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE))) {
+			switch_ivr_nomedia(val, SMF_FORCE);
+			sofia_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA);
+		}
+		switch_core_session_rwunlock(other_session);
+	}
+}
+
+char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup)
+{
+	char *url = NULL, *e;
+
+	if ((url = strchr(buf, '<')) && (e = strchr(url, '>'))) {
+		url++;
+		if (to_dup) {
+			url = strdup(url);
+			e = strchr(url, '>');
+		}
+
+		*e = '\0';
+	} else {
+		if (to_dup) {
+			url = strdup(buf);
+		} else {
+			url = buf;
+		}
+	}
+	return url;
+}
+
+sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, const char *key)
+{
+	sofia_profile_t *profile;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	if ((profile = (sofia_profile_t *) switch_core_hash_find(mod_sofia_globals.profile_hash, key))) {
+		if (!sofia_test_pflag(profile, PFLAG_RUNNING)) {
+#ifdef SOFIA_DEBUG_RWLOCKS
+			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is not running\n", profile->name);
+#endif
+			profile = NULL;
+			goto done;
+		}
+		if (switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) {
+#ifdef SOFIA_DEBUG_RWLOCKS
+			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is locked\n", profile->name);
+#endif
+			profile = NULL;
+		}
+	} else {
+#ifdef SOFIA_DEBUG_RWLOCKS
+		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is not in the hash\n", key);
+#endif
+	}
+#ifdef SOFIA_DEBUG_RWLOCKS
+	if (profile) {
+		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX LOCK %s\n", profile->name);
+	}
+#endif
+
+  done:
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+	return profile;
+}
+
+void sofia_glue_release_profile__(const char *file, const char *func, int line, sofia_profile_t *profile)
+{
+	if (profile) {
+#ifdef SOFIA_DEBUG_RWLOCKS
+		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX UNLOCK %s\n", profile->name);
+#endif
+		switch_thread_rwlock_unlock(profile->rwlock);
+	}
+}
+
+switch_status_t sofia_glue_add_profile(char *key, sofia_profile_t *profile)
+{
+	switch_status_t status = SWITCH_STATUS_FALSE;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	if (!switch_core_hash_find(mod_sofia_globals.profile_hash, key)) {
+		status = switch_core_hash_insert(mod_sofia_globals.profile_hash, key, profile);
+	}
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+	return status;
+}
+
+void sofia_glue_del_gateway(sofia_gateway_t *gp)
+{
+	if (!gp->deleted) {
+		if (gp->state != REG_STATE_NOREG) {
+			gp->retry = 0;
+			gp->state = REG_STATE_UNREGISTER;
+		}
+
+		gp->deleted = 1;
+	}
+}
+
+void sofia_glue_restart_all_profiles(void) 
+{
+	switch_hash_index_t *hi;
+	const void *var;
+    void *val;
+    sofia_profile_t *pptr;
+	switch_xml_t xml_root;
+	const char *err;
+
+	if ((xml_root = switch_xml_open_root(1, &err))) {
+		switch_xml_free(xml_root);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Reload XML [%s]\n", err);
+	}
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	if (mod_sofia_globals.profile_hash) {
+        for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+			switch_hash_this(hi, &var, NULL, &val);
+            if ((pptr = (sofia_profile_t *) val)) {
+				int rsec = 10;
+				int diff = (int) (switch_epoch_time_now(NULL) - pptr->started);
+				int remain = rsec - diff;
+				if (sofia_test_pflag(pptr, PFLAG_RESPAWN) || !sofia_test_pflag(pptr, PFLAG_RUNNING)) {
+					continue;
+				}
+
+				if (diff < rsec) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+									  "Profile %s must be up for at least %d seconds to stop/restart.\nPlease wait %d second%s\n",
+									  pptr->name, rsec, remain, remain == 1 ? "" : "s");
+					continue;
+				}
+				sofia_set_pflag_locked(pptr, PFLAG_RESPAWN);
+				sofia_clear_pflag_locked(pptr, PFLAG_RUNNING);
+			}
+		}
+	}
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+}
+
+void sofia_glue_del_profile(sofia_profile_t *profile)
+{
+	sofia_gateway_t *gp;
+	char *aliases[512];
+	int i = 0, j = 0;
+	switch_hash_index_t *hi;
+	const void *var;
+	void *val;
+	sofia_profile_t *pptr;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	if (mod_sofia_globals.profile_hash) {
+		for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+			switch_hash_this(hi, &var, NULL, &val);
+			if ((pptr = (sofia_profile_t *) val) && pptr == profile) {
+				aliases[i++] = strdup((char *) var);
+				if (i == 512) {
+					abort();
+				}
+			}
+		}
+
+		for (j = 0; j < i && j < 512; j++) {
+			switch_core_hash_delete(mod_sofia_globals.profile_hash, aliases[j]);
+			free(aliases[j]);
+		}
+
+		for (gp = profile->gateways; gp; gp = gp->next) {
+			switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp->name);
+			switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp->register_from);
+			switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp->register_contact);
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "deleted gateway %s\n", gp->name);
+			profile->gateways = NULL;
+		}
+	}
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+}
+
+int sofia_glue_init_sql(sofia_profile_t *profile)
+{
+	char *test_sql = NULL;
+
+	char reg_sql[] =
+		"CREATE TABLE sip_registrations (\n"
+		"   call_id         VARCHAR(255),\n"
+		"   sip_user        VARCHAR(255),\n"
+		"   sip_host        VARCHAR(255),\n"
+		"   presence_hosts  VARCHAR(255),\n"
+		"   contact         VARCHAR(1024),\n"
+		"   status          VARCHAR(255),\n"
+		"   rpid            VARCHAR(255),\n" 
+		"   expires         INTEGER,\n" 
+		"   user_agent      VARCHAR(255),\n" 
+		"   server_user     VARCHAR(255),\n"
+		"   server_host     VARCHAR(255),\n" 
+		"   profile_name    VARCHAR(255),\n" 
+		"   hostname        VARCHAR(255),\n" 
+		"   network_ip      VARCHAR(255),\n" 
+		"   network_port    VARCHAR(6),\n" 
+		"   sip_username    VARCHAR(255),\n" 
+		"   sip_realm       VARCHAR(255)\n" 
+		");\n";
+
+
+	char pres_sql[] =
+		"CREATE TABLE sip_presence (\n"
+		"   sip_user        VARCHAR(255),\n"
+		"   sip_host        VARCHAR(255),\n"
+		"   status          VARCHAR(255),\n"
+		"   rpid            VARCHAR(255),\n" 
+		"   expires         INTEGER,\n" 
+		"   user_agent      VARCHAR(255),\n" 
+		"   profile_name    VARCHAR(255),\n" 
+		"   hostname        VARCHAR(255),\n" 
+		"   network_ip      VARCHAR(255),\n" 
+		"   network_port    VARCHAR(6)\n" 
+		");\n";
+
+	char dialog_sql[] =
+		"CREATE TABLE sip_dialogs (\n"
+		"   call_id         VARCHAR(255),\n"
+		"   uuid            VARCHAR(255),\n"
+		"   sip_to_user     VARCHAR(255),\n"
+		"   sip_to_host     VARCHAR(255),\n"
+		"   sip_from_user   VARCHAR(255),\n"
+		"   sip_from_host   VARCHAR(255),\n"
+		"   contact_user    VARCHAR(255),\n"
+		"   contact_host    VARCHAR(255),\n"
+		"   state           VARCHAR(255),\n" 
+		"   direction       VARCHAR(255),\n" 
+		"   user_agent      VARCHAR(255),\n" 
+		"   profile_name    VARCHAR(255),\n"
+        "   hostname        VARCHAR(255)\n"
+		");\n";
+
+	char sub_sql[] =
+		"CREATE TABLE sip_subscriptions (\n"
+		"   proto           VARCHAR(255),\n"
+		"   sip_user        VARCHAR(255),\n"
+		"   sip_host        VARCHAR(255),\n"
+		"   sub_to_user     VARCHAR(255),\n"
+		"   sub_to_host     VARCHAR(255),\n"
+		"   presence_hosts  VARCHAR(255),\n"
+		"   event           VARCHAR(255),\n"
+		"   contact         VARCHAR(1024),\n"
+		"   call_id         VARCHAR(255),\n"
+		"   full_from       VARCHAR(255),\n"
+		"   full_via        VARCHAR(255),\n"
+		"   expires         INTEGER,\n" 
+		"   user_agent      VARCHAR(255),\n" 
+		"   accept          VARCHAR(255),\n"
+		"   profile_name    VARCHAR(255),\n"
+		"   hostname        VARCHAR(255),\n"
+		"   network_port    VARCHAR(6),\n"
+		"   network_ip      VARCHAR(255)\n"
+		");\n";
+
+	char auth_sql[] = 
+		"CREATE TABLE sip_authentication (\n" 
+		"   nonce           VARCHAR(255),\n" 
+		"   expires         INTEGER," 
+		"   profile_name    VARCHAR(255),\n"
+		"   hostname        VARCHAR(255)\n"
+		");\n";
+
+	/* should we move this glue to sofia_sla or keep it here where all db init happens? XXX MTK */
+	char shared_appearance_sql[] = 
+		"CREATE TABLE sip_shared_appearance_subscriptions (\n"
+		"   subscriber        VARCHAR(255),\n"
+		"   call_id           VARCHAR(255),\n"
+		"   aor               VARCHAR(255),\n"
+		"   profile_name      VARCHAR(255),\n"
+		"   hostname          VARCHAR(255),\n"
+		"   contact_str       VARCHAR(255),\n"
+		"   network_ip        VARCHAR(255)\n" 
+		");\n";
+
+	char shared_appearance_dialogs_sql[] = 
+		"CREATE TABLE sip_shared_appearance_dialogs (\n"
+		"   profile_name      VARCHAR(255),\n"
+		"   hostname          VARCHAR(255),\n"
+		"   contact_str       VARCHAR(255),\n"
+		"   call_id           VARCHAR(255),\n"
+		"   network_ip        VARCHAR(255),\n"
+		"   expires           INTEGER\n"
+		");\n";
+
+	if (switch_odbc_available() && profile->odbc_dsn) {
+		int x;
+		char *indexes[] = {
+			"create index sr_call_id on sip_registrations (call_id)",
+			"create index sr_sip_user on sip_registrations (sip_user)",
+			"create index sr_sip_host on sip_registrations (sip_host)",
+			"create index sr_profile_name on sip_registrations (profile_name)",
+			"create index sr_presence_hosts on sip_registrations (presence_hosts)",
+			"create index sr_contact on sip_registrations (contact)",
+			"create index sr_expires on sip_registrations (expires)",
+			"create index sr_hostname on sip_registrations (hostname)",
+			"create index sr_status on sip_registrations (status)",
+			"create index sr_network_ip on sip_registrations (network_ip)",
+			"create index sr_network_port on sip_registrations (network_port)",
+			"create index sr_sip_username on sip_registrations (sip_username)",
+			"create index sr_sip_realm on sip_registrations (sip_realm)",
+			"create index ss_call_id on sip_subscriptions (call_id)",
+			"create index ss_hostname on sip_subscriptions (hostname)",
+			"create index ss_hostname on sip_subscriptions (network_ip)",
+			"create index ss_sip_user on sip_subscriptions (sip_user)",
+			"create index ss_sip_host on sip_subscriptions (sip_host)",
+			"create index ss_presence_hosts on sip_subscriptions (presence_hosts)",
+			"create index ss_event on sip_subscriptions (event)",
+			"create index ss_proto on sip_subscriptions (proto)",
+			"create index ss_sub_to_user on sip_subscriptions (sub_to_user)",
+			"create index ss_sub_to_host on sip_subscriptions (sub_to_host)",
+			"create index sd_uuid on sip_dialogs (uuid)",
+			"create index sd_hostname on sip_dialogs (hostname)",
+			"create index sp_hostname on sip_presence (hostname)",
+			"create index sa_nonce on sip_authentication (nonce)",
+			"create index sa_hostname on sip_authentication (hostname)",
+			"create index ssa_hostname on sip_shared_appearance_subscriptions (hostname)",
+			"create index ssa_hostname on sip_shared_appearance_subscriptions (network_ip)",
+			"create index ssa_subscriber on sip_shared_appearance_subscriptions (subscriber)",
+			"create index ssa_profile_name on sip_shared_appearance_subscriptions (profile_name)",
+			"create index ssa_aor on sip_shared_appearance_subscriptions (aor)",
+			"create index ssd_profile_name on sip_shared_appearance_dialogs (profile_name)",
+			"create index ssd_hostname on sip_shared_appearance_dialogs (hostname)",
+			"create index ssd_contact_str on sip_shared_appearance_dialogs (contact_str)",
+			"create index ssd_call_id on sip_shared_appearance_dialogs (call_id)",
+			"create index ssd_expires on sip_shared_appearance_dialogs (expires)",
+			NULL	
+		};
+
+		if (!(profile->master_odbc = switch_odbc_handle_new(profile->odbc_dsn, profile->odbc_user, profile->odbc_pass))) {
+			return 0;
+		}
+		if (switch_odbc_handle_connect(profile->master_odbc) != SWITCH_ODBC_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Connecting ODBC DSN: %s\n", profile->odbc_dsn);
+			return 0;
+		}
+
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected ODBC DSN: %s\n", profile->odbc_dsn);
+		
+		test_sql = switch_mprintf("delete from sip_registrations where (contact like '%%TCP%%' "
+								  "or status like '%%TCP%%' or status like '%%TLS%%') and hostname='%q' "
+								  "and network_ip!='-1' and network_port!='-1' and sip_username != '-1'", 
+								  mod_sofia_globals.hostname);
+
+		if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+			switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_registrations", NULL);
+			switch_odbc_handle_exec(profile->master_odbc, reg_sql, NULL);
+		}
+		free(test_sql);
+
+
+		test_sql = switch_mprintf("delete from sip_subscriptions where hostname='%q' and network_ip!='-1' and network_port!='-1'", mod_sofia_globals.hostname);
+
+		if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+			switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_subscriptions", NULL);
+			switch_odbc_handle_exec(profile->master_odbc, sub_sql, NULL);
+		}
+
+		free(test_sql);
+		test_sql = switch_mprintf("delete from sip_dialogs where hostname='%q'", mod_sofia_globals.hostname);
+
+		if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+			switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_dialogs", NULL);
+			switch_odbc_handle_exec(profile->master_odbc, dialog_sql, NULL);
+		}
+
+		test_sql = switch_mprintf("delete from sip_presence where hostname='%q'", mod_sofia_globals.hostname);
+
+		if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+			switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_presence", NULL);
+			switch_odbc_handle_exec(profile->master_odbc, pres_sql, NULL);
+		}
+
+		free(test_sql);
+		test_sql = switch_mprintf("delete from sip_authentication where hostname='%q'", mod_sofia_globals.hostname);
+
+		if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+			switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_authentication", NULL);
+			switch_odbc_handle_exec(profile->master_odbc, auth_sql, NULL);
+		}
+		free(test_sql);
+
+		test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where contact_str='' or hostname='%q' and network_ip!='-1'",
+								  mod_sofia_globals.hostname);
+		if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+			switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_shared_appearance_subscriptions", NULL);
+			switch_odbc_handle_exec(profile->master_odbc, shared_appearance_sql, NULL);
+		}
+		free(test_sql);
+
+
+		test_sql = switch_mprintf("delete from sip_shared_appearance_dialogs where contact_str='' or hostname='%q' and network_ip!='-1'",
+								  mod_sofia_globals.hostname);
+		if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+			switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_shared_appearance_dialogs", NULL);
+			switch_odbc_handle_exec(profile->master_odbc, shared_appearance_dialogs_sql, NULL);
+		}
+		free(test_sql);
+
+
+		for (x = 0; indexes[x]; x++) {
+			switch_odbc_handle_exec(profile->master_odbc, indexes[x], NULL);
+		}
+
+
+	} else if (profile->odbc_dsn) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
+	} else {
+		if (!(profile->master_db = switch_core_db_open_file(profile->dbname))) {
+			return 0;
+		}
+
+		test_sql = switch_mprintf("delete from sip_registrations where (contact like '%%TCP%%' "
+								  "or status like '%%TCP%%' or status like '%%TLS%%') and hostname='%q' "
+								  "and network_ip!='-1' and network_port!='-1' and sip_username != '-1'",
+								  mod_sofia_globals.hostname);
+		
+		switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_registrations", reg_sql);
+		free(test_sql);
+
+		test_sql = switch_mprintf("delete from sip_subscriptions where hostname='%q' and network_ip!='-1'", mod_sofia_globals.hostname);
+		switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_subscriptions", sub_sql);
+		free(test_sql);
+
+		test_sql = switch_mprintf("delete from sip_dialogs where hostname='%q'", mod_sofia_globals.hostname);
+		switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_dialogs", dialog_sql);
+		free(test_sql);
+
+		test_sql = switch_mprintf("delete from sip_presence where hostname='%q'", mod_sofia_globals.hostname);
+		switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_presence", pres_sql);
+		free(test_sql);
+
+		test_sql = switch_mprintf("delete from sip_authentication where hostname='%q'", mod_sofia_globals.hostname);
+		switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_authentication", auth_sql);
+		free(test_sql);
+
+		
+		test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where contact_str = '' or hostname='%q' and network_ip!='-1'",
+								  mod_sofia_globals.hostname);
+		switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_shared_appearance_subscriptions", shared_appearance_sql);
+		free(test_sql);
+
+		test_sql = switch_mprintf("delete from sip_shared_appearance_dialogs where contact_str = '' or hostname='%q'", mod_sofia_globals.hostname);
+		switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_shared_appearance_dialogs", shared_appearance_dialogs_sql);
+		free(test_sql);
+		
+		switch_core_db_exec(profile->master_db, "create index if not exists ssa_hostname on sip_shared_appearance_subscriptions (hostname)", 
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssa_subscriber on sip_shared_appearance_subscriptions (subscriber)", 
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssa_profile_name on sip_shared_appearance_subscriptions (profile_name)", 
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssa_aor on sip_shared_appearance_subscriptions (aor)", NULL, NULL, NULL);
+		
+
+		switch_core_db_exec(profile->master_db, "create index if not exists ssd_profile_name on sip_shared_appearance_dialogs (profile_name)", 
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssd_hostname on sip_shared_appearance_dialogs (hostname)", 
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssd_hostname on sip_shared_appearance_dialogs (network_ip)", 
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssd_contact_str on sip_shared_appearance_dialogs (contact_str)",  
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssd_call_id on sip_shared_appearance_dialogs (call_id)",  
+							NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ssd_expires on sip_shared_appearance_dialogs (expires)", 
+							NULL, NULL, NULL);
+		
+
+
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_call_id on sip_registrations (call_id)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_sip_user on sip_registrations (sip_user)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_sip_host on sip_registrations (sip_host)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_profile_name on sip_registrations (profile_name)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_presence_hosts on sip_registrations (presence_hosts)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_contact on sip_registrations (contact)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_expires on sip_registrations (expires)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_hostname on sip_registrations (hostname)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_status on sip_registrations (status)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_network_ip on sip_registrations (network_ip)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_network_port on sip_registrations (network_port)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_sip_username on sip_registrations (sip_username)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sr_sip_realm on sip_registrations (sip_realm)", NULL, NULL, NULL);
+
+
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_call_id on sip_subscriptions (call_id)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_hostname on sip_subscriptions (hostname)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_hostname on sip_subscriptions (network_ip)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_sip_user on sip_subscriptions (sip_user)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_sip_host on sip_subscriptions (sip_host)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_presence_hosts on sip_subscriptions (presence_hosts)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_event on sip_subscriptions (event)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_proto on sip_subscriptions (proto)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_sub_to_user on sip_subscriptions (sub_to_user)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists ss_sub_to_host on sip_subscriptions (sub_to_host)", NULL, NULL, NULL);
+
+		switch_core_db_exec(profile->master_db, "create index if not exists sd_uuid on sip_dialogs (uuid)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sd_hostname on sip_dialogs (hostname)", NULL, NULL, NULL);
+
+		switch_core_db_exec(profile->master_db, "create index if not exists sp_hostname on sip_presence (hostname)", NULL, NULL, NULL);
+
+		switch_core_db_exec(profile->master_db, "create index if not exists sa_nonce on sip_authentication (nonce)", NULL, NULL, NULL);
+		switch_core_db_exec(profile->master_db, "create index if not exists sa_hostname on sip_authentication (hostname)", NULL, NULL, NULL);
+	}
+
+	if (switch_odbc_available() && profile->odbc_dsn) {
+		return profile->master_odbc ? 1 : 0;
+	}
+
+	return profile->master_db ? 1 : 0;
+}
+
+void sofia_glue_sql_close(sofia_profile_t *profile)
+{
+	if (switch_odbc_available() && profile->master_odbc) {
+		switch_odbc_handle_destroy(&profile->master_odbc);
+	} else {
+		switch_core_db_close(profile->master_db);
+		profile->master_db = NULL;
+	}
+}
+
+void sofia_glue_execute_sql(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic)
+{
+	switch_status_t status = SWITCH_STATUS_FALSE;
+	char *d_sql = NULL, *sql;
+
+	switch_assert(sqlp && *sqlp);
+	sql = *sqlp;
+
+	if (profile->sql_queue) {
+		if (sql_already_dynamic) {
+			d_sql = sql;
+		} else {
+			d_sql = strdup(sql);
+		}
+
+		switch_assert(d_sql);
+		if ((status = switch_queue_trypush(profile->sql_queue, d_sql)) == SWITCH_STATUS_SUCCESS) {
+			d_sql = NULL;
+		}
+	} else if (sql_already_dynamic) {
+		d_sql = sql;
+	}
+
+	if (status != SWITCH_STATUS_SUCCESS) {
+		sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex);
+	}
+
+	switch_safe_free(d_sql);
+
+	if (sql_already_dynamic) {
+		*sqlp = NULL;
+	}
+}
+
+void sofia_glue_actually_execute_sql(sofia_profile_t *profile, switch_bool_t master, char *sql, switch_mutex_t *mutex)
+{
+	switch_core_db_t *db;
+
+	if (mutex) {
+		switch_mutex_lock(mutex);
+	}
+
+	if (switch_odbc_available() && profile->odbc_dsn) {
+		switch_odbc_statement_handle_t stmt;
+		if (switch_odbc_handle_exec(profile->master_odbc, sql, &stmt) != SWITCH_ODBC_SUCCESS) {
+			char *err_str;
+			err_str = switch_odbc_handle_get_error(profile->master_odbc, stmt);
+			if (!switch_strlen_zero(err_str)) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, err_str);
+			}
+			switch_safe_free(err_str);
+		}
+		switch_odbc_statement_handle_free(&stmt);
+	} else if (profile->odbc_dsn) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
+	} else {
+		if (master) {
+			db = profile->master_db;
+		} else {
+			if (!(db = switch_core_db_open_file(profile->dbname))) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+				goto end;
+			}
+		}
+		switch_core_db_persistant_execute(db, sql, 1);
+
+		if (!master) {
+			switch_core_db_close(db);
+		}
+	}
+
+  end:
+	if (mutex) {
+		switch_mutex_unlock(mutex);
+	}
+}
+
+switch_bool_t sofia_glue_execute_sql_callback(sofia_profile_t *profile,
+											  switch_bool_t master, switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata)
+{
+	switch_bool_t ret = SWITCH_FALSE;
+	switch_core_db_t *db;
+	char *errmsg = NULL;
+
+	if (mutex) {
+		switch_mutex_lock(mutex);
+	}
+
+
+	if (switch_odbc_available() && profile->odbc_dsn) {
+		switch_odbc_handle_callback_exec(profile->master_odbc, sql, callback, pdata);
+	} else if (profile->odbc_dsn) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
+	} else {
+
+		if (master) {
+			db = profile->master_db;
+		} else {
+			if (!(db = switch_core_db_open_file(profile->dbname))) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+				goto end;
+			}
+		}
+
+		switch_core_db_exec(db, sql, callback, pdata, &errmsg);
+
+		if (errmsg) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
+			free(errmsg);
+		}
+
+		if (!master && db) {
+			switch_core_db_close(db);
+		}
+	}
+
+  end:
+	if (mutex) {
+		switch_mutex_unlock(mutex);
+	}
+	return ret;
+}
+
+static char *sofia_glue_execute_sql2str_odbc(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len)
+{
+	char *ret = NULL;
+
+	if (switch_odbc_handle_exec_string(profile->master_odbc, sql, resbuf, len) == SWITCH_ODBC_SUCCESS) {
+		ret = resbuf;
+	}
+
+	return ret;
+}
+
+
+char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len)
+{
+	switch_core_db_t *db;
+	switch_core_db_stmt_t *stmt;
+	char *ret = NULL;
+
+	if (switch_odbc_available() && profile->odbc_dsn) {
+		return sofia_glue_execute_sql2str_odbc(profile, mutex, sql, resbuf, len);
+	}
+
+	if (mutex) {
+		switch_mutex_lock(mutex);
+	}
+
+	if (!(db = switch_core_db_open_file(profile->dbname))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+		goto end;
+	}
+
+	if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error [%s]!\n", sql);
+		goto fail;
+	} else {
+		int running = 1;
+		int colcount;
+
+		while (running < 5000) {
+			int result = switch_core_db_step(stmt);
+			const unsigned char *txt;
+
+			if (result == SWITCH_CORE_DB_ROW) {
+				if ((colcount = switch_core_db_column_count(stmt)) > 0) {
+					if ((txt = switch_core_db_column_text(stmt, 0))) {
+						switch_copy_string(resbuf, (char *) txt, len);
+						ret = resbuf;
+					} else {
+						goto fail;
+					}
+				}
+				break;
+			} else if (result == SWITCH_CORE_DB_BUSY) {
+				running++;
+				switch_cond_next();
+				continue;
+			}
+			break;
+		}
+
+		switch_core_db_finalize(stmt);
+	}
+
+  fail:
+	switch_core_db_close(db);
+
+  end:
+	if (mutex) {
+		switch_mutex_unlock(mutex);
+	}
+
+	return ret;
+}
+
+int sofia_glue_get_user_host(char *in, char **user, char **host)
+{
+	char *p, *h, *u = in;
+
+	if (user) {
+		*user = NULL;
+	}
+
+	*host = NULL;
+
+	/* First isolate the host part from the user part */
+	if ((h = strchr(u, '@'))) {
+		*h++ = '\0';
+	} else {
+		return 0;
+	}
+
+	/* Clean out the user part of its protocol prefix (if any) */
+	if (user && (p = strchr(u, ':'))) {
+		*p++ = '\0';
+		u = p;
+	}
+
+	/* Clean out the host part of any suffix */
+	if ((p = strchr(h, ':'))) {
+		*p = '\0';
+	}
+	
+	if ((p = strchr(h, ';'))) {
+		*p = '\0';
+	}
+	
+	if ((p = strchr(h, ' '))) {
+		*p = '\0';
+	}
+
+	if (user) {
+	*user = u;
+	}
+
+	*host = h;
+
+	return 1;
+}
+
+const char *sofia_glue_strip_proto(const char *uri)
+{
+	char *p;
+
+	if ((p = strchr(uri, ':'))) {
+		return p+1;
+	}
+
+	return uri;
+}
+
+sofia_cid_type_t sofia_cid_name2type(const char *name)
+{
+	if (!strcasecmp(name, "rpid")) {
+		return CID_TYPE_RPID;
+	}
+
+	if (!strcasecmp(name, "pid")) {
+		return CID_TYPE_PID;
+	}
+
+	return CID_TYPE_NONE;
+	
+}
+
+/* all the values of the structure are initialized to NULL  */
+/* in case of failure the function returns NULL */
+/* sofia_destination->route can be NULL */
+sofia_destination_t* sofia_glue_get_destination(char *data)
+{
+	sofia_destination_t *dst = NULL;
+	char *to = NULL;
+	char *contact = NULL;
+    char *route = NULL;
+    char *route_uri = NULL;
+	char *eoc = NULL;
+	char *p = NULL;
+
+	if (switch_strlen_zero(data)) {
+		return NULL;
+	}
+
+	if (!(dst = (sofia_destination_t *)malloc(sizeof(sofia_destination_t)))) {
+		return NULL;
+	}
+
+	/* return a copy of what is in the buffer between the first < and > */
+	if (!(contact = sofia_glue_get_url_from_contact(data, 1))) {
+		goto mem_fail;
+	}
+
+	if((eoc = strstr(contact, ";fs_path="))) {
+		*eoc = '\0';
+
+		if(!(route = strdup(eoc + 9))) {
+			goto mem_fail;
+		}
+
+		for (p = route; p && *p ; p++) {
+			if (*p == '>' || *p == ';') {
+				*p = '\0';
+				break;
+			}
+		}
+
+		switch_url_decode(route);
+
+ 		if (!(route_uri = strdup(route))) {
+			goto mem_fail;
+		}
+		if ((p = strchr(route_uri, ','))) {
+			do {
+				*p = '\0';
+			} while ((--p > route_uri) && *p == ' ');
+		}
+	} 
+	
+	if (!(to = strdup(data))) {
+		goto mem_fail;
+	}
+
+	if((eoc = strstr(to, ";fs_path="))) {
+		*eoc++ = '>';	
+		*eoc = '\0';	
+	}
+	
+	if ((p = strstr(contact, ";fs_"))) {
+		*p = '\0';
+	}
+	
+	dst->contact = contact;
+	dst->to = to;
+	dst->route = route;
+	dst->route_uri = route_uri;
+	return dst;
+
+mem_fail:
+	switch_safe_free(contact);
+	switch_safe_free(to);
+	switch_safe_free(route);
+	switch_safe_free(route_uri);
+	switch_safe_free(dst);
+	return NULL;
+}
+
+void sofia_glue_free_destination(sofia_destination_t *dst)
+{
+	if (dst) {
+		switch_safe_free(dst->contact);
+		switch_safe_free(dst->route);
+		switch_safe_free(dst->route_uri);
+		switch_safe_free(dst->to);
+		switch_safe_free(dst);
+	}
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Copied: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_presence.c (from rev 14389, freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c) (0 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_presence.c	                        (rev 0)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_presence.c	2009-07-27 20:18:20 UTC (rev 14390)
@@ -0,0 +1,2195 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
+ * Paul D. Tinsley <pdt at jackhammer.org>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ *
+ *
+ * sofia_presence.c -- SOFIA SIP Endpoint (presence code)
+ *
+ */
+#include "mod_sofia.h"
+
+#define SUB_OVERLAP 300
+
+static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames);
+static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char **columnNames);
+static int sofia_presence_sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames);
+static int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames);
+static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames);
+
+struct presence_helper {
+	sofia_profile_t *profile;
+	switch_event_t *event;
+	switch_stream_handle_t stream;
+	char last_uuid[512];
+};
+
+switch_status_t sofia_presence_chat_send(const char *proto, const char *from, const char *to, const char *subject,
+										 const char *body, const char *type, const char *hint)
+{
+	char buf[256];
+	char *prof = NULL, *user = NULL, *host = NULL;
+	sofia_profile_t *profile = NULL;
+	char *ffrom = NULL;
+	nua_handle_t *msg_nh;
+	char *contact = NULL;
+	char *dup = NULL;
+	switch_status_t status = SWITCH_STATUS_FALSE;
+	const char *ct = "text/html";
+	sofia_destination_t *dst = NULL;
+
+	if (!to) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing To: header.\n");
+		goto end;
+	}
+
+	if (!switch_strlen_zero(type)) {
+		ct = type;
+	}
+
+	dup = strdup(to);
+	switch_assert(dup);
+	prof = dup;
+
+	/* Do we have a user of the form profile/user[@host]? */
+	if ((user = strchr(prof, '/'))) {
+		*user++ = '\0';
+	} else {
+		user = prof;
+		prof = NULL;
+	}  
+
+	if ((host = strchr(user, '@'))) {
+		*host++ = '\0';
+		if (!prof) prof = host;
+	}
+
+	if (!prof || !(profile = sofia_glue_find_profile(prof))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+						  "Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n", proto, from, to,
+						  body ? body : "[no body]", prof ? prof : "NULL");
+		goto end;
+	}
+
+	if (switch_strlen_zero(host)) {
+		host = profile->domain_name;
+		if (switch_strlen_zero(host)) {
+			host = prof;
+		}
+	}
+	if (!sofia_reg_find_reg_url(profile, user, host, buf, sizeof(buf))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find user. [%s][%s]\n", user, host);
+		goto end;
+	}
+
+	if (!strcasecmp(proto, SOFIA_CHAT_PROTO)) {
+		from = hint;
+	} else {
+		char *fp, *p = NULL;
+
+		fp = strdup(from);
+
+		if (!fp) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
+			goto end;
+		}
+
+		if ((p = strchr(fp, '@'))) {
+			*p++ = '\0';
+		}
+
+		if (switch_strlen_zero(p)) {
+			p = profile->domain_name;
+			if (switch_strlen_zero(p)) {
+				p = host;
+			}
+		}
+
+		ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fp, proto, fp, p);
+
+		from = ffrom;
+		switch_safe_free(fp);
+	}
+	
+	if (!(dst = sofia_glue_get_destination(buf))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
+		goto end;
+	}
+
+	/* sofia_glue is running sofia_overcome_sip_uri_weakness we do not, not sure if it matters */
+
+	status = SWITCH_STATUS_SUCCESS;
+	/* if this cries, add contact here too, change the 1 to 0 and omit the safe_free */
+	msg_nh = nua_handle(profile->nua, NULL, TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
+						SIPTAG_FROM_STR(from), NUTAG_URL(contact),
+						SIPTAG_TO_STR(dst->to), SIPTAG_CONTACT_STR(profile->url),
+						TAG_END());
+	nua_handle_bind(msg_nh, &mod_sofia_globals.destroy_private);
+	nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(body), TAG_END());
+	
+	
+ end:
+	sofia_glue_free_destination(dst);
+	switch_safe_free(contact);
+	switch_safe_free(ffrom);
+	switch_safe_free(dup);
+	if (profile) {
+		switch_thread_rwlock_unlock(profile->rwlock);
+	}
+
+	return status;
+}
+
+void sofia_presence_cancel(void)
+{
+	char *sql;
+	sofia_profile_t *profile;
+	switch_hash_index_t *hi;
+	void *val;
+	struct presence_helper helper = { 0 };
+
+	if (!mod_sofia_globals.profile_hash)
+		return;
+	
+	if ((sql = switch_mprintf(
+							  "select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
+							  "full_via,expires,user_agent,accept,profile_name,network_ip"
+							  ",-1,'unavailable','unavailable' from sip_subscriptions where event='presence' and hostname='%q'", 
+							  mod_sofia_globals.hostname))) {
+		switch_mutex_lock(mod_sofia_globals.hash_mutex);
+		for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+			switch_hash_this(hi, NULL, NULL, &val);
+			profile = (sofia_profile_t *) val;
+			if (profile->pres_type != PRES_TYPE_FULL) {
+				continue;
+			}
+			helper.profile = profile;
+			helper.event = NULL;
+			if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_callback, &helper) != SWITCH_TRUE) {
+				continue;
+			}
+		}
+		switch_safe_free(sql);
+		switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+	}
+}
+
+void sofia_presence_establish_presence(sofia_profile_t *profile)
+{
+
+	if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex,
+										"select sip_user,sip_host,'Registered','unknown','' from sip_registrations",
+										sofia_presence_resub_callback, profile) != SWITCH_TRUE) {
+		return;
+	}
+
+	if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex,
+										"select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions "
+										"where proto='ext' or proto='user' or proto='conf'", sofia_presence_resub_callback, profile) != SWITCH_TRUE) {
+		return;
+	}
+}
+
+char *sofia_presence_translate_rpid(char *in, char *ext)
+{
+	char *r = in;
+
+	if (in && (switch_stristr("null", in))) {
+		in = NULL;
+	}
+
+	if (!in) {
+		in = ext;
+	}
+
+	if (!in) {
+		return NULL;
+	}
+
+	if (!strcasecmp(in, "dnd") || !strcasecmp(in, "idle")) {
+		r = "busy";
+	}
+
+	return r;
+}
+
+struct mwi_helper {
+	sofia_profile_t *profile;
+	int total;
+};
+
+static void actual_sofia_presence_mwi_event_handler(switch_event_t *event)
+{
+	char *account, *dup_account, *yn, *host, *user;
+	char *sql;
+	sofia_profile_t *profile = NULL;
+	switch_stream_handle_t stream = { 0 };
+	switch_event_header_t *hp;
+	struct mwi_helper h = { 0 };
+	char *pname = NULL;
+	const char *call_id;
+	const char *sub_call_id;
+	int for_everyone = 0;
+
+	switch_assert(event != NULL);
+
+	if (!(account = switch_event_get_header(event, "mwi-message-account"))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required Header 'MWI-Message-Account'\n");
+		return;
+	}
+
+	if (!(yn = switch_event_get_header(event, "mwi-messages-waiting"))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required Header 'MWI-Messages-Waiting'\n");
+		return;
+	}
+
+	call_id = switch_event_get_header(event, "call-id");
+	sub_call_id = switch_event_get_header(event, "sub-call-id");
+
+	if (!call_id && !sub_call_id) {
+		for_everyone = 1;
+	}
+
+
+	dup_account = strdup(account);
+	switch_assert(dup_account != NULL);
+	sofia_glue_get_user_host(dup_account, &user, &host);
+
+
+	if ((pname = switch_event_get_header(event, "sofia-profile"))) {
+		if (!(profile = sofia_glue_find_profile(pname))) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No profile %s\n", pname);
+		}
+	}
+
+	if (!profile) {
+		if (!host || !(profile = sofia_glue_find_profile(host))) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find profile %s\n", switch_str_nil(host));
+			switch_safe_free(dup_account);
+			return;
+		}
+	}
+
+	if (profile->domain_name && strcasecmp(profile->domain_name, host)) {
+		host = profile->domain_name;
+	}
+
+	h.profile = profile;
+	h.total = 0;
+
+	SWITCH_STANDARD_STREAM(stream);
+
+	for (hp = event->headers; hp; hp = hp->next) {
+		if (!strncasecmp(hp->name, "mwi-", 4)) {
+			char *tmp = NULL;
+			char *value = hp->value;
+			if (!strcasecmp(hp->name, "mwi-message-account") && strncasecmp(hp->value, "sip:", 4)) {
+				tmp = switch_mprintf("sip:%s", hp->value);
+				value = tmp;
+			}
+			stream.write_function(&stream, "%s: %s\r\n", hp->name + 4, value);
+			switch_safe_free(tmp);
+		}
+	}
+
+	stream.write_function(&stream, "\r\n");
+	
+	sql = NULL;
+
+	if (for_everyone) {
+		sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
+							 "full_via,expires,user_agent,accept,profile_name,network_ip"
+							 ",'%q','%q' from sip_subscriptions where event='message-summary' "
+							 "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')",
+							 stream.data, host, user, host, host);
+	} else if (sub_call_id) {
+		sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
+							 "full_via,expires,user_agent,accept,profile_name,network_ip"
+							 ",'%q','%q' from sip_subscriptions where event='message-summary' "
+							 "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%' and call_id='%q')",
+							 stream.data, host, user, host, host, sub_call_id);
+	}
+
+
+	if (sql) {
+		sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_mwi_callback, &h);
+		free(sql);
+		sql = NULL;
+		
+	}
+
+	if (for_everyone) {
+		sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q' "
+							 "from sip_registrations where sip_user='%q' and sip_host='%q'", 
+							 stream.data, user, host);
+	} else if (call_id) {
+		sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q' "
+							 "from sip_registrations where sip_user='%q' and sip_host='%q' and call_id='%q'", 
+							 stream.data, user, host, call_id);
+	}
+
+	if (sql) {
+		switch_assert(sql != NULL);
+		sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_mwi_callback2, &h);
+		free(sql);
+		sql = NULL;
+	}
+
+	switch_safe_free(stream.data);
+	switch_safe_free(dup_account);
+
+	if (profile) {
+		sofia_glue_release_profile(profile);
+	}
+}
+
+static void actual_sofia_presence_event_handler(switch_event_t *event)
+{
+	sofia_profile_t *profile = NULL;
+	switch_hash_index_t *hi;
+	const void *var;
+	void *val;
+	char *from = switch_event_get_header(event, "from");
+	char *proto = switch_event_get_header(event, "proto");
+	char *rpid = switch_event_get_header(event, "rpid");
+	char *status = switch_event_get_header(event, "status");
+	char *event_type = switch_event_get_header(event, "event_type");
+	char *alt_event_type = switch_event_get_header(event, "alt_event_type");
+	char *sql = NULL;
+	char *euser = NULL, *user = NULL, *host = NULL;
+
+	if (!mod_sofia_globals.running) {
+		return;
+	}
+
+	if (rpid && !strcasecmp(rpid, "n/a")) {
+		rpid = NULL;
+	}
+
+	if (status && !strcasecmp(status, "n/a")) {
+		status = NULL;
+	}
+	
+	if (status && switch_stristr("CS_HANGUP", status)) {
+		status = "Call Ended";
+	}
+
+	if (rpid) {
+		rpid = sofia_presence_translate_rpid(rpid, status);
+	}
+	
+	if (event->event_id == SWITCH_EVENT_ROSTER) {
+		struct presence_helper helper = { 0 };
+
+		if (!mod_sofia_globals.profile_hash)
+			return;
+
+		if (from) {
+			sql = switch_mprintf(
+								 "select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
+								 "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,"
+								 "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
+								 "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
+								 "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip"
+								 ",1,'%q','%q',sip_presence.status,sip_presence.rpid "
+								 "from sip_subscriptions left join sip_presence on "
+								 "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
+								 "sip_subscriptions.profile_name=sip_presence.profile_name) "
+								 "where sip_subscriptions.event='presence' and sip_subscriptions.full_from like '%%%q%%'", 
+								 switch_str_nil(status), switch_str_nil(rpid), from);
+		} else {
+			sql = switch_mprintf(
+								 "select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
+								 "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,"
+								 "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
+								 "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
+								 "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip"
+								 ",1,'%q','%q',sip_presence.status,sip_presence.rpid "
+								 "from sip_subscriptions left join sip_presence on "
+								 "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
+								 "sip_subscriptions.profile_name=sip_presence.profile_name) "
+								 "where sip_subscriptions.event='presence'", switch_str_nil(status), switch_str_nil(rpid));
+		}
+
+		switch_assert(sql != NULL);
+		switch_mutex_lock(mod_sofia_globals.hash_mutex);
+		for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+			switch_hash_this(hi, &var, NULL, &val);
+			profile = (sofia_profile_t *) val;
+
+			if (strcmp((char *)var, profile->name)) {
+				if (mod_sofia_globals.debug_presence > 0) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s is an alias, skipping\n", (char *) var);
+				}
+				continue;
+			}
+			if (profile->pres_type != PRES_TYPE_FULL) {
+				if (mod_sofia_globals.debug_presence > 0) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s is passive, skipping\n", (char *) var);
+				}
+				continue;
+			}
+			helper.profile = profile;
+			helper.event = NULL;
+			sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_callback, &helper);
+		}
+		switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+		free(sql);
+		return;
+	}
+
+	if (switch_strlen_zero(event_type)) {
+		event_type = "presence";
+	}
+
+	if (switch_strlen_zero(alt_event_type)) {
+		alt_event_type = "presence";
+	}
+
+	if ((user = strdup(from))) {
+		if ((host = strchr(user, '@'))) {
+			char *p;
+			*host++ = '\0';
+			if ((p = strchr(host, '/'))) {
+				*p = '\0';
+			}
+		} else {
+			switch_safe_free(user);
+			return;
+		}
+		if ((euser = strchr(user, '+'))) {
+			euser++;
+		} else {
+			euser = user;
+		}
+	} else {
+		return;
+	}
+
+
+	switch (event->event_id) {
+	case SWITCH_EVENT_PRESENCE_PROBE:
+		if (proto) {
+			char *to = switch_event_get_header(event, "to");
+			char *probe_user = NULL, *probe_euser, *probe_host, *p;
+
+			if (!to || !(probe_user = strdup(to))) {
+				goto done;
+			}
+
+			if ((probe_host = strchr(probe_user, '@'))) {
+				*probe_host++ = '\0';
+			}
+			probe_euser = probe_user;
+			if ((p = strchr(probe_euser, '+'))) {
+				probe_euser = (p + 1);
+			}
+
+			if (probe_euser && probe_host && (profile = sofia_glue_find_profile(probe_host))) {
+				sql = switch_mprintf("select sip_registrations.sip_user, '%q', sip_registrations.status, "
+									 "sip_registrations.rpid,'', sip_dialogs.uuid, sip_dialogs.state, sip_dialogs.direction, "
+									 "sip_dialogs.sip_to_user, sip_dialogs.sip_to_host, sip_presence.status,sip_presence.rpid "
+									 "from sip_registrations left join sip_dialogs on "
+									 "(sip_dialogs.sip_from_user = sip_registrations.sip_user "
+									 "and sip_dialogs.sip_from_host = sip_registrations.sip_host) "
+									 "left join sip_presence on "
+									 "(sip_registrations.sip_user=sip_presence.sip_user and sip_registrations.sip_host=sip_presence.sip_host and "
+									 "sip_registrations.profile_name=sip_presence.profile_name) "
+									 "where sip_registrations.sip_user='%q' and "
+									 "(sip_registrations.sip_host='%q' or sip_registrations.presence_hosts like '%%%q%%')", 
+									 probe_host, probe_euser, probe_host, probe_host);
+				switch_assert(sql);
+
+				
+				if (mod_sofia_globals.debug_presence > 0) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s START_PRESENCE_PROBE_SQL\n", profile->name);
+				}
+
+				if (mod_sofia_globals.debug_presence > 1) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s DUMP PRESENCE_PROBE_SQL:\n%s\n", profile->name, sql);
+				}
+
+				sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_resub_callback, profile);
+				if (mod_sofia_globals.debug_presence > 0) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s END_PRESENCE_PROBE_SQL\n\n", profile->name);
+				}
+
+				sofia_glue_release_profile(profile);
+				switch_safe_free(sql);
+			}
+
+			switch_safe_free(probe_user);
+		}
+		goto done;
+	default:
+		break;
+	}
+
+	
+
+	if (!mod_sofia_globals.profile_hash)
+		goto done;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+		switch_hash_this(hi, &var, NULL, &val);
+		profile = (sofia_profile_t *) val;
+
+		if (strcmp((char *)var, profile->name)) {
+			if (mod_sofia_globals.debug_presence > 0) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s is an alias, skipping\n", (char *) var);
+			}
+			continue;
+		}
+
+		if (profile->pres_type != PRES_TYPE_FULL) {
+			if (mod_sofia_globals.debug_presence > 0) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s is passive, skipping\n", (char *) var);
+			}
+			continue;
+		}
+		
+
+		if ((sql = switch_mprintf(
+							 
+							 "select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
+							 "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,"
+							 "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
+							 "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
+							 "sip_subscriptions.accept,sip_subscriptions.profile_name"
+							 ",'%q','%q','%q',sip_presence.status,sip_presence.rpid "
+							 "from sip_subscriptions "
+							 "left join sip_presence on "
+							 "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
+							 "sip_subscriptions.profile_name=sip_presence.profile_name) "
+							 "where (event='%q' or event='%q') and sub_to_user='%q' "
+							 "and (sub_to_host='%q' or presence_hosts like '%%%q%%') "
+							 "and (sip_subscriptions.profile_name = '%q' or sip_subscriptions.presence_hosts != sip_subscriptions.sub_to_host)",
+							 switch_str_nil(status), switch_str_nil(rpid), host, event_type, alt_event_type, euser, host, host, profile->name))) {
+
+			struct presence_helper helper = { 0 };
+			helper.profile = profile;
+			helper.event = event;
+			SWITCH_STANDARD_STREAM(helper.stream);
+			switch_assert(helper.stream.data);
+			
+			if (mod_sofia_globals.debug_presence > 0) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s START_PRESENCE_SQL (%s)\n", 
+								  event->event_id == SWITCH_EVENT_PRESENCE_IN ? "IN" : "OUT", profile->name);
+			}
+
+			if (mod_sofia_globals.debug_presence) {
+				char *buf;
+				switch_event_serialize(event, &buf, SWITCH_FALSE);
+				switch_assert(buf);
+				if (mod_sofia_globals.debug_presence > 1) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DUMP PRESENCE SQL:\n%s\nEVENT DUMP:\n%s\n", sql, buf);
+				} else {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "EVENT DUMP:\n%s\n", buf);
+				}
+				free(buf);
+			}
+
+			sofia_glue_execute_sql_callback(profile, SWITCH_FALSE,
+											NULL, sql, sofia_presence_sub_callback, &helper);
+
+			if (mod_sofia_globals.debug_presence > 0) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s END_PRESENCE_SQL (%s)\n", 
+								  event->event_id == SWITCH_EVENT_PRESENCE_IN ? "IN" : "OUT", profile->name);
+			}
+			
+			switch_safe_free(sql);
+
+			if (!switch_strlen_zero((char *) helper.stream.data)) {
+				char *this_sql = (char *) helper.stream.data;
+				char *next = NULL;
+				char *last = NULL;
+
+				do {
+					if ((next = strchr(this_sql, ';'))) {
+						*next++ = '\0';
+						while (*next == '\n' || *next == ' ' || *next == '\r') {
+							*next++ = '\0';
+						}
+					}
+
+					if (!switch_strlen_zero(this_sql) && (!last || strcmp(last, this_sql))) {
+						sofia_glue_execute_sql(profile, &this_sql, SWITCH_FALSE);
+						last = this_sql;
+					}
+					this_sql = next;
+				} while (this_sql);
+			}
+			switch_safe_free(helper.stream.data);
+			helper.stream.data = NULL;
+		}
+	}
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+  done:
+	switch_safe_free(sql);
+	switch_safe_free(user);
+}
+
+static int EVENT_THREAD_RUNNING = 0;
+static int EVENT_THREAD_STARTED = 0;
+
+void *SWITCH_THREAD_FUNC sofia_presence_event_thread_run(switch_thread_t *thread, void *obj)
+{
+	void *pop;
+	int done = 0;
+
+	switch_mutex_lock(mod_sofia_globals.mutex);
+	if (!EVENT_THREAD_RUNNING) {
+		EVENT_THREAD_RUNNING++;
+		mod_sofia_globals.threads++;
+	} else {
+		done = 1;
+	}
+	switch_mutex_unlock(mod_sofia_globals.mutex);
+
+	if (done) {
+		return NULL;
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Started\n");
+
+	while (mod_sofia_globals.running == 1) {
+		int count = 0;
+		
+		if (switch_queue_trypop(mod_sofia_globals.presence_queue, &pop) == SWITCH_STATUS_SUCCESS) {
+			switch_event_t *event = (switch_event_t *) pop;
+
+			if (!pop) {
+				break;
+			}
+			actual_sofia_presence_event_handler(event);
+			switch_event_destroy(&event);
+			count++;
+		}
+
+		if (switch_queue_trypop(mod_sofia_globals.mwi_queue, &pop) == SWITCH_STATUS_SUCCESS) {
+			switch_event_t *event = (switch_event_t *) pop;
+
+			if (!pop) {
+				break;
+			}
+
+			actual_sofia_presence_mwi_event_handler(event);
+			switch_event_destroy(&event);
+			count++;
+		}
+
+		if (!count) {
+			switch_yield(100000);
+		}
+	}
+
+	while (switch_queue_trypop(mod_sofia_globals.presence_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
+		switch_event_t *event = (switch_event_t *) pop;
+		switch_event_destroy(&event);
+	}
+
+	while (switch_queue_trypop(mod_sofia_globals.mwi_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
+		switch_event_t *event = (switch_event_t *) pop;
+		switch_event_destroy(&event);
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Ended\n");
+
+	switch_mutex_lock(mod_sofia_globals.mutex);
+	mod_sofia_globals.threads--;
+	EVENT_THREAD_RUNNING = EVENT_THREAD_STARTED = 0;
+	switch_mutex_unlock(mod_sofia_globals.mutex);
+
+	return NULL;
+}
+
+void sofia_presence_event_thread_start(void)
+{
+	switch_thread_t *thread;
+	switch_threadattr_t *thd_attr = NULL;
+	int done = 0;
+
+	switch_mutex_lock(mod_sofia_globals.mutex);
+	if (!EVENT_THREAD_STARTED) {
+		EVENT_THREAD_STARTED++;
+	} else {
+		done = 1;
+	}
+	switch_mutex_unlock(mod_sofia_globals.mutex);
+
+	if (done) {
+		return;
+	}
+
+	switch_threadattr_create(&thd_attr, mod_sofia_globals.pool);
+	switch_threadattr_detach_set(thd_attr, 1);
+	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+	switch_threadattr_priority_increase(thd_attr);
+	switch_thread_create(&thread, thd_attr, sofia_presence_event_thread_run, NULL, mod_sofia_globals.pool);
+}
+
+
+void sofia_presence_event_handler(switch_event_t *event)
+{
+	switch_event_t *cloned_event;
+
+	switch_event_dup(&cloned_event, event);
+	switch_assert(cloned_event);
+	switch_queue_push(mod_sofia_globals.presence_queue, cloned_event);
+
+	if (!EVENT_THREAD_STARTED) {
+		sofia_presence_event_thread_start();
+	}
+}
+
+void sofia_presence_mwi_event_handler(switch_event_t *event)
+{
+	switch_event_t *cloned_event;
+
+	switch_event_dup(&cloned_event, event);
+	switch_assert(cloned_event);
+	switch_queue_push(mod_sofia_globals.mwi_queue, cloned_event);
+
+	if (!EVENT_THREAD_STARTED) {
+		sofia_presence_event_thread_start();
+	}
+}
+
+
+static int sofia_presence_sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	sofia_profile_t *profile = (sofia_profile_t *) pArg;
+	char *user = argv[1];
+	char *host = argv[2];
+	switch_event_t *event;
+	char *event_name = argv[5];
+
+	if (!strcasecmp(event_name, "message-summary")) {
+		if (switch_event_create(&event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Message-Account", "sip:%s@%s", user, host);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "VM-sub-call-id", argv[7]);
+			switch_event_fire(&event);
+		}
+		return 0;
+	}
+
+	if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe");
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event_name);
+		switch_event_fire(&event);
+	}
+
+	return 0;
+}
+
+static int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	sofia_profile_t *profile = (sofia_profile_t *) pArg;
+	char *user = argv[0];
+	char *host = argv[1];
+	char *status = argv[2];
+	char *rpid = argv[3];
+	char *proto = argv[4];
+
+	char *to_user = NULL;
+	char *uuid = NULL;
+	char *state = NULL;
+	char *direction = NULL;
+	switch_event_t *event;
+	char to_buf[128] = "";
+
+	if (argc > 5) {
+		uuid = switch_str_nil(argv[5]);
+		state = switch_str_nil(argv[6]);
+		direction = switch_str_nil(argv[7]);
+		if (argc > 8) {
+			switch_set_string(to_buf, argv[8]);
+			switch_url_decode(to_buf);
+			to_user = to_buf;
+		}
+		if (argc > 10 && !switch_strlen_zero(argv[9]) && !switch_strlen_zero(argv[10])) {
+			status = argv[9];
+			rpid = argv[10];
+		}
+	}
+
+	if (switch_strlen_zero(proto)) {
+		proto = NULL;
+	}
+
+	if (mod_sofia_globals.debug_presence > 0) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s PRESENCE_PROBE %s@%s\n", profile->name, user, host);
+	}
+
+	if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", proto ? proto : SOFIA_CHAT_PROTO);
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", status);
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
+		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", 0);
+
+		if (!switch_strlen_zero(to_user)) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to-user", to_user);
+		}
+		
+		if (switch_strlen_zero(state)) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", SOFIA_CHAT_PROTO);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "resubscribe");
+		} else {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", uuid);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", state);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", state);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "presence-call-direction", direction);
+		}
+
+		switch_event_fire(&event);
+	}
+
+	return 0;
+}
+
+static char *translate_rpid(char *in)
+{
+	char *r = in;
+
+	if (in && (strstr(in, "null") || strstr(in, "NULL"))) {
+		in = NULL;
+	}
+
+	if (!in || !strcasecmp(in, "unknown")) {
+		r = "online";
+		goto end;
+	}
+
+	if (!strcasecmp(in, "busy")) {
+		r = in;
+		goto end;
+	}
+
+	if (!strcasecmp(in, "unavailable")) {
+		r = "away";
+		goto end;
+	}
+
+	if (!strcasecmp(in, "idle")) {
+		r = "busy";
+	}
+
+  end:
+	return r;
+}
+
+
+static char *gen_pidf(char *user_agent, char *id, char *url, char *open, char *rpid, char *prpid, char *status, const char **ct)
+{
+	char *ret = NULL;
+
+	if (switch_stristr("polycom", user_agent)) {
+		*ct = "application/xpidf+xml";
+		
+		/* of course!, lets make a big deal over dashes. Now the stupidity is complete. */
+
+		if (!strcmp(prpid, "on-the-phone")) {
+			prpid = "onthephone";
+		}
+
+		ret = switch_mprintf(
+							  "<?xml version=\"1.0\"?>\n"
+							  "<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n"
+							  "<presence>\n"
+							  " <status>\n"
+							  "  <note>%s</note>\n"
+							  " </status>\n"
+							  " <presentity uri=\"%s;method=SUBSCRIBE\" />\n"
+							  " <atom id=\"%s\">\n"
+							  "  <address uri=\"%s;user=ip\" priority=\"0.800000\">\n"
+							  "   <status status=\"%s\" />\n"
+							  "   <msnsubstatus substatus=\"%s\" />\n"
+							  "  </address>\n"
+							  " </atom>\n"
+							  "</presence>\n", status, id, id, url, open, prpid
+							  );
+	} else {
+		*ct = "application/pidf+xml";
+		ret = switch_mprintf(
+							  "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> \n"
+							  "<presence xmlns='urn:ietf:params:xml:ns:pidf' \n"
+							  "xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model' \n"
+							  "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid' \n"
+							  "xmlns:c='urn:ietf:params:xml:ns:pidf:cipid' entity='%s'>\n"
+							  
+							  " <tuple id='t6a5ed77e'>\n"
+							  "  <status>\r\n"
+							  "   <basic>%s</basic>\n"
+							  "  </status>\n"
+							  " </tuple>\n"
+							  " <dm:person id='p06360c4a'>\n"
+							  "  <rpid:activities>\r\n" 
+							  "   <rpid:%s/>\n"
+							  "  </rpid:activities>\n"
+							  "  <dm:note>%s</dm:note>\n"
+							  " </dm:person>\n"
+							  "</presence>", id, open, prpid, status);
+	}
+
+
+	return ret;
+}
+
+static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	struct presence_helper *helper = (struct presence_helper *) pArg;
+	char *pl = NULL;
+	char *clean_id = NULL, *id = NULL;
+	char *proto = argv[0];
+	char *user = argv[1];
+	char *host = argv[2];
+	char *sub_to_user = argv[3];
+	char *event = argv[5];
+	char *call_id = argv[7];
+	char *expires = argv[10];
+	char *user_agent = argv[11];
+	char *profile_name = argv[13];
+	uint32_t in = 0;
+	char *status = argv[14];
+	char *rpid = argv[15];
+	char *sub_to_host = argv[16];
+
+	nua_handle_t *nh;
+	char *to = NULL;
+	char *open;
+	char *prpid;
+	const char *ct = "no/idea";
+	time_t exptime = switch_epoch_time_now(NULL) + 3600;
+	int is_dialog = 0;
+	sofia_profile_t *ext_profile = NULL, *profile = helper->profile;
+	char sstr[128] = "";
+	int kill_handle = 0;
+	char expires_str[10] = "";
+
+	if (argc > 18 && !switch_strlen_zero(argv[17]) && !switch_strlen_zero(argv[18])) {
+		status = argv[17];
+		rpid = argv[18];
+	}
+
+	in = helper->event && helper->event->event_id == SWITCH_EVENT_PRESENCE_IN;
+
+
+	if (switch_strlen_zero(rpid)) {
+		rpid = "unknown";
+	}
+
+	if (switch_strlen_zero(status)) {
+		if (!strcasecmp(rpid, "busy")) {
+			status = "Busy";
+		} else if (!strcasecmp(rpid, "unavailable")) {
+			status = "Idle";
+		} else if (!strcasecmp(rpid, "away")) {
+			status = "Idle";
+		} else {
+			status = "Available";
+		}
+	}
+	
+	if (profile_name && strcasecmp(profile_name, helper->profile->name)) {
+        if ((ext_profile = sofia_glue_find_profile(profile_name))) {
+            profile = ext_profile;
+        }
+    }
+	
+	if (!(nh = nua_handle_by_call_id(profile->nua, call_id))) {
+		goto end;
+	}
+	
+	if (expires) {
+		long tmp = atol(expires);
+		if (tmp > 0) {
+			exptime = tmp - switch_epoch_time_now(NULL) - SUB_OVERLAP;
+		} else {
+			exptime = tmp;
+		}
+	}
+	
+	if (!rpid) {
+		rpid = "unknown";
+	}
+
+	prpid = translate_rpid(rpid);
+
+	if (!strcasecmp(proto, SOFIA_CHAT_PROTO)) {
+		clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
+	} else {
+		clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
+	}
+
+	if (mod_sofia_globals.debug_presence > 0) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, 
+						  "SEND PRESENCE\nTo:      \t%s@%s\nFrom:    \t%s@%s\nCall-ID:  \t%s\nProfile:\t%s [%s]\n\n", 
+						  user, host, sub_to_user, sub_to_host, call_id, profile_name, helper->profile->name);
+	}
+
+	if (!strcasecmp(sub_to_host, host)) {
+		/* same host */
+		id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
+	} else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) {
+		/*encapsulate */
+		id = switch_mprintf("sip:%s+%s+%s@%s", proto, sub_to_user, sub_to_host, host);
+	} else {
+		id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
+	}
+
+	to = switch_mprintf("sip:%s@%s", user, host);
+
+	is_dialog = !strcmp(event, "dialog");
+
+	if (helper->event) {
+		switch_stream_handle_t stream = { 0 };
+		const char *direction = switch_str_nil(switch_event_get_header(helper->event, "presence-call-direction"));
+		const char *uuid = switch_str_nil(switch_event_get_header(helper->event, "unique-id"));
+		const char *state = switch_str_nil(switch_event_get_header(helper->event, "channel-state"));
+		const char *event_status = switch_str_nil(switch_event_get_header(helper->event, "status"));
+		const char *astate = switch_str_nil(switch_event_get_header(helper->event, "astate"));
+		const char *answer_state = switch_str_nil(switch_event_get_header(helper->event, "answer-state"));
+		const char *dft_state;
+		const char *from_id = switch_str_nil(switch_event_get_header(helper->event, "Other-Leg-Caller-ID-Number"));
+		const char *to_user = switch_str_nil(switch_event_get_header(helper->event, "variable_sip_to_user"));
+		const char *from_user = switch_str_nil(switch_event_get_header(helper->event, "variable_sip_from_user"));
+		char *clean_to_user = NULL;
+		char *clean_from_user = NULL;
+		const char *p_to_user = switch_str_nil(switch_event_get_header(helper->event, "to-user"));
+#if 0
+		char *buf;
+		switch_event_serialize(helper->event, &buf, SWITCH_FALSE);
+		switch_assert(buf);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf);
+		free(buf);
+#endif
+
+		if (is_dialog) {
+			SWITCH_STANDARD_STREAM(stream);
+		}
+
+		if (!strcasecmp(direction, "outbound")) {
+			direction = "recipient";
+			dft_state = "early";
+		} else {
+			direction = "initiator";
+			dft_state = "confirmed";
+		}
+
+		if ((!strcasecmp(state, "cs_execute") && !strstr(event_status, "hold")) || !strcasecmp(state, "cs_reporting")) {
+			goto end;
+		}
+
+		if (!strcasecmp(event_status, "Registered")) {
+			answer_state = "resubscribe";
+		}
+
+		if (is_dialog) {
+			stream.write_function(&stream,
+								  "<?xml version=\"1.0\"?>\n"
+								  "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" "
+								  "version=\"%s\" state=\"%s\" entity=\"%s\">\n",
+								  switch_str_nil(switch_event_get_header(helper->event, "event_count")),
+								  !strcasecmp(answer_state, "resubscribe") ? "partial" : "full", clean_id);
+		}
+
+		if (strcasecmp(answer_state, "resubscribe")) {
+
+			if (!strcasecmp(state, "cs_hangup")) {
+				astate = "terminated";
+			} else if (switch_strlen_zero(astate)) {
+				astate = switch_str_nil(switch_event_get_header(helper->event, "answer-state"));
+				if (switch_strlen_zero(astate)) {
+					if (is_dialog) {
+						astate = dft_state;
+					} else {
+						astate = "terminated";
+					}
+				}
+			}
+
+			if (!strcasecmp(event_status, "hold")) {
+				astate = "early";
+			}
+
+			if (!strcasecmp(astate, "answered")) {
+				astate = "confirmed";
+			}
+
+			if (!strcasecmp(astate, "ringing")) {
+				if (!strcasecmp(direction, "recipient")) {
+					astate = "early";
+				} else {
+					astate = "confirmed";
+				}
+			}
+			if (is_dialog) {
+				stream.write_function(&stream, "<dialog id=\"%s\" direction=\"%s\">\n", uuid, direction);
+				stream.write_function(&stream, "<state>%s</state>\n", astate);
+			}
+			if (!strcasecmp(astate, "early") || !strcasecmp(astate, "confirmed")) {
+
+				clean_to_user = switch_mprintf("%s", sub_to_user ? sub_to_user : to_user);
+				clean_from_user = switch_mprintf("%s", from_id ? from_id : from_user);
+
+				if (is_dialog) {
+					if (!switch_strlen_zero(clean_to_user) && !switch_strlen_zero(clean_from_user)) {
+						stream.write_function(&stream, "<local>\n<identity display=\"%s\">sip:%s@%s</identity>\n", clean_to_user, clean_to_user, host);
+						stream.write_function(&stream, "<target uri=\"sip:%s@%s\">\n", clean_to_user, host);
+						stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"%s\"/>\n",
+											  !strcasecmp(event_status, "hold") ? "no" : "yes");
+						stream.write_function(&stream, "</target>\n</local>\n");
+						stream.write_function(&stream, "<remote>\n<identity display=\"%s\">sip:%s@%s</identity>\n", clean_from_user, clean_from_user,
+											  host);
+						stream.write_function(&stream, "<target uri=\"sip:**%s@%s\"/>\n", clean_to_user, host);
+						stream.write_function(&stream, "</remote>\n");
+					} else if (!strcasecmp(proto, "park")) {
+						stream.write_function(&stream, "<local>\n<identity display=\"parking\">sip:parking@%s;fifo=%s</identity>\n",
+											  host, !switch_strlen_zero(clean_to_user) ? clean_to_user : "unknown");
+						stream.write_function(&stream, "<target uri=\"sip:parking@%s\">\n", host);
+						stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n</target>\n</local>\n");
+						stream.write_function(&stream, "<remote>\n<identity display=\"parking\">sip:%s</identity>\n", uuid);
+						stream.write_function(&stream, "<target uri=\"sip:park+%s\"/>\n", uuid);
+						stream.write_function(&stream, "</remote>\n");
+					} else if (!strcasecmp(proto, "conf")) {
+						stream.write_function(&stream, "<local>\n<identity display=\"conference\">sip:conference@%s;conference=%s</identity>\n",
+											  host, !switch_strlen_zero(clean_to_user) ? clean_to_user : "unknown");
+						stream.write_function(&stream, "<target uri=\"sip:conference@%s\">\n", host);
+						stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"yes\"/>\n</target>\n</local>\n");
+						stream.write_function(&stream, "<remote>\n<identity display=\"conference\">sip:%s@%s</identity>\n", uuid, host);
+						stream.write_function(&stream, "<target uri=\"sip:conf+%s@%s\"/>\n", uuid, host);
+						stream.write_function(&stream, "</remote>\n");
+					}
+				}
+
+				switch_safe_free(clean_to_user);
+				switch_safe_free(clean_from_user);
+			}
+			if (is_dialog) {
+				stream.write_function(&stream, "</dialog>\n");
+			}
+		}
+
+		if (is_dialog) {
+			stream.write_function(&stream, "</dialog-info>\n");
+			pl = stream.data;
+			ct = "application/dialog-info+xml";
+		}
+
+		if (!switch_strlen_zero(astate) && !switch_strlen_zero(uuid) && helper && helper->stream.data && strcmp(helper->last_uuid, uuid)) {
+			helper->stream.write_function(&helper->stream, "update sip_dialogs set state='%s' where uuid='%s';", astate, uuid);
+
+			switch_copy_string(helper->last_uuid, uuid, sizeof(helper->last_uuid));
+		}
+
+		if (!is_dialog) {
+			char status_line[256] = "";
+
+			switch_set_string(status_line, status);
+
+			if (in) {
+				if (!strcmp(astate, "early")) {
+					switch_snprintf(status_line, sizeof(status_line), "Ring %s", switch_str_nil(from_id));
+					rpid = "on-the-phone";
+				} else if (!strcmp(astate, "confirmed")) {
+					char *dest = switch_event_get_header(helper->event, "Caller-Destination-Number");
+					if (switch_strlen_zero(from_id) && !switch_strlen_zero(dest)) {
+						from_id = dest;
+					}
+
+					if (switch_strlen_zero(from_id)) {
+						from_id = p_to_user;
+					}
+					
+					if (switch_strlen_zero(from_id)) {
+						switch_snprintf(status_line, sizeof(status_line), "On The Phone %s", status);
+					} else {
+						switch_snprintf(status_line, sizeof(status_line), "Talk %s", switch_str_nil(from_id));
+					}
+					rpid = "on-the-phone";
+				}
+
+				open = "open";
+			} else {
+				open = "closed";
+			}
+			
+			prpid = translate_rpid(rpid);
+			pl = gen_pidf(user_agent, clean_id, profile->url, open, rpid, prpid, status_line, &ct);
+		}
+		
+	} else {
+		if (in) {
+			open = "open";
+		} else {
+			open = "closed";
+		}
+		prpid = translate_rpid(rpid);
+		pl = gen_pidf(user_agent, clean_id, profile->url, open, rpid, prpid, status, &ct);
+	}
+	
+	nua_handle_bind(nh, &mod_sofia_globals.keep_private);
+	
+	if (helper->event && helper->event->event_id == SWITCH_EVENT_PRESENCE_OUT) {
+		switch_set_string(sstr, "terminated;reason=noresource");
+		switch_set_string(expires_str, "0");
+        kill_handle = 1;
+	} else if (exptime > 0) {
+		switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned)exptime);
+	} else {
+		unsigned delta = (unsigned) (exptime * -1);
+		switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", delta);
+		switch_snprintf(expires_str, sizeof(expires_str), "%u", delta);
+		if (nh && nh->nh_ds && nh->nh_ds->ds_usage) {
+			nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, delta, delta);
+		}
+	}
+
+	if (mod_sofia_globals.debug_presence > 0 && pl) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "send payload:\n%s\n", pl);
+	}
+
+
+
+	nua_notify(nh, 
+			   TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)),
+			   SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
+			   SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(pl), TAG_END());
+	
+  end:
+	
+	if (ext_profile) {
+		sofia_glue_release_profile(ext_profile);
+	}
+
+	switch_safe_free(id);
+	switch_safe_free(clean_id);
+	switch_safe_free(pl);
+	switch_safe_free(to);
+
+	if (nh && kill_handle) {
+		nua_handle_destroy(nh);
+	}
+
+	return 0;
+}
+
+static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	char *sub_to_user = argv[3];
+	char *sub_to_host = argv[15];
+	char *event = argv[5];
+	char *call_id = argv[7];
+	char *expires = argv[10];
+	char *profile_name = argv[13];
+	char *body = argv[15];
+	char *id = NULL;
+	nua_handle_t *nh;
+	int expire_sec = atoi(expires);
+	struct mwi_helper *h = (struct mwi_helper *) pArg;
+	sofia_profile_t *ext_profile = NULL, *profile = h->profile;
+
+	if (profile_name && strcasecmp(profile_name, h->profile->name)) {
+		if ((ext_profile = sofia_glue_find_profile(profile_name))) {
+			profile = ext_profile;
+		}
+	}
+	
+	if (!(nh = nua_handle_by_call_id(h->profile->nua, call_id))) {
+		if (profile->debug) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot find handle for %s\n", call_id);
+		}
+		goto end;
+	}
+
+	id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
+	expire_sec = (int) (expire_sec - switch_epoch_time_now(NULL));
+	if (expire_sec < 0) {
+		expire_sec = 3600;
+	}
+
+	nua_handle_bind(nh, &mod_sofia_globals.keep_private);
+	nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active"),
+			   SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), SIPTAG_PAYLOAD_STR(body), TAG_END());
+
+	switch_safe_free(id);
+
+	h->total++;
+
+ end:
+
+	if (ext_profile) {
+		sofia_glue_release_profile(ext_profile);
+	}
+
+	return 0;
+}
+
+static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char **columnNames)
+{
+	char *sub_to_user = argv[0];
+	char *sub_to_host = argv[1];
+	char *event = "message-summary";
+	char *o_contact = argv[2];
+	char *profile_name = argv[3];
+	char *network_ip = argv[4];
+	char *body = argv[5];
+	char *id = NULL;
+	nua_handle_t *nh;
+	struct mwi_helper *h = (struct mwi_helper *) pArg;
+	sofia_profile_t *ext_profile = NULL, *profile = h->profile;
+	sofia_destination_t *dst = NULL;
+	char *contact_str, *contact, *user_via = NULL;
+
+	if (profile_name && strcasecmp(profile_name, h->profile->name)) {
+		if ((ext_profile = sofia_glue_find_profile(profile_name))) {
+			profile = ext_profile;
+		}
+	}
+
+	contact = sofia_glue_get_url_from_contact(o_contact, 1);
+	if (sofia_glue_check_nat(profile, network_ip)) {
+		char *ptr = NULL;
+		const char *transport_str = NULL;
+
+
+		id = switch_mprintf("sip:%s@%s", sub_to_user, profile->extsipip);
+		switch_assert(id);
+
+		if ((ptr = sofia_glue_find_parameter(o_contact, "transport="))) {
+			sofia_transport_t transport = sofia_glue_str2transport(ptr);
+			transport_str = sofia_glue_transport2str(transport);
+
+			switch (transport) {
+			case SOFIA_TRANSPORT_TCP:
+				contact_str = profile->tcp_public_contact;
+				break;
+			case SOFIA_TRANSPORT_TCP_TLS:
+				contact_str = profile->tls_public_contact;
+				break;
+			default:
+				contact_str = profile->public_url;
+				break;
+			}
+			user_via = sofia_glue_create_external_via(NULL, profile, transport);
+		} else {
+			user_via = sofia_glue_create_external_via(NULL, profile, SOFIA_TRANSPORT_UDP);
+			contact_str = profile->public_url;
+		}
+		
+	} else {
+		contact_str = profile->url;
+		id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
+	}
+
+	dst = sofia_glue_get_destination(o_contact);
+	switch_assert(dst);
+
+	nh = nua_handle(profile->nua, NULL, NUTAG_URL(contact),
+					SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id),
+					SIPTAG_CONTACT_STR(contact_str), TAG_END());
+	nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
+
+	nua_notify(nh,
+			   NUTAG_NEWSUB(1),
+			   TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
+			   TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+			   SIPTAG_EVENT_STR(event),
+			   SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+			   SIPTAG_PAYLOAD_STR(body), TAG_END());
+	
+	switch_safe_free(contact);
+	switch_safe_free(id);
+	sofia_glue_free_destination(dst);
+	switch_safe_free(user_via);
+
+	if (ext_profile) {
+		sofia_glue_release_profile(ext_profile);
+	}
+
+	return 0;
+}
+
+void sofia_presence_handle_sip_i_subscribe(int status,
+										   char const *phrase,
+										   nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+										   tagi_t tags[])
+{
+	if (sip) {
+		long exp_abs, exp_delta;
+		char exp_delta_str[30] = "";
+		sip_to_t const *to = sip->sip_to;
+		sip_from_t const *from = sip->sip_from;
+		sip_contact_t const *contact = sip->sip_contact;
+		const char *from_user = NULL, *from_host = NULL;
+		const char *to_user = NULL, *to_host = NULL;
+		char *my_to_user = NULL;
+		char *sql, *event = NULL;
+		char *proto = "sip";
+		char *d_user = NULL;
+		char *contact_str = "";
+		const char *call_id = NULL;
+		char *to_str = NULL;
+		char *full_from = NULL;
+		char *full_via = NULL;
+		char *full_agent = NULL;
+		char *sstr;
+		const char *display = "\"user\"";
+		switch_event_t *sevent;
+		int sub_state;
+		int sent_reply = 0;
+		int network_port = 0;
+		char network_ip[80];
+		const char *contact_host, *contact_user;
+		char *port;
+		char new_port[25] = "";
+		char *is_nat = NULL;
+		int is_auto_nat = 0;
+		const char *ipv6;
+
+		if (!(contact && sip->sip_contact->m_url)) {
+			nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
+			return;
+		}
+
+		sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &network_port);
+
+		if (sofia_glue_check_nat(profile, network_ip)) {
+			is_auto_nat = 1;
+		}	
+
+		tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END());
+
+		event = sip_header_as_string(profile->home, (void *) sip->sip_event);
+
+		port = (char *) contact->m_url->url_port;
+		contact_host = sip->sip_contact->m_url->url_host;
+		contact_user = sip->sip_contact->m_url->url_user;
+
+		display = contact->m_display;
+
+		if (switch_strlen_zero(display)) {
+			if (from) {
+				display = from->a_display;
+				if (switch_strlen_zero(display)) {
+					display = "\"user\"";
+				}
+			}
+		} else {
+			display = "\"user\"";
+		}
+
+		if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
+			if (sip && sip->sip_via) {
+				const char *v_port = sip->sip_via->v_port;
+				const char *v_host = sip->sip_via->v_host;
+
+				if (v_host && sip->sip_via->v_received) {
+					is_nat = "via received";
+				} else if (v_host && strcmp(network_ip, v_host)) {
+					is_nat = "via host";
+				} else if (v_port && atoi(v_port) != network_port) {
+					is_nat = "via port";
+				}
+			}
+		}
+
+		if (!is_nat && profile->nat_acl_count) {
+			uint32_t x = 0;
+			int ok = 1;
+			char *last_acl = NULL;
+
+			if (!switch_strlen_zero(contact_host)) {
+				for (x = 0; x < profile->nat_acl_count; x++) {
+					last_acl = profile->nat_acl[x];
+					if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
+						break;
+					}
+				}
+
+				if (ok) {
+					is_nat = last_acl;
+				}
+			}
+		}
+
+		if (is_nat) {
+			contact_host = network_ip;
+			switch_snprintf(new_port, sizeof(new_port), ":%d", network_port);
+			port = NULL;
+		}
+
+
+		if (port) {
+			switch_snprintf(new_port, sizeof(new_port), ":%s", port);
+		}
+
+		ipv6 = strchr(contact_host, ':');
+		if (contact->m_url->url_params) {
+			contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s;%s>%s",
+										display, contact->m_url->url_user,
+										ipv6 ? "[" : "",
+										contact_host,
+										ipv6 ? "]" : "",
+										new_port,
+										contact->m_url->url_params,
+										is_nat ? ";fs_nat" : "");
+		} else {
+			contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s>%s",
+										display,
+										contact->m_url->url_user,
+										ipv6 ? "[" : "",
+										contact_host,
+										ipv6 ? "]" : "",
+										new_port,
+										is_nat ?  ";fs_nat" : "");
+		}
+
+
+
+		/* the following could be refactored back to the calling event handler in sofia.c XXX MTK */
+		if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
+			if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
+				/* only fire this on <200 to try to avoid resubscribes. probably better ways to do this? */
+				if (status < 200) {
+					sofia_sla_handle_sip_i_subscribe(nua, contact_str, profile, nh, sip, tags);
+				}
+				switch_safe_free(contact_str);
+				return;
+			}
+		}
+
+
+
+		if (to) {
+			to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host);
+		}
+
+		if (to) {
+			to_user = to->a_url->url_user;
+			to_host = to->a_url->url_host;
+		}
+
+		if (sip && sip->sip_from) {
+			from_user = sip->sip_from->a_url->url_user;
+			from_host = sip->sip_from->a_url->url_host;
+		} else {
+			from_user = "n/a";
+			from_host = "n/a";
+		}
+
+		if (to_user && (strstr(to_user, "ext+") || strstr(to_user, "user+"))) {
+			char protocol[80];
+			char *p;
+
+			switch_copy_string(protocol, to_user, sizeof(protocol));
+			if ((p = strchr(protocol, '+'))) {
+				*p = '\0';
+			}
+
+			if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+				switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", protocol);
+				switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
+				switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host);
+				switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "rpid", "active");
+				switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call");
+				switch_event_fire(&sevent);
+			}
+
+		} else {
+			if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+				switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+				switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
+				switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+				switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, to_host);
+				switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event);
+				switch_event_fire(&sevent);
+			}
+		}
+
+		if (to_user && strchr(to_user, '+')) {
+			char *h;
+			if ((proto = (d_user = strdup(to_user)))) {
+				if ((my_to_user = strchr(d_user, '+'))) {
+					*my_to_user++ = '\0';
+					to_user = my_to_user;
+					if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
+						*h++ = '\0';
+						to_host = h;
+					}
+				}
+			}
+
+			if (!(proto && to_user && to_host)) {
+				nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
+				goto end;
+			}
+		}
+
+		call_id = sip->sip_call_id->i_id;
+		full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
+		full_via = sip_header_as_string(profile->home, (void *) sip->sip_via);
+		
+		exp_delta = profile->force_subscription_expires ? profile->force_subscription_expires : (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
+		
+		if (exp_delta) {
+			exp_abs = (long) switch_epoch_time_now(NULL) + exp_delta;
+		} else {
+			exp_abs = 0;
+			sub_state = nua_substate_terminated;
+		}
+
+		switch_snprintf(exp_delta_str, sizeof(exp_delta_str), "%ld", exp_delta);
+		
+		if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
+			sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id);
+		} else {
+			sql = switch_mprintf("delete from sip_subscriptions where "
+								 "proto='%q' and sip_user='%q' and sip_host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' and hostname='%q'",
+								 proto, from_user, from_host, to_user, to_host, event, mod_sofia_globals.hostname);
+		}
+
+		switch_mutex_lock(profile->ireg_mutex);
+		switch_assert(sql != NULL);
+		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+
+		if (sub_state == nua_substate_terminated) {
+			sstr = switch_mprintf("terminated");
+		} else {
+			sip_accept_t *ap = sip->sip_accept;
+			char accept[256] = "";
+			full_agent = sip_header_as_string(profile->home, (void *) sip->sip_user_agent);
+			while (ap) {
+				switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : "");
+				ap = ap->ac_next;
+			}
+
+			/* negative in exptime means keep bumping up sub time to avoid a snafu where every device has it's own rules about subscriptions
+			   that somehow barely resemble the RFC not that I blame them because the RFC MAY be amibiguous and SHOULD be deleted.
+			   So to avoid the problem we keep resetting the expiration date of the subscription so it never expires.
+
+			   Eybeam completely ignores this option and most other subscription-state: directives from rfc3265 and still expires.
+			   Polycom is happy to keep upping the subscription expiry back to the original time on each new notify.
+			   The rest ... who knows...?
+
+			*/
+
+			sql = switch_mprintf("insert into sip_subscriptions "
+								 "(proto,sip_user,sip_host,sub_to_user,sub_to_host,presence_hosts,event,contact,call_id,full_from,"
+								 "full_via,expires,user_agent,accept,profile_name,hostname,network_ip) "
+								 "values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%q')",
+								 proto, from_user, from_host, to_user, to_host, profile->presence_hosts ? profile->presence_hosts : to_host, 
+								 event, contact_str, call_id, full_from, full_via, 
+								 exp_delta * -1, 
+								 full_agent, accept, profile->name,mod_sofia_globals.hostname, network_ip);
+								 
+			
+			if (mod_sofia_globals.debug_presence > 0) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s SUBSCRIBE %s@%s %s@%s\n", profile->name, from_user, from_host, to_user, to_host);
+			}
+
+			switch_assert(sql != NULL);
+			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+
+			sstr = switch_mprintf("active;expires=%ld", exp_delta);
+		}
+
+		switch_mutex_unlock(profile->ireg_mutex);
+
+		if (status < 200) {
+			char *sticky = NULL;
+			char *contactstr = profile->url;
+			
+			if (is_nat) {
+				char params[128] = "";
+				if (contact->m_url->url_params) {
+					switch_snprintf(params, sizeof(params), ";%s", contact->m_url->url_params);
+				}
+				ipv6 = strchr(network_ip, ':');
+				sticky = switch_mprintf("sip:%s@%s%s%s:%d%s",
+										contact_user,
+										ipv6 ? "[" : "",
+										network_ip,
+										ipv6 ? "]" : "",
+										network_port,
+										params);
+			}
+
+			if (is_auto_nat) {
+				contactstr = profile->public_url;
+			} else {
+				contactstr = profile->url;
+			}
+
+			
+			if (switch_stristr("port=tcp", contact->m_url->url_params)) {
+				if (is_auto_nat) {
+					contactstr = profile->tcp_public_contact;
+				} else {
+					contactstr = profile->tcp_contact;
+				}
+			} else if (switch_stristr("port=tls", contact->m_url->url_params)) {
+				if (is_auto_nat) {
+					contactstr = profile->tls_contact;
+				} else {
+					contactstr = profile->tls_public_contact;
+				}
+			}
+
+			if (nh && nh->nh_ds && nh->nh_ds->ds_usage) {
+				nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta + SUB_OVERLAP, exp_delta + SUB_OVERLAP);
+			}
+
+			nua_respond(nh, SIP_202_ACCEPTED,
+						SIPTAG_CONTACT_STR(contactstr),
+						NUTAG_WITH_THIS(nua), 
+						SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
+						SIPTAG_EXPIRES_STR(exp_delta_str),
+						TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END());
+
+			switch_safe_free(sticky);
+
+		}
+
+		sent_reply++;
+
+#if 0
+		nua_notify(nh,
+				   SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event),
+				   SIPTAG_EXPIRES_STR(exp_delta_str),
+				   SIPTAG_CONTENT_TYPE_STR("application/notice"),
+				   SIPTAG_PAYLOAD_STR("Note: Come to ClueCon http://www.cluecon.com\n\n"), TAG_END());
+#endif
+
+		switch_safe_free(sstr);
+
+		if ((sql = switch_mprintf(
+								  "select proto,sip_user,'%q',sub_to_user,sub_to_host,event,contact,call_id,full_from,"
+								  "full_via,expires,user_agent,accept,profile_name,network_ip"
+								  " from sip_subscriptions where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')", 
+								  to_host, to_user, to_host, to_host))) {
+			sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_presence_sub_reg_callback, profile);
+			
+			switch_safe_free(sql);
+		}
+	  end:
+
+		if (event) {
+			su_free(profile->home, event);
+		}
+
+		if (full_from) {
+			su_free(profile->home, full_from);
+		}
+		if (full_via) {
+			su_free(profile->home, full_via);
+		}
+		if (full_agent) {
+			su_free(profile->home, full_agent);
+		}
+
+		switch_safe_free(d_user);
+		switch_safe_free(to_str);
+		switch_safe_free(contact_str);
+
+		if (!sent_reply) {
+			nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
+		}
+	}
+}
+
+sofia_gateway_subscription_t *sofia_find_gateway_subscription(sofia_gateway_t *gateway_ptr, const char *event) {
+	sofia_gateway_subscription_t *gw_sub_ptr;
+	for (gw_sub_ptr = gateway_ptr->subscriptions; gw_sub_ptr; gw_sub_ptr = gw_sub_ptr->next) {
+		if (!strcasecmp(gw_sub_ptr->event, event)) {
+			/* this is the gateway subscription we are interested in */
+			return gw_sub_ptr;
+		}
+	}
+	return NULL;
+}
+
+void sofia_presence_handle_sip_r_subscribe(int status,
+										   char const *phrase,
+										   nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+										   tagi_t tags[])
+{
+	sip_event_t const *o = NULL;
+	sofia_gateway_subscription_t *gw_sub_ptr;
+	
+	if (!sip) {
+		return;
+	}
+
+	tl_gets(tags, SIPTAG_EVENT_REF(o), TAG_END());
+	/* o->o_type: message-summary (for example) */
+	if (!o) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event information not given\n");
+		return;
+	}
+
+	/* the following could possibly be refactored back towards the calling event handler in sofia.c XXX MTK */
+	if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
+		if (!strcasecmp(o->o_type, "dialog") && msg_params_find(o->o_params, "sla")) {
+			sofia_sla_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+			return;
+		}
+	}
+
+	if (!sofia_private || !sofia_private->gateway) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
+		return;
+	}
+	
+	/* Find the subscription if one exists */
+	if (!(gw_sub_ptr = sofia_find_gateway_subscription(sofia_private->gateway, o->o_type))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Could not find gateway subscription.  Gateway: %s.  Subscription Event: %s\n",
+				sofia_private->gateway->name, o->o_type);
+		return;
+	}
+	
+	/* Update the subscription status for the subscription */
+	switch (status) {
+	case 200:
+		/* TODO: in the spec it is possible for the other side to change the original expiry time,
+		 * this needs to be researched (eg, what sip header this information will be in) and implemented.
+		 * Although, since it seems the sofia stack is pretty much handling the subscription expiration
+		 * anyway, then maybe its not even worth bothering.
+		 */
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got 200 OK response, updated state to SUB_STATE_SUBSCRIBE.\n");
+		gw_sub_ptr->state = SUB_STATE_SUBSCRIBE;
+		break;
+	case 100:
+		break;
+	default:
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "status (%d) != 200, updated state to SUB_STATE_FAILED.\n", status);
+		gw_sub_ptr->state = SUB_STATE_FAILED;
+		
+		if (sofia_private) {
+			nua_handle_destroy(sofia_private->gateway->sub_nh);
+			sofia_private->gateway->sub_nh = NULL;
+			nua_handle_bind(sofia_private->gateway->sub_nh, NULL);
+			sofia_private_free(sofia_private);
+		} else {
+			nua_handle_destroy(nh);
+		}
+
+		break;
+	}
+}
+
+void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+										 tagi_t tags[])
+{
+	if (sip) {
+		sip_from_t const *from = sip->sip_from;
+		char *from_user = NULL;
+		char *from_host = NULL;
+		char *rpid = "unknown";
+		sip_payload_t *payload = sip->sip_payload;
+		char *event_type;
+
+		/* the following could instead be refactored back to the calling event handler in sofia.c XXX MTK */
+		if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
+			/* also it probably is unsafe to dereference so many things in a row without testing XXX MTK */
+			if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) {
+				sofia_sla_handle_sip_i_publish(nua, profile, nh, sip, tags);
+				return;
+			}
+		}
+
+		if (from) {
+			from_user = (char *) from->a_url->url_user;
+			from_host = (char *) from->a_url->url_host;
+		}
+
+		if (payload) {
+			switch_xml_t xml, note, person, tuple, status, basic, act;
+			switch_event_t *event;
+			uint8_t in = 0;
+			char *sql;
+			char *full_agent = NULL;
+			long exp, exp_delta;
+
+			if ((xml = switch_xml_parse_str(payload->pl_data, strlen(payload->pl_data)))) {
+				char *status_txt = "", *note_txt = "";
+
+				if (sip->sip_user_agent) {
+					full_agent = sip_header_as_string(profile->home, (void *) sip->sip_user_agent);
+				}
+				
+				if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status"))
+					&& (basic = switch_xml_child(status, "basic"))) {
+					status_txt = basic->txt;
+				}
+
+				if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) {
+					note_txt = note->txt;
+				}
+
+				if (person && (act = switch_xml_child(person, "rpid:activities")) && act->child && act->child->name) {
+					if ((rpid = strchr(act->child->name, ':'))) {
+						rpid++;
+					} else {
+						rpid = act->child->name;
+					}
+				}
+
+				if (!strcasecmp(status_txt, "open")) {
+					if (switch_strlen_zero(note_txt)) {
+						note_txt = "Available";
+					}
+					in = 1;
+				} else if (!strcasecmp(status_txt, "closed")) {
+					if (switch_strlen_zero(note_txt)) {
+						note_txt = "Unavailable";
+					}
+				}
+
+				exp_delta = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
+				exp = (long) switch_epoch_time_now(NULL) + exp_delta;
+
+				if ((sql =
+					 switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' "
+									" and profile_name='%q' and hostname='%q'",
+									from_user, from_host, profile->name, mod_sofia_globals.hostname
+									))) {
+					sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+				}
+					 
+				if ((sql =
+					 switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent, profile_name, hostname) "
+									"values ('%q','%q','%q','%q',%ld,'%q','%q','%q')",
+									from_user, from_host, note_txt, rpid, exp, full_agent, profile->name, mod_sofia_globals.hostname))) {
+					sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+				}
+				
+				event_type = sip_header_as_string(profile->home, (void *) sip->sip_event);
+
+				if (in) {
+					if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent", full_agent);
+						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", note_txt);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", event_type);
+						switch_event_fire(&event);
+					}
+				} else {
+					if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent", full_agent);
+						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", event_type);
+						switch_event_fire(&event);
+					}
+				}
+
+				if (event_type) {
+					su_free(profile->home, event_type);
+				}
+
+				if (full_agent) {
+					su_free(profile->home, full_agent);
+				}
+				switch_xml_free(xml);
+			}
+		}
+	}
+	nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+}
+
+void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
+{
+	url_t *to = sip->sip_to->a_url;
+	url_t *from = sip->sip_from->a_url;
+	switch_snprintf(hash_key, len, "%s%s%s", from->url_user, from->url_host, to->url_user);
+}
+
+void sofia_presence_handle_sip_i_message(int status,
+										 char const *phrase,
+										 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+										 tagi_t tags[])
+{
+	if (sip) {
+		sip_from_t const *from = sip->sip_from;
+		const char *from_user = NULL;
+		const char *from_host = NULL;
+		sip_to_t const *to = sip->sip_to;
+		const char *to_user = NULL;
+		const char *to_host = NULL;
+		sip_subject_t const *sip_subject = sip->sip_subject;
+		sip_payload_t *payload = sip->sip_payload;
+		const char *subject = "n/a";
+		char *msg = NULL;
+
+		if (sip->sip_content_type && sip->sip_content_type->c_subtype) {
+			if (strstr(sip->sip_content_type->c_subtype, "composing")) {
+				return;
+			}
+		}
+
+		if (from) {
+			from_user = from->a_url->url_user;
+			from_host = from->a_url->url_host;
+		}
+
+		if (to) {
+			to_user = to->a_url->url_user;
+			to_host = to->a_url->url_host;
+		}
+
+		if (!to_user) {
+			return;
+		}
+
+		if (payload) {
+			msg = payload->pl_data;
+		}
+
+		if (sip_subject) {
+			subject = sip_subject->g_value;
+		}
+
+		if (nh) {
+			char hash_key[512];
+			private_object_t *tech_pvt;
+			switch_channel_t *channel;
+			switch_event_t *event;
+			char *to_addr;
+			char *from_addr;
+			char *p;
+			char *full_from;
+			char proto[512] = SOFIA_CHAT_PROTO;
+
+			full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
+
+			if ((p = strchr(to_user, '+'))) {
+				switch_copy_string(proto, to_user, sizeof(proto));
+				p = strchr(proto, '+');
+				*p++ = '\0';
+				
+				if ((to_addr = strdup(p))) {
+					if ((p = strchr(to_addr, '+'))) {
+						*p = '@';
+					}
+				}
+			} else {
+				to_addr = switch_mprintf("%s@%s", to_user, to_host);
+			}
+
+			from_addr = switch_mprintf("%s@%s", from_user, from_host);
+
+			sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
+			if ((tech_pvt = (private_object_t *) switch_core_hash_find(profile->chat_hash, hash_key))) {
+				channel = switch_core_session_get_channel(tech_pvt->session);
+				if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", from_addr);
+					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hint", full_from);
+					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to", to_addr);
+					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE");
+					if (msg) {
+						switch_event_add_body(event, "%s", msg);
+					}
+					
+					if (switch_core_session_queue_event(tech_pvt->session, &event) != SWITCH_STATUS_SUCCESS) {
+						switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
+						switch_event_fire(&event);
+					}
+				}
+			} else {
+				switch_core_chat_send(proto, SOFIA_CHAT_PROTO, from_addr, to_addr, "", msg, NULL, full_from);
+			}
+			switch_safe_free(to_addr);
+			switch_safe_free(from_addr);
+			if (full_from) {
+				su_free(profile->home, full_from);
+			}
+		}
+	}
+}
+
+void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip)
+{
+	char hash_key[256] = "";
+	char buf[512];
+	su_home_t *home = NULL;
+
+	if (!tech_pvt || tech_pvt->hash_key || !sip || !sip->sip_from || !sip->sip_from->a_url || 
+		!sip->sip_from->a_url->url_user || !sip->sip_from->a_url->url_host) {
+		return;
+	}
+
+	if (sofia_reg_find_reg_url(tech_pvt->profile, sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host, buf, sizeof(buf))) {
+		home = su_home_new(sizeof(*home));
+		switch_assert(home != NULL);
+		tech_pvt->chat_from = sip_header_as_string(home, (const sip_header_t *) sip->sip_to);
+		tech_pvt->chat_to = switch_core_session_strdup(tech_pvt->session, buf);
+		sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
+		su_home_unref(home);
+		home = NULL;
+	} else {
+		return;
+	}
+	
+	switch_mutex_lock(tech_pvt->profile->flag_mutex);
+	tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
+	switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
+	switch_mutex_unlock(tech_pvt->profile->flag_mutex);
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Copied: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_reg.c (from rev 14389, freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c) (0 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_reg.c	                        (rev 0)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_reg.c	2009-07-27 20:18:20 UTC (rev 14390)
@@ -0,0 +1,2153 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Ken Rice, <krice at cometsig.com>  (work sponsored by Comet Signaling LLC, CopperCom, Inc and Asteria Solutions Group, Inc)
+ * Paul D. Tinsley <pdt at jackhammer.org>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ * Marcel Barbulescu <marcelbarbulescu@gmail.com>
+ * David Knell <>
+ * Eliot Gable <egable AT.AT broadvox.com>
+ *
+ *
+ * sofia_ref.c -- SOFIA SIP Endpoint (registration code)
+ *
+ */
+#include "mod_sofia.h"
+
+static void sofia_reg_new_handle(sofia_gateway_t *gateway_ptr, int attach)
+{
+	int ss_state = nua_callstate_authenticating;
+
+	if (gateway_ptr->nh) {
+		nua_handle_bind(gateway_ptr->nh, NULL);
+		nua_handle_destroy(gateway_ptr->nh);
+		gateway_ptr->nh = NULL;
+		sofia_private_free(gateway_ptr->sofia_private);
+	}
+
+	gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL,
+								 SIPTAG_CALL_ID_STR(gateway_ptr->uuid_str),
+								 SIPTAG_TO_STR(gateway_ptr->register_to),
+								 NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END());
+	if (attach) {
+		if (!gateway_ptr->sofia_private) {
+			gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private));
+			switch_assert(gateway_ptr->sofia_private);
+		}
+		memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private));
+	
+		gateway_ptr->sofia_private->gateway = gateway_ptr;
+		nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
+	}
+}
+
+static void sofia_reg_kill_reg(sofia_gateway_t *gateway_ptr)
+{
+
+	if (gateway_ptr->state != REG_STATE_REGED) {
+		if (gateway_ptr->nh) {
+			nua_handle_destroy(gateway_ptr->nh);
+			gateway_ptr->nh = NULL;
+		}
+		return;
+	}
+	
+	/*
+	if (!gateway_ptr->nh) {
+		sofia_reg_new_handle(gateway_ptr, SWITCH_FALSE);
+	}
+	*/
+
+	if (gateway_ptr->nh) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "UN-Registering %s\n", gateway_ptr->name);
+		nua_unregister(gateway_ptr->nh,
+					   NUTAG_URL(gateway_ptr->register_url),
+					   NUTAG_REGISTRAR(gateway_ptr->register_proxy), 
+					   TAG_END());
+	}
+	
+
+
+}
+
+static void sofia_reg_fire_custom_gateway_state_event(sofia_gateway_t *gateway) {
+	switch_event_t *s_event;
+	if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_GATEWAY_STATE) == SWITCH_STATUS_SUCCESS) {
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Gateway", gateway->name);
+		switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "State", sofia_state_string(gateway->state));
+		switch_event_fire(&s_event);
+	}
+}
+
+void sofia_reg_unregister(sofia_profile_t *profile)
+{
+	sofia_gateway_t *gateway_ptr;
+	for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+
+		if (gateway_ptr->sofia_private) {
+			sofia_private_free(gateway_ptr->sofia_private);
+		}
+
+		if (gateway_ptr->state == REG_STATE_REGED) {
+			sofia_reg_kill_reg(gateway_ptr);
+		}
+
+	}
+}
+
+void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now)
+{
+	/* NOTE: A lot of the mechanism in place here for refreshing subscriptions is
+	 * pretty much redundant, as the sofia stack takes it upon itself to
+	 * refresh subscriptions on its own, based on the value of the Expires
+	 * header (which we control in the outgoing subscription request)
+	 */
+	sofia_gateway_t *gateway_ptr;
+	
+	for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+		sofia_gateway_subscription_t *gw_sub_ptr;
+
+		for (gw_sub_ptr = gateway_ptr->subscriptions; gw_sub_ptr; gw_sub_ptr = gw_sub_ptr->next) {
+			int ss_state = nua_callstate_authenticating;
+			sub_state_t ostate = gw_sub_ptr->state;
+			char *user_via = NULL;
+			
+			if (!now) {
+				gw_sub_ptr->state = ostate = SUB_STATE_UNSUBED;
+				gw_sub_ptr->expires_str = "0";
+			}
+
+			if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+				user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
+			}
+
+			switch (ostate) {
+			case SUB_STATE_NOSUB:
+				break;
+			case SUB_STATE_SUBSCRIBE:
+				gw_sub_ptr->expires = now + gw_sub_ptr->freq;
+				gw_sub_ptr->state = SUB_STATE_SUBED;
+				break;
+			case SUB_STATE_UNSUBSCRIBE:
+				gw_sub_ptr->state = SUB_STATE_NOSUB;
+
+				/* not tested .. */
+				nua_unsubscribe(gateway_ptr->nh,
+								NUTAG_URL(gateway_ptr->register_url),
+								TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+								SIPTAG_EVENT_STR(gw_sub_ptr->event),
+								SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type),
+								SIPTAG_TO_STR(gateway_ptr->register_from),
+								SIPTAG_FROM_STR(gateway_ptr->register_from),
+								SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+								TAG_NULL());
+				
+				break;
+			case SUB_STATE_UNSUBED:
+				gateway_ptr->sub_nh = nua_handle(gateway_ptr->profile->nua, NULL,
+												 NUTAG_URL(gateway_ptr->register_proxy),
+												 TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+												 SIPTAG_TO_STR(gateway_ptr->register_to),
+												 NUTAG_CALLSTATE_REF(ss_state), 
+												 SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END());
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "subscribing to [%s] on gateway [%s]\n", gw_sub_ptr->event, gateway_ptr->name);
+				
+				gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private));
+				switch_assert(gateway_ptr->sofia_private);
+				
+				memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private));
+
+				gateway_ptr->sofia_private->gateway = gateway_ptr;
+				nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
+
+				if (now) {
+					nua_subscribe(gateway_ptr->sub_nh,
+								  NUTAG_URL(gateway_ptr->register_url),
+								  TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+								  SIPTAG_EVENT_STR(gw_sub_ptr->event),
+								  SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type),  
+								  SIPTAG_TO_STR(gateway_ptr->register_from),
+								  SIPTAG_FROM_STR(gateway_ptr->register_from),
+								  SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+								  SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str),  // sofia stack bases its auto-refresh stuff on this
+								  TAG_NULL());
+					gw_sub_ptr->retry = now + gw_sub_ptr->retry_seconds;
+				} else {
+					nua_unsubscribe(gateway_ptr->sub_nh,
+									NUTAG_URL(gateway_ptr->register_url),
+									TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+									SIPTAG_EVENT_STR(gw_sub_ptr->event),
+									SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type),
+									SIPTAG_FROM_STR(gateway_ptr->register_from),
+									SIPTAG_TO_STR(gateway_ptr->register_from),
+									SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+									SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str),
+									TAG_NULL());
+				}
+				gw_sub_ptr->state = SUB_STATE_TRYING;
+				break;
+				
+			case SUB_STATE_FAILED:
+			case SUB_STATE_TRYING:
+				if (gw_sub_ptr->retry && now >= gw_sub_ptr->retry) {
+					gw_sub_ptr->state = SUB_STATE_UNSUBED;
+					gw_sub_ptr->retry = 0;
+				}
+				break;
+			default:
+				if (now >= gw_sub_ptr->expires) {
+					gw_sub_ptr->state = SUB_STATE_UNSUBED;
+				}
+				break;
+			}
+			switch_safe_free(user_via);
+		}
+	}
+}
+
+void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
+{
+	sofia_gateway_t *gateway_ptr, *last = NULL;
+
+	for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+		if (gateway_ptr->deleted && gateway_ptr->state == REG_STATE_NOREG) {
+			if (last) {
+				last->next = gateway_ptr->next;
+			} else {
+				profile->gateways = gateway_ptr->next;
+			}
+
+			switch_core_hash_delete(mod_sofia_globals.gateway_hash, gateway_ptr->name);
+			switch_core_hash_delete(mod_sofia_globals.gateway_hash, gateway_ptr->register_from);
+			switch_core_hash_delete(mod_sofia_globals.gateway_hash, gateway_ptr->register_contact);
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleted gateway %s\n", gateway_ptr->name);
+			if (gateway_ptr->ob_vars) {
+				switch_event_destroy(&gateway_ptr->ob_vars);
+			}
+			if (gateway_ptr->ib_vars) {
+				switch_event_destroy(&gateway_ptr->ib_vars);
+			}
+		} else {
+			last = gateway_ptr;
+		}
+	}
+
+	for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+		reg_state_t ostate = gateway_ptr->state;
+		char *user_via = NULL;
+
+		if (!now) {
+			gateway_ptr->state = ostate = REG_STATE_UNREGED;
+			gateway_ptr->expires_str = "0";
+		}
+
+		if (gateway_ptr->ping && !gateway_ptr->pinging && (now >= gateway_ptr->ping && (ostate == REG_STATE_NOREG || ostate == REG_STATE_REGED)) &&
+			!gateway_ptr->deleted) {
+			nua_handle_t *nh = nua_handle(profile->nua, NULL, NUTAG_URL(gateway_ptr->register_url), TAG_END());
+			sofia_private_t *pvt;
+
+			if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+				user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
+			}
+
+			pvt = malloc(sizeof(*pvt));
+			switch_assert(pvt);
+			memset(pvt, 0, sizeof(*pvt));
+			pvt->destroy_nh = 1;
+			pvt->destroy_me = 1;
+			switch_copy_string(pvt->gateway_name, gateway_ptr->name, sizeof(pvt->gateway_name));
+			nua_handle_bind(nh, pvt);
+
+			gateway_ptr->pinging = 1;
+			nua_options(nh, 
+						TAG_IF(gateway_ptr->register_sticky_proxy, NUTAG_PROXY(gateway_ptr->register_sticky_proxy)),
+						TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+						SIPTAG_TO_STR(gateway_ptr->register_from),
+						SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+						SIPTAG_FROM_STR(gateway_ptr->register_from),
+						TAG_END());
+
+			switch_safe_free(user_via);
+			user_via = NULL;
+		}
+
+		switch (ostate) {
+		case REG_STATE_NOREG:
+			if (!gateway_ptr->ping && !gateway_ptr->pinging) {
+				gateway_ptr->status = SOFIA_GATEWAY_UP;
+			}
+			break;
+		case REG_STATE_REGISTER:
+			if (profile->debug) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Registered %s\n", gateway_ptr->name);
+			}
+
+			gateway_ptr->failures = 0;
+
+			if (gateway_ptr->freq > 60) {
+				gateway_ptr->expires = now + (gateway_ptr->freq - 15);
+			} else {
+				gateway_ptr->expires = now + (gateway_ptr->freq - 2);
+			}
+
+			gateway_ptr->state = REG_STATE_REGED;
+			gateway_ptr->status = SOFIA_GATEWAY_UP;
+			break;
+
+		case REG_STATE_UNREGISTER:
+			sofia_reg_kill_reg(gateway_ptr);
+			gateway_ptr->state = REG_STATE_NOREG;
+			break;
+		case REG_STATE_UNREGED:
+			gateway_ptr->status = SOFIA_GATEWAY_DOWN;
+
+			if (!gateway_ptr->nh) sofia_reg_new_handle(gateway_ptr, now ? 1 : 0);
+
+			if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+				user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
+			}
+
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Registering %s\n", gateway_ptr->name);
+			
+			if (now) {
+				nua_register(gateway_ptr->nh,
+							 NUTAG_URL(gateway_ptr->register_url),
+							 TAG_IF(gateway_ptr->register_sticky_proxy, NUTAG_PROXY(gateway_ptr->register_sticky_proxy)),
+							 TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+							 SIPTAG_TO_STR(gateway_ptr->register_from),
+							 SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+							 SIPTAG_FROM_STR(gateway_ptr->register_from),					 
+							 SIPTAG_EXPIRES_STR(gateway_ptr->expires_str),
+							 NUTAG_REGISTRAR(gateway_ptr->register_proxy),
+							 NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL());
+				gateway_ptr->retry = now + gateway_ptr->retry_seconds;
+			} else {
+				nua_unregister(gateway_ptr->nh,
+							   NUTAG_URL(gateway_ptr->register_url),
+							   TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+							   SIPTAG_FROM_STR(gateway_ptr->register_from),
+							   SIPTAG_TO_STR(gateway_ptr->register_from),
+							   SIPTAG_EXPIRES_STR(gateway_ptr->expires_str),
+							   NUTAG_REGISTRAR(gateway_ptr->register_proxy),
+							   NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL());
+			}
+			gateway_ptr->retry = now + gateway_ptr->retry_seconds;
+			gateway_ptr->state = REG_STATE_TRYING;			
+			switch_safe_free(user_via);
+			user_via = NULL;
+			break;
+
+		case REG_STATE_FAILED:
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s Failed Registration, setting retry to %d seconds.\n", 
+								  gateway_ptr->name, gateway_ptr->retry_seconds * (gateway_ptr->failures + 1));
+			gateway_ptr->retry =  now + (gateway_ptr->retry_seconds * (gateway_ptr->failures + 1));
+			gateway_ptr->status = SOFIA_GATEWAY_DOWN;
+			gateway_ptr->state = REG_STATE_FAIL_WAIT;
+			break;
+		case REG_STATE_FAIL_WAIT:
+			if (!gateway_ptr->retry || now >= gateway_ptr->retry) {
+				gateway_ptr->state = REG_STATE_UNREGED;
+			}
+			break;
+		case REG_STATE_TRYING:
+			if (!gateway_ptr->retry || now >= gateway_ptr->retry) {
+				gateway_ptr->state = REG_STATE_FAILED;
+			}
+			break;
+		default:
+			if (now >= gateway_ptr->expires) {
+				gateway_ptr->state = REG_STATE_UNREGED;
+			}
+			break;
+		}
+		if (ostate != gateway_ptr->state) {
+			sofia_reg_fire_custom_gateway_state_event(gateway_ptr);
+		}
+	}
+}
+
+
+int sofia_reg_find_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	struct callback_t *cbt = (struct callback_t *) pArg;
+
+	switch_copy_string(cbt->val, argv[0], cbt->len);
+	cbt->matches++;
+	return 0;
+}
+
+int sofia_reg_nat_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	sofia_profile_t *profile = (sofia_profile_t *) pArg;
+	nua_handle_t *nh;
+	char to[128] = "";
+	sofia_destination_t *dst = NULL;
+
+	switch_snprintf(to, sizeof(to), "sip:%s@%s", argv[1], argv[2]);
+	dst = sofia_glue_get_destination(argv[3]);
+	switch_assert(dst);
+
+	nh = nua_handle(profile->nua, NULL, SIPTAG_FROM_STR(profile->url), SIPTAG_TO_STR(to), NUTAG_URL(dst->contact), SIPTAG_CONTACT_STR(profile->url), TAG_END());
+	nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
+	nua_options(nh, 
+				TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)),
+				TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
+				TAG_END());
+
+	sofia_glue_free_destination(dst);
+
+	return 0;
+}
+
+
+int sofia_sub_del_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	sofia_profile_t *profile = (sofia_profile_t *) pArg;
+	nua_handle_t *nh;
+
+	if (argv[0]) {
+		if ((nh = nua_handle_by_call_id(profile->nua, argv[0]))) {
+			nua_handle_destroy(nh);
+		}
+	}
+	return 0;
+}
+
+void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent, const char *network_ip)
+{
+	const char *event = "check-sync";
+	nua_handle_t *nh;
+	char *contact_url = NULL;
+	char *contact_str = NULL;
+	char *user_via = NULL;
+	char *id = NULL;
+
+	if (switch_stristr("snom", user_agent)) {
+		event = "check-sync;reboot=true";
+	} else if (switch_stristr("linksys", user_agent)) {
+		event = "reboot_now";
+	}
+
+	if ((contact_url = sofia_glue_get_url_from_contact((char *)contact, 1))) {
+		char *p;
+		id = switch_mprintf("sip:%s@%s", user, network_ip);
+
+		if ((p = strstr(contact_url, ";fs_"))) {
+			*p = '\0';
+		}
+		if (sofia_glue_check_nat(profile, network_ip)) {
+			char *ptr = NULL;
+			const char *transport_str = NULL;
+			
+			if ((ptr = sofia_glue_find_parameter(contact_url, "transport="))) {
+				sofia_transport_t transport = sofia_glue_str2transport(ptr);
+				transport_str = sofia_glue_transport2str(transport);
+				
+				switch (transport) {
+				case SOFIA_TRANSPORT_TCP:
+					contact_str = profile->tcp_public_contact;
+					break;
+				case SOFIA_TRANSPORT_TCP_TLS:
+					contact_str = profile->tls_public_contact;
+					break;
+				default:
+					contact_str = profile->public_url;
+					break;
+				}
+				
+				user_via = sofia_glue_create_external_via(NULL, profile, transport);
+			} else {
+				user_via = sofia_glue_create_external_via(NULL, profile, SOFIA_TRANSPORT_UDP);
+				contact_str = profile->public_url;
+			}
+		
+		} else {
+			contact_str = profile->url;
+		}
+
+		nh = nua_handle(profile->nua, NULL, 
+						NUTAG_URL(contact_url), 
+						SIPTAG_FROM_STR(id), 
+						SIPTAG_TO_STR(id), 
+						SIPTAG_CONTACT_STR(contact_str), 
+						TAG_END());
+
+		nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
+		nua_notify(nh,
+				   NUTAG_NEWSUB(1),
+				   TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+				   SIPTAG_EVENT_STR(event), 
+				   SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+				   SIPTAG_PAYLOAD_STR(""),
+				   TAG_END());
+
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Sending reboot command to %s\n", contact_url);
+		free(contact_url);
+	}
+
+	switch_safe_free(user_via);
+	switch_safe_free(id);
+}
+
+int sofia_sla_dialog_del_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	sofia_profile_t *profile = (sofia_profile_t *) pArg;
+	nua_handle_t *nh = NULL;
+
+	if ((nh = nua_handle_by_call_id(profile->nua, argv[0]))) {
+		nua_handle_destroy(nh);
+	}
+	
+	return 0;
+}
+
+int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	switch_event_t *s_event;
+	sofia_profile_t *profile = (sofia_profile_t *) pArg;
+	
+	if (argc > 12 && atoi(argv[12]) == 1) {
+		sofia_reg_send_reboot(profile, argv[1], argv[2], argv[3], argv[7], argv[11]);
+	}
+
+	if (argc >= 3) {
+		if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", argv[10]);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", argv[0]);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "user", argv[1]);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "host", argv[2]);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", argv[3]);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "expires", argv[6]);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "user-agent", argv[7]);
+			switch_event_fire(&s_event);
+		}
+	}
+	return 0;
+}
+
+void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id, int reboot)
+{
+	char sql[1024];
+	char sqlextra[1024] = "";
+	char *psql = sql;
+	char *dup = strdup(call_id);
+	char *host = NULL, *user = NULL;
+
+	switch_assert(dup);
+
+	if ((host = strchr(dup, '@'))) {
+		*host++ = '\0';
+		user = dup;
+	} else {
+		host = dup;
+	}
+
+	if (!host) {
+		host = "none";
+	}
+
+	if (switch_strlen_zero(user)) {
+		switch_snprintf(sqlextra, sizeof(sqlextra), " or (sip_host='%s')", host);
+	} else {
+		switch_snprintf(sqlextra, sizeof(sqlextra), " or (sip_user='%s' and sip_host='%s')", user, host);
+	}
+
+	switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires"
+					",user_agent,server_user,server_host,profile_name,network_ip"
+					",%d from sip_registrations where call_id='%s' %s", 
+					reboot, call_id, sqlextra);
+	
+	switch_mutex_lock(profile->ireg_mutex);
+	sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_reg_del_callback, profile);
+	switch_mutex_unlock(profile->ireg_mutex);
+
+	switch_snprintf(sql, sizeof(sql), "delete from sip_registrations where call_id='%s' or (sip_user='%s' and sip_host='%s')", 
+					call_id, user, host);
+	sofia_glue_execute_sql(profile, &psql, SWITCH_FALSE);
+
+	switch_safe_free(dup);
+
+}
+
+void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
+{
+	char sql[1024];
+
+	if (switch_odbc_available() && profile->odbc_dsn) {
+		if (!profile->master_odbc) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+			return;
+		}
+	} else {
+		if (!profile->master_db) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+			return;
+		}
+	}
+
+	switch_mutex_lock(profile->ireg_mutex);
+
+	if (now) {
+		switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires"
+						",user_agent,server_user,server_host,profile_name,network_ip"
+						",%d from sip_registrations where expires > 0 and expires <= %ld", reboot, (long) now);
+	} else {
+		switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,expires"
+						",user_agent,server_user,server_host,profile_name,network_ip"
+						",%d from sip_registrations where expires > 0", reboot);
+	}
+
+	sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_reg_del_callback, profile);
+	if (now) {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires <= %ld and hostname='%s'", 
+						(long) now, mod_sofia_globals.hostname);
+	} else {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and hostname='%s'", mod_sofia_globals.hostname);
+	}
+
+	sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+
+
+	if (now) {
+		switch_snprintf(sql, sizeof(sql), "select call_id from sip_shared_appearance_dialogs where hostname='%s' "
+						"and profile_name='%s' and expires <= %ld", 
+						mod_sofia_globals.hostname, profile->name, (long) now);
+	
+		sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_sla_dialog_del_callback, profile);
+		switch_snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and hostname='%s' and expires <= %ld", 
+						mod_sofia_globals.hostname, (long) now);
+
+
+		sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+	}
+
+
+	if (now) {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_presence where expires > 0 and expires <= %ld and hostname='%s'", 
+						(long) now, mod_sofia_globals.hostname);
+	} else {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_presence where expires > 0 and hostname='%s'", mod_sofia_globals.hostname);
+	}
+
+	sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+	if (now) {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires <= %ld and hostname='%s'", 
+						(long) now, mod_sofia_globals.hostname);
+	} else {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and hostname='%s'", mod_sofia_globals.hostname);
+	}
+
+	sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+
+
+	if (now) {
+		switch_snprintf(sql, sizeof(sql), "select call_id from sip_subscriptions where expires > 0 and expires <= %ld and hostname='%s'", 
+						(long) now, mod_sofia_globals.hostname);
+	} else {
+		switch_snprintf(sql, sizeof(sql), "select call_id from sip_subscriptions where expires > 0 and hostname='%s'", mod_sofia_globals.hostname);
+	}
+
+	sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_sub_del_callback, profile);
+
+	if (now) {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires <= %ld and hostname='%s'", 
+						(long) now, mod_sofia_globals.hostname);
+	} else {
+		switch_snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and hostname='%s'", mod_sofia_globals.hostname);
+	}
+
+	sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+
+	if (now && sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) {
+		switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,"
+						"expires,user_agent,server_user,server_host,profile_name"
+						" from sip_registrations where (status like '%%AUTO-NAT%%' "
+						"or status like '%%UDP-NAT%%') and hostname='%s'", mod_sofia_globals.hostname);
+
+		sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_reg_nat_callback, profile);
+	}
+
+	switch_mutex_unlock(profile->ireg_mutex);
+
+}
+
+char *sofia_reg_find_reg_url(sofia_profile_t *profile, const char *user, const char *host, char *val, switch_size_t len)
+{
+	struct callback_t cbt = { 0 };
+	char sql[512] = "";
+
+	if (!user) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n");
+		return NULL;
+	}
+
+	cbt.val = val;
+	cbt.len = len;
+
+	if (host) {
+		switch_snprintf(sql, sizeof(sql), "select contact from sip_registrations where sip_user='%s' and (sip_host='%s' or presence_hosts like '%%%s%%')"
+						, user, host, host);
+	} else {
+		switch_snprintf(sql, sizeof(sql), "select contact from sip_registrations where sip_user='%s'", user);
+	}
+
+
+	sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_reg_find_callback, &cbt);
+
+
+	if (cbt.matches) {
+		return val;
+	} else {
+		return NULL;
+	}
+}
+
+
+void sofia_reg_auth_challenge(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_regtype_t regtype, const char *realm, int stale)
+{
+	switch_uuid_t uuid;
+	char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+	char *sql, *auth_str;
+
+	switch_uuid_get(&uuid);
+	switch_uuid_format(uuid_str, &uuid);
+
+	sql = switch_mprintf("insert into sip_authentication (nonce,expires,profile_name,hostname) "
+						 "values('%q', %ld, '%q', '%q')", uuid_str, switch_epoch_time_now(NULL) + profile->nonce_ttl, profile->name, mod_sofia_globals.hostname);
+	switch_assert(sql != NULL);
+	sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex);
+	switch_safe_free(sql);
+
+	auth_str = switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", realm, uuid_str, stale ? " stale=\"true\"," : "");
+
+	if (regtype == REG_REGISTER) {
+		nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_IF(nua, NUTAG_WITH_THIS(nua)), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
+	} else if (regtype == REG_INVITE) {
+		nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED, TAG_IF(nua, NUTAG_WITH_THIS(nua)), SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
+	}
+
+	switch_safe_free(auth_str);
+}
+
+uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, sofia_regtype_t regtype, char *key,
+								  uint32_t keylen, switch_event_t **v_event, const char *is_nat)
+{
+	sip_to_t const *to = NULL;
+	sip_from_t const *from = NULL;
+	sip_expires_t const *expires = NULL;
+	sip_authorization_t const *authorization = NULL;
+	sip_contact_t const *contact = NULL;
+	char *sql;
+	switch_event_t *s_event;
+	const char *to_user = NULL;
+	const char *to_host = NULL;
+	const char *from_user = NULL;
+	const char *from_host = NULL;
+	const char *reg_host = profile->reg_db_domain;
+	char contact_str[1024] = "";
+	int nat_hack = 0;
+	uint8_t multi_reg = 0, multi_reg_contact = 0, avoid_multi_reg = 0;
+	uint8_t stale = 0, forbidden = 0;
+	auth_res_t auth_res;
+	long exptime = 300;
+	switch_event_t *event;
+	const char *rpid = "unknown";
+	const char *display = "\"user\"";
+	char network_ip[80];
+	char network_port_c[6];
+	char url_ip[80];
+	char *register_gateway = NULL;
+	int network_port;
+	const char *reg_desc = "Registered";
+	const char *call_id = NULL;
+	char *force_user;
+	char received_data[128] = "";
+	char *path_val = NULL;
+	switch_event_t *auth_params = NULL;
+	int r = 0;
+
+	/* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */
+	switch_assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL);
+
+	sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &network_port);
+
+	snprintf(network_port_c, sizeof(network_port_c), "%d", network_port);
+
+	snprintf(url_ip, sizeof(url_ip), (msg_addrinfo(nua_current_request(nua)))->ai_addr->sa_family == AF_INET6 ? "[%s]" : "%s", network_ip);
+
+	expires = sip->sip_expires;
+	authorization = sip->sip_authorization;
+	contact = sip->sip_contact;
+	to = sip->sip_to;
+
+	if (to) {
+		to_user = to->a_url->url_user;
+		to_host = to->a_url->url_host;
+	}
+
+	if (!to_user || !to_host) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete from header\n");
+		nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
+		switch_goto_int(r, 1, end);
+	}
+
+	if (!reg_host) {
+		reg_host = to_host;
+	}
+
+	from = sip->sip_from;
+
+	if (from) {
+		from_user = from->a_url->url_user;
+		from_host = from->a_url->url_host;
+	}
+
+	if (contact->m_url) {
+		const char *port = contact->m_url->url_port;
+		char new_port[25] = "";
+		const char *contact_host = contact->m_url->url_host;
+		char *path_encoded = NULL;
+		int path_encoded_len = 0;
+		const char *proto = "sip";
+		int is_tls = 0, is_tcp = 0;
+
+
+		if (switch_stristr("transport=tls", sip->sip_contact->m_url->url_params)) {
+			is_tls += 1;
+		}
+		
+		if (sip->sip_contact->m_url->url_type == url_sips) {
+			proto = "sips";
+			is_tls += 2;
+		}
+		
+		if (switch_stristr("transport=tcp", sip->sip_contact->m_url->url_params)) {
+			is_tcp = 1;
+		}
+		
+		display = contact->m_display;
+		
+		if (is_nat) {
+			if (is_tls) {
+				reg_desc = "Registered(TLS-NAT)";
+			} else if (is_tcp) {
+				reg_desc = "Registered(TCP-NAT)";
+			} else {
+				reg_desc = "Registered(UDP-NAT)";
+			}
+			//contact_host = url_ip;
+			//switch_snprintf(new_port, sizeof(new_port), ":%d", network_port);
+			//port = NULL;
+		} else {
+			if (is_tls) {
+				reg_desc = "Registered(TLS)";
+			} else if (is_tcp) {
+				reg_desc = "Registered(TCP)";
+			} else {
+				reg_desc = "Registered(UDP)";
+			}
+		}
+
+		if (switch_strlen_zero(display)) {
+			if (to) {
+				display = to->a_display;
+				if (switch_strlen_zero(display)) {
+					display = "\"user\"";
+				}
+			}
+		}
+
+		if (sip->sip_path) {
+			path_val = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_path);
+			path_encoded_len = (strlen(path_val) * 3) + 1;
+			switch_zmalloc(path_encoded, path_encoded_len);
+			switch_copy_string(path_encoded, ";fs_path=", 10);
+			switch_url_encode(path_val, path_encoded + 9, path_encoded_len - 9);
+		} else if (is_nat) {
+			char my_contact_str[1024];
+			if (sip->sip_contact->m_url->url_params) {
+				switch_snprintf(my_contact_str, sizeof(my_contact_str), "sip:%s@%s:%d;%s", 
+								contact->m_url->url_user, url_ip, network_port, sip->sip_contact->m_url->url_params);
+			} else {
+				switch_snprintf(my_contact_str, sizeof(my_contact_str), "sip:%s@%s:%d", contact->m_url->url_user, url_ip, network_port);
+			}
+
+			path_encoded_len = (strlen(my_contact_str) * 3) + 1;
+
+			switch_zmalloc(path_encoded, path_encoded_len);
+			switch_copy_string(path_encoded, ";fs_path=", 10);
+			switch_url_encode(my_contact_str, path_encoded + 9, path_encoded_len - 9);
+			exptime = 30;
+		}
+
+		if (port) {
+			switch_snprintf(new_port, sizeof(new_port), ":%s", port);
+		}
+
+		if (is_nat && sofia_test_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT)) {
+			switch_snprintf(received_data, sizeof(received_data), ";received=%s:%d", url_ip, network_port);
+		}
+
+		if (contact->m_url->url_params) {
+			switch_snprintf(contact_str, sizeof(contact_str), "%s <%s:%s@%s%s;%s%s%s%s>",
+							display, proto, contact->m_url->url_user, contact_host, new_port, 
+							contact->m_url->url_params, received_data, is_nat ? ";fs_nat=yes" : "", path_encoded ? path_encoded : "");
+		} else {
+			switch_snprintf(contact_str, sizeof(contact_str), "%s <%s:%s@%s%s%s%s%s>", display, proto, contact->m_url->url_user, contact_host, new_port,
+							received_data, is_nat ? ";fs_nat=yes" : "", path_encoded ? path_encoded : "");
+		}
+
+		switch_safe_free(path_encoded);
+	}
+
+	if (expires) {
+		exptime = expires->ex_delta;
+	} else if (contact->m_expires) {
+		exptime = atol(contact->m_expires);
+	}
+
+	if (regtype == REG_REGISTER) {
+		authorization = sip->sip_authorization;
+	} else if (regtype == REG_INVITE) {
+		authorization = sip->sip_proxy_authorization;
+	}
+
+	if (regtype == REG_AUTO_REGISTER || (regtype == REG_REGISTER && sofia_test_pflag(profile, PFLAG_BLIND_REG))) {
+		regtype = REG_REGISTER;
+		goto reg;
+	}
+
+	if (authorization) {
+		char *v_contact_str;
+		if ((auth_res = sofia_reg_parse_auth(profile, authorization, sip, sip->sip_request->rq_method_name,
+											 key, keylen, network_ip, v_event, exptime, regtype, to_user, &auth_params)) == AUTH_STALE) {
+			stale = 1;
+		}
+
+		if (exptime && v_event && *v_event) {
+			char *exp_var;
+			char *allow_multireg = NULL;
+
+			allow_multireg = switch_event_get_header(*v_event, "sip-allow-multiple-registrations");
+			if ( allow_multireg && switch_false(allow_multireg) ) {
+				avoid_multi_reg = 1;
+			}
+
+			register_gateway = switch_event_get_header(*v_event, "sip-register-gateway");
+
+			/* Allow us to force the SIP user to be something specific - needed if 
+			 * we - for example - want to be able to ensure that the username a UA can
+			 * be contacted at is the same one that they used for authentication.
+			 */
+			if ((force_user = switch_event_get_header(*v_event, "sip-force-user"))) {
+				to_user = force_user;
+			}
+
+			if ((v_contact_str = switch_event_get_header(*v_event, "sip-force-contact"))) {
+				if (!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction-2.0")) {
+					char *path_encoded;
+					size_t path_encoded_len;
+					char my_contact_str[1024];
+
+					switch_snprintf(my_contact_str, sizeof(my_contact_str), "sip:%s@%s:%d", contact->m_url->url_user, url_ip, network_port);
+					path_encoded_len = (strlen(my_contact_str) * 3) + 1;
+
+					switch_zmalloc(path_encoded, path_encoded_len);
+					switch_copy_string(path_encoded, ";fs_nat=yes;fs_path=", 21);
+					switch_url_encode(my_contact_str, path_encoded + 20, path_encoded_len - 20);
+					reg_desc = "Registered(AUTO-NAT-2.0)";
+					exptime = 30;
+					switch_snprintf(contact_str + strlen(contact_str), sizeof(contact_str) - strlen(contact_str), "%s", path_encoded);
+					free(path_encoded);
+				} else {
+					if (*received_data && sofia_test_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT)) {
+						switch_snprintf(received_data, sizeof(received_data), ";received=%s:%d", url_ip, network_port);
+					}
+
+	
+					if (!strcasecmp(v_contact_str, "nat-connectile-dysfunction") ||
+						!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction") || !strcasecmp(v_contact_str, "NDLB-tls-connectile-dysfunction")) {
+						if (contact->m_url->url_params) {
+							switch_snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%d;%s%s;fs_nat=yes>",
+											display, contact->m_url->url_user, url_ip, network_port, contact->m_url->url_params, received_data);
+						} else {
+							switch_snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%d%s;fs_nat=yes>", display, contact->m_url->url_user, url_ip,
+											network_port, received_data);
+						}
+						if (strstr(v_contact_str, "tls")) {
+							reg_desc = "Registered(TLSHACK)";
+						} else {
+							reg_desc = "Registered(AUTO-NAT)";
+							exptime = 30;
+						}
+						nat_hack = 1;
+					} else {
+						char *p;
+						switch_copy_string(contact_str, v_contact_str, sizeof(contact_str));
+						for (p = contact_str; p && *p; p++) {
+							if (*p == '\'' || *p == '[' || *p == ']') {
+								*p = '"';
+							}
+						}
+					}
+				}
+			}
+
+			if ((exp_var = switch_event_get_header(*v_event, "sip-force-expires"))) {
+				int tmp = atoi(exp_var);
+				if (tmp > 0) {
+					exptime = tmp;
+				}
+			}
+		}
+
+		if (auth_res != AUTH_OK && !stale) {
+			if (profile->debug) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s for [%s@%s]\n", forbidden ? "forbidden" : "challenge", to_user, to_host);
+			}
+			if (auth_res == AUTH_FORBIDDEN) {
+				nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
+			} else {
+				nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
+			}
+			switch_goto_int(r, 1, end);
+		}
+	}
+
+	if (!authorization || stale) {
+		const char *realm = profile->challenge_realm;
+
+		if (switch_strlen_zero(realm) || !strcasecmp(realm, "auto_to")) {
+			realm = to_host;
+		} else if (!strcasecmp(realm, "auto_from")) {
+			realm = from_host;
+		}
+
+		if (regtype == REG_REGISTER) {
+			sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale);
+			if (profile->debug) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", to_user, to_host);
+			}
+		} else {
+			sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale);
+		}
+		switch_goto_int(r, 1, end);
+	}
+  reg:
+
+	if (regtype != REG_REGISTER) {
+		switch_goto_int(r, 0, end);
+	}
+
+	call_id = sip->sip_call_id->i_id;
+	switch_assert(call_id);
+
+	/* Does this profile supports multiple registrations ? */
+	multi_reg = ( sofia_test_pflag(profile, PFLAG_MULTIREG) ) ? 1 : 0;
+	multi_reg_contact = ( sofia_test_pflag(profile, PFLAG_MULTIREG_CONTACT) ) ? 1 : 0;
+
+	if ( multi_reg && avoid_multi_reg ) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
+					"Disabling multiple registrations on a per-user basis for %s@%s\n", 
+					switch_str_nil(to_user), switch_str_nil(to_host) );
+		multi_reg = 0;
+	}
+
+	if (exptime) {
+		const char *agent = "dunno";
+		char guess_ip4[256];
+		const char *username = "unknown";
+		const char *realm = reg_host;
+
+		if (auth_params) {
+			username = switch_event_get_header(auth_params, "sip_auth_username");
+			realm = switch_event_get_header(auth_params, "sip_auth_realm");
+		}
+
+		if (sip->sip_user_agent) {
+			agent = sip->sip_user_agent->g_string;
+		}
+
+		if (multi_reg) {
+			if (multi_reg_contact) {
+				sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, reg_host, contact_str);
+			} else {
+				sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id);
+			}
+		} else {
+			sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", 
+								 to_user, reg_host);
+		}
+		switch_mutex_lock(profile->ireg_mutex);
+		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+		
+		switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET);
+		sql = switch_mprintf("insert into sip_registrations "
+							 "(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires,"
+							 "user_agent,server_user,server_host,profile_name,hostname,network_ip,network_port,sip_username,sip_realm) "
+							 "values ('%q','%q', '%q','%q','%q','%q', '%q', %ld, '%q', '%q', '%q', '%q', '%q', '%q', '%q','%q','%q')", 
+							 call_id, to_user, reg_host, profile->presence_hosts ? profile->presence_hosts : reg_host, 
+							 contact_str, reg_desc, rpid, (long) switch_epoch_time_now(NULL) + (long) exptime * 2, 
+							 agent, from_user, guess_ip4, profile->name, mod_sofia_globals.hostname, network_ip, network_port_c, username, realm);
+							 
+		if (sql) {
+			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+		}
+
+
+		switch_mutex_unlock(profile->ireg_mutex);
+
+		if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-host", reg_host);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "presence-hosts", profile->presence_hosts ? profile->presence_hosts : reg_host);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", call_id);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "statusd", reg_desc);
+			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-user", from_user);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-host", from_host);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "network-ip", network_ip);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "network-port", network_port_c);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "username", username);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "realm", realm);
+			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "user-agent", agent);
+			switch_event_fire(&s_event);
+		}
+
+
+
+		if (profile->debug) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+							  "Register:\nFrom:    [%s@%s]\nContact: [%s]\nExpires: [%ld]\n", to_user, reg_host, contact_str, (long) exptime);
+		}
+
+		
+#if 0
+		if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent",
+										   (sip && sip->sip_user_agent) ? sip->sip_user_agent->g_string : "unknown");
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, reg_host);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "Registered");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+			switch_event_fire(&event);
+		}
+#else
+		if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "sip");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, reg_host);
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, reg_host);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "Registered");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+			switch_event_fire(&event);
+		}
+#endif
+
+
+	} else {
+
+		if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent",
+										   (sip && sip->sip_user_agent) ? sip->sip_user_agent->g_string : "unknown");
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, reg_host);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "Unregistered");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+			switch_event_fire(&event);
+		}
+#if 0
+		if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "sip");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_PROTO, to_user, reg_host);
+
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "unavailable");
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+			switch_event_fire(&event);
+		}
+#endif
+
+		if (multi_reg) {
+			char *icontact, *p;
+			icontact = sofia_glue_get_url_from_contact(contact_str, 1);
+			if ((p = strchr(icontact, ';'))) {
+				*p = '\0';
+			}
+			if ((p = strchr(icontact + 4, ':'))) {
+				*p = '\0';
+			}
+
+			if (multi_reg_contact) {
+				sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, reg_host, contact_str);
+			} else {
+				sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id);
+			}
+
+			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+
+			if (multi_reg_contact) {
+				sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, reg_host, contact_str);
+			} else {
+				sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id);
+			}
+
+			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+
+			switch_safe_free(icontact);
+		} else {
+			if ((sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, reg_host))) {
+				sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+			}
+
+			if ((sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", to_user, reg_host))) {
+				sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+			}
+		}
+	}
+
+
+	if (regtype == REG_REGISTER) {
+		char exp_param[128] = "";
+		char date[80] = "";
+
+		s_event = NULL;
+
+		if (exptime) {
+			switch_snprintf(exp_param, sizeof(exp_param), "expires=%ld", exptime);
+			sip_contact_add_param(nua_handle_home(nh), sip->sip_contact, exp_param);
+
+			if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER)) {
+				if (switch_event_create(&s_event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
+					switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "Message-Account", "sip:%s@%s", to_user, reg_host);
+					switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);
+					switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "VM-Call-ID", call_id);
+				}
+			}
+		} else {
+			if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) {
+				switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
+				switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user);
+				switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-host", reg_host);
+				switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
+				switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", call_id);
+				switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", rpid);
+				switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
+			}
+		}
+		
+		switch_rfc822_date(date, switch_micro_time_now());
+		nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip->sip_contact),
+					TAG_IF(path_val, SIPTAG_PATH_STR(path_val)),
+					NUTAG_WITH_THIS(nua),
+					SIPTAG_DATE_STR(date),
+					TAG_END());
+
+		if (s_event) {
+			switch_event_fire(&s_event);
+		}
+
+		if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
+			char *full_contact = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_contact);
+			if (full_contact && switch_stristr("SUBSCRIBE", full_contact)) {
+				sofia_sla_handle_register(nua, profile, sip, exptime, full_contact);
+				su_free(nua_handle_home(nh), full_contact);
+			}
+		}
+
+		switch_goto_int(r, 1, end);
+	}
+
+
+ end:
+
+	if (auth_params) {
+		switch_event_destroy(&auth_params);
+	}
+
+	return (uint8_t)r;
+}
+
+
+
+void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+									 tagi_t tags[])
+{
+	char key[128] = "";
+	switch_event_t *v_event = NULL;
+	char network_ip[80];
+	sofia_regtype_t type = REG_REGISTER;
+	int network_port = 0;
+	char *is_nat = NULL;
+
+	sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &network_port);
+
+	if (!(sip->sip_contact && sip->sip_contact->m_url)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
+		nua_respond(nh, 400, "Missing Contact Header", TAG_END());
+		goto end;
+	}
+
+	if (!(profile->mflags & MFLAG_REGISTER)) {
+		nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
+		goto end;
+	}
+
+	if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
+		if (sip && sip->sip_via) {
+			const char *port = sip->sip_via->v_port;
+			const char *host = sip->sip_via->v_host;
+					
+			if (host && sip->sip_via->v_received) {
+				is_nat = "via received";
+			} else if (host && strcmp(network_ip, host)) {
+				is_nat = "via host";
+			} else if (port && atoi(port) != network_port) {
+				is_nat = "via port";
+			}
+		}
+	}
+
+	if (!is_nat && profile->nat_acl_count) {
+		uint32_t x = 0;
+		int ok = 1;
+		char *last_acl = NULL;
+		const char *contact_host = NULL;
+
+		if (sip && sip->sip_contact && sip->sip_contact->m_url) {
+			contact_host = sip->sip_contact->m_url->url_host;
+		}
+
+		if (!switch_strlen_zero(contact_host)) {
+			for (x = 0; x < profile->nat_acl_count; x++) {
+				last_acl = profile->nat_acl[x];
+				if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
+					break;
+				}
+			}
+				
+			if (ok) {
+				is_nat = last_acl;
+			}
+		}
+	}
+			
+	if (profile->reg_acl_count) {
+		uint32_t x = 0;
+		int ok = 1;
+		char *last_acl = NULL;
+
+		for (x = 0; x < profile->reg_acl_count; x++) {
+			last_acl = profile->reg_acl[x];
+			if (!(ok = switch_check_network_list_ip(network_ip, last_acl))) {
+				break;
+			}
+		}
+
+		if (ok && !sofia_test_pflag(profile, PFLAG_BLIND_REG)) {
+			type = REG_AUTO_REGISTER;
+		} else if (!ok) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", network_ip, profile->reg_acl[x]);
+			nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
+			goto end;
+		}
+	}
+
+	if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
+		nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+		goto end;
+	}
+
+	sofia_reg_handle_register(nua, profile, nh, sip, type, key, sizeof(key), &v_event, is_nat);
+	
+	if (v_event) {
+		switch_event_fire(&v_event);
+	}
+
+  end:
+
+	nua_handle_destroy(nh);
+
+}
+
+
+void sofia_reg_handle_sip_r_register(int status,
+									 char const *phrase,
+									 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+									 tagi_t tags[])
+{
+	if (sofia_private && sofia_private->gateway) {
+		reg_state_t ostate = sofia_private->gateway->state;
+		switch (status) {
+		case 200:
+			if (sip && sip->sip_contact) {
+				sip_contact_t *contact = sip->sip_contact;
+				const char *new_expires;
+				uint32_t expi;
+				if (contact->m_next) {
+					const char *sipip = profile->extsipip ?  profile->extsipip : profile->sipip;
+					for ( ; contact && strcasecmp(contact->m_url->url_host, sipip); contact = contact->m_next);
+				}
+
+				if (!contact) {
+					contact = sip->sip_contact;
+				}
+
+				if (contact->m_expires) {
+					new_expires = contact->m_expires;
+					expi = (uint32_t) atoi(new_expires);
+	
+					if (expi > 0 && expi != sofia_private->gateway->freq) {
+						sofia_private->gateway->freq = expi;
+						sofia_private->gateway->expires_str = switch_core_sprintf(sofia_private->gateway->pool, "%d", expi);
+
+						if (expi > 60) {
+							sofia_private->gateway->expires = switch_epoch_time_now(NULL) + (expi - 15);
+						} else {
+							sofia_private->gateway->expires = switch_epoch_time_now(NULL) + (expi - 2);
+						}
+
+
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+										  "Changing expire time to %d by request of proxy %s\n", expi, sofia_private->gateway->register_proxy);
+					}
+				}
+			}
+			sofia_private->gateway->state = REG_STATE_REGISTER;
+			break;
+		case 100:
+			break;
+		default:
+			sofia_private->gateway->state = REG_STATE_FAILED;
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s Registration Failed with status %s [%d]. failure #%d\n", 
+							  sofia_private->gateway->name, switch_str_nil(phrase), status, ++sofia_private->gateway->failures);
+			break;
+		}
+		if (ostate != sofia_private->gateway->state) {
+			sofia_reg_fire_custom_gateway_state_event(sofia_private->gateway);
+		}
+	}
+}
+
+void sofia_reg_handle_sip_r_challenge(int status,
+									  char const *phrase,
+									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private,
+									  switch_core_session_t *session, sofia_gateway_t *gateway, sip_t const *sip, tagi_t tags[])
+{
+	sip_www_authenticate_t const *authenticate = NULL;
+	char const *realm = NULL;
+	char const *scheme = NULL;
+	int indexnum;
+	char *cur;
+	char authentication[256] = "";
+	int ss_state;
+	sofia_gateway_t *var_gateway = NULL;
+	const char *gw_name = NULL;
+	switch_channel_t *channel = NULL;
+	const char *sip_auth_username = NULL;
+	const char *sip_auth_password = NULL;
+
+	if (session && (channel = switch_core_session_get_channel(session))) {
+		sip_auth_username = switch_channel_get_variable(channel, "sip_auth_username");
+		sip_auth_password = switch_channel_get_variable(channel, "sip_auth_password");
+	}
+
+	if (sofia_private && *sofia_private->auth_gateway_name) {
+		gw_name = sofia_private->auth_gateway_name;
+	}
+
+	if (session) {
+		private_object_t *tech_pvt;
+
+		if ((tech_pvt = switch_core_session_get_private(session)) && sofia_test_flag(tech_pvt, TFLAG_REFER)) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received reply from REFER\n");
+			goto end;
+		}
+
+		gw_name = switch_channel_get_variable(switch_core_session_get_channel(session), "sip_use_gateway");
+	}
+
+
+	if (sip->sip_www_authenticate) {
+		authenticate = sip->sip_www_authenticate;
+	} else if (sip->sip_proxy_authenticate) {
+		authenticate = sip->sip_proxy_authenticate;
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing Authenticate Header!\n");
+		goto end;
+	}
+	scheme = (char const *) authenticate->au_scheme;
+	if (authenticate->au_params) {
+		for (indexnum = 0; (cur = (char *) authenticate->au_params[indexnum]); indexnum++) {
+			if ((realm = strstr(cur, "realm="))) {
+				realm += 6;
+				break;
+			}
+		}
+	}
+
+	if (!gateway) {
+		if (gw_name) {
+			var_gateway = sofia_reg_find_gateway((char *)gw_name);
+		}
+
+
+		if (!var_gateway && realm) {
+			char rb[512] = "";
+			char *p = (char *) realm;
+			while((*p == '"')) {
+				p++;
+			}
+			switch_set_string(rb, p);
+			if ((p = strchr(rb, '"'))) {
+				*p = '\0';
+			}
+			var_gateway = sofia_reg_find_gateway(rb);
+		}
+
+		if (!var_gateway && sip && sip->sip_to) {
+			var_gateway = sofia_reg_find_gateway(sip->sip_to->a_url->url_host);
+		}
+		
+		if (var_gateway) {
+			gateway = var_gateway;
+		}
+	}
+
+	
+
+
+	if (!(scheme && realm)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No scheme and realm!\n");
+		goto end;
+	}
+
+	if (sip_auth_username && sip_auth_password) {
+		switch_snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, sip_auth_username, sip_auth_password);
+	} else if (gateway) {
+		switch_snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->auth_username, gateway->register_password);
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Matching gateway found\n");
+		goto cancel;		
+	}
+
+	if (profile->debug) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authenticating '%s' with '%s'.\n",
+			(sip_auth_username && sip_auth_password) ? sip_auth_username : gateway->auth_username, authentication);
+	}
+
+	ss_state = nua_callstate_authenticating;
+
+	tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), SIPTAG_WWW_AUTHENTICATE_REF(authenticate), TAG_END());
+
+	nua_authenticate(nh, SIPTAG_EXPIRES_STR(gateway ? gateway->expires_str : "3600"), NUTAG_AUTH(authentication), TAG_END());
+
+	goto end;
+
+  cancel:
+
+	if (session) {
+		switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_MANDATORY_IE_MISSING);
+	} else {
+		nua_cancel(nh, TAG_END());
+	}
+
+ end:
+
+	if (var_gateway) {
+		sofia_reg_release_gateway(var_gateway);
+	}
+
+	return;
+
+
+
+}
+
+auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile, 
+								sip_authorization_t const *authorization, 
+								sip_t const *sip, 
+								const char *regstr,
+								char *np, 
+								size_t nplen, 
+								char *ip, 
+								switch_event_t **v_event, 
+								long exptime, 
+								sofia_regtype_t 
+								regtype, 
+								const char *to_user,
+								switch_event_t **auth_params)
+{
+	int indexnum;
+	const char *cur;
+	su_md5_t ctx;
+	char uridigest[2 * SU_MD5_DIGEST_SIZE + 1];
+	char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1];
+	char *username, *realm, *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL;
+	auth_res_t ret = AUTH_FORBIDDEN;
+	int first = 0;
+	const char *passwd = NULL;
+	const char *a1_hash = NULL;
+	char *sql;
+	char *number_alias = NULL;
+	switch_xml_t domain, xml = NULL, user, param, uparams, dparams, group = NULL, gparams = NULL;
+	char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1] = "";
+	char *domain_name = NULL;
+	switch_event_t *params = NULL;
+	const char *auth_acl = NULL;
+
+	username = realm = nonce = uri = qop = cnonce = nc = response = NULL;
+
+	if (authorization->au_params) {
+		for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) {
+			char *var, *val, *p, *work;
+			var = val = work = NULL;
+			if ((work = strdup(cur))) {
+				var = work;
+				if ((val = strchr(var, '='))) {
+					*val++ = '\0';
+					while (*val == '"') {
+						*val++ = '\0';
+					}
+					if ((p = strchr(val, '"'))) {
+						*p = '\0';
+					}
+
+					if (!strcasecmp(var, "username")) {
+						username = strdup(val);
+					} else if (!strcasecmp(var, "realm")) {
+						realm = strdup(val);
+					} else if (!strcasecmp(var, "nonce")) {
+						nonce = strdup(val);
+					} else if (!strcasecmp(var, "uri")) {
+						uri = strdup(val);
+					} else if (!strcasecmp(var, "qop")) {
+						qop = strdup(val);
+					} else if (!strcasecmp(var, "cnonce")) {
+						cnonce = strdup(val);
+					} else if (!strcasecmp(var, "response")) {
+						response = strdup(val);
+					} else if (!strcasecmp(var, "nc")) {
+						nc = strdup(val);
+					}
+				}
+
+				free(work);
+			}
+		}
+	}
+
+	if (!(username && realm && nonce && uri && response)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Authorization header!\n");
+		ret = AUTH_STALE;
+		goto end;
+	}
+
+	/* Optional check that auth name == SIP username */
+	if ((regtype == REG_REGISTER) && sofia_test_pflag(profile, PFLAG_CHECKUSER)) {
+		if (switch_strlen_zero(username) || switch_strlen_zero(to_user) || strcasecmp(to_user, username)) {
+			/* Names don't match, so fail */
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SIP username %s does not match auth username\n", switch_str_nil(to_user));
+			goto end;
+		}
+	}
+
+	if (switch_strlen_zero(np)) {
+		first = 1;
+		sql = switch_mprintf("select nonce from sip_authentication where nonce='%q'", nonce);
+		switch_assert(sql != NULL);
+		if (!sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, np, nplen)) {
+			free(sql);
+			ret = AUTH_STALE;
+			goto end;
+		}
+		free(sql);
+	}
+
+	switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
+	switch_assert(params);
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "sip_auth");
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_user_agent",
+								   (sip && sip->sip_user_agent) ? sip->sip_user_agent->g_string : "unknown");
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_username", username);
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_realm", realm);
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_nonce", nonce);
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_uri", uri);
+
+	if (sip->sip_contact) {
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_contact_user", sip->sip_contact->m_url->url_user);
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_contact_host", sip->sip_contact->m_url->url_host);
+	}
+
+	if (sip->sip_to) {
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_to_user", sip->sip_to->a_url->url_user);
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_to_host", sip->sip_to->a_url->url_host);
+		if (sip->sip_to->a_url->url_port) {
+			switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_to_port", sip->sip_to->a_url->url_port);
+		}
+	}
+
+	if (sip->sip_from) {
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_from_user", sip->sip_from->a_url->url_user);
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_from_host", sip->sip_from->a_url->url_host);
+		if (sip->sip_from->a_url->url_port) {
+			switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_from_port", sip->sip_from->a_url->url_port);
+		}
+	}
+
+	if (sip->sip_request) {
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_request_user", sip->sip_request->rq_url->url_user);
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_request_host", sip->sip_request->rq_url->url_host);
+		if (sip->sip_request->rq_url->url_port) {
+			switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_request_port", sip->sip_request->rq_url->url_port);
+		}
+	}
+
+	if (qop) {
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_qop", qop);
+	}
+	if (cnonce) {
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_cnonce", cnonce);
+	}
+	if (nc) {
+		switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_nc", nc);
+	}
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_response", response);
+
+	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "sip_auth_method", (sip && sip->sip_request) ? sip->sip_request->rq_method_name : NULL);
+
+	if (auth_params) {
+		switch_event_dup(auth_params, params);
+	}
+
+
+	if (!switch_strlen_zero(profile->reg_domain)) {
+		domain_name = profile->reg_domain;
+	} else {
+		domain_name = realm;
+	}
+
+	if (switch_xml_locate_user("id", switch_strlen_zero(username) ? "nobody" : username, 
+							   domain_name, ip, &xml, &domain, &user, &group, params) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Can't find user [%s@%s]\n"
+						  "You must define a domain called '%s' in your directory and add a user with the id=\"%s\" attribute\n"
+						  "and you must configure your device to use the proper domain in it's authentication credentials.\n"
+						  , username, domain_name, domain_name, username);
+
+		ret = AUTH_FORBIDDEN;
+		goto end;
+	} else {
+		const char *type = switch_xml_attr(user, "type");
+		if (type && !strcasecmp(type, "pointer")) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cant register a pointer.\n");
+			ret = AUTH_FORBIDDEN;
+			goto end;
+		}
+	}
+	
+	if (!(number_alias = (char *) switch_xml_attr(user, "number-alias"))) {
+		number_alias = switch_strlen_zero(username) ? "nobody" : username;
+	}
+
+	dparams = switch_xml_child(domain, "params");
+	uparams = switch_xml_child(user, "params");
+	if (group) {
+		gparams = switch_xml_child(group, "params");
+	}
+
+	if (!(dparams || uparams)) {
+		ret = AUTH_OK;
+		goto skip_auth;
+	}
+
+	if (dparams) {
+		for (param = switch_xml_child(dparams, "param"); param; param = param->next) {
+			const char *var = switch_xml_attr_soft(param, "name");
+			const char *val = switch_xml_attr_soft(param, "value");
+
+			if (!strcasecmp(var, "sip-forbid-register") && switch_true(val)) {
+				ret = AUTH_FORBIDDEN;
+				goto end;
+			}
+
+			if (!strcasecmp(var, "password")) {
+				passwd = val;
+			}
+
+			if (!strcasecmp(var, "auth-acl")) {
+				auth_acl = val;
+			}
+
+			if (!strcasecmp(var, "a1-hash")) {
+				a1_hash = val;
+			}
+		}
+	}
+
+	if (gparams) {
+		for (param = switch_xml_child(gparams, "param"); param; param = param->next) {
+			const char *var = switch_xml_attr_soft(param, "name");
+			const char *val = switch_xml_attr_soft(param, "value");
+
+			if (!strcasecmp(var, "sip-forbid-register") && switch_true(val)) {
+				ret = AUTH_FORBIDDEN;
+				goto end;
+			}
+
+			if (!strcasecmp(var, "password")) {
+				passwd = val;
+			}
+
+			if (!strcasecmp(var, "auth-acl")) {
+				auth_acl = val;
+			}
+
+			if (!strcasecmp(var, "a1-hash")) {
+				a1_hash = val;
+			}
+		}
+	}
+
+	if (uparams) {
+		for (param = switch_xml_child(uparams, "param"); param; param = param->next) {
+			const char *var = switch_xml_attr_soft(param, "name");
+			const char *val = switch_xml_attr_soft(param, "value");
+
+			if (!strcasecmp(var, "sip-forbid-register") && switch_true(val)) {
+				ret = AUTH_FORBIDDEN;
+				goto end;
+			}
+
+			if (!strcasecmp(var, "password")) {
+				passwd = val;
+			}
+
+			if (!strcasecmp(var, "auth-acl")) {
+				auth_acl = val;
+			}
+
+			if (!strcasecmp(var, "a1-hash")) {
+				a1_hash = val;
+			}
+		}
+	}
+
+	if (auth_acl) {
+		if (!switch_check_network_list_ip(ip, auth_acl)) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by user acl %s\n", ip, auth_acl);
+			ret = AUTH_FORBIDDEN;
+			goto end;
+		}
+	}
+
+	if (switch_strlen_zero(passwd) && switch_strlen_zero(a1_hash)) {
+		ret = AUTH_OK;
+		goto skip_auth;
+	}
+
+	if (!a1_hash) {
+		input = switch_mprintf("%s:%s:%s", username, realm, passwd);
+		su_md5_init(&ctx);
+		su_md5_strupdate(&ctx, input);
+		su_md5_hexdigest(&ctx, hexdigest);
+		su_md5_deinit(&ctx);
+		switch_safe_free(input);
+		a1_hash = hexdigest;
+
+	}
+
+  for_the_sake_of_interop:
+
+	if ((input = switch_mprintf("%s:%q", regstr, uri))) {
+		su_md5_init(&ctx);
+		su_md5_strupdate(&ctx, input);
+		su_md5_hexdigest(&ctx, uridigest);
+		su_md5_deinit(&ctx);
+	}
+
+	if (nc && cnonce && qop) {
+		input2 = switch_mprintf("%s:%s:%s:%s:%s:%s", a1_hash, nonce, nc, cnonce, qop, uridigest);
+	} else {
+		input2 = switch_mprintf("%s:%s:%s", a1_hash, nonce, uridigest);
+	}
+
+	switch_assert(input2);
+
+	memset(&ctx, 0, sizeof(ctx));
+	su_md5_init(&ctx);
+	su_md5_strupdate(&ctx, input2);
+	su_md5_hexdigest(&ctx, bigdigest);
+	su_md5_deinit(&ctx);
+
+	if (!strcasecmp(bigdigest, response)) {
+		ret = AUTH_OK;
+	} else {
+		if ((profile->ndlb & PFLAG_NDLB_BROKEN_AUTH_HASH) && strcasecmp(regstr, "REGISTER") && strcasecmp(regstr, "INVITE")) {
+			/* some clients send an ACK with the method 'INVITE' in the hash which will break auth so we will
+			   try again with INVITE so we don't get people complaining to us when someone else's client has a bug......
+			 */
+			switch_safe_free(input);
+			switch_safe_free(input2);
+			regstr = "INVITE";
+			goto for_the_sake_of_interop;
+		}
+
+		ret = AUTH_FORBIDDEN;
+	}
+
+
+  skip_auth:
+
+	if (first && ret == AUTH_OK) {
+		if (v_event) {
+			switch_event_create_plain(v_event, SWITCH_EVENT_REQUEST_PARAMS);
+		}
+
+		
+		if (v_event && *v_event) {
+			short int xparams_type[6];
+			switch_xml_t xparams[6];
+			int i = 0;
+
+			switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, "sip_number_alias", number_alias);
+			switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, "sip_auth_username", username);
+			switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, "sip_auth_realm", realm);
+			switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, "number_alias", number_alias);
+			switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, "user_name", username);
+			switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, "domain_name", domain_name);
+
+			if ((uparams = switch_xml_child(user, "params"))) {
+				xparams_type[i] = 0;
+				xparams[i++] = uparams;
+			}
+
+			if (group && (gparams = switch_xml_child(group, "params"))) {
+				xparams_type[i] = 0;
+				xparams[i++] = gparams;
+			}
+
+			if ((dparams = switch_xml_child(domain, "params"))) {
+				xparams_type[i] = 0;
+				xparams[i++] = dparams;
+			}
+
+			if ((uparams = switch_xml_child(user, "variables"))) {
+				xparams_type[i] = 1;
+				xparams[i++] = uparams;
+			}
+
+			if (group && (gparams = switch_xml_child(group, "variables"))) {
+				xparams_type[i] = 1;
+				xparams[i++] = gparams;
+			}
+
+			if ((dparams = switch_xml_child(domain, "variables"))) {
+				xparams_type[i] = 1;
+				xparams[i++] = dparams;
+			}
+
+			if (i <= 6) {
+				int j = 0;
+
+				for (j = 0; j < i; j++) {
+					for (param = switch_xml_child(xparams[j], (xparams_type[j]?"variable":"param")); param; param = param->next) {
+						const char *var = switch_xml_attr_soft(param, "name");
+						const char *val = switch_xml_attr_soft(param, "value");
+						sofia_gateway_t *gateway_ptr = NULL;
+
+						if (!switch_strlen_zero(var) && !switch_strlen_zero(val) && (xparams_type[j] == 1 || !strncasecmp(var, "sip-",4) || !strcasecmp(var, "register-gateway")) ) {
+							if (!switch_event_get_header(*v_event, var)) {
+								if (profile->debug) {
+									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event_add_header -> '%s' = '%s'\n",var, val);
+								}
+								switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, var, val);
+							} else {
+								continue;
+							}
+
+							if (!strcasecmp(var, "register-gateway")) {
+								if (!strcasecmp(val, "all")) {
+									switch_xml_t gateways_tag, gateway_tag;
+									if ((gateways_tag = switch_xml_child(user, "gateways"))) {
+										for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) {
+											char *name = (char *) switch_xml_attr_soft(gateway_tag, "name");
+											if (switch_strlen_zero(name)) {
+												name = "anonymous";
+											}
+
+											if ((gateway_ptr = sofia_reg_find_gateway(name))) {
+												reg_state_t ostate = gateway_ptr->state;
+												gateway_ptr->retry = 0;
+												if (exptime) {
+													gateway_ptr->state = REG_STATE_UNREGED;
+												} else {
+													gateway_ptr->state = REG_STATE_UNREGISTER;
+												}
+												if (ostate != gateway_ptr->state) {
+													sofia_reg_fire_custom_gateway_state_event(gateway_ptr);
+												}
+												sofia_reg_release_gateway(gateway_ptr);
+											}
+
+										}
+									}
+								} else {
+									int x, argc;
+									char *mydata, *argv[50];
+
+									mydata = strdup(val);
+									switch_assert(mydata != NULL);
+
+									argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
+
+									for (x = 0; x < argc; x++) {
+										if ((gateway_ptr = sofia_reg_find_gateway((char *) argv[x]))) {
+											reg_state_t ostate = gateway_ptr->state;
+											gateway_ptr->retry = 0;
+											if (exptime) {
+												gateway_ptr->state = REG_STATE_UNREGED;
+											} else {
+												gateway_ptr->state = REG_STATE_UNREGISTER;
+											}
+											if (ostate != gateway_ptr->state) {
+												sofia_reg_fire_custom_gateway_state_event(gateway_ptr);
+											}
+											sofia_reg_release_gateway(gateway_ptr);
+										} else {
+											switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Gateway '%s' not found.\n", argv[x]);
+										}
+									}
+
+									free(mydata);
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+  end:
+
+	switch_event_destroy(&params);
+
+	if (xml) {
+		switch_xml_free(xml);
+	}
+
+	switch_safe_free(input);
+	switch_safe_free(input2);
+	switch_safe_free(username);
+	switch_safe_free(realm);
+	switch_safe_free(nonce);
+	switch_safe_free(uri);
+	switch_safe_free(qop);
+	switch_safe_free(cnonce);
+	switch_safe_free(nc);
+	switch_safe_free(response);
+
+	return ret;
+
+}
+
+
+sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, int line, const char *key)
+{
+	sofia_gateway_t *gateway = NULL;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	if ((gateway = (sofia_gateway_t *) switch_core_hash_find(mod_sofia_globals.gateway_hash, key))) {
+		if (!sofia_test_pflag(gateway->profile, PFLAG_RUNNING) || gateway->deleted) {
+			gateway = NULL;
+			goto done;
+		}
+		if (switch_thread_rwlock_tryrdlock(gateway->profile->rwlock) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is locked\n", gateway->profile->name);
+			gateway = NULL;
+		}
+	}
+	if (gateway) {
+#ifdef SOFIA_DEBUG_RWLOCKS
+		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX GW LOCK %s\n", gateway->profile->name);
+#endif
+	}
+
+  done:
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+	return gateway;
+}
+
+void sofia_reg_release_gateway__(const char *file, const char *func, int line, sofia_gateway_t *gateway)
+{
+	switch_thread_rwlock_unlock(gateway->profile->rwlock);
+#ifdef SOFIA_DEBUG_RWLOCKS
+	switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX GW UNLOCK %s\n", gateway->profile->name);
+#endif
+}
+
+switch_status_t sofia_reg_add_gateway(char *key, sofia_gateway_t *gateway)
+{
+	switch_status_t status = SWITCH_STATUS_FALSE;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	if (!switch_core_hash_find(mod_sofia_globals.gateway_hash, key)) {
+		status = switch_core_hash_insert(mod_sofia_globals.gateway_hash, key, gateway);
+	}
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+	if (status == SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Added gateway '%s' to profile '%s'\n", gateway->name, gateway->profile->name);
+	}
+
+	return status;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Copied: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_sla.c (from rev 14389, freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_sla.c) (0 => 14390)


--- freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_sla.c	                        (rev 0)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_sla.c	2009-07-27 20:18:20 UTC (rev 14390)
@@ -0,0 +1,366 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
+ * Paul D. Tinsley <pdt at jackhammer.org>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ * Brian West <brian@freeswitch.org>
+ *
+ * sofia_sla.c -- SOFIA SIP Endpoint (support for shared line appearance)
+ *  This file (and calls into it) developed by Matthew T Kaufman <matthew@matthew.at>
+ *
+ */
+#include "mod_sofia.h"
+
+static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **columnNames);
+
+struct sla_helper {
+	char call_id[1024];
+};
+
+static int get_call_id_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	struct sla_helper *sh = (struct sla_helper *) pArg;
+
+	switch_set_string(sh->call_id, argv[0]);
+	return 0;
+}
+
+void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip, long exptime, const char *full_contact)
+{
+	nua_handle_t *nh = NULL;
+	char exp_str[256] = "";
+	char my_contact[256] = "";
+	char *sql;
+	struct sla_helper sh = { { 0 } };
+	char *contact_str = sofia_glue_strip_uri(full_contact);
+	sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url);
+	char network_ip[80];
+	int network_port = 0;
+
+	sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &network_port);
+
+	sql = switch_mprintf("select call_id from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'", 
+						 mod_sofia_globals.hostname, profile->name, contact_str);
+	sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, get_call_id_callback, &sh);
+
+	free(sql);
+	
+	if (*sh.call_id) {
+		if (!(nh = nua_handle_by_call_id(profile->nua, sh.call_id))) {
+			if ((sql = switch_mprintf("delete from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'", 
+									  mod_sofia_globals.hostname, profile->name, contact_str))) {
+				sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+			}
+		}
+	}
+
+	if (!nh) {
+		nh = nua_handle(nua, NULL, NUTAG_URL(sip->sip_contact->m_url), TAG_NULL());
+	}
+
+	nua_handle_bind(nh, &mod_sofia_globals.keep_private);
+
+	switch_snprintf(exp_str, sizeof(exp_str), "%ld", exptime + 30);
+	if (sofia_glue_check_nat(profile, network_ip)) { 
+		switch_snprintf(my_contact, sizeof(my_contact), "<sip:%s@%s;transport=%s>;expires=%s", profile->sla_contact, 
+						profile->extsipip, sofia_glue_transport2str(transport), exp_str);
+	} else {
+		switch_snprintf(my_contact, sizeof(my_contact), "<sip:%s@%s;transport=%s>;expires=%s", profile->sla_contact, 
+						profile->sipip, sofia_glue_transport2str(transport), exp_str);
+	}
+	nua_subscribe(nh,
+				  SIPTAG_TO(sip->sip_to),
+				  SIPTAG_FROM(sip->sip_to),
+				  SIPTAG_CONTACT_STR(my_contact),
+				  SIPTAG_EXPIRES_STR(exp_str),
+				  SIPTAG_EVENT_STR("dialog;sla"),	/* some phones want ;include-session-description too? */
+				  TAG_NULL());
+
+	free(contact_str);
+}
+
+void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[])
+{
+	/* at present there's no SLA versions that we deal with that do publish. to be safe, we say "OK" */
+	nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+}
+
+void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[])
+{
+	char *aor = NULL;
+	char *subscriber = NULL;
+	char *sql = NULL;
+	char *route_uri = NULL;
+	char *sla_contact = NULL;
+	char network_ip[80];
+	int network_port = 0;
+	sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url);
+
+	sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &network_port);
+	/*
+	 * XXX MTK FIXME - we don't look at the tag to see if NUTAG_SUBSTATE(nua_substate_terminated) or
+	 * a Subscription-State header with state "terminated" and/or expiration of 0. So we never forget
+	 * about them here.
+	 * likewise, we also don't have a hook against nua_r_notify events, so we can't see nua_substate_terminated there.
+	*/
+
+	/*
+	 * extracting AOR is weird...
+	 * the From is the main extension, not the third-party one...
+	 * and the contact has the phone's own network address, not the AOR address
+	 * so we do what openser's pua_bla does and...
+	 */
+
+	/* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */
+	aor = switch_mprintf("sip:%s@%s", sip->sip_contact->m_url->url_user, profile->sipip);
+
+	/*
+	 * ok, and now that we HAVE the AOR, we REALLY should go check in the XML config and see if this particular
+	 * extension is set up to have shared appearances managed. right now it is all-or-nothing on the profile,
+	 * which won't be sufficient for real life. FIXME XXX MTK
+	*/
+
+	/* then the subscriber is the user at their network location... this is arguably the wrong way, but works so far... */
+
+	subscriber = switch_mprintf("sip:%s@%s;transport=%s", sip->sip_from->a_url->url_user,
+								sip->sip_contact->m_url->url_host, sofia_glue_transport2str(transport));
+ 
+	if ((sql =
+		switch_mprintf("delete from sip_shared_appearance_subscriptions where subscriber='%q' and profile_name='%q' and hostname='%q'",
+			subscriber, profile->name, mod_sofia_globals.hostname
+			))) {
+		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+	}
+
+	if ((sql =
+		 switch_mprintf("insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname, contact_str, network_ip) "
+		               "values ('%q','%q','%q','%q','%q','%q','%q')",
+		                subscriber, sip->sip_call_id->i_id, aor, profile->name, mod_sofia_globals.hostname, contact_str, network_ip))) {
+		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+	}
+
+	if (strstr(contact_str, ";fs_nat")) {
+		char *p;
+		route_uri = sofia_glue_get_url_from_contact((char *)contact_str, 1);
+		if ((p = strstr(contact_str, ";fs_"))) {
+			*p = '\0';
+		}
+	}
+
+	if (route_uri) {
+		char *p;
+
+		while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) {
+			route_uri++;
+		}
+		if ((p = strchr(route_uri, '>'))) {
+			*p++ = '\0';
+		}
+	}
+	if (sofia_glue_check_nat(profile, network_ip)) { 
+		sla_contact = switch_mprintf("<sip:%s@%s;transport=%s>", profile->sla_contact, profile->extsipip, sofia_glue_transport2str(transport));
+	} else {
+		sla_contact = switch_mprintf("<sip:%s@%s;transport=%s>", profile->sla_contact, profile->sipip, sofia_glue_transport2str(transport));
+	}
+
+	nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_CONTACT_STR(sla_contact), NUTAG_WITH_THIS(nua),
+				TAG_IF(route_uri, NUTAG_PROXY(route_uri)),
+				SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* you thought the OTHER time was fake... need delta here FIXME XXX MTK */
+				SIPTAG_EXPIRES_STR("300"), /* likewise, totally fake - FIXME XXX MTK */
+				/*  sofia_presence says something about needing TAG_IF(sticky, NUTAG_PROXY(sticky)) for NAT stuff? */
+				TAG_END());
+
+	switch_safe_free(aor);
+	switch_safe_free(subscriber);
+	switch_safe_free(route_uri);
+	switch_safe_free(sla_contact);
+	switch_safe_free(sql);
+}
+
+struct sla_notify_helper {
+	sofia_profile_t *profile;
+	char *payload;
+};
+
+void sofia_sla_handle_sip_r_subscribe(int status,
+									  char const *phrase,
+									  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
+{
+	if (status >= 300) {
+		nua_handle_destroy(nh);
+		sofia_private_free(sofia_private);
+	} else {
+		char *full_contact = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_contact);
+		time_t expires = switch_epoch_time_now(NULL);
+		char *sql;
+		char *contact_str = sofia_glue_strip_uri(full_contact);
+
+		if (sip && sip->sip_expires) {
+			expires += sip->sip_expires->ex_delta + 30;
+		}
+
+		if ((sql = switch_mprintf("insert into sip_shared_appearance_dialogs (profile_name, hostname, contact_str, call_id, expires) "
+								  "values ('%q','%q','%q','%q','%ld')", 
+								  profile->name, mod_sofia_globals.hostname, contact_str, sip->sip_call_id->i_id, (long)expires))) {
+			sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+		}
+
+		free(contact_str);
+	}
+}
+
+void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, tagi_t tags[])
+{
+	char *sql = NULL;
+	struct sla_notify_helper helper;
+	char *aor = NULL;
+	char *contact = NULL;
+	sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url);
+
+	/*
+	 * things we know we don't do:
+	 *   draft-anil-sipping-bla says we should look and see if the specific appearance is in use and if it is
+	 *     return an error for the i_notify, to handle the initial line-seize for dialing out case.
+	 *     to do that we would need to really track all the appearances *and* override sofia's autoresponder for i_notify
+	 *     because at this point, it already sent the 200 for us.
+	 *   and we simply don't track all the appearance status by decoding the XML payload out and recording that in
+	 *     an SQL line appearance database yet. we'll need to do that in order to do the above, and in order to make
+	 *     interoperation possible between devices that disagree on the dialog xml payload OR don't even do it that
+	 *     way and instead use things like call-info/line-seize events like the old Broadsoft spec.
+	 *     instead we cheat and just reflect the entire payload back to the subscribers (who, because we don't
+	 *     yet check each AOR as it comes in to see if it is to be managed, is more subscribers than we probably
+	 *     should have). for the current prototype stage, this works ok anyway.
+	 *   and because we don't parse the XML, we even reflect it right back to the notifier/sender (which is called
+     *     "target" in the payload XML, of course).
+	 *   also because we don't track on a per-appearance basis, there IS NOT a hook back from sofia_glue to add
+	 *     an appearance index to the outbound invite for the "next free appearance". this can lead to race 
+	 *     conditions where a call shows up on slightly different line key numbers at different phones, making
+	 *     "pick up on line X" meaningless if such a race occurs. again, it is a prototype. we can fix it later.
+	*/
+
+
+	/* the dispatcher calls us just because it is aimed at us, so check to see if it is dialog;sla at the very least... */
+
+	if (  (!sip->sip_event) 
+	   || (strcasecmp(sip->sip_event->o_type, "dialog"))
+	   || !msg_params_find(sip->sip_event->o_params, "sla") ) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,"sent to sla-agent but not dialog;sla\n");
+		return;
+	}
+
+	/* calculate the AOR we're trying to tell people about. should probably double-check before derferencing XXX MTK */
+	/* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */
+	aor = switch_mprintf("sip:%s@%s", sip->sip_to->a_url->url_user, profile->sipip);
+
+	/* this isn't sufficient because on things like the polycom, the subscriber is the 'main' ext number, but the
+	 * 'main' ext number isn't in ANY of the headers they send us in the notify. of course.
+	 * as a side effect, the subscriber<>'%q' below isn't sufficient to prevent reflecting the event back
+	 * at a phone that has the ext # != third-party#. see above, can only fix by parsing the XML for the 'target'
+	 * so we don't reflect it back at anyone who is the "boss" config, but we do reflect it back at the "secretary"
+	 * config. if that breaks the phone, just set them all up as the "boss" config where ext#==third-party#
+	 */
+	contact = switch_mprintf("sip:%s@%s;transport=%s",sip->sip_contact->m_url->url_user,
+							 sip->sip_contact->m_url->url_host, sofia_glue_transport2str(transport));
+
+	if (sip->sip_payload && sip->sip_payload->pl_data) {
+		sql = switch_mprintf("select subscriber,call_id,aor,profile_name,hostname,contact_str,network_ip from sip_shared_appearance_subscriptions where "
+		"aor='%q' and profile_name='%q' and hostname='%q'",
+		aor, profile->name, mod_sofia_globals.hostname); 
+
+		helper.profile = profile;
+		helper.payload = sip->sip_payload->pl_data; 	/* could just send the WHOLE payload. you'd get the type that way. */
+
+		/* which mutex if any is correct to hold in this callback? XXX MTK FIXME */
+		sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile->ireg_mutex, sql, sofia_sla_sub_callback, &helper);
+
+		switch_safe_free(sql);
+		switch_safe_free(aor);
+		switch_safe_free(contact);
+	}
+}
+
+static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+	struct sla_notify_helper *helper = pArg;
+	/* char *subscriber = argv[0]; */
+	char *call_id = argv[1];
+	/* char *aor = argv[2]; */
+	/* char *profile_name = argv[3]; */
+	/* char *hostname = argv[4]; */
+	char *contact_str = argv[5];
+	char *network_ip = argv[6];
+	nua_handle_t *nh;
+	char *route_uri = NULL;
+	char *xml_fixup = NULL;
+	char *fixup = NULL;
+	nh = nua_handle_by_call_id(helper->profile->nua, call_id);  /* that's all you need to find the subscription's nh */
+
+	if (nh) {
+
+		if (strstr(contact_str, ";fs_nat")) {
+			char *p;
+			route_uri = sofia_glue_get_url_from_contact(contact_str, 1);
+			if ((p = strstr(contact_str, ";fs_"))) {
+				*p = '\0';
+			}
+		}
+
+		if (route_uri) {
+			char *p;
+
+			while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) {
+				route_uri++;
+			}
+			if ((p = strchr(route_uri, '>'))) {
+				*p++ = '\0';
+			}
+		}
+
+		if (sofia_test_pflag(helper->profile, PFLAG_AUTO_NAT)) {
+			if (sofia_glue_check_nat(helper->profile, network_ip)) { 
+				fixup = switch_string_replace(helper->payload, helper->profile->sipip, helper->profile->extsipip);
+			} else  {
+				fixup = switch_string_replace(helper->payload, helper->profile->extsipip, helper->profile->sipip);
+			}
+			xml_fixup = fixup;
+		} else {
+			xml_fixup = helper->payload;
+		}
+		
+		nua_notify(nh,
+				   SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* XXX MTK FIXME - this is totally fake calculation */
+				   TAG_IF(route_uri, NUTAG_PROXY(route_uri)),
+				   SIPTAG_CONTENT_TYPE_STR("application/dialog-info+xml"),	/* could've just kept the type from the payload */
+				   SIPTAG_PAYLOAD_STR(xml_fixup),
+				   TAG_END());
+		switch_safe_free(route_uri);
+		if (fixup && fixup != helper->payload) { 
+			free(fixup);
+		}
+	}
+	return 0;
+}