<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][14390] </title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=14390">14390</a></dd>
<dt>Author</dt> <dd>cseket</dd>
<dt>Date</dt> <dd>2009-07-27 15:18:20 -0500 (Mon, 27 Jul 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>merge from trunk <a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=14389">r14389</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiac">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiah">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.h</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiavcproj">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiasofiac">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiaMakefileam">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/Makefile.am</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofia2008vcproj">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.2008.vcproj</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_gluec">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_glue.c</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_presencec">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_presence.c</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_regc">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_reg.c</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_slac">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia_sla.c</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiaMakefile">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/Makefile</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofia">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiac">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiavcproj">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj</a></li>
<li><a href="#freeswitchbranchescseketsrcmodendpointsmod_sofiasofiac">freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofia"></a>
<div class="propset"><h4>Property changes: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia</h4>
<pre class="diff"><span>
<span class="cx">Name: svn:ignore
</span><span class="cx">   - Release
</span><span class="cx">Debug
</span><span class="cx">*.user
</span><span class="cx">*.so
</span><span class="cx">*.pdb
</span><span class="cx">*.dylib
</span><span class="cx">   + mod_sofia.log
</span><span class="cx">Release
</span><span class="cx">Debug
</span><span class="cx">*.user
</span><span class="cx">*.so
</span><span class="cx">*.pdb
</span><span class="cx">*.dylib
</span><span class="cx">*.o
</span><span class="cx">.libs
</span><span class="cx">Makefile.in
</span><span class="cx">.deps
</span><span class="cx">Makefile
</span><span class="cx">debug
</span><span class="cx">cisco
</span><span class="cx">Win32
</span><span class="cx">x64
</span><span class="cx">sofia.diff
</span><span class="cx">diff.txt
</span></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiaMakefile"></a>
<div class="delfile"><h4>Deleted: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/Makefile</h4></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiaMakefileamfromrev14389freeswitchtrunksrcmodendpointsmod_sofiaMakefileam"></a>
<div class="copfile"><h4>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)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+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 &quot;`link=\`echo $@|grep .la;echo $@|grep .so;echo $@|grep .dll\`;if test -n &quot;$$link&quot;; then echo Creating $@;fi`&quot;;`if test -z &quot;$(VERBOSE)&quot; ; \
+then echo $(SHELL) $(switch_builddir)/quiet_libtool ;else echo $(SHELL) $(switch_builddir)/libtool;  fi`
+AM_MAKEFLAGS=`test -n &quot;$(VERBOSE)&quot; || echo -s`
+# Dirty trick to override the link output
+LIBS+=&gt; $(MODNAME).log || error=&quot;yes&quot;;if test -n &quot;$(VERBOSE)&quot; -o &quot;$$error&quot; = &quot;yes&quot;;then cat $(MODNAME).log;fi;if test &quot;$$error&quot; = &quot;yes&quot;;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) &amp;&amp; $(MAKE) SOFIA_CFLAGS=&quot;$(AM_CFLAGS)&quot;
+        $(TOUCH_TARGET)
+
+../../../../libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h: $(SOFIALA)
+
</ins></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofia2008vcprojfromrev14389freeswitchtrunksrcmodendpointsmod_sofiamod_sofia2008vcproj"></a>
<div class="copfile"><h4>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)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,327 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;Windows-1252&quot;?&gt;
+&lt;VisualStudioProject
+        ProjectType=&quot;Visual C++&quot;
+        Version=&quot;9.00&quot;
+        Name=&quot;mod_sofia&quot;
+        ProjectGUID=&quot;{0DF3ABD0-DDC0-4265-B778-07C66780979B}&quot;
+        RootNamespace=&quot;mod_sofia&quot;
+        Keyword=&quot;Win32Proj&quot;
+        TargetFrameworkVersion=&quot;131072&quot;
+        &gt;
+        &lt;Platforms&gt;
+                &lt;Platform
+                        Name=&quot;Win32&quot;
+                /&gt;
+                &lt;Platform
+                        Name=&quot;x64&quot;
+                /&gt;
+        &lt;/Platforms&gt;
+        &lt;ToolFiles&gt;
+        &lt;/ToolFiles&gt;
+        &lt;Configurations&gt;
+                &lt;Configuration
+                        Name=&quot;Debug|Win32&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_debug.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&amp;quot;&quot;
+                                PreprocessorDefinitions=&quot;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                                DisableSpecificWarnings=&quot;4201&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                AdditionalDependencies=&quot;ws2_32.lib advapi32.lib iphlpapi.lib&quot;
+                                AdditionalLibraryDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Debug|x64&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_debug.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                                TargetEnvironment=&quot;3&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&amp;quot;&quot;
+                                PreprocessorDefinitions=&quot;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                                DisableSpecificWarnings=&quot;4201&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                AdditionalDependencies=&quot;ws2_32.lib advapi32.lib iphlpapi.lib&quot;
+                                OutputFile=&quot;$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll&quot;
+                                AdditionalLibraryDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                                TargetMachine=&quot;17&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Release|Win32&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_release.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&amp;quot;&quot;
+                                PreprocessorDefinitions=&quot;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                                DisableSpecificWarnings=&quot;4201&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                AdditionalDependencies=&quot;ws2_32.lib advapi32.lib iphlpapi.lib&quot;
+                                AdditionalLibraryDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+                &lt;Configuration
+                        Name=&quot;Release|x64&quot;
+                        ConfigurationType=&quot;2&quot;
+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_release.vsprops&quot;
+                        CharacterSet=&quot;2&quot;
+                        &gt;
+                        &lt;Tool
+                                Name=&quot;VCPreBuildEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCustomBuildTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXMLDataGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCWebServiceProxyGeneratorTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCMIDLTool&quot;
+                                TargetEnvironment=&quot;3&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCCLCompilerTool&quot;
+                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&amp;quot;&quot;
+                                PreprocessorDefinitions=&quot;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
+                                UsePrecompiledHeader=&quot;0&quot;
+                                DisableSpecificWarnings=&quot;4201&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManagedResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCResourceCompilerTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPreLinkEventTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCLinkerTool&quot;
+                                AdditionalDependencies=&quot;ws2_32.lib advapi32.lib iphlpapi.lib&quot;
+                                OutputFile=&quot;$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll&quot;
+                                AdditionalLibraryDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
+                                RandomizedBaseAddress=&quot;1&quot;
+                                DataExecutionPrevention=&quot;0&quot;
+                                TargetMachine=&quot;17&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCALinkTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCManifestTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCXDCMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCBscMakeTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCFxCopTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCAppVerifierTool&quot;
+                        /&gt;
+                        &lt;Tool
+                                Name=&quot;VCPostBuildEventTool&quot;
+                        /&gt;
+                &lt;/Configuration&gt;
+        &lt;/Configurations&gt;
+        &lt;References&gt;
+        &lt;/References&gt;
+        &lt;Files&gt;
+                &lt;File
+                        RelativePath=&quot;.\mod_sofia.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\mod_sofia.h&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_glue.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_presence.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_reg.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_sla.c&quot;
+                        &gt;
+                &lt;/File&gt;
+        &lt;/Files&gt;
+        &lt;Globals&gt;
+        &lt;/Globals&gt;
+&lt;/VisualStudioProject&gt;
</ins></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiac"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c (14389 => 14390)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /* 
</span><span class="cx">  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
</span><del>- * Copyright (C) 2005/2006, Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Copyright (C) 2005-2009, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  *
</span><span class="cx">  * Version: MPL 1.1
</span><span class="cx">  *
</span><span class="lines">@@ -17,14 +17,14 @@
</span><span class="cx">  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
</span><span class="cx">  *
</span><span class="cx">  * The Initial Developer of the Original Code is
</span><del>- * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  * Portions created by the Initial Developer are Copyright (C)
</span><span class="cx">  * the Initial Developer. All Rights Reserved.
</span><span class="cx">  *
</span><span class="cx">  * Contributor(s):
</span><span class="cx">  * 
</span><del>- * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
- * Ken Rice, Asteria Solutions Group, Inc &lt;ken@asteriasgi.com&gt;
</del><ins>+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ * Ken Rice &lt;krice at cometsig.com&gt;
</ins><span class="cx">  * Paul D. Tinsley &lt;pdt at jackhammer.org&gt;
</span><span class="cx">  * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
</span><span class="cx">  *
</span><span class="lines">@@ -35,1255 +35,166 @@
</span><span class="cx"> 
</span><span class="cx"> /* Best viewed in a 160 x 60 VT100 Terminal or so the line below at least fits across your screen*/
</span><span class="cx"> /*************************************************************************************************************************************************************/
</span><ins>+#include &quot;mod_sofia.h&quot;
+#include &quot;sofia-sip/sip_extra.h&quot;
+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);
</ins><span class="cx"> 
</span><del>-
-/*Defines etc..*/
-/*************************************************************************************************************************************************************/
-#define HAVE_APR
-#include &lt;switch.h&gt;
-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 &quot;sofia::register&quot;
-#define MY_EVENT_EXPIRE &quot;sofia::expire&quot;
-#define MULTICAST_EVENT &quot;multicast::event&quot;
-#define SOFIA_REPLACES_HEADER &quot;_sofia_replaces_&quot;
-#define SOFIA_USER_AGENT &quot;FreeSWITCH(mod_sofia)&quot;
-#define SOFIA_CHAT_PROTO &quot;sip&quot;
-#define SOFIA_SIP_HEADER_PREFIX &quot;sip_h_&quot;
-#define SOFIA_SIP_HEADER_PREFIX_T &quot;~sip_h_&quot;
-
-#include &lt;sofia-sip/nua.h&gt;
-#include &lt;sofia-sip/sip_status.h&gt;
-#include &lt;sofia-sip/sdp.h&gt;
-#include &lt;sofia-sip/sip_protos.h&gt;
-#include &lt;sofia-sip/auth_module.h&gt;
-#include &lt;sofia-sip/su_md5.h&gt;
-#include &lt;sofia-sip/su_log.h&gt;
-#include &lt;sofia-sip/nea.h&gt;
-#include &lt;sofia-sip/msg_addr.h&gt;
-
-extern su_log_t tport_log[];
-
</del><ins>+struct mod_sofia_globals mod_sofia_globals;
+switch_endpoint_interface_t *sofia_endpoint_interface;
</ins><span class="cx"> static switch_frame_t silence_frame = { 0 };
</span><span class="cx"> static char silence_data[13] = &quot;&quot;;
</span><span class="cx"> 
</span><del>-
-static char reg_sql[] =
-&quot;CREATE TABLE sip_registrations (\n&quot;
-&quot;   user            VARCHAR(255),\n&quot;
-&quot;   host            VARCHAR(255),\n&quot;
-&quot;   contact         VARCHAR(1024),\n&quot;
-&quot;   status          VARCHAR(255),\n&quot;
-&quot;   rpid            VARCHAR(255),\n&quot;
-&quot;   expires         INTEGER(8)&quot;
-&quot;);\n&quot;;
-
-
-static char sub_sql[] =
-&quot;CREATE TABLE sip_subscriptions (\n&quot;
-&quot;   proto           VARCHAR(255),\n&quot;
-&quot;   user            VARCHAR(255),\n&quot;
-&quot;   host            VARCHAR(255),\n&quot;
-&quot;   sub_to_user     VARCHAR(255),\n&quot;
-&quot;   sub_to_host     VARCHAR(255),\n&quot;
-&quot;   event           VARCHAR(255),\n&quot;
-&quot;   contact         VARCHAR(1024),\n&quot;
-&quot;   call_id         VARCHAR(255),\n&quot;
-&quot;   full_from       VARCHAR(255),\n&quot;
-&quot;   full_via        VARCHAR(255),\n&quot;
-&quot;   expires         INTEGER(8)&quot;
-&quot;);\n&quot;;
-
-
-static char auth_sql[] =
-&quot;CREATE TABLE sip_authentication (\n&quot;
-&quot;   user            VARCHAR(255),\n&quot;
-&quot;   host            VARCHAR(255),\n&quot;
-&quot;   passwd            VARCHAR(255),\n&quot;
-&quot;   nonce           VARCHAR(255),\n&quot;
-&quot;   expires         INTEGER(8)&quot;
-&quot;);\n&quot;;
-
-static const char modname[] = &quot;mod_sofia&quot;;
</del><span class="cx"> #define STRLEN 15
</span><span class="cx"> 
</span><del>-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-&gt;Anchor) {delete t-&gt;Anchor;} t-&gt;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 &lt;&lt; 0),
-        PFLAG_BLIND_REG = (1 &lt;&lt; 1),
-        PFLAG_AUTH_ALL = (1 &lt;&lt; 2),
-        PFLAG_FULL_ID = (1 &lt;&lt; 3),
-        PFLAG_PRESENCE = (1 &lt;&lt; 4),
-        PFLAG_PASS_RFC2833 = (1 &lt;&lt; 5),
-    PFLAG_DISABLE_TRANSCODING = (1 &lt;&lt; 6)
-} PFLAGS;
-
-typedef enum {
-        TFLAG_IO = (1 &lt;&lt; 0),
-        TFLAG_CHANGE_MEDIA = (1 &lt;&lt; 1),
-        TFLAG_OUTBOUND = (1 &lt;&lt; 2),
-        TFLAG_READING = (1 &lt;&lt; 3),
-        TFLAG_WRITING = (1 &lt;&lt; 4),
-        TFLAG_HUP = (1 &lt;&lt; 5),
-        TFLAG_RTP = (1 &lt;&lt; 6),
-        TFLAG_BYE = (1 &lt;&lt; 7),
-        TFLAG_ANS = (1 &lt;&lt; 8),
-        TFLAG_EARLY_MEDIA = (1 &lt;&lt; 9),
-        TFLAG_SECURE = (1 &lt;&lt; 10),
-        TFLAG_VAD_IN = ( 1 &lt;&lt; 11),
-        TFLAG_VAD_OUT = ( 1 &lt;&lt; 12),
-        TFLAG_VAD = ( 1 &lt;&lt; 13),
-        TFLAG_TIMER = (1 &lt;&lt; 14),
-        TFLAG_READY = (1 &lt;&lt; 15),
-        TFLAG_REINVITE = (1 &lt;&lt; 16),
-        TFLAG_REFER = (1 &lt;&lt; 17),
-        TFLAG_NOHUP = (1 &lt;&lt; 18),
-        TFLAG_XFER = (1 &lt;&lt; 19),
-        TFLAG_NOMEDIA = (1 &lt;&lt; 20),
-        TFLAG_BUGGY_2833 = (1 &lt;&lt; 21),
-        TFLAG_SIP_HOLD = (1 &lt;&lt; 22),
-        TFLAG_INB_NOMEDIA = (1 &lt;&lt; 23),
-        TFLAG_LATE_NEGOTIATION = (1 &lt;&lt; 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 &lt;&lt; 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 */
-/*************************************************************************************************************************************************************/
</del><span class="cx"> static switch_status_t sofia_on_init(switch_core_session_t *session);
</span><span class="cx"> 
</span><del>-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);
-
</del><ins>+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);
</ins><span class="cx"> static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig);
</span><span class="cx"> 
</span><del>-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);
-
</del><span class="cx"> /* BODY OF THE MODULE */
</span><span class="cx"> /*************************************************************************************************************************************************************/
</span><span class="cx"> 
</span><del>-typedef enum {
-        AUTH_OK,
-        AUTH_FORBIDDEN,
-        AUTH_STALE,
-} auth_res_t;
-
-
-static char *get_url_from_contact(char *buf, uint8_t to_dup)
</del><ins>+/* 
+   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)
</ins><span class="cx"> {
</span><del>-        char *url = NULL, *e;
</del><ins>+        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;
</ins><span class="cx"> 
</span><del>-        if ((url = strchr(buf, '&lt;')) &amp;&amp; (e = strchr(url, '&gt;'))) {
-                url++;
-                if (to_dup) {
-                        url = strdup(url);
-                        e = strchr(url, '&gt;');
-                }
</del><ins>+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-                *e = '\0';
</del><ins>+        tech_pvt-&gt;read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
+        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s SOFIA INIT\n&quot;, 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);
</ins><span class="cx">         }
</span><del>-        
-        return url;
-}
</del><span class="cx"> 
</span><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+                const char *var;
</ins><span class="cx"> 
</span><del>-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-&gt;au_params) {
-                for(indexnum = 0; (cur=authorization-&gt;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 == '&quot;') {
-                                                *val++ = '\0';
-                                        }
-                                        if ((p = strchr(val, '&quot;'))) {
-                                                *p = '\0';
-                                        }
-
-                                        if (!strcasecmp(var, &quot;nonce&quot;)) {
-                                                nonce = strdup(val);
-                                                cnt++;
-                                        } else if (!strcasecmp(var, &quot;uri&quot;)) {
-                                                uri = strdup(val);
-                                                cnt++;
-                                        } else if (!strcasecmp(var, &quot;qop&quot;)) {
-                                                qop = strdup(val);
-                                                cnt++;
-                                        } else if (!strcasecmp(var, &quot;cnonce&quot;)) {
-                                                cnonce = strdup(val);
-                                                cnt++;
-                                        } else if (!strcasecmp(var, &quot;response&quot;)) {
-                                                response = strdup(val);
-                                                cnt++;
-                                        } else if (!strcasecmp(var, &quot;nc&quot;)) {
-                                                nc = strdup(val);
-                                                cnt++;
-                                        }
-                                }
-                                
-                                free(work);
</del><ins>+                if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) &amp;&amp; !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);
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><del>-        }
</del><span class="cx"> 
</span><del>-        if (cnt != 6) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Authorization header!\n&quot;);
-                goto end;
-        }
</del><span class="cx"> 
</span><del>-        if (switch_strlen_zero(np)) {
-                if (!get_auth_data(profile-&gt;dbname, nonce, np, nplen, profile-&gt;ireg_mutex)) {
-                        ret = AUTH_STALE;
</del><ins>+                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;
</ins><span class="cx">                         goto end;
</span><del>-                } 
-        }
-
-        npassword = np;
-
-        if ((input = switch_mprintf(&quot;%s:%q&quot;, regstr, uri))) {
-                su_md5_init(&amp;ctx);
-                su_md5_strupdate(&amp;ctx, input);
-                su_md5_hexdigest(&amp;ctx, uridigest);
-                su_md5_deinit(&amp;ctx);
-        }
-
-        if ((input2 = switch_mprintf(&quot;%q:%q:%q:%q:%q:%q&quot;, npassword, nonce, nc, cnonce, qop, uridigest))) {
-                memset(&amp;ctx, 0, sizeof(ctx));
-                su_md5_init(&amp;ctx);
-                su_md5_strupdate(&amp;ctx, input2);
-                su_md5_hexdigest(&amp;ctx, bigdigest);
-                su_md5_deinit(&amp;ctx);
-
-                if (!strcasecmp(bigdigest, response)) {
-                        ret = AUTH_OK;
-                } else {
-                        ret = AUTH_FORBIDDEN;
</del><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>- 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);
</del><ins>+        /* Move channel's state machine to ROUTING */
+        switch_channel_set_state(channel, CS_ROUTING);
+        assert(switch_channel_get_state(channel) != CS_INIT);
</ins><span class="cx"> 
</span><del>-        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, &quot;Error Opening DB %s\n&quot;, dbname);
-                goto end;
-        }
-        switch_core_db_persistant_execute(db, sql, 25);
-        switch_core_db_close(db);
-
</del><span class="cx">  end:
</span><del>-        if (mutex) {
-                switch_mutex_unlock(mutex);
-        }
-}
</del><span class="cx"> 
</span><ins>+        switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
</ins><span class="cx"> 
</span><del>-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-&gt;val, argv[0], cbt-&gt;len);
-        cbt-&gt;matches++;
-        return 0;
</del><ins>+        return status;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static int del_callback(void *pArg, int argc, char **argv, char **columnNames){
-        switch_event_t *s_event;
-
-        if (argc &gt;=3 ) {
-                if (switch_event_create_subclass(&amp;s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) {
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile-name&quot;, &quot;%s&quot;, argv[0]);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;user&quot;, &quot;%s&quot;, argv[1]);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;host&quot;, &quot;%s&quot;, argv[2]);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;contact&quot;, &quot;%s&quot;, argv[3]);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;expires&quot;, &quot;%d&quot;, argv[4]);
-                        switch_event_fire(&amp;s_event);
-                }
-        }
-        return 0;
-}
-
-static void check_expire(switch_core_db_t *db, sofia_profile_t *profile, time_t now)
</del><ins>+static switch_status_t sofia_on_routing(switch_core_session_t *session)
</ins><span class="cx"> {
</span><del>-        char sql[1024];
-        char *errmsg;
</del><ins>+        private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-        if (!db) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                return;
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+                sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        switch_mutex_lock(profile-&gt;ireg_mutex);
-        snprintf(sql, sizeof(sql), &quot;select '%s',* from sip_registrations where expires &gt; 0 and expires &lt; %ld&quot;, profile-&gt;name, (long) now);        
-        switch_core_db_exec(db, sql, del_callback, NULL, &amp;errmsg);
</del><ins>+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s SOFIA ROUTING\n&quot;, switch_channel_get_name(switch_core_session_get_channel(session)));
</ins><span class="cx"> 
</span><del>-        if (errmsg) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;SQL ERR [%s][%s]\n&quot;, sql, errmsg);
-                switch_safe_free(errmsg);
-                errmsg = NULL;
-        }
-        
-        snprintf(sql, sizeof(sql), &quot;delete from sip_registrations where expires &gt; 0 and expires &lt; %ld&quot;, (long) now);
-        switch_core_db_persistant_execute(db, sql, 1000);
-        snprintf(sql, sizeof(sql), &quot;delete from sip_authentication where expires &gt; 0 and expires &lt; %ld&quot;, (long) now);
-        switch_core_db_persistant_execute(db, sql, 1000);
-        snprintf(sql, sizeof(sql), &quot;delete from sip_subscriptions where expires &gt; 0 and expires &lt; %ld&quot;, (long) now);
-        switch_core_db_persistant_execute(db, sql, 1000);
-
-        switch_mutex_unlock(profile-&gt;ireg_mutex);
-
</del><ins>+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-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;
</del><span class="cx"> 
</span><del>-        if (!user) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Called with null user!\n&quot;);
-        return NULL;
-        }
-
-        if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                return NULL;
-        }
-
-        cbt.val = val;
-        cbt.len = len;
-        switch_mutex_lock(profile-&gt;ireg_mutex);
-        if (host) {
-                snprintf(val, len, &quot;select contact from sip_registrations where user='%s' and host='%s'&quot;, user, host);        
-        } else {
-                snprintf(val, len, &quot;select contact from sip_registrations where user='%s'&quot;, user);        
-        }
-
-        switch_core_db_exec(db, val, find_callback, &amp;cbt, &amp;errmsg);
-
-        if (errmsg) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;SQL ERR [%s][%s]\n&quot;, val, errmsg);
-                switch_safe_free(errmsg);
-                errmsg = NULL;
-        }
-
-        switch_mutex_unlock(profile-&gt;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)
</del><ins>+static switch_status_t sofia_on_reset(switch_core_session_t *session)
</ins><span class="cx"> {
</span><del>-        char buf[2048];
-        switch_time_t now = switch_time_now();
-    int ptime = 0;
</del><ins>+        private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-        if (!force &amp;&amp; !ip &amp;&amp; !sr &amp;&amp; switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-                return;
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+                sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!ip) {
-                if (!(ip = tech_pvt-&gt;adv_sdp_audio_ip)) {
-                        ip = tech_pvt-&gt;proxy_sdp_audio_ip;
-                }
-        }
-        if (!port) {
-                if (!(port = tech_pvt-&gt;adv_sdp_audio_port)) {
-                        port = tech_pvt-&gt;proxy_sdp_audio_port;
-                }
-        }
-        if (!sr) {
-                sr = &quot;sendrecv&quot;;
-        }
</del><ins>+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s SOFIA RESET\n&quot;, switch_channel_get_name(switch_core_session_get_channel(session)));
</ins><span class="cx"> 
</span><del>-        snprintf(buf, sizeof(buf), 
-                         &quot;v=0\n&quot;
-                         &quot;o=FreeSWITCH %d%&quot;APR_TIME_T_FMT&quot; %d%&quot;APR_TIME_T_FMT&quot; IN IP4 %s\n&quot;
-                         &quot;s=FreeSWITCH\n&quot;
-                         &quot;c=IN IP4 %s\n&quot;
-                         &quot;t=0 0\n&quot;
-                         &quot;a=%s\n&quot;
-                         &quot;m=audio %d RTP/AVP&quot;,
-                         port,
-                         now,
-                         port,
-                         now,
-                         ip,
-                         ip,
-                         sr,
-                         port
-                         );
-
-        if (tech_pvt-&gt;rm_encoding) {
-                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, tech_pvt-&gt;pt);
-        } else if (tech_pvt-&gt;num_codecs) {
-                int i;
-                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
-                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
-
-                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, imp-&gt;ianacode);
-            if (!ptime) {
-                ptime = imp-&gt;microseconds_per_frame / 1000;
-            }
-                }
-        }
-
-        if (tech_pvt-&gt;te &gt; 95) {
-                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, tech_pvt-&gt;te);
-        }
-
-        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;\n&quot;);
-
-        if (tech_pvt-&gt;rm_encoding) {
-                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d %s/%ld\n&quot;, tech_pvt-&gt;pt, tech_pvt-&gt;rm_encoding, tech_pvt-&gt;rm_rate);
-                if (tech_pvt-&gt;fmtp_out) {
-                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=fmtp:%d %s\n&quot;, tech_pvt-&gt;pt, tech_pvt-&gt;fmtp_out);
-                }
-                if (tech_pvt-&gt;read_codec.implementation &amp;&amp; ! ptime) {
-            ptime = tech_pvt-&gt;read_codec.implementation-&gt;microseconds_per_frame / 1000;
-                }
-
-        } else if (tech_pvt-&gt;num_codecs) {
-                int i;
-                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
-                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
-            if (ptime &amp;&amp; ptime != imp-&gt;microseconds_per_frame / 1000) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;ptime %u != advertised ptime %u\n&quot;, imp-&gt;microseconds_per_frame / 1000, ptime);
-            }
-                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d %s/%d\n&quot;, imp-&gt;ianacode, imp-&gt;iananame, imp-&gt;samples_per_second);
-                        if (imp-&gt;fmtp) {
-                                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=fmtp:%d %s\n&quot;, imp-&gt;ianacode, imp-&gt;fmtp);
-                        }
-                }
-        }
-        
-        if (tech_pvt-&gt;te &gt; 95) {
-                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n&quot;, tech_pvt-&gt;te, tech_pvt-&gt;te);
-        }
-
-    if (ptime) {
-        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=ptime:%d\n&quot;, ptime);
-    }
-
-        tech_pvt-&gt;local_sdp_str = switch_core_session_strdup(tech_pvt-&gt;session, buf);
</del><ins>+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-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;
</del><span class="cx"> 
</span><del>-        if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-                return;
-        }
-
-        if (tech_pvt-&gt;num_codecs) {
-                return;
-        }
-
-    assert(tech_pvt-&gt;session != NULL);
-
-    channel = switch_core_session_get_channel(tech_pvt-&gt;session);
-    assert (channel != NULL);
-
-
-    if ((abs = switch_channel_get_variable(channel, &quot;absolute_codec_string&quot;))) {
-        codec_string = abs;
-    } else {
-        if (!(codec_string = switch_channel_get_variable(channel, &quot;codec_string&quot;))) {
-                        if (tech_pvt-&gt;profile-&gt;codec_string) {
-                                codec_string = tech_pvt-&gt;profile-&gt;codec_string;
-                        }
-        }
-        
-        if ((ocodec = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
-            if (!codec_string || (tech_pvt-&gt;profile-&gt;pflags &amp; PFLAG_DISABLE_TRANSCODING)) {
-                codec_string = ocodec;
-            } else {
-                if ((csdyn = switch_mprintf(&quot;%s,%s&quot;, 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-&gt;codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt-&gt;codec_order, SWITCH_MAX_CODECS);
-                        tech_pvt-&gt;num_codecs = switch_loadable_module_get_codecs_sorted(tech_pvt-&gt;codecs,
-                                                                                                                                                        SWITCH_MAX_CODECS,
-                                                                                                                                                        tech_pvt-&gt;codec_order,
-                                                                                                                                                        tech_pvt-&gt;codec_order_last);
-                        free(tmp_codec_string);
-                }
-        } else {
-                tech_pvt-&gt;num_codecs = switch_loadable_module_get_codecs(switch_core_session_get_pool(tech_pvt-&gt;session), tech_pvt-&gt;codecs,
-                                                                                                                                 sizeof(tech_pvt-&gt;codecs) / sizeof(tech_pvt-&gt;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)
</del><ins>+static switch_status_t sofia_on_hibernate(switch_core_session_t *session)
</ins><span class="cx"> {
</span><del>-        switch_channel_t *channel;
-        char name[256];
</del><ins>+        private_object_t *tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-        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(&amp;tech_pvt-&gt;flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
-        switch_mutex_lock(tech_pvt-&gt;flag_mutex);
-        tech_pvt-&gt;flags = profile-&gt;flags;
-        switch_mutex_unlock(tech_pvt-&gt;flag_mutex);
-        tech_pvt-&gt;profile = profile;
-        if (tech_pvt-&gt;bte) {
-                tech_pvt-&gt;te = tech_pvt-&gt;bte;
-        } else {
-                tech_pvt-&gt;te = profile-&gt;te;
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+                sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
</ins><span class="cx">         }
</span><del>-        tech_pvt-&gt;session = session;
-        tech_pvt-&gt;home = su_home_new(sizeof(*tech_pvt-&gt;home));
</del><span class="cx"> 
</span><del>-        switch_core_session_set_private(session, tech_pvt);
</del><ins>+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s SOFIA HIBERNATE\n&quot;, switch_channel_get_name(switch_core_session_get_channel(session)));
</ins><span class="cx"> 
</span><del>-
-        snprintf(name, sizeof(name), &quot;sofia/%s/%s&quot;, profile-&gt;name, channame);
-    switch_channel_set_name(channel, name);
-        //tech_set_codecs(tech_pvt);
-
</del><ins>+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line)
</del><ins>+static switch_status_t sofia_on_execute(switch_core_session_t *session)
</ins><span class="cx"> {
</span><del>-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Term called from line: %d\n&quot;, 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;
</del><ins>+        private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-                tech_pvt = switch_core_session_get_private(*session);
-
-                if (tech_pvt) {
-                        if (state &lt; CS_HANGUP) {
-                                switch_channel_hangup(channel, cause);
-                        }
-                        
-                        if (!switch_test_flag(tech_pvt, TFLAG_READY)) {
-                                if (state &gt; CS_INIT &amp;&amp; state &lt; CS_HANGUP) {
-                                        sofia_on_hangup(*session);
-                                }
-                                switch_core_session_destroy(session);
-                        } 
-                } else {
-                        switch_core_session_destroy(session);
-                }
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
+                sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
</ins><span class="cx">         }
</span><del>-}
</del><ins>+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s SOFIA EXECUTE\n&quot;, switch_channel_get_name(switch_core_session_get_channel(session)));
</ins><span class="cx"> 
</span><del>-
-static switch_status_t tech_choose_port(private_object_t *tech_pvt)
-{
-        char *ip = tech_pvt-&gt;profile-&gt;rtpip;
-        switch_channel_t *channel;
-        switch_port_t sdp_port;
-        char *err;
-        char tmp[50];
-
-        channel = switch_core_session_get_channel(tech_pvt-&gt;session);
-        
-        if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA) || tech_pvt-&gt;adv_sdp_audio_port) {
-                return SWITCH_STATUS_SUCCESS;
-        }
-        
-        tech_pvt-&gt;local_sdp_audio_ip = ip;
-        tech_pvt-&gt;local_sdp_audio_port = switch_rtp_request_port();
-        sdp_port = tech_pvt-&gt;local_sdp_audio_port;
-
-
-        if (tech_pvt-&gt;profile-&gt;extrtpip) {
-                if (!strncasecmp(tech_pvt-&gt;profile-&gt;extrtpip, &quot;stun:&quot;, 5)) {
-                        char *stun_ip = tech_pvt-&gt;profile-&gt;extrtpip + 5;
-                        if (!stun_ip) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Stun Failed! NO STUN SERVER\n&quot;);
-                                terminate_session(&amp;tech_pvt-&gt;session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-                                return SWITCH_STATUS_FALSE;
-                        }
-                        if (switch_stun_lookup(&amp;ip,
-                                                                   &amp;sdp_port,
-                                                                   stun_ip,
-                                                                   SWITCH_STUN_DEFAULT_PORT,
-                                                                   &amp;err,
-                                                                   switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Stun Failed! %s:%d [%s]\n&quot;, stun_ip, SWITCH_STUN_DEFAULT_PORT, err);
-                                terminate_session(&amp;tech_pvt-&gt;session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-                                return SWITCH_STATUS_FALSE;
-                        }
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Stun Success [%s]:[%d]\n&quot;, ip, sdp_port);
-                } else {
-                        ip = tech_pvt-&gt;profile-&gt;extrtpip;
-                }
-        }
-
-        tech_pvt-&gt;adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt-&gt;session, ip);
-        tech_pvt-&gt;adv_sdp_audio_port = sdp_port;
-
-        snprintf(tmp, sizeof(tmp), &quot;%d&quot;, sdp_port);
-        switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt-&gt;adv_sdp_audio_ip);
-        switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
-        
-
</del><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t do_invite(switch_core_session_t *session)
</del><ins>+char * generate_pai_str(switch_core_session_t *session) 
</ins><span class="cx"> {
</span><del>-        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 = &quot;&quot;;
-        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;
</del><ins>+        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;
</ins><span class="cx"> 
</span><del>-    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-&gt;caller_id_name;
-        cid_num = (char *) caller_profile-&gt;caller_id_number;
-    tech_set_codecs(tech_pvt);
-
-        if ((tech_pvt-&gt;from_str = switch_mprintf(&quot;\&quot;%s\&quot; &lt;sip:%s@%s&gt;&quot;, 
-                                                                                                         cid_name,
-                                                                                                         cid_num,
-                                                                                                         tech_pvt-&gt;profile-&gt;extsipip ? tech_pvt-&gt;profile-&gt;extsipip : tech_pvt-&gt;profile-&gt;sipip
-                                                                                                         ))) {
-
-                char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
-
-                if ((alertbuf = switch_channel_get_variable(channel, &quot;alert_info&quot;))) {
-                        snprintf(alert_info, sizeof(alert_info) - 1, &quot;Alert-Info: %s&quot;, alertbuf);
</del><ins>+        if ((callee_name = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_callee_id_name&quot;))) {
+                if (!(callee_number = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_callee_id_number&quot;))) {
+                        callee_number = tech_pvt-&gt;caller_profile-&gt;destination_number;
</ins><span class="cx">                 }
</span><del>-
-                if ((forwardbuf = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE))) {
-                        forwardval = atoi(forwardbuf) - 1;
-                        snprintf(max_forwards, sizeof(max_forwards) - 1, &quot;%d&quot;, 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 = &quot;off&quot;;
-                        const char *screen = &quot;no&quot;;
-                        if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) {
-                                priv = &quot;name&quot;;
-                                if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
-                                        priv = &quot;yes&quot;;
-                                }
-                        } else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
-                                priv = &quot;yes&quot;;
-                        }
-                        if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
-                                screen = &quot;yes&quot;;
-                        }
-
-                        snprintf(rpid, sizeof(rpid) - 1, &quot;Remote-Party-ID: %s;party=calling;screen=%s;privacy=%s&quot;, tech_pvt-&gt;from_str, screen, priv);
-                                                                
-                }
-
-                if (!tech_pvt-&gt;nh) {
-                        char *url =  get_url_from_contact(tech_pvt-&gt;dest, 1);
-                        tech_pvt-&gt;nh = nua_handle(tech_pvt-&gt;profile-&gt;nua, NULL,
-                                                                          NUTAG_URL(url),
-                                                                          SIPTAG_TO_STR(tech_pvt-&gt;dest_to),
-                                                                          SIPTAG_FROM_STR(tech_pvt-&gt;from_str),
-                                                                          SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
-                                                                          TAG_END());
-                        switch_safe_free(url);
-
-            if (!(tech_pvt-&gt;sofia_private = malloc(sizeof(*tech_pvt-&gt;sofia_private)))) {
-                abort();
-            }
-            memset(tech_pvt-&gt;sofia_private, 0, sizeof(*tech_pvt-&gt;sofia_private));
-                        switch_copy_string(tech_pvt-&gt;sofia_private-&gt;uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt-&gt;sofia_private-&gt;uuid));
-                        nua_handle_bind(tech_pvt-&gt;nh, tech_pvt-&gt;sofia_private);
-
-                }
-
-
-                if (tech_pvt-&gt;e_dest &amp;&amp; (e_dest = strdup(tech_pvt-&gt;e_dest))) {
-                        char *user = e_dest, *host = NULL;
-                        char hash_key[256] = &quot;&quot;;
-
-                        if ((host = strchr(user, '@'))) {
-                                *host++ = '\0';
-                        }
-                        snprintf(hash_key, sizeof(hash_key), &quot;%s%s%s&quot;, user, host, cid_num);
-
-                        tech_pvt-&gt;chat_from = tech_pvt-&gt;from_str;
-                        tech_pvt-&gt;chat_to = tech_pvt-&gt;dest;
-                        tech_pvt-&gt;hash_key = switch_core_session_strdup(tech_pvt-&gt;session, hash_key);
-                        switch_core_hash_insert(tech_pvt-&gt;profile-&gt;chat_hash, tech_pvt-&gt;hash_key, tech_pvt);
-                        free(e_dest);                        
-                }
-
-                holdstr = switch_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? &quot;*&quot; : &quot;&quot;;
-
-
-                SWITCH_STANDARD_STREAM(stream);
-                for (hi = switch_channel_variable_first(channel, switch_core_session_get_pool(tech_pvt-&gt;session)); hi; hi = switch_hash_next(hi)) {
-            switch_hash_this(hi, &amp;vvar, NULL, &amp;vval);
-            if (vvar &amp;&amp; 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(&amp;stream, &quot;%s: %s\r\n&quot;, hname, value);
-                                }
-                        }
-                }
-                
-                if (stream.data) {
-                        extra_headers = stream.data;
-                }
-
-                nua_invite(tech_pvt-&gt;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-&gt;profile-&gt;url),
-                                   SOATAG_USER_SDP_STR(tech_pvt-&gt;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, &quot;Memory Error!\n&quot;);
</del><ins>+                pai = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;P-Asserted-Identity: \&quot;%s\&quot; &lt;%s&gt;&quot;, callee_name, callee_number);
</ins><span class="cx">         }
</span><del>-
-        return status;
-        
</del><ins>+        return pai;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-
-static void do_xfer_invite(switch_core_session_t *session)
</del><ins>+/* map QSIG cause codes to SIP from RFC4497 section 8.4.1 */
+static int hangup_cause_to_sip(switch_call_cause_t cause)
</ins><span class="cx"> {
</span><del>-        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-&gt;from_str = switch_mprintf(&quot;\&quot;%s\&quot; &lt;sip:%s@%s&gt;&quot;, 
-                                                                                                         (char *) caller_profile-&gt;caller_id_name, 
-                                                                                                         (char *) caller_profile-&gt;caller_id_number,
-                                                                                                         tech_pvt-&gt;profile-&gt;extsipip ? tech_pvt-&gt;profile-&gt;extsipip : tech_pvt-&gt;profile-&gt;sipip
-                                                                                                         ))) {
-
-                char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
-
-                tech_pvt-&gt;nh2 = nua_handle(tech_pvt-&gt;profile-&gt;nua, NULL,
-                                                                  SIPTAG_TO_STR(tech_pvt-&gt;dest),
-                                                                  SIPTAG_FROM_STR(tech_pvt-&gt;from_str),
-                                                                  SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
-                                                                  TAG_END());
-                        
-        
-                nua_handle_bind(tech_pvt-&gt;nh2, tech_pvt-&gt;sofia_private);
-
-                nua_invite(tech_pvt-&gt;nh2,
-                                   TAG_IF(rpid, SIPTAG_HEADER_STR(rpid)),
-                                   SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
-                                   SOATAG_USER_SDP_STR(tech_pvt-&gt;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, &quot;Memory Error!\n&quot;);
-        }
-        
-}
-
-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-&gt;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-&gt;home, sdp_str, (int)strlen(sdp_str), 0))) {
-                        if ((sdp = sdp_session(parser))) {
-                                for (m = sdp-&gt;sdp_media; m ; m = m-&gt;m_next) {
-                                        if (m-&gt;m_type != sdp_media_audio) {
-                                                continue;
-                                        }
-
-                                        connection = sdp-&gt;sdp_connection;
-                                        if (m-&gt;m_connections) {
-                                                connection = m-&gt;m_connections;
-                                        }
-
-                                        if (connection) {
-                                                tech_pvt-&gt;proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt-&gt;session, connection-&gt;c_address);
-                                        }
-                                        tech_pvt-&gt;proxy_sdp_audio_port = (switch_port_t)m-&gt;m_port;
-                                        if (tech_pvt-&gt;proxy_sdp_audio_ip &amp;&amp; tech_pvt-&gt;proxy_sdp_audio_port) {
-                                                break;
-                                        }
-                                }
-                        }
-                        sdp_parser_free(parser);
-                }        
-                tech_pvt-&gt;local_sdp_str = switch_core_session_strdup(tech_pvt-&gt;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-&gt;read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
-
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;SOFIA INIT\n&quot;);
-        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, &quot;SOFIA RING\n&quot;);
-
-        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, &quot;SOFIA EXECUTE\n&quot;);
-
-        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) {
</del><span class="cx">         switch (cause) {
</span><ins>+        case SWITCH_CAUSE_UNALLOCATED_NUMBER:
</ins><span class="cx">         case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
</span><span class="cx">         case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
</span><span class="cx">                 return 404;
</span><span class="lines">@@ -1292,7 +203,6 @@
</span><span class="cx">         case SWITCH_CAUSE_NO_USER_RESPONSE:
</span><span class="cx">                 return 408;
</span><span class="cx">         case SWITCH_CAUSE_NO_ANSWER:
</span><del>-                return 480;
</del><span class="cx">         case SWITCH_CAUSE_SUBSCRIBER_ABSENT:
</span><span class="cx">                 return 480;
</span><span class="cx">         case SWITCH_CAUSE_CALL_REJECTED:
</span><span class="lines">@@ -1316,421 +226,378 @@
</span><span class="cx">                 return 503;
</span><span class="cx">         case SWITCH_CAUSE_OUTGOING_CALL_BARRED:
</span><span class="cx">         case SWITCH_CAUSE_INCOMING_CALL_BARRED:
</span><del>-        case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH: 
</del><ins>+        case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH:
</ins><span class="cx">                 return 403;
</span><span class="cx">         case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL:
</span><span class="cx">                 return 503;
</span><span class="cx">         case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL:
</span><ins>+        case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
</ins><span class="cx">                 return 488;
</span><span class="cx">         case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
</span><span class="cx">         case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED:
</span><span class="cx">                 return 501;
</span><del>-        case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
-                return 503;
</del><span class="cx">         case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
</span><span class="cx">                 return 504;
</span><span class="cx">         case SWITCH_CAUSE_ORIGINATOR_CANCEL:
</span><span class="cx">                 return 487;
</span><ins>+        case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR:
+                return 483;
</ins><span class="cx">         default:
</span><span class="cx">                 return 480;
</span><span class="cx">         }
</span><ins>+}
</ins><span class="cx"> 
</span><ins>+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, &quot;%s SOFIA DESTROY\n&quot;, switch_channel_get_name(channel));
+
+        if (tech_pvt) {
+                if (switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;read_codec);
+                }
+                
+                if (switch_core_codec_ready(&amp;tech_pvt-&gt;write_codec)) {
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;write_codec);
+                }
+
+                switch_core_session_unset_read_codec(session);
+                switch_core_session_unset_write_codec(session);
+
+                switch_mutex_lock(tech_pvt-&gt;profile-&gt;flag_mutex);
+                tech_pvt-&gt;profile-&gt;inuse--;
+                switch_mutex_unlock(tech_pvt-&gt;profile-&gt;flag_mutex);
+
+                sofia_glue_deactivate_rtp(tech_pvt);
+        }
+
+        return SWITCH_STATUS_SUCCESS;
+
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t sofia_on_hangup(switch_core_session_t *session)
</del><ins>+switch_status_t sofia_on_hangup(switch_core_session_t *session)
</ins><span class="cx"> {
</span><span class="cx">         switch_core_session_t *a_session;
</span><del>-        private_object_t *tech_pvt;
-        switch_channel_t *channel = NULL;
-        switch_call_cause_t cause;
-        int sip_cause;
</del><ins>+        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;
</ins><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(session);
-        assert(channel != NULL);
</del><ins>+        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
</ins><span class="cx"> 
</span><del>-        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-        assert(tech_pvt != NULL);
</del><ins>+        if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+                if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+                        tech_pvt-&gt;profile-&gt;ob_failed_calls++;
+                } else {
+                        tech_pvt-&gt;profile-&gt;ib_failed_calls++;
+                }
+        }
</ins><span class="cx"> 
</span><del>-        cause = switch_channel_get_cause(channel);
-        sip_cause = hangup_cause_to_sip(cause);
</del><ins>+        if (!((use_my_cause = switch_channel_get_variable(channel, &quot;sip_ignore_remote_cause&quot;)) &amp;&amp; switch_true(use_my_cause))) {
+                ps_cause = switch_channel_get_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE);
+        }
</ins><span class="cx"> 
</span><del>-        deactivate_rtp(tech_pvt);
</del><ins>+        if (!switch_strlen_zero(ps_cause) &amp;&amp; (!strncasecmp(ps_cause, &quot;sip:&quot;, 4) || !strncasecmp(ps_cause, &quot;sips:&quot;, 5))) {
+                int new_cause = atoi(sofia_glue_strip_proto(ps_cause));
+                if (new_cause) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s Overriding SIP cause %d with %d from the other leg\n&quot;,
+                                                          switch_channel_get_name(channel), sip_cause, new_cause);
+                        sip_cause = new_cause;
+                }
+        }
</ins><span class="cx"> 
</span><del>-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Channel %s hanging up, cause: %s\n&quot;, 
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD) &amp;&amp; cause != SWITCH_CAUSE_ATTENDED_TRANSFER) {
+                const char *buuid;
+                switch_core_session_t *bsession;
+                switch_channel_t *bchannel;
+                const char *lost_ext;
+
+                if (tech_pvt-&gt;max_missed_packets) {
+                        switch_rtp_set_max_missed_packets(tech_pvt-&gt;rtp_session, tech_pvt-&gt;max_missed_packets);
+                }
+                switch_channel_presence(tech_pvt-&gt;channel, &quot;unknown&quot;, &quot;unhold&quot;, 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, &quot;left_hanging_extension&quot;))) {
+                                                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, &quot;Channel %s hanging up, cause: %s\n&quot;,
</ins><span class="cx">                                           switch_channel_get_name(channel), switch_channel_cause2str(cause));
</span><span class="cx"> 
</span><span class="cx">         if (tech_pvt-&gt;hash_key) {
</span><span class="cx">                 switch_core_hash_delete(tech_pvt-&gt;profile-&gt;chat_hash, tech_pvt-&gt;hash_key);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (session &amp;&amp; tech_pvt-&gt;profile-&gt;pres_type) {
+                char *sql = switch_mprintf(&quot;delete from sip_dialogs where call_id='%q'&quot;, tech_pvt-&gt;call_id);
+                switch_assert(sql);
+                sofia_glue_execute_sql(tech_pvt-&gt;profile, &amp;sql, SWITCH_TRUE);
+        }
+
</ins><span class="cx">         if (tech_pvt-&gt;kick &amp;&amp; (a_session = switch_core_session_locate(tech_pvt-&gt;kick))) {
</span><span class="cx">                 switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
</span><span class="cx">                 switch_channel_hangup(a_channel, switch_channel_get_cause(channel));
</span><span class="cx">                 switch_core_session_rwunlock(a_session);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (tech_pvt-&gt;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, &quot;Sending BYE to %s\n&quot;, switch_channel_get_name(channel));
-                                nua_bye(tech_pvt-&gt;nh, TAG_END());
</del><ins>+        if (tech_pvt-&gt;nh &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                char reason[128] = &quot;&quot;;
+                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-&gt;next) {
+                                const char *name = (char *) hi-&gt;name;
+                                char *value = (char *) hi-&gt;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(&amp;stream, &quot;%s: %s\r\n&quot;, hname, value);
+                                }
+                        }
+                        switch_channel_variable_last(channel);
+                }
+
+                if (stream.data) {
+                        bye_headers = stream.data;
+                }
+                
+                if (cause &gt; 0 &amp;&amp; cause &lt; 128) {
+                        switch_snprintf(reason, sizeof(reason), &quot;Q.850;cause=%d;text=\&quot;%s\&quot;&quot;, cause, switch_channel_cause2str(cause));
+                } else if (cause == SWITCH_CAUSE_PICKED_OFF || cause == SWITCH_CAUSE_LOSE_RACE) {
+                        switch_snprintf(reason, sizeof(reason), &quot;SIP;cause=200;text=\&quot;Call completed elsewhere\&quot;&quot;);
+                } else {
+                        switch_snprintf(reason, sizeof(reason), &quot;%s;cause=%d;text=\&quot;%s\&quot;&quot;,
+                                        tech_pvt-&gt;profile-&gt;username, 
+                                        cause,
+                                        switch_channel_cause2str(cause));
+                }
+
+                if (switch_channel_test_flag(channel, CF_ANSWERED)) {
+                        if (!tech_pvt-&gt;got_bye) {
+                                switch_channel_set_variable(channel, &quot;sip_hangup_disposition&quot;, &quot;send_bye&quot;);
+                        }
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Sending BYE to %s\n&quot;, switch_channel_get_name(channel));
+                        if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                nua_bye(tech_pvt-&gt;nh, 
+                                                SIPTAG_REASON_STR(reason),
+                                                TAG_IF(!switch_strlen_zero(tech_pvt-&gt;user_via), SIPTAG_VIA_STR(tech_pvt-&gt;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, &quot;Sending CANCEL to %s\n&quot;, switch_channel_get_name(channel));
+                                if (!tech_pvt-&gt;got_bye) {
+                                        switch_channel_set_variable(channel, &quot;sip_hangup_disposition&quot;, &quot;send_cancel&quot;);
+                                }
+                                if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                        nua_cancel(tech_pvt-&gt;nh, 
+                                                           SIPTAG_REASON_STR(reason), 
+                                                           TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)),
+                                                           TAG_END());
+                                }
</ins><span class="cx">                         } else {
</span><del>-                                if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Responding to INVITE with: %d\n&quot;, sip_cause);
-                                        nua_respond(tech_pvt-&gt;nh, sip_cause, NULL, TAG_END());
-                                } else {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Sending CANCEL to %s\n&quot;, switch_channel_get_name(channel));
-                                        nua_cancel(tech_pvt-&gt;nh, TAG_END());
</del><ins>+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Responding to INVITE with: %d\n&quot;, sip_cause);
+                                if (!tech_pvt-&gt;got_bye) {
+                                        switch_channel_set_variable(channel, &quot;sip_hangup_disposition&quot;, &quot;send_refuse&quot;);
</ins><span class="cx">                                 }
</span><ins>+                                if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                        nua_respond(tech_pvt-&gt;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());
+                                }
</ins><span class="cx">                         }
</span><del>-                        switch_set_flag_locked(tech_pvt, TFLAG_BYE);
</del><span class="cx">                 }
</span><del>-        }
</del><span class="cx"> 
</span><del>-        if (tech_pvt-&gt;from_str) {
-                switch_safe_free(tech_pvt-&gt;from_str);
</del><ins>+                sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+                switch_safe_free(stream.data);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        switch_clear_flag_locked(tech_pvt, TFLAG_IO);
</del><ins>+        sofia_clear_flag(tech_pvt, TFLAG_IO);
</ins><span class="cx"> 
</span><del>-        if (tech_pvt-&gt;home) {
-                su_home_unref(tech_pvt-&gt;home);
-                tech_pvt-&gt;home = NULL;
</del><ins>+        if (tech_pvt-&gt;sofia_private) {
+                *tech_pvt-&gt;sofia_private-&gt;uuid = '\0';
</ins><span class="cx">         }
</span><ins>+        
</ins><span class="cx"> 
</span><del>-    if (tech_pvt-&gt;sofia_private) {
-        *tech_pvt-&gt;sofia_private-&gt;uuid = '\0';
-    }
</del><ins>+        sofia_glue_set_rtp_stats(tech_pvt);
</ins><span class="cx"> 
</span><ins>+        switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
+
</ins><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t sofia_on_loopback(switch_core_session_t *session)
</del><ins>+static switch_status_t sofia_on_exchange_media(switch_core_session_t *session)
</ins><span class="cx"> {
</span><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;SOFIA LOOPBACK\n&quot;);
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t sofia_on_transmit(switch_core_session_t *session)
</del><ins>+static switch_status_t sofia_on_soft_execute(switch_core_session_t *session)
</ins><span class="cx"> {
</span><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;SOFIA TRANSMIT\n&quot;);
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void deactivate_rtp(private_object_t *tech_pvt)
</del><ins>+static switch_status_t sofia_answer_channel(switch_core_session_t *session)
</ins><span class="cx"> {
</span><del>-        int loops = 0;//, sock = -1;
-        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
-                while (loops &lt; 10 &amp;&amp; (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
-                        switch_yield(10000);
-                        loops++;
-                }
-                switch_rtp_destroy(&amp;tech_pvt-&gt;rtp_session);
-        }
-}
-
-static switch_status_t tech_set_codec(private_object_t *tech_pvt, int force)
-{
-        switch_channel_t *channel;
-
-        if (tech_pvt-&gt;read_codec.implementation) {
-                if (!force) {
-                        return SWITCH_STATUS_SUCCESS;
-                }
-                if (strcasecmp(tech_pvt-&gt;read_codec.implementation-&gt;iananame, tech_pvt-&gt;rm_encoding) ||
-                        tech_pvt-&gt;read_codec.implementation-&gt;samples_per_second != tech_pvt-&gt;rm_rate) {
-
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Changing Codec from %s to %s\n&quot;,
-                                                          tech_pvt-&gt;read_codec.implementation-&gt;iananame, tech_pvt-&gt;rm_encoding);
-                switch_core_codec_destroy(&amp;tech_pvt-&gt;read_codec);
-                switch_core_codec_destroy(&amp;tech_pvt-&gt;write_codec);
-                switch_core_session_reset(tech_pvt-&gt;session);
-                } else {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Already using %s\n&quot;,
-                                                          tech_pvt-&gt;read_codec.implementation-&gt;iananame);
-                        return SWITCH_STATUS_SUCCESS;
-                }
-        }
-
-        channel = switch_core_session_get_channel(tech_pvt-&gt;session);
-        assert(channel != NULL);
-
-        if (!tech_pvt-&gt;rm_encoding) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec with no name?\n&quot;);
-                terminate_session(&amp;tech_pvt-&gt;session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-                return SWITCH_STATUS_FALSE;
-        }
-
-        if (switch_core_codec_init(&amp;tech_pvt-&gt;read_codec,  
-                                                           tech_pvt-&gt;rm_encoding,
-                                                           tech_pvt-&gt;rm_fmtp,
-                                                           tech_pvt-&gt;rm_rate,
-                                                           tech_pvt-&gt;codec_ms,
-                                                           1,
-                                                           SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt-&gt;profile-&gt;codec_flags,
-                                                           NULL,
-                                                           switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec?\n&quot;);
-                terminate_session(&amp;tech_pvt-&gt;session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-                return SWITCH_STATUS_FALSE;
-        } else {
-                if (switch_core_codec_init(&amp;tech_pvt-&gt;write_codec,
-                                                                   tech_pvt-&gt;rm_encoding,
-                                                                   tech_pvt-&gt;rm_fmtp,
-                                                                   tech_pvt-&gt;rm_rate,
-                                                                   tech_pvt-&gt;codec_ms,
-                                                                   1,
-                                                                   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt-&gt;profile-&gt;codec_flags,
-                                                                   NULL,
-                                                                   switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec?\n&quot;);
-                        terminate_session(&amp;tech_pvt-&gt;session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-                        return SWITCH_STATUS_FALSE;
-                } else {
-                        int ms;
-                        tech_pvt-&gt;read_frame.rate = tech_pvt-&gt;rm_rate;
-                        ms = tech_pvt-&gt;write_codec.implementation-&gt;microseconds_per_frame / 1000;
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Set Codec %s %s/%d %d ms\n&quot;,
-                                                          switch_channel_get_name(channel),
-                                                          tech_pvt-&gt;rm_encoding, tech_pvt-&gt;rm_rate, tech_pvt-&gt;codec_ms);
-                        tech_pvt-&gt;read_frame.codec = &amp;tech_pvt-&gt;read_codec;
-                                
-                        switch_core_session_set_read_codec(tech_pvt-&gt;session, &amp;tech_pvt-&gt;read_codec);
-                        switch_core_session_set_write_codec(tech_pvt-&gt;session, &amp;tech_pvt-&gt;write_codec);
-                        tech_pvt-&gt;fmtp_out = switch_core_session_strdup(tech_pvt-&gt;session, tech_pvt-&gt;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;
</del><ins>+        private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+        switch_channel_t *channel = switch_core_session_get_channel(session);
</ins><span class="cx">         switch_status_t status;
</span><del>-        char tmp[50];
-        assert(tech_pvt != NULL);
</del><ins>+        uint32_t session_timeout = tech_pvt-&gt;profile-&gt;session_timeout;
+        const char *val;
+        const char *b_sdp = NULL;
+        int is_proxy = 0;
+        char *sticky = NULL;
</ins><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(tech_pvt-&gt;session);
-        assert(channel != NULL);
-
-        if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_test_flag(channel, CF_OUTBOUND)) {
</ins><span class="cx">                 return SWITCH_STATUS_SUCCESS;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_rtp_ready(tech_pvt-&gt;rtp_session) &amp;&amp; !switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
-                return SWITCH_STATUS_SUCCESS;
-        }
</del><span class="cx"> 
</span><del>-        if ((status = tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
-                return status;
-        }
-        
-        bw = tech_pvt-&gt;read_codec.implementation-&gt;bits_per_second;
-        ms = tech_pvt-&gt;read_codec.implementation-&gt;microseconds_per_frame;
</del><ins>+        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));
</ins><span class="cx"> 
</span><del>-        flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
</del><ins>+        if (b_sdp &amp;&amp; is_proxy) {
+                sofia_glue_tech_set_local_sdp(tech_pvt, b_sdp, SWITCH_TRUE);
</ins><span class="cx"> 
</span><del>-        if (switch_test_flag(tech_pvt, TFLAG_BUGGY_2833)) {
-                flags |= SWITCH_RTP_FLAG_BUGGY_2833;
-        }
-
-    if ((tech_pvt-&gt;profile-&gt;pflags &amp; PFLAG_PASS_RFC2833) || ((val = switch_channel_get_variable(channel, &quot;pass_rfc2833&quot;)) &amp;&amp; switch_true(val))) {
-        flags |= SWITCH_RTP_FLAG_PASS_RFC2833;
-    }
-
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;RTP [%s] %s:%d-&gt;%s:%d codec: %u ms: %d\n&quot;,
-                                          switch_channel_get_name(channel),
-                                          tech_pvt-&gt;local_sdp_audio_ip,
-                                          tech_pvt-&gt;local_sdp_audio_port,
-                                          tech_pvt-&gt;remote_sdp_audio_ip,
-                                          tech_pvt-&gt;remote_sdp_audio_port,
-                                          tech_pvt-&gt;agreed_pt,
-                                          tech_pvt-&gt;read_codec.implementation-&gt;microseconds_per_frame / 1000);
-
-        snprintf(tmp, sizeof(tmp), &quot;%d&quot;, tech_pvt-&gt;remote_sdp_audio_port);
-        switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt-&gt;adv_sdp_audio_ip);
-        switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
-        
-        if (tech_pvt-&gt;rtp_session &amp;&amp; switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
-                switch_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
-                
-                if (switch_rtp_set_remote_address(tech_pvt-&gt;rtp_session,
-                                                                                  tech_pvt-&gt;remote_sdp_audio_ip,
-                                                                                  tech_pvt-&gt;remote_sdp_audio_port,
-                                                                                  &amp;err) != SWITCH_STATUS_SUCCESS) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;RTP REPORTS ERROR: [%s]\n&quot;, err);
-                } else {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;RTP CHANGING DEST TO: [%s:%d]\n&quot;, 
-                                                          tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port);
-            /* Reactivate the NAT buster flag. */
-            switch_rtp_set_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
</del><ins>+                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;
+                        }
</ins><span class="cx">                 }
</span><del>-                return SWITCH_STATUS_SUCCESS;
-        }
</del><ins>+        } else {
+                /* This if statement check and handles the 3pcc proxy mode */
+                if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_3PCC_PROXY) &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_3PCC)) {
+                        /* Send the 200 OK */
+                        if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                nua_respond(tech_pvt-&gt;nh, SIP_200_OK,
+                                                        SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
+                                                        SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
+                                                        SOATAG_REUSE_REJECTED(1),
+                                                        SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
</ins><span class="cx"> 
</span><del>-        tech_pvt-&gt;rtp_session = switch_rtp_new(tech_pvt-&gt;local_sdp_audio_ip,
-                                                                                   tech_pvt-&gt;local_sdp_audio_port,
-                                                                                   tech_pvt-&gt;remote_sdp_audio_ip,
-                                                                                   tech_pvt-&gt;remote_sdp_audio_port,
-                                                                                   tech_pvt-&gt;agreed_pt,
-                                                                                   tech_pvt-&gt;read_codec.implementation-&gt;encoded_bytes_per_frame,
-                                                                                   tech_pvt-&gt;codec_ms * 1000,
-                                                                                   (switch_rtp_flag_t) flags,
-                                                                                   NULL,
-                                                                                   tech_pvt-&gt;profile-&gt;timer_name,
-                                                                                   &amp;err,
-                                                                                   switch_core_session_get_pool(tech_pvt-&gt;session));
-        
-        if (switch_rtp_ready(tech_pvt-&gt;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;
</del><ins>+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;3PCC-PROXY, Sent a 200 OK, waiting for ACK\n&quot;);
+                        }
</ins><span class="cx"> 
</span><del>-                tech_pvt-&gt;ssrc = switch_rtp_get_ssrc(tech_pvt-&gt;rtp_session);
-                switch_set_flag_locked(tech_pvt, TFLAG_RTP);
-                switch_set_flag_locked(tech_pvt, TFLAG_IO);
-                
-                if ((vad_in &amp;&amp; inb) || (vad_out &amp;&amp; !inb)) {
-                        switch_rtp_enable_vad(tech_pvt-&gt;rtp_session, tech_pvt-&gt;session, &amp;tech_pvt-&gt;read_codec, SWITCH_VAD_FLAG_TALKING);
-                        switch_set_flag_locked(tech_pvt, TFLAG_VAD);
-            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;RTP Engage VAD for %s ( %s %s )\n&quot;, 
-                              switch_channel_get_name(switch_core_session_get_channel(tech_pvt-&gt;session)),
-                              vad_in ? &quot;in&quot; : &quot;&quot;, vad_out ? &quot;out&quot; : &quot;&quot;);
</del><ins>+                        /* Unlock the session signal to allow the ack to make it in */
+                        // Maybe we should timeout?
+                        switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
+                        
+                        while(switch_channel_ready(channel) &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) {
+                                switch_cond_next();
+                        }
+                        
+                        /*  Regain lock on sofia */
+                        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+                        
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;3PCC-PROXY, Done waiting for ACK\n&quot;);
</ins><span class="cx">                 }
</span><del>-        } else {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;RTP REPORTS ERROR: [%s]\n&quot;, err);
-                terminate_session(&amp;tech_pvt-&gt;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;
-}
</del><span class="cx"> 
</span><del>-static switch_status_t tech_media(private_object_t *tech_pvt, char *r_sdp)
-{
-    sdp_parser_t *parser = sdp_parse(tech_pvt-&gt;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-&gt;session);
</del><ins>+                if ((is_proxy &amp;&amp; !b_sdp) || sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || !tech_pvt-&gt;iananame) {
+                        sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
</ins><span class="cx"> 
</span><del>-    assert(tech_pvt != NULL);
</del><ins>+                        if (is_proxy) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Disabling proxy mode due to call answer with no bridge\n&quot;);
+                                switch_channel_clear_flag(channel, CF_PROXY_MEDIA);
+                                switch_channel_clear_flag(channel, CF_PROXY_MODE);
+                        }
</ins><span class="cx"> 
</span><del>-    if (switch_strlen_zero(r_sdp)) {
-        return SWITCH_STATUS_FALSE;
-    }
</del><ins>+                        if (!switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND)) {
+                                const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
+                                tech_pvt-&gt;num_codecs = 0;
+                                sofia_glue_tech_prepare_codecs(tech_pvt);
</ins><span class="cx"> 
</span><del>-    if (tech_pvt-&gt;num_codecs) {
-        if ((sdp = sdp_session(parser))) {
-            match = negotiate_sdp(tech_pvt-&gt;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, &quot;EARLY MEDIA&quot;);
-        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) &amp;&amp; !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-&gt;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) {
</del><ins>+                                if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                                         switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;CODEC NEGOTIATION ERROR&quot;);
</span><del>-                                        nua_respond(tech_pvt-&gt;nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
</del><ins>+                                        //switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+                                        //nua_respond(tech_pvt-&gt;nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+                                        //switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
</ins><span class="cx">                                         return SWITCH_STATUS_FALSE;
</span><span class="cx">                                 }
</span><del>-                                switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
</del><span class="cx">                         }
</span><ins>+                }
</ins><span class="cx"> 
</span><del>-                        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);
</del><ins>+                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;
+                }
</ins><span class="cx">                 
</span><del>-                        if (tech_pvt-&gt;nh) {
-                                if (tech_pvt-&gt;local_sdp_str) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Local SDP %s:\n%s\n&quot;,
-                                                                          switch_channel_get_name(channel),
-                                                                  tech_pvt-&gt;local_sdp_str);
-                                }
</del><ins>+                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-&gt;nh) {
+                        if (tech_pvt-&gt;local_sdp_str) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Local SDP %s:\n%s\n&quot;, switch_channel_get_name(channel), tech_pvt-&gt;local_sdp_str);
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><del>-                nua_respond(tech_pvt-&gt;nh, SIP_200_OK, 
-                                        SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
</del><ins>+        }
+
+        if ((val = switch_channel_get_variable(channel, SOFIA_SESSION_TIMEOUT))) {
+                int v_session_timeout = atoi(val);
+                if (v_session_timeout &gt;= 0) {
+                        session_timeout = v_session_timeout;
+                }
+        }
+
+        if (sofia_test_flag(tech_pvt, TFLAG_NAT) ||
+                (val = switch_channel_get_variable(channel, &quot;sip-force-contact&quot;)) ||
+                ((val = switch_channel_get_variable(channel, &quot;sip_sticky_contact&quot;)) &amp;&amp; switch_true(val))) {
+                sticky = tech_pvt-&gt;record_route;
+                session_timeout = SOFIA_NAT_SESSION_TIMEOUT;
+                switch_channel_set_variable(channel, &quot;sip_nat_detected&quot;, &quot;true&quot;);
+        }
+
+        if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                nua_respond(tech_pvt-&gt;nh, SIP_200_OK,
+                                        NUTAG_AUTOANSWER(0),
+                                        TAG_IF(sticky, NUTAG_PROXY(tech_pvt-&gt;record_route)),
+                                        SIPTAG_HEADER_STR(generate_pai_str(session)),
+                                        NUTAG_SESSION_TIMER(session_timeout),
+                                        SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
+                                        SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt-&gt;channel, SOFIA_SIP_HEADER_PREFIX &quot;call_info&quot;)),
</ins><span class="cx">                                         SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
</span><del>-                                        SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;),
-                                        NUTAG_INCLUDE_EXTRA_SDP(1),
-                                        TAG_END());
-        } 
</del><ins>+                                        SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
+                sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
+        }
</ins><span class="cx"> 
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-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)
</del><ins>+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)
</ins><span class="cx"> {
</span><del>-        private_object_t *tech_pvt = NULL;
-        switch_channel_t *channel = NULL;
</del><ins>+        private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+        switch_channel_t *channel = switch_core_session_get_channel(session);
</ins><span class="cx">         int payload = 0;
</span><del>-        
-        channel = switch_core_session_get_channel(session);
-        assert(channel != NULL);
</del><span class="cx"> 
</span><del>-        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-        assert(tech_pvt != NULL);
</del><ins>+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-        if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
</ins><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        while (!(tech_pvt-&gt;read_codec.implementation &amp;&amp; switch_rtp_ready(tech_pvt-&gt;rtp_session))) {
</del><ins>+        while (!(tech_pvt-&gt;video_read_codec.implementation &amp;&amp; switch_rtp_ready(tech_pvt-&gt;video_rtp_session))) {
</ins><span class="cx">                 if (switch_channel_ready(channel)) {
</span><span class="cx">                         switch_yield(10000);
</span><span class="cx">                 } else {
</span><span class="lines">@@ -1738,107 +605,60 @@
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        tech_pvt-&gt;video_read_frame.datalen = 0;
</ins><span class="cx"> 
</span><del>-        tech_pvt-&gt;read_frame.datalen = 0;
-        switch_set_flag_locked(tech_pvt, TFLAG_READING);
-
-#if 0        
-        if (tech_pvt-&gt;last_read) {
-                elapsed = (unsigned int)((switch_time_now() - tech_pvt-&gt;last_read) / 1000);
-                if (elapsed &gt; 60000) {
-                        return SWITCH_STATUS_TIMEOUT;
-                }
-        }
-#endif
-
-
-        if (switch_test_flag(tech_pvt, TFLAG_IO)) {
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_IO)) {
</ins><span class="cx">                 switch_status_t status;
</span><span class="cx"> 
</span><del>-                if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
</del><ins>+                if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
</ins><span class="cx">                         return SWITCH_STATUS_GENERR;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                assert(tech_pvt-&gt;rtp_session != NULL);
-                tech_pvt-&gt;read_frame.datalen = 0;
</del><ins>+                switch_assert(tech_pvt-&gt;rtp_session != NULL);
+                tech_pvt-&gt;video_read_frame.datalen = 0;
</ins><span class="cx"> 
</span><ins>+                while (sofia_test_flag(tech_pvt, TFLAG_IO) &amp;&amp; tech_pvt-&gt;video_read_frame.datalen == 0) {
+                        tech_pvt-&gt;video_read_frame.flags = SFF_NONE;
</ins><span class="cx"> 
</span><del>-                while (switch_test_flag(tech_pvt, TFLAG_IO) &amp;&amp; tech_pvt-&gt;read_frame.datalen == 0) {
-                        tech_pvt-&gt;read_frame.flags = SFF_NONE;
-
-                        status = switch_rtp_zerocopy_read_frame(tech_pvt-&gt;rtp_session, &amp;tech_pvt-&gt;read_frame);
</del><ins>+                        status = switch_rtp_zerocopy_read_frame(tech_pvt-&gt;video_rtp_session, &amp;tech_pvt-&gt;video_read_frame, flags);
</ins><span class="cx">                         if (status != SWITCH_STATUS_SUCCESS &amp;&amp; status != SWITCH_STATUS_BREAK) {
</span><del>-                                return SWITCH_STATUS_FALSE;
-                        }
-
-                        
-                        
-                        payload = tech_pvt-&gt;read_frame.payload;
-
-#if 0
-                        elapsed = (unsigned int)((switch_time_now() - started) / 1000);
-
-                        if (timeout &gt; -1) {
-                                if (elapsed &gt;= (unsigned int)timeout) {
-                                        return SWITCH_STATUS_BREAK;
</del><ins>+                                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-&gt;channel, SWITCH_CAUSE_MEDIA_TIMEOUT);
</ins><span class="cx">                                 }
</span><ins>+                                return status;
</ins><span class="cx">                         }
</span><del>-                        
-                        elapsed = (unsigned int)((switch_time_now() - last_act) / 1000);
-                        if (elapsed &gt;= hard_timeout) {
-                                return SWITCH_STATUS_BREAK;
-                        }
-#endif
-                        if (switch_rtp_has_dtmf(tech_pvt-&gt;rtp_session)) {
-                                char dtmf[128];
-                                switch_rtp_dequeue_dtmf(tech_pvt-&gt;rtp_session, dtmf, sizeof(dtmf));
-                                switch_channel_queue_dtmf(channel, dtmf);
-                        }
</del><span class="cx"> 
</span><ins>+                        payload = tech_pvt-&gt;video_read_frame.payload;
</ins><span class="cx"> 
</span><del>-                        if (tech_pvt-&gt;read_frame.datalen &gt; 0) {
-                size_t bytes = 0;
-                int frames = 1;
-                                //tech_pvt-&gt;last_read = switch_time_now();
-                if (!switch_test_flag((&amp;tech_pvt-&gt;read_frame), SFF_CNG)) {
-                    if ((bytes = tech_pvt-&gt;read_codec.implementation-&gt;encoded_bytes_per_frame)) {
-                        frames = (tech_pvt-&gt;read_frame.datalen / bytes);
-                    }
-                    tech_pvt-&gt;read_frame.samples = (int) (frames * tech_pvt-&gt;read_codec.implementation-&gt;samples_per_frame);
-                }
</del><ins>+                        if (tech_pvt-&gt;video_read_frame.datalen &gt; 0) {
</ins><span class="cx">                                 break;
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><del>-        
-        switch_clear_flag_locked(tech_pvt, TFLAG_READING);
</del><span class="cx"> 
</span><del>-        if (tech_pvt-&gt;read_frame.datalen == 0) {
</del><ins>+        if (tech_pvt-&gt;video_read_frame.datalen == 0) {
</ins><span class="cx">                 *frame = NULL;
</span><span class="cx">                 return SWITCH_STATUS_GENERR;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        *frame = &amp;tech_pvt-&gt;read_frame;
</del><ins>+        *frame = &amp;tech_pvt-&gt;video_read_frame;
</ins><span class="cx"> 
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-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)
</del><ins>+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)
</ins><span class="cx"> {
</span><del>-        private_object_t *tech_pvt;
-        switch_channel_t *channel = NULL;
</del><ins>+        private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+        switch_channel_t *channel = switch_core_session_get_channel(session);
</ins><span class="cx">         switch_status_t status = SWITCH_STATUS_SUCCESS;
</span><del>-        int bytes = 0, samples = 0, frames = 0;
</del><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(session);
-        assert(channel != NULL);
</del><ins>+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-        assert(tech_pvt != NULL);
-
-        while (!(tech_pvt-&gt;read_codec.implementation &amp;&amp; switch_rtp_ready(tech_pvt-&gt;rtp_session))) {
</del><ins>+        while (!(tech_pvt-&gt;video_read_codec.implementation &amp;&amp; switch_rtp_ready(tech_pvt-&gt;video_rtp_session))) {
</ins><span class="cx">                 if (switch_channel_ready(channel)) {
</span><span class="cx">                         switch_yield(10000);
</span><span class="cx">                 } else {
</span><span class="lines">@@ -1846,4046 +666,2723 @@
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
</ins><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
</ins><span class="cx">                 return SWITCH_STATUS_GENERR;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_IO)) {
</ins><span class="cx">                 return SWITCH_STATUS_SUCCESS;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        switch_set_flag_locked(tech_pvt, TFLAG_WRITING);
</del><ins>+        if (!switch_test_flag(frame, SFF_CNG)) {
+                switch_rtp_write_frame(tech_pvt-&gt;video_rtp_session, frame);
+        }
</ins><span class="cx"> 
</span><del>-
-        if (tech_pvt-&gt;read_codec.implementation-&gt;encoded_bytes_per_frame) {
-                bytes = tech_pvt-&gt;read_codec.implementation-&gt;encoded_bytes_per_frame;
-                frames = ((int) frame-&gt;datalen / bytes);
-        } else
-                frames = 1;
-
-        samples = frames * tech_pvt-&gt;read_codec.implementation-&gt;samples_per_frame;
-
-#if 0
-        printf(&quot;%s %s-&gt;%s send %d bytes %d samples in %d frames ts=%d\n&quot;,
-                   switch_channel_get_name(channel),
-                   tech_pvt-&gt;local_sdp_audio_ip,
-                   tech_pvt-&gt;remote_sdp_audio_ip,
-                   frame-&gt;datalen,
-                   samples,
-                   frames,
-                   tech_pvt-&gt;timestamp_send);
-#endif
-
-        tech_pvt-&gt;timestamp_send += samples;
-        switch_rtp_write_frame(tech_pvt-&gt;rtp_session, frame, tech_pvt-&gt;timestamp_send);
-
-        switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
</del><span class="cx">         return status;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-
-static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig)
</del><ins>+static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
</ins><span class="cx"> {
</span><del>-        private_object_t *tech_pvt;
-        switch_channel_t *channel = NULL;
</del><ins>+        private_object_t *tech_pvt = switch_core_session_get_private(session);
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+        int payload = 0;
</ins><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(session);
-        assert(channel != NULL);
</del><ins>+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-        assert(tech_pvt != NULL);
</del><ins>+        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_RUNNING)) {
+                switch_channel_hangup(tech_pvt-&gt;channel, SWITCH_CAUSE_NORMAL_CLEARING);
+                return SWITCH_STATUS_FALSE;
+        }
</ins><span class="cx"> 
</span><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
+                return SWITCH_STATUS_FALSE;
+        }
</ins><span class="cx"> 
</span><del>-    switch(sig) {
-    case SWITCH_SIG_BREAK:
-        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
-                        switch_rtp_set_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_BREAK);
</del><ins>+        while (!(tech_pvt-&gt;read_codec.implementation &amp;&amp; switch_rtp_ready(tech_pvt-&gt;rtp_session) &amp;&amp; !switch_channel_test_flag(channel, CF_REQ_MEDIA))) {
+                if (switch_channel_ready(channel)) {
+                        switch_yield(10000);
+                } else {
+                        return SWITCH_STATUS_GENERR;
</ins><span class="cx">                 }
</span><del>-        break;
-    case SWITCH_SIG_KILL:
-    default:
-        switch_clear_flag_locked(tech_pvt, TFLAG_IO);
-        switch_set_flag_locked(tech_pvt, TFLAG_HUP);
</del><ins>+        }
</ins><span class="cx"> 
</span><del>-        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
-            switch_rtp_kill_socket(tech_pvt-&gt;rtp_session);
-        }
-        break;
-    }
</del><ins>+        tech_pvt-&gt;read_frame.datalen = 0;
+        sofia_set_flag_locked(tech_pvt, TFLAG_READING);
</ins><span class="cx"> 
</span><del>-        return SWITCH_STATUS_SUCCESS;
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_HUP) || sofia_test_flag(tech_pvt, TFLAG_BYE) || !tech_pvt-&gt;read_codec.implementation || 
+                !switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                return SWITCH_STATUS_FALSE;
+        }
</ins><span class="cx"> 
</span><del>-}
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_IO)) {
+                switch_status_t status;
</ins><span class="cx"> 
</span><del>-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;
</del><ins>+                if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
+                        return SWITCH_STATUS_GENERR;
+                }
</ins><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(session);
-        assert(channel != NULL);
</del><ins>+                switch_assert(tech_pvt-&gt;rtp_session != NULL);
+                tech_pvt-&gt;read_frame.datalen = 0;
+                
+                while (sofia_test_flag(tech_pvt, TFLAG_IO) &amp;&amp; tech_pvt-&gt;read_frame.datalen == 0) {
+                        tech_pvt-&gt;read_frame.flags = SFF_NONE;
</ins><span class="cx"> 
</span><del>-        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-        assert(tech_pvt != NULL);
</del><ins>+                        status = switch_rtp_zerocopy_read_frame(tech_pvt-&gt;rtp_session, &amp;tech_pvt-&gt;read_frame, flags);
</ins><span class="cx"> 
</span><del>-        return SWITCH_STATUS_SUCCESS;
-}
</del><ins>+                        if (status != SWITCH_STATUS_SUCCESS &amp;&amp; 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-&gt;channel, SWITCH_CAUSE_MEDIA_TIMEOUT);
+                                }
+                                return status;
+                        }
</ins><span class="cx"> 
</span><ins>+                        /* Fast PASS! */
+                        if (switch_test_flag((&amp;tech_pvt-&gt;read_frame), SFF_PROXY_PACKET)) {
+                                sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
+                                *frame = &amp;tech_pvt-&gt;read_frame;
+                                return SWITCH_STATUS_SUCCESS;
+                        }
</ins><span class="cx"> 
</span><del>-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;
</del><ins>+                        payload = tech_pvt-&gt;read_frame.payload;
</ins><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(session);
-        assert(channel != NULL);
</del><ins>+                        if (switch_rtp_has_dtmf(tech_pvt-&gt;rtp_session)) {
+                                switch_dtmf_t dtmf = { 0 };
+                                switch_rtp_dequeue_dtmf(tech_pvt-&gt;rtp_session, &amp;dtmf);
+                                switch_channel_queue_dtmf(channel, &amp;dtmf);
+                        }
</ins><span class="cx"> 
</span><del>-        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-        assert(tech_pvt != NULL);
</del><ins>+                        if (tech_pvt-&gt;read_frame.datalen &gt; 0) {
+                                size_t bytes = 0;
+                                int frames = 1;
+                                
+                                if (!switch_test_flag((&amp;tech_pvt-&gt;read_frame), SFF_CNG)) {
+                                        if (!tech_pvt-&gt;read_codec.implementation || !switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                                                *frame = NULL;
+                                                return SWITCH_STATUS_GENERR;
+                                        }
+                                        
+                                        if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_AUTOFIX_TIMING) &amp;&amp; tech_pvt-&gt;check_frames++ &lt; MAX_CODEC_CHECK_FRAMES) {
+                                                if (!tech_pvt-&gt;read_impl.encoded_bytes_per_packet) {
+                                                        tech_pvt-&gt;check_frames = MAX_CODEC_CHECK_FRAMES;
+                                                        goto skip;
+                                                }
</ins><span class="cx"> 
</span><del>-        return SWITCH_STATUS_SUCCESS;
</del><ins>+                                                if (tech_pvt-&gt;last_ts &amp;&amp; tech_pvt-&gt;read_frame.datalen != tech_pvt-&gt;read_impl.encoded_bytes_per_packet) {
+                                                        switch_size_t codec_ms = (int)(tech_pvt-&gt;read_frame.timestamp - 
+                                                                                                                   tech_pvt-&gt;last_ts) / (tech_pvt-&gt;read_impl.samples_per_second / 1000);
</ins><span class="cx"> 
</span><del>-}
</del><ins>+                                                        if ((codec_ms % 10) != 0) {
+                                                                tech_pvt-&gt;check_frames = MAX_CODEC_CHECK_FRAMES;
+                                                                goto skip;
+                                                        }
+                                                        
+                                                        if (tech_pvt-&gt;last_codec_ms &amp;&amp; tech_pvt-&gt;last_codec_ms == codec_ms) {
+                                                                tech_pvt-&gt;mismatch_count++;
+                                                        }
</ins><span class="cx"> 
</span><del>-static switch_status_t sofia_send_dtmf(switch_core_session_t *session, char *digits)
-{
-        private_object_t *tech_pvt;
</del><ins>+                                                        tech_pvt-&gt;last_codec_ms = codec_ms;
</ins><span class="cx"> 
</span><del>-        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
-    assert(tech_pvt != NULL);
</del><ins>+                                                        if (tech_pvt-&gt;mismatch_count &gt; MAX_MISMATCH_FRAMES) {
+                                                                if (switch_rtp_ready(tech_pvt-&gt;rtp_session) &amp;&amp; codec_ms != tech_pvt-&gt;codec_ms) {
+                                                                        const char *val;
+                                                                        int rtp_timeout_sec = 0;
+                                                                        int rtp_hold_timeout_sec = 0;
+                                                                
+                                                                        if (codec_ms &gt; 120) { /* yeah right */
+                                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+                                                                                                                  &quot;Your phone is trying to send timestamps that suggest an increment of %dms per packet\n&quot;
+                                                                                                                  &quot;That seems hard to believe so I am going to go on ahead and um ignore that, mmkay?&quot;, (int)codec_ms);
+                                                                                tech_pvt-&gt;check_frames = MAX_CODEC_CHECK_FRAMES;
+                                                                                goto skip;
+                                                                        }
</ins><span class="cx"> 
</span><del>-        return switch_rtp_queue_rfc2833(tech_pvt-&gt;rtp_session,
-                                                                        digits,
-                                                                        tech_pvt-&gt;profile-&gt;dtmf_duration * (tech_pvt-&gt;read_codec.implementation-&gt;samples_per_second / 1000));
-        
-}
</del><ins>+                                                                        tech_pvt-&gt;read_frame.datalen = 0;
+                                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+                                                                                                          &quot;We were told to use ptime %d but what they meant to say was %d\n&quot;
+                                                                                                          &quot;This issue has so far been identified to happen on the following broken platforms/devices:\n&quot; 
+                                                                                                          &quot;Linksys/Sipura aka Cisco\n&quot;
+                                                                                                          &quot;ShoreTel\n&quot;
+                                                                                                          &quot;Sonus/L3\n&quot;
+                                                                                                          &quot;We will try to fix it but some of the devices on this list are so broken who knows what will happen..\n&quot;
+                                                                                                          , 
+                                                                                                          (int)tech_pvt-&gt;codec_ms, (int)codec_ms);
+                                                                        tech_pvt-&gt;codec_ms = codec_ms;
+                                                                        switch_core_session_lock_codec_write(session);
+                                                                        switch_core_session_lock_codec_read(session);
</ins><span class="cx"> 
</span><del>-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;
</del><ins>+                                                                        switch_core_codec_destroy(&amp;tech_pvt-&gt;read_codec);                                                                        
+                                                                        switch_core_codec_destroy(&amp;tech_pvt-&gt;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-&gt;channel, &quot;rtp_timeout_sec&quot;))) {
+                                                                                int v = atoi(val);
+                                                                                if (v &gt;= 0) {
+                                                                                        rtp_timeout_sec = v;
+                                                                                }
+                                                                        }
+                                                                        
+                                                                        if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_hold_timeout_sec&quot;))) {
+                                                                                int v = atoi(val);
+                                                                                if (v &gt;= 0) {
+                                                                                        rtp_hold_timeout_sec = v;
+                                                                                }
+                                                                        }
+                                                                        
+                                                                        if (rtp_timeout_sec) {
+                                                                                tech_pvt-&gt;max_missed_packets = (tech_pvt-&gt;read_impl.samples_per_second * rtp_timeout_sec) /
+                                                                                        tech_pvt-&gt;read_impl.samples_per_packet;
+                                                                                
+                                                                                switch_rtp_set_max_missed_packets(tech_pvt-&gt;rtp_session, tech_pvt-&gt;max_missed_packets);
+                                                                                if (!rtp_hold_timeout_sec) {
+                                                                                        rtp_hold_timeout_sec = rtp_timeout_sec * 10;
+                                                                                }
+                                                                        }
+                                                                        
+                                                                        if (rtp_hold_timeout_sec) {
+                                                                                tech_pvt-&gt;max_missed_hold_packets = (tech_pvt-&gt;read_impl.samples_per_second * rtp_hold_timeout_sec) /
+                                                                                        tech_pvt-&gt;read_impl.samples_per_packet;
+                                                                        }
+                                                                        
+                                                                        if (switch_rtp_change_interval(tech_pvt-&gt;rtp_session, 
+                                                                                                                                   tech_pvt-&gt;codec_ms * 1000,
+                                                                                                                                   tech_pvt-&gt;read_impl.samples_per_packet
+                                                                                                                                   ) != SWITCH_STATUS_SUCCESS) {
+                                                                                switch_channel_hangup(tech_pvt-&gt;channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                                                                
+                                                                        }
</ins><span class="cx"> 
</span><del>-        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);
</del><ins>+                                                                        tech_pvt-&gt;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);
</ins><span class="cx"> 
</span><ins>+                                                                }
+                                                        
+                                                        }
+                                                        
+                                                } else {
+                                                        tech_pvt-&gt;mismatch_count = 0;
+                                                }
+                                                tech_pvt-&gt;last_ts = tech_pvt-&gt;read_frame.timestamp;
+                                        }
+                                skip:
+                                        
+                                        if ((bytes = tech_pvt-&gt;read_impl.encoded_bytes_per_packet)) {
+                                                frames = (tech_pvt-&gt;read_frame.datalen / bytes);
+                                        }
+                                        tech_pvt-&gt;read_frame.samples = (int) (frames * tech_pvt-&gt;read_impl.samples_per_packet);
</ins><span class="cx"> 
</span><del>-        switch (msg-&gt;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-&gt;local_sdp_str = NULL;
-                if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) &amp;&amp; (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 &amp;&amp; port) {
-                                set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1);
</del><ins>+                                        if (tech_pvt-&gt;read_frame.datalen == 0) {
+                                                continue;
+                                        }
+                                }
+                                break;
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><del>-                if (!tech_pvt-&gt;local_sdp_str) {
-                        tech_absorb_sdp(tech_pvt);
-                }
-                do_invite(session);
</del><span class="cx">         }
</span><del>-                break;
-        case SWITCH_MESSAGE_INDICATE_MEDIA: {
-                switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-                tech_pvt-&gt;local_sdp_str = NULL;
-                if (!switch_rtp_ready(tech_pvt-&gt;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-&gt;rtp_session) &amp;&amp; switch_channel_get_state(channel) &lt; CS_HANGUP) {
-                        switch_yield(1000);
-                }
-        }
-                break;
</del><span class="cx"> 
</span><del>-        case SWITCH_MESSAGE_INDICATE_HOLD: {
-                switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-                do_invite(session);
-        }
-                break;
</del><ins>+        sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
</ins><span class="cx"> 
</span><del>-        case SWITCH_MESSAGE_INDICATE_UNHOLD: {
-                switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-                do_invite(session);
</del><ins>+        if (tech_pvt-&gt;read_frame.datalen == 0) {
+                *frame = NULL;
+                return SWITCH_STATUS_GENERR;
</ins><span class="cx">         }
</span><del>-                break;
-        case SWITCH_MESSAGE_INDICATE_BRIDGE:
</del><span class="cx"> 
</span><del>-                if (switch_test_flag(tech_pvt, TFLAG_XFER)) {
-                        switch_clear_flag_locked(tech_pvt, TFLAG_XFER);
-                        if (msg-&gt;pointer_arg) {
-                                switch_core_session_t *a_session, *b_session = msg-&gt;pointer_arg;
</del><ins>+        *frame = &amp;tech_pvt-&gt;read_frame;
</ins><span class="cx"> 
</span><del>-                                if ((a_session = switch_core_session_locate(tech_pvt-&gt;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-&gt;remote_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt-&gt;remote_sdp_audio_ip);
-                                        a_tech_pvt-&gt;remote_sdp_audio_port = b_tech_pvt-&gt;remote_sdp_audio_port;
-                                        a_tech_pvt-&gt;local_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt-&gt;local_sdp_audio_ip);
-                                        a_tech_pvt-&gt;local_sdp_audio_port = b_tech_pvt-&gt;local_sdp_audio_port;
-                                        activate_rtp(a_tech_pvt);
-                                        
-                                        b_tech_pvt-&gt;kick = switch_core_session_strdup(b_session, tech_pvt-&gt;xferto);
-                    switch_core_session_rwunlock(a_session);
-                                }
-
-                                
-                                msg-&gt;pointer_arg = NULL;
-                                return SWITCH_STATUS_FALSE;
-                        }
-                }
-                if (tech_pvt-&gt;rtp_session &amp;&amp; switch_test_flag(tech_pvt, TFLAG_TIMER)) {
-                        switch_rtp_clear_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;De-activate timed RTP!\n&quot;);
-                }
-                break;
-        case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
-                if (tech_pvt-&gt;rtp_session &amp;&amp; switch_test_flag(tech_pvt, TFLAG_TIMER)) {
-                        switch_rtp_set_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Re-activate timed RTP!\n&quot;);
-                }
-                break;
-        case SWITCH_MESSAGE_INDICATE_REDIRECT:
-                if(msg-&gt;string_arg) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Re-directing to %s\n&quot;, msg-&gt;string_arg);
-                        nua_respond(tech_pvt-&gt;nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg-&gt;string_arg), TAG_END());
-                }
-                break;
-        case SWITCH_MESSAGE_INDICATE_RINGING:
-                nua_respond(tech_pvt-&gt;nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;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, &quot;Asked to send early media by %s\n&quot;, msg-&gt;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-&gt;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, &quot;CODEC NEGOTIATION ERROR&quot;);
-                                                nua_respond(tech_pvt-&gt;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-&gt;local_sdp_str) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Ring SDP:\n%s\n&quot;, tech_pvt-&gt;local_sdp_str);
-                                }
-                        }
-                        
-                        nua_respond(tech_pvt-&gt;nh,
-                                                SIP_183_SESSION_PROGRESS,
-                                                SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
-                                                SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
-                                                SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;),
-                                                TAG_END());
-            }
-        }
-                break;
-        default:
-                break;
-        }
-
</del><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event)
</del><ins>+static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
</ins><span class="cx"> {
</span><del>-        switch_channel_t *channel;
-    struct private_object *tech_pvt;
-        char *body;
-        nua_handle_t *msg_nh;
</del><ins>+        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;
</ins><span class="cx"> 
</span><del>-    channel = switch_core_session_get_channel(session);
-    assert(channel != NULL);
</del><ins>+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-    tech_pvt = switch_core_session_get_private(session);
-    assert(tech_pvt != NULL);
</del><ins>+        while (!(tech_pvt-&gt;read_codec.implementation &amp;&amp; switch_rtp_ready(tech_pvt-&gt;rtp_session) &amp;&amp; !switch_channel_test_flag(channel, CF_REQ_MEDIA))) {
+                if (switch_channel_ready(channel)) {
+                        switch_yield(10000);
+                } else {
+                        return SWITCH_STATUS_GENERR;
+                }
+        }
</ins><span class="cx"> 
</span><ins>+        if (!tech_pvt-&gt;read_codec.implementation || !switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                return SWITCH_STATUS_GENERR;
+        }
</ins><span class="cx"> 
</span><del>-        if (!(body = switch_event_get_body(event))) {
-                body = &quot;&quot;;
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
+                return SWITCH_STATUS_FALSE;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (tech_pvt-&gt;hash_key) {
-                msg_nh = nua_handle(tech_pvt-&gt;profile-&gt;nua, NULL,
-                                                        SIPTAG_FROM_STR(tech_pvt-&gt;chat_from),
-                                                        NUTAG_URL(tech_pvt-&gt;chat_to),
-                                                        SIPTAG_TO_STR(tech_pvt-&gt;chat_to),
-                                                        SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
-                                                        TAG_END());
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
+                return SWITCH_STATUS_GENERR;
+        }
</ins><span class="cx"> 
</span><del>-                nua_message(msg_nh,
-                                        SIPTAG_CONTENT_TYPE_STR(&quot;text/html&quot;),
-                                        SIPTAG_PAYLOAD_STR(body),
-                                        TAG_END());
</del><ins>+        if (!sofia_test_flag(tech_pvt, TFLAG_IO)) {
+                return SWITCH_STATUS_SUCCESS;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        return SWITCH_STATUS_SUCCESS;
-}
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_BYE) || !tech_pvt-&gt;read_codec.implementation || !switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                return SWITCH_STATUS_FALSE;
+        }
</ins><span class="cx"> 
</span><del>-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
-};
</del><ins>+        sofia_set_flag_locked(tech_pvt, TFLAG_WRITING);
</ins><span class="cx"> 
</span><del>-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
-};
</del><ins>+        if (!switch_test_flag(frame, SFF_CNG) &amp;&amp; !switch_test_flag(frame, SFF_PROXY_PACKET)) {
+                if (tech_pvt-&gt;read_impl.encoded_bytes_per_packet) {
+                        bytes = tech_pvt-&gt;read_impl.encoded_bytes_per_packet;
+                        frames = ((int) frame-&gt;datalen / bytes);
+                } else
+                        frames = 1;
</ins><span class="cx"> 
</span><del>-static const switch_endpoint_interface_t sofia_endpoint_interface = {
-        /*.interface_name */ &quot;sofia&quot;,
-        /*.io_routines */ &amp;sofia_io_routines,
-        /*.event_handlers */ &amp;sofia_event_handlers,
-        /*.private */ NULL,
-        /*.next */ NULL
-};
</del><ins>+                samples = frames * tech_pvt-&gt;read_impl.samples_per_packet;
+        }
</ins><span class="cx"> 
</span><del>-static const switch_chat_interface_t sofia_chat_interface = {
-        /*.name */ SOFIA_CHAT_PROTO,
-        /*.chat_send */ chat_send,
-        
-};
</del><ins>+        tech_pvt-&gt;timestamp_send += samples;
+        switch_rtp_write_frame(tech_pvt-&gt;rtp_session, frame);
</ins><span class="cx"> 
</span><del>-static const switch_loadable_module_interface_t sofia_module_interface = {
-        /*.module_name */ modname,
-        /*.endpoint_interface */ &amp;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 */ &amp;sofia_chat_interface
-};
</del><ins>+        sofia_clear_flag_locked(tech_pvt, TFLAG_WRITING);
+        return status;
+}
</ins><span class="cx"> 
</span><del>-
-static void logger(void *logarg, char const *fmt, va_list ap)
</del><ins>+static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig)
</ins><span class="cx"> {
</span><del>-        char *data = NULL;
</del><ins>+        private_object_t *tech_pvt = switch_core_session_get_private(session);
</ins><span class="cx"> 
</span><del>-        if (fmt) {
-#ifdef HAVE_VASPRINTF
-                int ret;
-                ret = vasprintf(&amp;data, fmt, ap);
-                if ((ret == -1) || !data) {
-                        return;
</del><ins>+        if (!tech_pvt) {
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch (sig) {
+        case SWITCH_SIG_BREAK:
+                if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                        switch_rtp_break(tech_pvt-&gt;rtp_session);
</ins><span class="cx">                 }
</span><del>-#else
-                data = (char *) malloc(2048);
-                if (data) {
-                        vsnprintf(data, 2048, fmt, ap);
-                } else { 
-                        return;
</del><ins>+                if (switch_rtp_ready(tech_pvt-&gt;video_rtp_session)) {
+                        switch_rtp_break(tech_pvt-&gt;video_rtp_session);
</ins><span class="cx">                 }
</span><del>-#endif
</del><ins>+                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-&gt;rtp_session)) {
+                        switch_rtp_kill_socket(tech_pvt-&gt;rtp_session);
+                }
+                if (switch_rtp_ready(tech_pvt-&gt;video_rtp_session)) {
+                        switch_rtp_kill_socket(tech_pvt-&gt;video_rtp_session);
+                }
+                break;
</ins><span class="cx">         }
</span><del>-        if (data) {
-                switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, (char*) &quot;%s&quot;, data);
-                free(data);
-        }
</del><ins>+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-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)
</del><ins>+static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
</ins><span class="cx"> {
</span><del>-        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;
</del><ins>+        private_object_t *tech_pvt;
+        char message[128] = &quot;&quot;;
+        sofia_dtmf_t dtmf_type;
</ins><span class="cx"> 
</span><del>-        *new_session = NULL;
</del><ins>+        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-        if (!(nsession = switch_core_session_request(&amp;sofia_endpoint_interface, pool))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Error Creating Session\n&quot;);
-                goto done;
-        }
</del><ins>+        dtmf_type = tech_pvt-&gt;dtmf_type;
</ins><span class="cx"> 
</span><del>-        if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Error Creating Session\n&quot;);
-                terminate_session(&amp;nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
-                goto done;
</del><ins>+        /* We only can send INFO when we have no media */
+        if (!tech_pvt-&gt;rtp_session || !switch_channel_media_ready(tech_pvt-&gt;channel) || switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MODE)) {
+                dtmf_type = DTMF_INFO;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        data = switch_core_session_strdup(nsession, outbound_profile-&gt;destination_number);
-        profile_name = data;
-        
-        if (!(dest = strchr(profile_name, '/'))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid URL\n&quot;);
-        terminate_session(&amp;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, &quot;Invalid Profile\n&quot;);
-        terminate_session(&amp;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-&gt;dest_to = switch_core_session_alloc(nsession, strlen(dest_to) + 5);
-                snprintf(tech_pvt-&gt;dest_to, strlen(dest_to) + 5, &quot;sip:%s&quot;, dest_to);
-        }
-
-        if ((host = strchr(dest, '%'))) {
-                char buf[128];
-                *host = '@';
-                tech_pvt-&gt;e_dest = switch_core_session_strdup(nsession, dest);
-                *host++ = '\0';
-                if (find_reg_url(profile, dest, host, buf, sizeof(buf))) {
-                        tech_pvt-&gt;dest = switch_core_session_strdup(nsession, buf);
-                        
-                } else {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Cannot locate registered user %s@%s\n&quot;, dest, host);
-                        cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
-                        terminate_session(&amp;nsession, cause, __LINE__);
-                        goto done;
</del><ins>+        switch (dtmf_type) {
+        case DTMF_2833:
+                {
+                        return switch_rtp_queue_rfc2833(tech_pvt-&gt;rtp_session, dtmf);
</ins><span class="cx">                 }
</span><del>-        } else if (!strchr(dest, '@')) {
-                char buf[128];
-                tech_pvt-&gt;e_dest = switch_core_session_strdup(nsession, dest);
-                if (find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) {
-            tech_pvt-&gt;dest = switch_core_session_strdup(nsession, buf);
-
-        } else {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Cannot locate registered user %s@%s\n&quot;, dest, profile_name);
-                        cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
-            terminate_session(&amp;nsession, cause, __LINE__);
-            goto done;
-        }
-        } else {
-                tech_pvt-&gt;dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
-                snprintf(tech_pvt-&gt;dest, strlen(dest) + 5, &quot;sip:%s&quot;, dest);
-        }
-
-        if (!tech_pvt-&gt;dest_to) {
-                tech_pvt-&gt;dest_to = tech_pvt-&gt;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-&gt;bte = ctech_pvt-&gt;te;
</del><ins>+        case DTMF_INFO:
+                {
+                        snprintf(message, sizeof(message), &quot;Signal=%c\r\nDuration=%d\r\n&quot;, dtmf-&gt;digit, dtmf-&gt;duration / 8);
+                        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+                        nua_info(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;application/dtmf-relay&quot;), SIPTAG_PAYLOAD_STR(message), TAG_END());
+                        switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
</ins><span class="cx">                 }
</span><ins>+                break;
+        case DTMF_NONE:
+                break;
+        default:
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Unhandled DTMF type!\n&quot;);
+                break;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>- done:
-        return cause;
</del><ins>+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
</del><ins>+static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
</ins><span class="cx"> {
</span><del>-        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;
</del><ins>+        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;
</ins><span class="cx"> 
</span><del>-        tech_pvt = switch_core_session_get_private(session);
-        assert(tech_pvt != NULL);
-
-        channel = switch_core_session_get_channel(session);
-        
-        if ((tech_pvt-&gt;origin = switch_core_session_strdup(session, (char *) sdp-&gt;sdp_origin-&gt;o_username))) {
-                if (strstr(tech_pvt-&gt;origin, &quot;CiscoSystemsSIP-GW-UserAgent&quot;)) {
-                        switch_set_flag_locked(tech_pvt, TFLAG_BUGGY_2833);
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Activate Buggy RFC2833 Mode!\n&quot;);
-                }
</del><ins>+        if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                status = SWITCH_STATUS_FALSE;
+                goto end;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        for (a = sdp-&gt;sdp_attributes; a; a = a-&gt;a_next) {
-                if (!strcasecmp(a-&gt;a_name, &quot;sendonly&quot;)) {
-                        switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-                } else if (!strcasecmp(a-&gt;a_name, &quot;sendrecv&quot;)) {
-                        switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-                } else if (!strcasecmp(a-&gt;a_name, &quot;ptime&quot;)) {
-            dptime = atoi(a-&gt;a_value);
</del><ins>+        /* ones that do not need to lock sofia mutex */
+        switch (msg-&gt;message_id) {
+        case SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY:
+                if (tech_pvt-&gt;rtp_session &amp;&amp; switch_rtp_test_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Pass 2833 mode may not work on a transcoded call.\n&quot;);
</ins><span class="cx">                 }
</span><del>-        }
</del><ins>+                goto end;
</ins><span class="cx"> 
</span><del>-        for (m = sdp-&gt;sdp_media; m ; m = m-&gt;m_next) {
-        sdp_connection_t *connection;
</del><ins>+        case SWITCH_MESSAGE_INDICATE_BRIDGE:
+                if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                        const char *val;
+                        int ok = 0;
</ins><span class="cx"> 
</span><del>-        ptime = dptime;
-        for (a = m-&gt;m_attributes; a; a = a-&gt;a_next) {
-            if (!strcasecmp(a-&gt;a_name, &quot;ptime&quot;) &amp;&amp; a-&gt;a_value) {
-                ptime = atoi(a-&gt;a_value);
-            }
-        }
</del><ins>+                        if (sofia_test_flag(tech_pvt, TFLAG_PASS_RFC2833) &amp;&amp; switch_channel_test_flag_partner(channel, CF_FS_RTP)) {
+                                switch_rtp_set_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s activate passthru 2833 mode.\n&quot;, switch_channel_get_name(channel));
+                        }
</ins><span class="cx"> 
</span><del>-                if (m-&gt;m_type == sdp_media_audio) {
-                        sdp_rtpmap_t *map;
</del><ins>+                        if ((val = switch_channel_get_variable(channel, &quot;rtp_autoflush_during_bridge&quot;))) {
+                                ok = switch_true(val);
+                        } else {
+                                ok = sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
+                        }
+                        
+                        if (ok) {
+                                rtp_flush_read_buffer(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLUSH_STICK);
+                        } else {
+                                rtp_flush_read_buffer(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLUSH_ONCE);
+                        }
+                }
+                goto end;
+        case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+                if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                        const char *val;
+                        int ok = 0;
</ins><span class="cx"> 
</span><del>-                        connection = sdp-&gt;sdp_connection;
-                        if (m-&gt;m_connections) {
-                                connection = m-&gt;m_connections;
</del><ins>+                        if (switch_rtp_test_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s deactivate passthru 2833 mode.\n&quot;, switch_channel_get_name(channel));
+                                switch_rtp_clear_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
</ins><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        if (!connection) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot find a c= line in the sdp at media or session level!\n&quot;);
-                                match = 0;
-                                break;
</del><ins>+                        if ((val = switch_channel_get_variable(channel, &quot;rtp_autoflush_during_bridge&quot;))) {
+                                ok = switch_true(val);
+                        } else {
+                                ok = sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
</ins><span class="cx">                         }
</span><ins>+                        
+                        if (ok) {
+                                rtp_flush_read_buffer(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLUSH_UNSTICK);
+                        } else {
+                                rtp_flush_read_buffer(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLUSH_ONCE);
+                        }
</ins><span class="cx"> 
</span><del>-                        for (map = m-&gt;m_rtpmaps; map; map = map-&gt;rm_next) {
-                                int32_t i;
-                const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
</del><ins>+                }
+                goto end;
+        case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+                if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                        rtp_flush_read_buffer(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLUSH_ONCE);
+                }
+                goto end;
</ins><span class="cx"> 
</span><del>-                                if (!te &amp;&amp; !strcasecmp(map-&gt;rm_encoding, &quot;telephone-event&quot;)) {
-                                        te = tech_pvt-&gt;te = (switch_payload_t)map-&gt;rm_pt;
-                                }
-
-                                if (match) {
-                                        if (te) {
-                                                break;
-                                        }
-                                        continue;
-                                }
-
-                                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
-                                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Codec Compare [%s:%d]/[%s:%d]\n&quot;, 
-                                                                          map-&gt;rm_encoding, map-&gt;rm_pt, imp-&gt;iananame, imp-&gt;ianacode);
-                                        if (map-&gt;rm_pt &lt; 96) {
-                                                match = (map-&gt;rm_pt == imp-&gt;ianacode) ? 1 : 0;
-                                        } else {
-                                                match = strcasecmp(map-&gt;rm_encoding, imp-&gt;iananame) ? 0 : 1;
-                                        }
-
-                                        if (match &amp;&amp; (map-&gt;rm_rate == imp-&gt;samples_per_second)) {
-                        if (ptime &amp;&amp; ptime * 1000 != imp-&gt;microseconds_per_frame) {
-                            near_match = imp;
-                            match = 0;
-                            continue;
-                        }
-                        mimp = imp;
-                                                break;
-                                        } else {
-                                                match = 0;
-                                        }
-                }
-                
-                if (!match &amp;&amp; near_match) {
-                    const switch_codec_implementation_t *search[1];
-                    char *prefs[1];
-                    char tmp[80];
-                    int num;
-                    
-                    snprintf(tmp, sizeof(tmp), &quot;%s@%uk@%ui&quot;,
-                             near_match-&gt;iananame,
-                             near_match-&gt;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, &quot;Substituting codec %s@%ums\n&quot;, 
-                                      mimp-&gt;iananame, mimp-&gt;microseconds_per_frame / 1000 );
-                    match = 1;
-                }
-
-                if (mimp) {
-                    if ((tech_pvt-&gt;rm_encoding = switch_core_session_strdup(session, (char *)map-&gt;rm_encoding))) {
-                        char tmp[50];
-                        tech_pvt-&gt;pt = (switch_payload_t)map-&gt;rm_pt;
-                        tech_pvt-&gt;rm_rate = map-&gt;rm_rate;
-                        tech_pvt-&gt;codec_ms = mimp-&gt;microseconds_per_frame / 1000;
-                        tech_pvt-&gt;remote_sdp_audio_ip = switch_core_session_strdup(session, (char *)connection-&gt;c_address);
-                        tech_pvt-&gt;rm_fmtp = switch_core_session_strdup(session, (char *)map-&gt;rm_fmtp);
-                        tech_pvt-&gt;remote_sdp_audio_port = (switch_port_t)m-&gt;m_port;
-                        tech_pvt-&gt;agreed_pt = (switch_payload_t)map-&gt;rm_pt;
-                        snprintf(tmp, sizeof(tmp), &quot;%d&quot;, tech_pvt-&gt;remote_sdp_audio_port);
-                        switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt-&gt;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;
-                                        }
-                                }
</del><ins>+        case SWITCH_MESSAGE_INDICATE_ANSWER:
+        case SWITCH_MESSAGE_INDICATE_PROGRESS:
+                {
+                        const char *var;
+                        if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) &amp;&amp; switch_true(var)) {
+                                sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><ins>+                break;
+        default:
+                break;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        return match;
-}
</del><ins>+        /* ones that do need to lock sofia mutex */
+        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
</ins><span class="cx"> 
</span><del>-// 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;
-
</del><ins>+        if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                status = SWITCH_STATUS_FALSE;
+                goto end_lock;
</ins><span class="cx">         }
</span><del>-}
</del><span class="cx"> 
</span><ins>+        switch (msg-&gt;message_id) {
+        case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
+                {
+                        const char *pl =
+                                &quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;utf-8\&quot; ?&gt;\r\n&quot;
+                                &quot; &lt;media_control&gt;\r\n&quot;
+                                &quot;  &lt;vc_primitive&gt;\r\n&quot;
+                                &quot;   &lt;to_encoder&gt;\r\n&quot;
+                                &quot;    &lt;picture_fast_update&gt;\r\n&quot; 
+                                &quot;    &lt;/picture_fast_update&gt;\r\n&quot; 
+                                &quot;   &lt;/to_encoder&gt;\r\n&quot; 
+                                &quot;  &lt;/vc_primitive&gt;\r\n&quot; 
+                                &quot; &lt;/media_control&gt;\r\n&quot;;
</ins><span class="cx"> 
</span><del>-static void set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
-{
</del><ins>+                        nua_info(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;application/media_control+xml&quot;), SIPTAG_PAYLOAD_STR(pl), TAG_END());
</ins><span class="cx"> 
</span><del>-        snprintf(hash_key, len, &quot;%s%s%s&quot;,
-                         (char *) sip-&gt;sip_from-&gt;a_url-&gt;url_user,
-                         (char *) sip-&gt;sip_from-&gt;a_url-&gt;url_host,
-                         (char *) sip-&gt;sip_to-&gt;a_url-&gt;url_user
-                         );        
</del><ins>+                }
+                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 &amp;&amp; port) {
+                                sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), msg-&gt;string_arg, 1);
+                        }
</ins><span class="cx"> 
</span><ins>+                        if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                nua_respond(tech_pvt-&gt;nh, SIP_200_OK,
+                                                        SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
+                                                        SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
+                                                        SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), 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;
</ins><span class="cx"> 
</span><del>-#if 0
-        /* nicer one we cant use in both directions &gt;=0 */
-        snprintf(hash_key, len, &quot;%s%s%s%s%s%s&quot;,
-                         (char *) sip-&gt;sip_to-&gt;a_url-&gt;url_user,
-                         (char *) sip-&gt;sip_to-&gt;a_url-&gt;url_host,
-                         (char *) sip-&gt;sip_to-&gt;a_url-&gt;url_params,
-                         
-                         (char *) sip-&gt;sip_from-&gt;a_url-&gt;url_user,
-                         (char *) sip-&gt;sip_from-&gt;a_url-&gt;url_host,
-                         (char *) sip-&gt;sip_from-&gt;a_url-&gt;url_params
-                         );        
-#endif
</del><ins>+                        switch_channel_set_flag(channel, CF_PROXY_MODE);
+                        sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE);
</ins><span class="cx"> 
</span><del>-}
</del><ins>+                        if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+                                &amp;&amp; (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 &amp;&amp; port) {
+                                        sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1);
+                                }
+                        }
</ins><span class="cx"> 
</span><del>-static void set_chat_hash(private_object_t *tech_pvt, sip_t const *sip)
-{
-        char hash_key[256] = &quot;&quot;;
-        char buf[512];
</del><span class="cx"> 
</span><del>-        if (tech_pvt-&gt;hash_key || !sip || !sip-&gt;sip_from ||
-                !sip-&gt;sip_from-&gt;a_url ||
-                !sip-&gt;sip_from-&gt;a_url-&gt;url_user ||
-                !sip-&gt;sip_from-&gt;a_url-&gt;url_host) {
-                return;
-        }
-
-        if (find_reg_url(tech_pvt-&gt;profile, sip-&gt;sip_from-&gt;a_url-&gt;url_user, sip-&gt;sip_from-&gt;a_url-&gt;url_host, buf, sizeof(buf))) {
-                tech_pvt-&gt;chat_from = sip_header_as_string(tech_pvt-&gt;home, (const sip_header_t *)sip-&gt;sip_to);
-                tech_pvt-&gt;chat_to = switch_core_session_strdup(tech_pvt-&gt;session, buf);
-                set_hash_key(hash_key, sizeof(hash_key), sip);
-        } else {
-                return;
-        }
-
-        tech_pvt-&gt;hash_key = switch_core_session_strdup(tech_pvt-&gt;session, hash_key);
-        switch_core_hash_insert(tech_pvt-&gt;profile-&gt;chat_hash, tech_pvt-&gt;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-&gt;sip_from;
-                char *from_user = NULL;
-                char *from_host = NULL;
-                sip_to_t const *to = sip-&gt;sip_to;
-                char *to_user = NULL;
-                char *to_host = NULL;
-                sip_subject_t const *sip_subject = sip-&gt;sip_subject;
-                sip_payload_t *payload = sip-&gt;sip_payload;
-                const char *subject = &quot;n/a&quot;;
-                char *msg = NULL;
-
-                if (sip-&gt;sip_content_type) {
-                        if (strstr((char*)sip-&gt;sip_content_type-&gt;c_subtype, &quot;composing&quot;)) {
-                                return;
</del><ins>+                        if (!tech_pvt-&gt;local_sdp_str) {
+                                sofia_glue_tech_absorb_sdp(tech_pvt);
</ins><span class="cx">                         }
</span><ins>+                        sofia_glue_do_invite(session);
</ins><span class="cx">                 }
</span><ins>+                break;
</ins><span class="cx"> 
</span><del>-                if (from) {
-                        from_user = (char *) from-&gt;a_url-&gt;url_user;
-                        from_host = (char *) from-&gt;a_url-&gt;url_host;
-                }
</del><ins>+        case SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT:
+                {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s Sending media re-direct:\n%s\n&quot;, 
+                                                          switch_channel_get_name(channel), msg-&gt;string_arg);
+                        sofia_glue_tech_set_local_sdp(tech_pvt, msg-&gt;string_arg, SWITCH_TRUE);
</ins><span class="cx"> 
</span><del>-                if (to) {
-                        to_user = (char *) to-&gt;a_url-&gt;url_user;
-                        to_host = (char *) to-&gt;a_url-&gt;url_host;
</del><ins>+                        sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
+                        sofia_glue_do_invite(session);
</ins><span class="cx">                 }
</span><ins>+                break;
</ins><span class="cx"> 
</span><del>-        
-                if (!to_user) {
-                        return;
-                }
</del><span class="cx"> 
</span><del>-                if (payload) {
-                        msg = payload-&gt;pl_data;
-                }
</del><ins>+        case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:
+                {
+                        switch_t38_options_t *t38_options = (switch_t38_options_t *) msg-&gt;pointer_arg;
</ins><span class="cx"> 
</span><del>-                if (sip_subject) {
-                        subject = sip_subject-&gt;g_value;
-                }
</del><ins>+                        sofia_glue_set_image_sdp(tech_pvt, t38_options);
</ins><span class="cx"> 
</span><del>-                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;
</del><ins>+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s Sending request for image media. %s\n&quot;, 
+                                                          switch_channel_get_name(channel), tech_pvt-&gt;local_sdp_str);
+                                                          
</ins><span class="cx">                         
</span><del>-                        full_from = sip_header_as_string(profile-&gt;home, (void *)sip-&gt;sip_from);
</del><ins>+                        sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
+                        sofia_glue_do_invite(session);
+                }
+                break;
</ins><span class="cx"> 
</span><del>-                        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(&quot;%s@%s&quot;, to_user, to_host);
-                        }
</del><ins>+        case SWITCH_MESSAGE_INDICATE_MEDIA:
+                {
+                        uint32_t send_invite = 1;
</ins><span class="cx"> 
</span><del>-                        from_addr = switch_mprintf(&quot;%s@%s&quot;, from_user, from_host);
</del><ins>+                        switch_channel_clear_flag(channel, CF_PROXY_MODE);
+                        sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE);
</ins><span class="cx"> 
</span><ins>+                        if (!switch_channel_media_ready(channel)) {
+                                if (!switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND)) {
+                                        const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
</ins><span class="cx"> 
</span><del>-                        set_hash_key(hash_key, sizeof(hash_key), sip);
-                        if ((tech_pvt = (private_object_t *) switch_core_hash_find(profile-&gt;chat_hash, hash_key))) {
-                                channel = switch_core_session_get_channel(tech_pvt-&gt;session);
-                                if (switch_event_create(&amp;event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
-                                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
-                                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;url);
-                                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s&quot;, tech_pvt-&gt;hash_key);
-                                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;to&quot;, &quot;%s&quot;, to_addr);
-                                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;subject&quot;, &quot;SIMPLE MESSAGE&quot;);
-                                        if (msg) {
-                                                switch_event_add_body(event, &quot;%s&quot;, msg);
</del><ins>+                                        tech_pvt-&gt;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, &quot;CODEC NEGOTIATION ERROR&quot;);
+                                                status = SWITCH_STATUS_FALSE;
+                                                goto end_lock;
</ins><span class="cx">                                         }
</span><del>-                                        if (switch_core_session_queue_event(tech_pvt-&gt;session, &amp;event) != SWITCH_STATUS_SUCCESS) {
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;delivery-failure&quot;, &quot;true&quot;);
-                                                switch_event_fire(&amp;event);
-                                        }
</del><ins>+                                        send_invite = 0;
</ins><span class="cx">                                 }
</span><del>-                        } else {
-                                switch_chat_interface_t *ci;
-                                
-                                if ((ci = switch_loadable_module_get_chat_interface(proto))) {
-                                        ci-&gt;chat_send(SOFIA_CHAT_PROTO, from_addr, to_addr, &quot;&quot;, msg, full_from);
-                                } else {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Chat Interface [%s]!\n&quot;, proto ? proto : &quot;(none)&quot;);
</del><ins>+                        }
+
+                        if (!switch_rtp_ready(tech_pvt-&gt;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;
</ins><span class="cx">                                 }
</span><del>-                                
</del><span class="cx">                         }
</span><del>-                        switch_safe_free(to_addr);
-                        switch_safe_free(from_addr);
-                        if (full_from) {
-                                su_free(profile-&gt;home, full_from);
</del><ins>+                        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);
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><ins>+                break;
</ins><span class="cx"> 
</span><del>-        }
-}
</del><ins>+        case SWITCH_MESSAGE_INDICATE_DISPLAY:
+                {
+                        if (!switch_strlen_zero(msg-&gt;string_arg)) {
+                                char message[256] = &quot;&quot;;
+                                const char *ua = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_user_agent&quot;);
</ins><span class="cx"> 
</span><del>-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-&gt;session);
-        assert(channel != NULL);
-        
-        if ((val = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_VARIABLE)) &amp;&amp; (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);
</del><ins>+                                if (ua &amp;&amp; switch_stristr(&quot;snom&quot;, ua)) {
+                                        snprintf(message, sizeof(message), &quot;From:\r\nTo: \&quot;%s\&quot; %s\r\n&quot;, msg-&gt;string_arg, tech_pvt-&gt;caller_profile-&gt;destination_number);
+                                        nua_info(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;), SIPTAG_PAYLOAD_STR(message), TAG_END());
+                                } else if (ua &amp;&amp; switch_stristr(&quot;polycom&quot;, ua)) {
+                                        snprintf(message, sizeof(message), &quot;P-Asserted-Identity: \&quot;%s\&quot; &lt;%s&gt;&quot;, msg-&gt;string_arg, tech_pvt-&gt;caller_profile-&gt;destination_number);
+                                        nua_update(tech_pvt-&gt;nh,
+                                                           TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)),
+                                                           TAG_END());
+                                }
+                        }
</ins><span class="cx">                 }
</span><ins>+                break;
</ins><span class="cx"> 
</span><del>-                if (!switch_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) &amp;&amp; (
-                        switch_channel_test_flag(other_channel, CF_OUTBOUND) &amp;&amp; 
-                        //switch_channel_test_flag(other_channel, CF_NOMEDIA) &amp;&amp; 
-                        switch_channel_test_flag(channel, CF_OUTBOUND) &amp;&amp; 
-                        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);
-        }
-}
</del><ins>+        case SWITCH_MESSAGE_INDICATE_HOLD:
+                {
+                        sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                        sofia_glue_do_invite(session);
+                        if (!switch_strlen_zero(msg-&gt;string_arg)) {
+                                char message[256] = &quot;&quot;;
+                                const char *ua = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_user_agent&quot;);
</ins><span class="cx"> 
</span><del>-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] = &quot;&quot;;
-
-
-    if (sofia_private) {
-        if (!switch_strlen_zero(sofia_private-&gt;uuid)) {
-            if (!(session = switch_core_session_locate(sofia_private-&gt;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-&gt;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, &quot;Channel %s entering state [%s]\n&quot;, 
-                                                  switch_channel_get_name(channel),
-                                                  nua_callstate_name(ss_state));
-
-                if (r_sdp) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Remote SDP:\n%s\n&quot;, r_sdp);                        
-                        tech_pvt-&gt;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);
-
</del><ins>+                                if (ua &amp;&amp; switch_stristr(&quot;snom&quot;, ua)) {
+                                        snprintf(message, sizeof(message), &quot;From:\r\nTo: \&quot;%s\&quot; %s\r\n&quot;, msg-&gt;string_arg, tech_pvt-&gt;caller_profile-&gt;destination_number);
+                                        nua_info(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;), SIPTAG_PAYLOAD_STR(message), TAG_END());
+                                } else if (ua &amp;&amp; switch_stristr(&quot;polycom&quot;, ua)) {
+                                        snprintf(message, sizeof(message), &quot;P-Asserted-Identity: \&quot;%s\&quot; &lt;%s&gt;&quot;, msg-&gt;string_arg, tech_pvt-&gt;caller_profile-&gt;destination_number);
+                                        nua_update(tech_pvt-&gt;nh,
+                                                           TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)),
+                                                           TAG_END());
+                                }
+                        }
</ins><span class="cx">                 }
</span><del>-        }
</del><ins>+                break;
</ins><span class="cx"> 
</span><del>-        if (status == 988) {
-                goto done;
-        }
-
-        switch ((enum nua_callstate)ss_state) {
-        case nua_callstate_init:
</del><ins>+        case SWITCH_MESSAGE_INDICATE_UNHOLD:
+                {
+                        sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                        sofia_glue_do_invite(session);
+                }
</ins><span class="cx">                 break;
</span><del>-        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)) &amp;&amp; (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, &amp;msg);
-                                                        switch_core_session_rwunlock(other_session);
-                                                }
-                                                
-                                        } else {
-                                                switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
-                                        }
-                                }
</del><ins>+        case SWITCH_MESSAGE_INDICATE_REDIRECT:
+                if (!switch_strlen_zero(msg-&gt;string_arg)) {
+                        if (!switch_channel_test_flag(channel, CF_ANSWERED) &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Redirecting to %s\n&quot;, msg-&gt;string_arg);
+                                nua_respond(tech_pvt-&gt;nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg-&gt;string_arg), TAG_END());
+                                sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+                        } else {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Too late for redirecting to %s, already answered\n&quot;, msg-&gt;string_arg);
</ins><span class="cx">                         }
</span><ins>+                }
+                break;
+        case SWITCH_MESSAGE_INDICATE_DEFLECT:
+                {
+                        char ref_to[128] = &quot;&quot;;
+                        const char *var;
</ins><span class="cx"> 
</span><del>-                        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) &amp;&amp; 
-                                                (uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) &amp;&amp; (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, &quot;DELAYED NEGOTIATION&quot;);
-                                        } else {
-                                                if (tech_media(tech_pvt, (char *)r_sdp) != SWITCH_STATUS_SUCCESS) {
-                                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;CODEC NEGOTIATION ERROR&quot;);
-                                                        nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
-                                                }
-                                        }
-                                        goto done;
-                }
</del><ins>+                        if (!strstr(msg-&gt;string_arg, &quot;sip:&quot;)) {
+                                const char *format = strchr(tech_pvt-&gt;profile-&gt;sipip, ':') ? &quot;sip:%s@[%s]&quot; : &quot;sip:%s@%s&quot;;
+                                switch_snprintf(ref_to, sizeof(ref_to), format, msg-&gt;string_arg, tech_pvt-&gt;profile-&gt;sipip);
+                        } else {
+                                switch_set_string(ref_to, msg-&gt;string_arg);
</ins><span class="cx">                         }
</span><ins>+                        nua_refer(tech_pvt-&gt;nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt-&gt;contact_url), TAG_END());
+                        switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
+                        sofia_wait_for_reply(tech_pvt, 9999, 300);
+                        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+                        if ((var = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_refer_reply&quot;))) {
+                                msg-&gt;string_reply = switch_core_session_strdup(session, var); 
+                        } else {
+                                msg-&gt;string_reply = &quot;no reply&quot;;
+                        }
</ins><span class="cx">                 }
</span><span class="cx">                 break;
</span><del>-        case nua_callstate_completing:
-                nua_ack(nh, TAG_END());
-                break;
-        case nua_callstate_received: 
-                if (session &amp;&amp; switch_core_session_running(session)) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Re-Entering Call State Received!\n&quot;);
-            goto done;
-                }
</del><span class="cx"> 
</span><del>-                if (channel) {
-                        if (r_sdp) {
-                                if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;RECEIVED_NOMEDIA&quot;);
-                                        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-&gt;home, r_sdp, (int)strlen(r_sdp), 0);
-                                        sdp_session_t *sdp;
-                                        uint8_t match = 0;
-                                
-                                        if (tech_pvt-&gt;num_codecs) {
-                                                if ((sdp = sdp_session(parser))) {
-                                                        match = negotiate_sdp(session, sdp);
</del><ins>+        case SWITCH_MESSAGE_INDICATE_RESPOND:
+                if (msg-&gt;numeric_arg || msg-&gt;string_arg) {
+                        int code = msg-&gt;numeric_arg;
+                        const char *reason = NULL;
+                        
+                        if (code) {
+                                reason = msg-&gt;string_arg;
+                        } else {
+                                if (!switch_strlen_zero(msg-&gt;string_arg)) {
+                                        if ((code = atoi(msg-&gt;string_arg))) {
+                                                if ((reason = strchr(msg-&gt;string_arg, ' '))) {
+                                                        reason++;
</ins><span class="cx">                                                 }
</span><span class="cx">                                         }
</span><ins>+                                }
+                        }
</ins><span class="cx"> 
</span><del>-                                        if (parser) {
-                                                sdp_parser_free(parser);
-                                        }
</del><ins>+                        if (!code) {
+                                code = 488;
+                        }
</ins><span class="cx"> 
</span><del>-                                        if (match) {
-                                                nua_handle_t *bnh;
-                                                sip_replaces_t *replaces;
-                                                switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;RECEIVED&quot;);
-                                                switch_channel_set_state(channel, CS_INIT);
-                                                switch_set_flag_locked(tech_pvt, TFLAG_READY);
</del><ins>+                        if (!switch_channel_test_flag(channel, CF_ANSWERED) &amp;&amp; code &gt;= 300) {
+                                if (sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                        goto end_lock;
+                                }
+                        }
+                        
+                        if (switch_strlen_zero(reason) &amp;&amp; code != 407 &amp;&amp; code != 302) {
+                                reason = sip_status_phrase(code);
+                                if (switch_strlen_zero(reason)) {
+                                        reason = &quot;Because&quot;;
+                                }
+                        }
</ins><span class="cx"> 
</span><del>-                                                switch_core_session_thread_launch(session);
-                                                
-                                                if (replaces_str &amp;&amp; (replaces = sip_replaces_make(tech_pvt-&gt;home, replaces_str)) &amp;&amp; (bnh = nua_handle_by_replaces(nua, replaces))) {
-                                                        sofia_private_t *b_private;
</del><ins>+                        if (code == 407 &amp;&amp; !msg-&gt;numeric_arg) {
+                                const char *to_uri = switch_channel_get_variable(channel, &quot;sip_to_uri&quot;);
+                                const char *to_host = reason;
</ins><span class="cx"> 
</span><del>-                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Processing Replaces Attended Transfer\n&quot;);
-                                                        while (switch_channel_get_state(channel) &lt; CS_EXECUTE) {
-                                                                switch_yield(10000);
-                                                        }
</del><ins>+                                if (switch_strlen_zero(to_host)) {
+                                        to_host = switch_channel_get_variable(channel, &quot;sip_to_host&quot;);
+                                }
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Challenging call %s\n&quot;, to_uri);
+                                sofia_reg_auth_challenge(NULL, tech_pvt-&gt;profile, tech_pvt-&gt;nh, REG_INVITE, to_host, 0);
+                                switch_channel_hangup(channel, SWITCH_CAUSE_USER_CHALLENGE);
+                        } else if (code == 484 &amp;&amp; msg-&gt;numeric_arg) {
+                                const char *to = switch_channel_get_variable(channel, &quot;sip_to_uri&quot;);
+                                const char *max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE);
</ins><span class="cx"> 
</span><del>-                                                        if ((b_private = nua_handle_magic(bnh))) {
-                                                                char *br_b = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE);
-                                                                char *br_a = b_private-&gt;uuid;
</del><ins>+                                char *to_uri = NULL;
</ins><span class="cx"> 
</span><del>-                                                                if (br_b) {
-                                                                        switch_ivr_uuid_bridge(br_a, br_b);
-                                                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER&quot;);
-                                                                        switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
-                                                                } else {
-                                                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER_ERROR&quot;);
-                                                                        switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-                                                                }
-                                                        } else {
-                                                                switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER_ERROR&quot;);
-                                                                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-                                                        }
-                                                        nua_handle_unref(bnh);
-                                                }
-                        goto done;
</del><ins>+                                if (to) {
+                                        char *p;
+                                        to_uri = switch_core_session_sprintf(session, &quot;sip:%s&quot;, to);
+                                        if ((p = strstr(to_uri, &quot;:5060&quot;))) {
+                                                *p = '\0';
</ins><span class="cx">                                         }
</span><ins>+                                }
</ins><span class="cx"> 
</span><del>-                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;NO CODECS&quot;);
-                                        nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
-                                                                TAG_END());
</del><ins>+                                if (!switch_channel_test_flag(channel, CF_ANSWERED) &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Overlap Dial with %d %s\n&quot;, code, reason);
+                                        nua_respond(tech_pvt-&gt;nh, code, su_strdup(nua_handle_home(tech_pvt-&gt;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);
</ins><span class="cx">                                 }
</span><del>-                        }
-                }
</del><ins>+                        } else if (code == 302 &amp;&amp; !switch_strlen_zero(msg-&gt;string_arg)) {
+                                char *p;
</ins><span class="cx"> 
</span><del>-                break;                
-        case nua_callstate_early:
-                break;
-        case nua_callstate_completed:
-                if (tech_pvt &amp;&amp; r_sdp) {
-                        if (r_sdp) {
-                                if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-                    goto done;
-                                } else {
-                                        sdp_parser_t *parser = sdp_parse(tech_pvt-&gt;home, r_sdp, (int)strlen(r_sdp), 0);
-                                        sdp_session_t *sdp;
-                                        uint8_t match = 0;
-
-                                        if (tech_pvt-&gt;num_codecs) {
-                                                if ((sdp = sdp_session(parser))) {
-                                                        match = negotiate_sdp(session, sdp);
</del><ins>+                                if ((p = strchr(msg-&gt;string_arg, ' '))) {
+                                        *p = '\0';
+                                        msg-&gt;string_arg = p;
+                                }
+                                
+                                msg-&gt;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, &quot;Responding with %d [%s]\n&quot;, code, reason);
+                                        if (!switch_strlen_zero(((char *) msg-&gt;pointer_arg))) {
+                                                sofia_glue_tech_set_local_sdp(tech_pvt, (char *) msg-&gt;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);
</ins><span class="cx">                                                 }
</span><ins>+                                                nua_respond(tech_pvt-&gt;nh, code, su_strdup(nua_handle_home(tech_pvt-&gt;nh), reason), SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
+                                                                        SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
+                                                                        SOATAG_REUSE_REJECTED(1),
+                                                                        SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
+                                        } else {
+                                                nua_respond(tech_pvt-&gt;nh, code, su_strdup(nua_handle_home(tech_pvt-&gt;nh), reason), SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact), TAG_END());
</ins><span class="cx">                                         }
</span><del>-                                        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, &quot;Processing Reinvite\n&quot;);
-                                                if (parser) {
-                                                        sdp_parser_free(parser);
-                                                }
-                                        }
</del><span class="cx">                                 }
</span><span class="cx">                         }
</span><ins>+
</ins><span class="cx">                 }
</span><span class="cx">                 break;
</span><del>-        case nua_callstate_ready:
-                if (tech_pvt &amp;&amp; nh == tech_pvt-&gt;nh2) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Cheater Reinvite!\n&quot;);
-                        switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
-                        tech_pvt-&gt;nh = tech_pvt-&gt;nh2;
-                        tech_pvt-&gt;nh2 = NULL;
-                        if (tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
-                activate_rtp(tech_pvt);
-            }
-                        goto done;
</del><ins>+        case SWITCH_MESSAGE_INDICATE_RINGING:
+                if (!switch_channel_test_flag(channel, CF_RING_READY) &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_BYE) &amp;&amp;
+                        !switch_channel_test_flag(channel, CF_EARLY_MEDIA) &amp;&amp; !switch_channel_test_flag(channel, CF_ANSWERED)) {
+                        nua_respond(tech_pvt-&gt;nh, SIP_180_RINGING,
+                                                SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
+                                                SIPTAG_HEADER_STR(generate_pai_str(session)), TAG_END());
+                        switch_channel_mark_ring_ready(channel);
</ins><span class="cx">                 }
</span><ins>+                break;
+        case SWITCH_MESSAGE_INDICATE_ANSWER:
+                status = sofia_answer_channel(session);
+                break;
+        case SWITCH_MESSAGE_INDICATE_PROGRESS:
+                {
+                        char *sticky = NULL;
+                        const char *val = NULL;
</ins><span class="cx"> 
</span><del>-                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)) &amp;&amp; (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;
-                        }
</del><ins>+                        if (!sofia_test_flag(tech_pvt, TFLAG_ANS) &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
</ins><span class="cx"> 
</span><del>-                        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)) &amp;&amp; (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);
</del><ins>+                                sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+                                switch_log_printf(SWITCH_CHANNEL_ID_LOG, msg-&gt;_file, msg-&gt;_func, msg-&gt;_line, NULL, SWITCH_LOG_INFO, &quot;Sending early media\n&quot;);
+
+                                /* 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;
</ins><span class="cx">                                                 }
</span><del>-                                                switch_channel_answer(other_channel);
-                                                switch_core_session_rwunlock(other_session);
</del><span class="cx">                                         }
</span><del>-                                        goto done;
</del><span class="cx">                                 } else {
</span><del>-                                        sdp_parser_t *parser = sdp_parse(tech_pvt-&gt;home, r_sdp, (int)strlen(r_sdp), 0);
-                                        sdp_session_t *sdp;
-                                        uint8_t match = 0;
</del><ins>+                                        if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || !tech_pvt-&gt;iananame) {
+                                                sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
+                                                if (!switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND)) {
+                                                        const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
</ins><span class="cx"> 
</span><del>-                                        if (tech_pvt-&gt;num_codecs) {
-                                                if ((sdp = sdp_session(parser))) {
-                                                        match = negotiate_sdp(session, sdp);
</del><ins>+                                                        tech_pvt-&gt;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, &quot;CODEC NEGOTIATION ERROR&quot;);
+                                                                //nua_respond(tech_pvt-&gt;nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+                                                                status = SWITCH_STATUS_FALSE;
+                                                                goto end_lock;
+                                                        }
</ins><span class="cx">                                                 }
</span><span class="cx">                                         }
</span><span class="cx"> 
</span><del>-                                        if (parser) {
-                                                sdp_parser_free(parser);
</del><ins>+                                        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;
</ins><span class="cx">                                         }
</span><ins>+                                        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-&gt;local_sdp_str) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Ring SDP:\n%s\n&quot;, tech_pvt-&gt;local_sdp_str);
+                                        }
+                                }
+                                switch_channel_mark_pre_answered(channel);
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-                                        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, &quot;NO CODECS&quot;);
-                                        nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
</del><ins>+                                if (sofia_test_flag(tech_pvt, TFLAG_NAT) ||
+                                        (val = switch_channel_get_variable(channel, &quot;sip-force-contact&quot;)) ||
+                                        ((val = switch_channel_get_variable(channel, &quot;sip_sticky_contact&quot;)) &amp;&amp; switch_true(val))) {
+                                        sticky = tech_pvt-&gt;record_route;
+                                        switch_channel_set_variable(channel, &quot;sip_nat_detected&quot;, &quot;true&quot;);
</ins><span class="cx">                                 }
</span><del>-                        }
-                        
-                }
-                
-                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), &quot;%d&quot;, status);
-                                        switch_channel_set_variable(channel, &quot;sip_term_status&quot;, st);
-                                        terminate_session(&amp;session, sip_cause_to_freeswitch(status), __LINE__);
</del><ins>+
+                                if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                                        nua_respond(tech_pvt-&gt;nh,
+                                                                SIP_183_SESSION_PROGRESS,
+                                                                NUTAG_AUTOANSWER(0),
+                                                                TAG_IF(sticky, NUTAG_PROXY(tech_pvt-&gt;record_route)),
+                                                                SIPTAG_HEADER_STR(generate_pai_str(session)),
+                                                                SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
+                                                                SOATAG_REUSE_REJECTED(1),
+                                                                SOATAG_ORDERED_USER(1),
+                                                                SOATAG_ADDRESS(tech_pvt-&gt;adv_sdp_audio_ip),
+                                                                SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), TAG_END());
</ins><span class="cx">                                 }
</span><span class="cx">                         }
</span><del>-
-            if (tech_pvt-&gt;sofia_private) {
-                free(tech_pvt-&gt;sofia_private);
-                tech_pvt-&gt;sofia_private = NULL;
-            }
-                        tech_pvt-&gt;nh = NULL;
-                } else if (sofia_private) {
-            free(sofia_private);
-        }
-
-                if (nh) {
-            nua_handle_bind(nh, NULL);
-                        nua_handle_destroy(nh);
</del><span class="cx">                 }
</span><span class="cx">                 break;
</span><ins>+        default:
+                break;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>- done:
</del><ins>+ end_lock:
</ins><span class="cx"> 
</span><del>-    if (session) {
-        switch_core_session_rwunlock(session);
-    }
-}
</del><ins>+        switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
</ins><span class="cx"> 
</span><ins>+  end:
</ins><span class="cx"> 
</span><del>-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);
</del><ins>+        if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                status = SWITCH_STATUS_FALSE;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!dbname) {
-                goto end;
-        }
</del><ins>+        return status;
</ins><span class="cx"> 
</span><del>-        if (!(db = switch_core_db_open_file(dbname))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, dbname);
-                goto end;
-        }
</del><ins>+}
</ins><span class="cx"> 
</span><del>-        sql = switch_mprintf(&quot;select passwd from sip_authentication where nonce='%q'&quot;, nonce);
-        if (switch_core_db_prepare(db, sql, -1, &amp;stmt, 0)) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Statement Error!\n&quot;);
-                goto fail;
-        } else {
-                int running = 1;
-                int colcount;
</del><ins>+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;
</ins><span class="cx"> 
</span><del>-                while (running &lt; 5000) {
-                        int result = switch_core_db_step(stmt);
</del><ins>+        switch_assert(tech_pvt != NULL);
</ins><span class="cx"> 
</span><del>-                        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);
</del><ins>+        if (!(body = switch_event_get_body(event))) {
+                body = &quot;&quot;;
</ins><span class="cx">         }
</span><del>-        
</del><span class="cx"> 
</span><del>- fail:
-
-        switch_core_db_close(db);
-
- end:
-        if (mutex) {
-                switch_mutex_unlock(mutex);
</del><ins>+        if (tech_pvt-&gt;hash_key) {
+                switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+                msg_nh = nua_handle(tech_pvt-&gt;profile-&gt;nua, NULL,
+                                                        SIPTAG_FROM_STR(tech_pvt-&gt;chat_from),
+                                                        NUTAG_URL(tech_pvt-&gt;chat_to), SIPTAG_TO_STR(tech_pvt-&gt;chat_to), SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url), TAG_END());
+                nua_handle_bind(msg_nh, &amp;mod_sofia_globals.destroy_private);
+                nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR(&quot;text/html&quot;), SIPTAG_PAYLOAD_STR(body), TAG_END());
+                switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (sql) {
-                switch_safe_free(sql);
-        }
-        
-        return ret;
</del><ins>+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+typedef switch_status_t (*sofia_command_t) (char **argv, int argc, switch_stream_handle_t *stream);
</ins><span class="cx"> 
</span><del>-typedef enum {
-        REG_REGISTER,
-        REG_INVITE
-} sofia_regtype_t;
</del><ins>+static const char *sofia_state_names[] = { 
+        &quot;UNREGED&quot;,
+        &quot;TRYING&quot;,
+        &quot;REGISTER&quot;,
+        &quot;REGED&quot;,
+        &quot;UNREGISTER&quot;,
+        &quot;FAILED&quot;,
+        &quot;FAIL_WAIT&quot;,
+        &quot;EXPIRED&quot;,
+        &quot;NOREG&quot;,
+        NULL
+};
</ins><span class="cx"> 
</span><del>-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)
</del><ins>+const char * sofia_state_string(int state) 
</ins><span class="cx"> {
</span><del>-        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] = &quot;&quot;;
-        char *sql;
-        switch_event_t *s_event;
-        const char *from_user = NULL;
-        const char *from_host = NULL;
-        char contact_str[1024] = &quot;&quot;;
-        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 = &quot;unknown&quot;;
-        const char *display = &quot;\&quot;user\&quot;&quot;;
</del><ins>+        return sofia_state_names[state];
+}
</ins><span class="cx"> 
</span><del>-        /* all callers must confirm that sip, sip-&gt;sip_request and sip-&gt;sip_contact are not NULL */
-        assert(sip != NULL &amp;&amp; sip-&gt;sip_contact != NULL &amp;&amp; sip-&gt;sip_request != NULL);
</del><ins>+struct cb_helper {
+        sofia_profile_t *profile;
+        switch_stream_handle_t *stream;
+};
</ins><span class="cx"> 
</span><del>-        expires = sip-&gt;sip_expires;
-        authorization = sip-&gt;sip_authorization;
-        contact = sip-&gt;sip_contact;
-        from = sip-&gt;sip_from;
</del><span class="cx"> 
</span><del>-        if (from) {
-                from_user = from-&gt;a_url-&gt;url_user;
-                from_host = from-&gt;a_url-&gt;url_host;
-        }
</del><span class="cx"> 
</span><del>-        if (!from_user || !from_host) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can not do authorization without a complete from header\n&quot;);
-                nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
-                return 1;
-        }
</del><ins>+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] = &quot;&quot;;
+        switch_time_exp_t tm;
</ins><span class="cx"> 
</span><del>-        if (contact-&gt;m_url) {
-                const char *port = contact-&gt;m_url-&gt;url_port;
-                display = contact-&gt;m_display;
</del><ins>+        if (argv[6]) {
+                switch_time_t etime = atoi(argv[6]);
+                switch_size_t retsize;
</ins><span class="cx"> 
</span><del>-                if (switch_strlen_zero(display)) {
-                        if (from) {
-                                display = from-&gt;a_display;
-                                if (switch_strlen_zero(display)) {
-                                        display = &quot;\&quot;user\&quot;&quot;;
-                                }
-                        }
-                }
-                
-                if (!port) {
-                        port = &quot;5060&quot;;
-                }
-
-                if (contact-&gt;m_url-&gt;url_params) {
-                        snprintf(contact_str, sizeof(contact_str), &quot;%s &lt;sip:%s@%s:%s;%s&gt;&quot;, 
-                                         display, contact-&gt;m_url-&gt;url_user, contact-&gt;m_url-&gt;url_host, port, contact-&gt;m_url-&gt;url_params);
-                } else {
-                        snprintf(contact_str, sizeof(contact_str), &quot;%s &lt;sip:%s@%s:%s&gt;&quot;, 
-                                         display, contact-&gt;m_url-&gt;url_user, contact-&gt;m_url-&gt;url_host, port);
-                }
</del><ins>+                switch_time_exp_lt(&amp;tm, switch_time_from_sec(etime));
+                switch_strftime_nocheck(exp_buf, &amp;retsize, sizeof(exp_buf), &quot;%Y-%m-%d %T&quot;, &amp;tm);
</ins><span class="cx">         }
</span><del>-        
-        if (expires) {
-                exptime = expires-&gt;ex_delta;
-        } else if (contact-&gt;m_expires) {
-                exptime = atol(contact-&gt;m_expires);
-        } 
</del><span class="cx"> 
</span><del>-        if (regtype == REG_REGISTER) {
-                authorization = sip-&gt;sip_authorization;
-        } else if (regtype == REG_INVITE) {
-                authorization = sip-&gt;sip_proxy_authorization;
-        }
</del><ins>+        cb-&gt;stream-&gt;write_function(cb-&gt;stream,
+                                                           &quot;Call-ID:    \t%s\n&quot;
+                                                           &quot;User:       \t%s@%s\n&quot;
+                                                           &quot;Contact:    \t%s\n&quot;
+                                                           &quot;Agent:      \t%s\n&quot;
+                                                           &quot;Status:     \t%s(%s) EXP(%s)\n&quot;
+                                                           &quot;Host:       \t%s\n&quot;
+                                                           &quot;IP:         \t%s\n&quot;
+                                                           &quot;Port:       \t%s\n&quot;
+                                                           &quot;Auth-User:  \t%s\n&quot;
+                                                           &quot;Auth-Realm: \t%s\n\n&quot;,
+                                                           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;
+}
</ins><span class="cx"> 
</span><del>-        if ((profile-&gt;pflags &amp; PFLAG_BLIND_REG)) {
-                goto reg;
</del><ins>+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] = &quot;&quot;;
+        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(&amp;tm, switch_time_from_sec(etime));
+                switch_strftime_nocheck(exp_buf, &amp;retsize, sizeof(exp_buf), &quot;%Y-%m-%d %T&quot;, &amp;tm);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (authorization) {
-                if ((auth_res = parse_auth(profile, authorization, sip-&gt;sip_request-&gt;rq_method_name, key, keylen)) == AUTH_STALE) {
-            stale = 1;
-        }
</del><ins>+        cb-&gt;stream-&gt;write_function(cb-&gt;stream,
+                                                           &quot;    &lt;registration&gt;\n&quot;
+                                                           &quot;        &lt;call-id&gt;%s&lt;/call-id&gt;\n&quot;
+                                                           &quot;        &lt;user&gt;%s@%s&lt;/user&gt;\n&quot;
+                                                           &quot;        &lt;contact&gt;%s&lt;/contact&gt;\n&quot;
+                                                           &quot;        &lt;agent&gt;%s&lt;/agent&gt;\n&quot;
+                                                           &quot;        &lt;status&gt;%s(%s) exp(%s)&lt;/status&gt;\n&quot;
+                                                           &quot;        &lt;host&gt;%s&lt;/host&gt;\n&quot;
+                                                           &quot;        &lt;network-ip&gt;%s&lt;/network-ip&gt;\n&quot;
+                                                           &quot;        &lt;network-port&gt;%s&lt;/network-port&gt;\n&quot;
+                                                           &quot;        &lt;sip-auth-user&gt;%s&lt;/sip-auth-user&gt;\n&quot;
+                                                           &quot;        &lt;sip-auth-realm&gt;%s&lt;/sip-auth-realm&gt;\n&quot;
+                                                           &quot;    &lt;/registration&gt;\n&quot;, 
+                                                           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;
+}
</ins><span class="cx"> 
</span><del>-                if (auth_res != AUTH_OK &amp;&amp; !stale) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;send %s for [%s@%s]\n&quot;,
-                                                          forbidden ? &quot;forbidden&quot; : &quot;challange&quot;,
-                                                          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;
-                }
-        } 
</del><ins>+static const char *status_names[] = { &quot;DOWN&quot;, &quot;UP&quot;, NULL };
</ins><span class="cx"> 
</span><del>-        if (!authorization || stale) {
-                snprintf(params, sizeof(params), &quot;from_user=%s&amp;from_host=%s&amp;contact=%s&quot;,
-                                 from_user,
-                                 from_host,
-                                 contact_str
-                                 );
</del><ins>+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 = &quot;=================================================================================================&quot;;
</ins><span class="cx"> 
</span><del>-                
-                if (switch_xml_locate(&quot;directory&quot;, &quot;domain&quot;, &quot;name&quot;, from_host, &amp;xml, &amp;domain, params) != SWITCH_STATUS_SUCCESS) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;can't find domain for [%s@%s]\n&quot;, from_user, from_host);
-                        nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
-                        return 1;
</del><ins>+        if (argc &gt; 0) {
+                if (argc == 1) {
+                        stream-&gt;write_function(stream, &quot;Invalid Syntax!\n&quot;);
+                        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx">                 }
</span><ins>+                if (!strcasecmp(argv[0], &quot;gateway&quot;)) {
+                        if ((gp = sofia_reg_find_gateway(argv[1]))) {
+                                switch_assert(gp-&gt;state &lt; REG_STATE_LAST);
</ins><span class="cx"> 
</span><del>-                if (!(user = switch_xml_find_child(domain, &quot;user&quot;, &quot;id&quot;, from_user))) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;can't find user [%s@%s]\n&quot;, 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, &quot;params&quot;))) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;can't find params for user [%s@%s]\n&quot;, 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, &quot;param&quot;); param; param = param-&gt;next) {
-                        const char *var = switch_xml_attr_soft(param, &quot;name&quot;);
-                        const char *val = switch_xml_attr_soft(param, &quot;value&quot;);
-                
-                        if (!strcasecmp(var, &quot;password&quot;)) {
-                                passwd = val;
</del><ins>+                                stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+                                stream-&gt;write_function(stream, &quot;Name    \t%s\n&quot;, switch_str_nil(gp-&gt;name));
+                                stream-&gt;write_function(stream, &quot;Scheme  \t%s\n&quot;, switch_str_nil(gp-&gt;register_scheme));
+                                stream-&gt;write_function(stream, &quot;Realm   \t%s\n&quot;, switch_str_nil(gp-&gt;register_realm));
+                                stream-&gt;write_function(stream, &quot;Username\t%s\n&quot;, switch_str_nil(gp-&gt;register_username));
+                                stream-&gt;write_function(stream, &quot;Password\t%s\n&quot;, switch_strlen_zero(gp-&gt;register_password) ? &quot;no&quot; : &quot;yes&quot;);
+                                stream-&gt;write_function(stream, &quot;From    \t%s\n&quot;, switch_str_nil(gp-&gt;register_from));
+                                stream-&gt;write_function(stream, &quot;Contact \t%s\n&quot;, switch_str_nil(gp-&gt;register_contact));
+                                stream-&gt;write_function(stream, &quot;Exten   \t%s\n&quot;, switch_str_nil(gp-&gt;extension));
+                                stream-&gt;write_function(stream, &quot;To      \t%s\n&quot;, switch_str_nil(gp-&gt;register_to));
+                                stream-&gt;write_function(stream, &quot;Proxy   \t%s\n&quot;, switch_str_nil(gp-&gt;register_proxy));
+                                stream-&gt;write_function(stream, &quot;Context \t%s\n&quot;, switch_str_nil(gp-&gt;register_context));
+                                stream-&gt;write_function(stream, &quot;Expires \t%s\n&quot;, switch_str_nil(gp-&gt;expires_str));
+                                stream-&gt;write_function(stream, &quot;Freq    \t%d\n&quot;, gp-&gt;freq);
+                                stream-&gt;write_function(stream, &quot;Ping    \t%d\n&quot;, gp-&gt;ping);
+                                stream-&gt;write_function(stream, &quot;PingFreq\t%d\n&quot;, gp-&gt;ping_freq);
+                                stream-&gt;write_function(stream, &quot;State   \t%s\n&quot;, sofia_state_names[gp-&gt;state]);
+                                stream-&gt;write_function(stream, &quot;Status  \t%s%s\n&quot;, status_names[gp-&gt;status], gp-&gt;pinging ? &quot; (ping)&quot; : &quot;&quot;);
+                                stream-&gt;write_function(stream, &quot;CallsIN \t%d\n&quot;, gp-&gt;ib_calls);
+                                stream-&gt;write_function(stream, &quot;CallsOUT\t%d\n&quot;, gp-&gt;ob_calls);
+                                stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+                                sofia_reg_release_gateway(gp);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;Invalid Gateway!\n&quot;);
</ins><span class="cx">                         }
</span><ins>+                } else if (!strcasecmp(argv[0], &quot;profile&quot;)) {
+                        struct cb_helper cb;
+                        char *sql = NULL;
</ins><span class="cx"> 
</span><del>-                        if (!strcasecmp(var, &quot;a1-hash&quot;)) {
-                a1_hash = val;
-                        }
-                }
-        
-                if (passwd || a1_hash) {
-                        switch_uuid_t uuid;
-                        char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
-                        char *sql, *auth_str;
</del><ins>+                        if ((argv[1]) &amp;&amp; (profile = sofia_glue_find_profile(argv[1]))) {
+                                if (!argv[2] || strcasecmp(argv[2], &quot;reg&quot;)) {
+                                        stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+                                        stream-&gt;write_function(stream, &quot;Name             \t%s\n&quot;, switch_str_nil(argv[1]));
+                                        stream-&gt;write_function(stream, &quot;Domain Name      \t%s\n&quot;, profile-&gt;domain_name ? profile-&gt;domain_name : &quot;N/A&quot;);
+                                        if (strcasecmp(argv[1], profile-&gt;name)) {
+                                        stream-&gt;write_function(stream, &quot;Alias Of         \t%s\n&quot;, switch_str_nil(profile-&gt;name));
+                                        }
+                                        stream-&gt;write_function(stream, &quot;DBName           \t%s\n&quot;, switch_str_nil(profile-&gt;dbname));
+                                        stream-&gt;write_function(stream, &quot;Pres Hosts       \t%s\n&quot;, switch_str_nil(profile-&gt;presence_hosts));
+                                        stream-&gt;write_function(stream, &quot;Dialplan         \t%s\n&quot;, switch_str_nil(profile-&gt;dialplan));
+                                        stream-&gt;write_function(stream, &quot;Context          \t%s\n&quot;, switch_str_nil(profile-&gt;context));
+                                        stream-&gt;write_function(stream, &quot;Challenge Realm  \t%s\n&quot;, 
+                                                                                   switch_strlen_zero(profile-&gt;challenge_realm) ? &quot;auto_to&quot; : profile-&gt;challenge_realm);
+                                        stream-&gt;write_function(stream, &quot;RTP-IP           \t%s\n&quot;, switch_str_nil(profile-&gt;rtpip));
+                                        if (profile-&gt;extrtpip) {
+                                        stream-&gt;write_function(stream, &quot;Ext-RTP-IP       \t%s\n&quot;, profile-&gt;extrtpip);
+                                        }
</ins><span class="cx"> 
</span><del>-                        su_md5_t ctx;
-                        char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1];
-                        char *input;
</del><ins>+                                        stream-&gt;write_function(stream, &quot;SIP-IP           \t%s\n&quot;, switch_str_nil(profile-&gt;sipip));
+                                        if (profile-&gt;extsipip) {
+                                        stream-&gt;write_function(stream, &quot;Ext-SIP-IP       \t%s\n&quot;, profile-&gt;extsipip);
+                                        }
+                                        stream-&gt;write_function(stream, &quot;URL              \t%s\n&quot;, switch_str_nil(profile-&gt;url));
+                                        stream-&gt;write_function(stream, &quot;BIND-URL         \t%s\n&quot;, switch_str_nil(profile-&gt;bindurl));
+                                        if (sofia_test_pflag(profile, PFLAG_TLS)) {
+                                        stream-&gt;write_function(stream, &quot;TLS-URL          \t%s\n&quot;, switch_str_nil(profile-&gt;tls_url));
+                                        stream-&gt;write_function(stream, &quot;TLS-BIND-URL     \t%s\n&quot;, switch_str_nil(profile-&gt;tls_bindurl));
+                                        }
+                                        stream-&gt;write_function(stream, &quot;HOLD-MUSIC       \t%s\n&quot;, switch_strlen_zero(profile-&gt;hold_music) ? &quot;N/A&quot; : profile-&gt;hold_music);
+                                        stream-&gt;write_function(stream, &quot;OUTBOUND-PROXY   \t%s\n&quot;, switch_strlen_zero(profile-&gt;outbound_proxy) ? &quot;N/A&quot; : profile-&gt;outbound_proxy);
+                                        stream-&gt;write_function(stream, &quot;CODECS           \t%s\n&quot;, switch_str_nil(profile-&gt;codec_string));
+                                        stream-&gt;write_function(stream, &quot;TEL-EVENT        \t%d\n&quot;, profile-&gt;te);
+                                        if (profile-&gt;dtmf_type == DTMF_2833) {
+                                        stream-&gt;write_function(stream, &quot;DTMF-MODE        \trfc2833\n&quot;);
+                                        } else if (profile-&gt;dtmf_type == DTMF_INFO) {
+                                        stream-&gt;write_function(stream, &quot;DTMF-MODE        \tinfo\n&quot;);
+                                        } else {
+                                        stream-&gt;write_function(stream, &quot;DTMF-MODE        \tnone\n&quot;);
+                                        }
+                                        stream-&gt;write_function(stream, &quot;CNG              \t%d\n&quot;, profile-&gt;cng_pt);
+                                        stream-&gt;write_function(stream, &quot;SESSION-TO       \t%d\n&quot;, profile-&gt;session_timeout);
+                                        stream-&gt;write_function(stream, &quot;MAX-DIALOG       \t%d\n&quot;, profile-&gt;max_proceeding);
+                                        stream-&gt;write_function(stream, &quot;NOMEDIA          \t%s\n&quot;, sofia_test_flag(profile, TFLAG_INB_NOMEDIA) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;LATE-NEG         \t%s\n&quot;, sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;PROXY-MEDIA      \t%s\n&quot;, sofia_test_flag(profile, TFLAG_PROXY_MEDIA) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;AGGRESSIVENAT    \t%s\n&quot;, sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;STUN-ENABLED     \t%s\n&quot;, sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;STUN-AUTO-DISABLE\t%s\n&quot;, sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;CALLS-IN         \t%d\n&quot;, profile-&gt;ib_calls);
+                                        stream-&gt;write_function(stream, &quot;FAILED-CALLS-IN  \t%d\n&quot;, profile-&gt;ib_failed_calls);
+                                        stream-&gt;write_function(stream, &quot;CALLS-OUT        \t%d\n&quot;, profile-&gt;ob_calls);
+                                        stream-&gt;write_function(stream, &quot;FAILED-CALLS-OUT \t%d\n&quot;, profile-&gt;ob_failed_calls);
+                                }
+                                stream-&gt;write_function(stream, &quot;\nRegistrations:\n%s\n&quot;, line);
</ins><span class="cx"> 
</span><del>-            if (!a1_hash) {
-                input = switch_mprintf(&quot;%s:%s:%s&quot;, from_user, from_host, passwd);
-                su_md5_init(&amp;ctx);
-                su_md5_strupdate(&amp;ctx, input);
-                su_md5_hexdigest(&amp;ctx, hexdigest);
-                su_md5_deinit(&amp;ctx);
-                switch_safe_free(input);
</del><ins>+                                cb.profile = profile;
+                                cb.stream = stream;
+                                
+                                if (argv[3]) {
+                                        if (argv[4]) {
+                                                if (!strcasecmp(argv[3], &quot;pres&quot;)) {
+                                                        sql = switch_mprintf(&quot;select call_id,sip_user,sip_host,contact,status,&quot;
+                                                                                                 &quot;rpid,expires,user_agent,server_user,server_host,profile_name,hostname,&quot;
+                                                                                                 &quot;network_ip,network_port,sip_username,sip_realm&quot;
+                                                                                                 &quot; from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'&quot;, 
+                                                                                                 profile-&gt;name, argv[4]);
+                                                }
+                                        } else {
+                                                sql = switch_mprintf(&quot;select call_id,sip_user,sip_host,contact,status,&quot;
+                                                                                         &quot;rpid,expires,user_agent,server_user,server_host,profile_name,hostname,&quot;
+                                                                                         &quot;network_ip,network_port,sip_username,sip_realm&quot;
+                                                                                         &quot; from sip_registrations where profile_name='%q' and contact like '%%%q%%'&quot;, 
+                                                                                         profile-&gt;name, argv[3]);
+                                        }
+                                }
</ins><span class="cx"> 
</span><del>-                switch_uuid_get(&amp;uuid);
-                switch_uuid_format(uuid_str, &amp;uuid);
-                a1_hash = hexdigest;
-            }
</del><ins>+                                if (!sql) {
+                                        sql = switch_mprintf(&quot;select call_id,sip_user,sip_host,contact,status,&quot;
+                                                                                 &quot;rpid,expires,user_agent,server_user,server_host,profile_name,hostname,&quot;
+                                                                                 &quot;network_ip,network_port,sip_username,sip_realm&quot;
+                                                                                 &quot; from sip_registrations where profile_name='%q'&quot;, 
+                                                                                 profile-&gt;name);
+                                }
</ins><span class="cx"> 
</span><del>-                        sql = switch_mprintf(&quot;delete from sip_authentication where user='%q' and host='%q';\n&quot;
-                                 &quot;insert into sip_authentication values('%q','%q','%q','%q', %ld)&quot;,
-                                 from_user,
-                                 from_host,
-                                 from_user,
-                                 from_host,
-                                 a1_hash,
-                                 uuid_str,
-                                 time(NULL) + profile-&gt;nonce_ttl);
-                        auth_str = switch_mprintf(&quot;Digest realm=\&quot;%q\&quot;, nonce=\&quot;%q\&quot;,%s algorithm=MD5, qop=\&quot;auth\&quot;&quot;, from_host, uuid_str, 
-                                                                                          stale ? &quot; stale=\&quot;true\&quot;,&quot; : &quot;&quot;);
</del><ins>+                                sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, show_reg_callback, &amp;cb);
+                                free(sql);
</ins><span class="cx"> 
</span><ins>+                                stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
</ins><span class="cx"> 
</span><del>-                        if (regtype == REG_REGISTER) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Requesting Registration from: [%s@%s]\n&quot;, 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());
-
</del><ins>+                                sofia_glue_release_profile(profile);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;Invalid Profile!\n&quot;);
</ins><span class="cx">                         }
</span><del>-
-                        execute_sql(profile-&gt;dbname, sql, profile-&gt;ireg_mutex);
-                        switch_safe_free(sql);
-                        switch_safe_free(auth_str);
-                        ret = 1;
</del><span class="cx">                 } else {
</span><del>-                        ret = 0;
</del><ins>+                        stream-&gt;write_function(stream, &quot;Invalid Syntax!\n&quot;);
</ins><span class="cx">                 }
</span><del>-                
-                switch_xml_free(xml);
</del><span class="cx"> 
</span><del>-                if (ret) {
-                        return ret;
-                }
</del><ins>+                return SWITCH_STATUS_SUCCESS;
</ins><span class="cx">         }
</span><del>- reg:
</del><span class="cx"> 
</span><del>-        if (exptime) {
-                if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
-                        sql = switch_mprintf(&quot;insert into sip_registrations values ('%q','%q','%q','Registered', '%q', %ld)&quot;, 
-                                                                 from_user,
-                                                                 from_host,
-                                                                 contact_str,
-                                                                 rpid,
-                                                                 (long) time(NULL) + (long)exptime * 2);
</del><ins>+        stream-&gt;write_function(stream, &quot;%25s\t%s\t  %32s\t%s\n&quot;, &quot;Name&quot;, &quot;   Type&quot;, &quot;Data&quot;, &quot;State&quot;);
+        stream-&gt;write_function(stream, &quot;%s\n&quot;, 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, &amp;vvar, NULL, &amp;val);
+                profile = (sofia_profile_t *) val;
+                if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
</ins><span class="cx"> 
</span><del>-                } else {
-                        sql = switch_mprintf(&quot;update sip_registrations set contact='%q', expires=%ld, rpid='%q' where user='%q' and host='%q'&quot;,
-                                                                 contact_str,
-                                                                 (long) time(NULL) + (long)exptime * 2,
-                                                                 rpid,
-                                                                 from_user,
-                                                                 from_host);
-                
-                }
</del><ins>+                        if (strcmp(vvar, profile-&gt;name)) {
+                                ac++;
+                                stream-&gt;write_function(stream, &quot;%25s\t%s\t  %32s\t%s\n&quot;, vvar, &quot;  alias&quot;, profile-&gt;name, &quot;ALIASED&quot;);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;%25s\t%s\t  %32s\t%s (%u)\n&quot;, profile-&gt;name, &quot;profile&quot;, profile-&gt;url,
+                                                                           sofia_test_pflag(profile, PFLAG_RUNNING) ? &quot;RUNNING&quot; : &quot;DOWN&quot;, profile-&gt;inuse);
</ins><span class="cx"> 
</span><del>-                if (switch_event_create_subclass(&amp;s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) {
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile-name&quot;, &quot;%s&quot;, profile-&gt;name);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;from-user&quot;, &quot;%s&quot;, from_user);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;from-host&quot;, &quot;%s&quot;, from_host);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;contact&quot;, &quot;%s&quot;, contact_str);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;%s&quot;, rpid);
-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;expires&quot;, &quot;%ld&quot;, (long)exptime);
-                        switch_event_fire(&amp;s_event);
-                }
</del><ins>+                                if (sofia_test_pflag(profile, PFLAG_TLS)) {
+                                        stream-&gt;write_function(stream, &quot;%25s\t%s\t  %32s\t%s (%u) (TLS)\n&quot;, profile-&gt;name, &quot;profile&quot;, profile-&gt;tls_url,
+                                                                                   sofia_test_pflag(profile, PFLAG_RUNNING) ? &quot;RUNNING&quot; : &quot;DOWN&quot;, profile-&gt;inuse);
+                                }
</ins><span class="cx"> 
</span><del>-                if (sql) {
-                        execute_sql(profile-&gt;dbname, sql, profile-&gt;ireg_mutex);
-                        switch_safe_free(sql);
-                        sql = NULL;
-                }
-        
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Register:\nFrom:    [%s@%s]\nContact: [%s]\nExpires: [%ld]\n&quot;, 
-                                                  from_user, 
-                                                  from_host,
-                                          contact_str,
-                                          (long)exptime
-                                          );
</del><ins>+                                c++;
</ins><span class="cx"> 
</span><del>-
-                if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, &quot;sip&quot;);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;url);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;%s&quot;, rpid);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, from_user, from_host);
-                        
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;Registered&quot;);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
-                        switch_event_fire(&amp;event);
</del><ins>+                                for (gp = profile-&gt;gateways; gp; gp = gp-&gt;next) {
+                                        switch_assert(gp-&gt;state &lt; REG_STATE_LAST);
+                                        stream-&gt;write_function(stream, &quot;%25s\t%s\t  %32s\t%s&quot;, gp-&gt;name, &quot;gateway&quot;, gp-&gt;register_to, sofia_state_names[gp-&gt;state]);
+                                        if (gp-&gt;state == REG_STATE_FAILED || gp-&gt;state == REG_STATE_TRYING) {
+                                                time_t now = switch_epoch_time_now(NULL);
+                                                if (gp-&gt;retry &gt; now) {
+                                                        stream-&gt;write_function(stream, &quot; (retry: %ds)&quot;, gp-&gt;retry - now);
+                                                } else {
+                                                        stream-&gt;write_function(stream, &quot; (retry: NEVER)&quot;);
+                                                }
+                                        }
+                                        stream-&gt;write_function(stream, &quot;\n&quot;);
+                                }
+                        }
</ins><span class="cx">                 }
</span><del>-        } else {
-                if ((sql = switch_mprintf(&quot;delete from sip_subscriptions where user='%q' and host='%q'&quot;, from_user, from_host))) {
-                        execute_sql(profile-&gt;dbname, sql, profile-&gt;ireg_mutex);
-                        switch_safe_free(sql);
-                        sql = NULL;
-                }
-                if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, &quot;sip&quot;);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;url);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s+%s@%s&quot;, SOFIA_CHAT_PROTO, from_user, from_host);
-                
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;unavailable&quot;);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;%s&quot;, rpid);
-                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
-                        switch_event_fire(&amp;event);
-                }
</del><span class="cx">         }
</span><del>-
-
-        if (switch_event_create(&amp;event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) {
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, &quot;sip&quot;);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, from_user, from_host);
-                switch_event_fire(&amp;event);
-        }
-
-        if (regtype == REG_REGISTER) {
-                nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(contact),
-                                        NUTAG_WITH_THIS(nua),
-                                        TAG_END());
-                return 1;
-        }
-
-        return 0;
</del><ins>+        switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+        stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+        stream-&gt;write_function(stream, &quot;%d profile%s %d alias%s\n&quot;, c, c == 1 ? &quot;&quot; : &quot;s&quot;, ac, ac == 1 ? &quot;&quot; : &quot;es&quot;);
+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-static int sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
</del><ins>+static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handle_t *stream)
</ins><span class="cx"> {
</span><del>-        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 = &quot;Available&quot;;
-        }
-        if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;url);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, user, host);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;%s&quot;, status);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_subtype&quot;, &quot;probe&quot;);
-                switch_event_fire(&amp;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(&amp;event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, &quot;%s&quot;, proto ? proto : SOFIA_CHAT_PROTO);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;url);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, user, host);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;%s&quot;, status);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;%s&quot;, rpid);
-                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
-                switch_event_fire(&amp;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 = &quot;unknown&quot;;
-        }
-
-        if (in) {
-                note = switch_mprintf(&quot;&lt;dm:note&gt;%s&lt;/dm:note&gt;&quot;, status);
-                open = &quot;open&quot;;
-        } else {
-                note = NULL;
-                open = &quot;closed&quot;;
-        }
-
-    if (!strcasecmp(sub_to_host, host)) {
-        /* same host */
-                id = switch_mprintf(&quot;sip:%s+%s@%s&quot;, proto, sub_to_user, sub_to_host);
-        } else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) {
-                /*encapsulate*/
-                id = switch_mprintf(&quot;sip:%s+%s+%s@%s&quot;, proto, sub_to_user, sub_to_host, host);
-        } else {
-                id = switch_mprintf(&quot;sip:%s@%s&quot;, sub_to_user, sub_to_host);
-        }
-
-        to = switch_mprintf(&quot;sip:%s@%s&quot;, user, host);
-        pl = switch_mprintf(&quot;&lt;?xml version='1.0' encoding='UTF-8'?&gt;\r\n&quot;
-                                                                &quot;&lt;presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n&quot;
-                                                                &quot;xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n&quot;
-                                                                &quot;xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n&quot;
-                                                                &quot;xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n&quot;
-                                                                &quot;entity='pres:%s'&gt;\r\n&quot;
-                                                                &quot;&lt;tuple id='t6a5ed77e'&gt;\r\n&quot;
-                                                                &quot;&lt;status&gt;\r\n&quot;
-                                                                &quot;&lt;basic&gt;%s&lt;/basic&gt;\r\n&quot;
-                                                                &quot;&lt;/status&gt;\r\n&quot;
-                                                                &quot;&lt;/tuple&gt;\r\n&quot;
-                                                                &quot;&lt;dm:person id='p06360c4a'&gt;\r\n&quot;
-                                                                &quot;&lt;rpid:activities&gt;\r\n&quot;
-                                                                &quot;&lt;rpid:%s/&gt;\r\n&quot;
-                                                                &quot;&lt;/rpid:activities&gt;%s&lt;/dm:person&gt;\r\n&quot;
-                                                                &quot;&lt;/presence&gt;&quot;, id, open, rpid, note);
-
</del><ins>+        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 = &quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;ISO-8859-1\&quot;?&gt;&quot;;
</ins><span class="cx">         
</span><ins>+  if (argc &gt; 0) {
+                if (argc == 1) {
+                        stream-&gt;write_function(stream, &quot;Invalid Syntax!\n&quot;);
+                        return SWITCH_STATUS_SUCCESS;
+                }
+                if (!strcasecmp(argv[0], &quot;gateway&quot;)) {
+                        if ((gp = sofia_reg_find_gateway(argv[1]))) {
+                                switch_assert(gp-&gt;state &lt; REG_STATE_LAST);
+                                stream-&gt;write_function(stream, &quot;%s\n&quot;, header);
+                                stream-&gt;write_function(stream, &quot;  &lt;gateway&gt;\n&quot;);
+                                stream-&gt;write_function(stream, &quot;    &lt;name&gt;%s&lt;/name&gt;\n&quot;, switch_str_nil(gp-&gt;name));
+                                stream-&gt;write_function(stream, &quot;    &lt;scheme&gt;%s&lt;/scheme&gt;\n&quot;, switch_str_nil(gp-&gt;register_scheme));
+                                stream-&gt;write_function(stream, &quot;    &lt;realm&gt;%s&lt;/realm&gt;\n&quot;, switch_str_nil(gp-&gt;register_realm));
+                                stream-&gt;write_function(stream, &quot;    &lt;username&gt;%s&lt;/username&gt;\n&quot;, switch_str_nil(gp-&gt;register_username));
+                                stream-&gt;write_function(stream, &quot;    &lt;password&gt;%s&lt;/password&gt;\n&quot;, switch_strlen_zero(gp-&gt;register_password) ? &quot;no&quot; : &quot;yes&quot;);
+                                stream-&gt;write_function(stream, &quot;    &lt;from&gt;%s&lt;/from&gt;\n&quot;, switch_amp_encode(switch_str_nil(gp-&gt;register_from),xmlbuf,buflen));
+                                stream-&gt;write_function(stream, &quot;    &lt;contact&gt;%s&lt;/contact&gt;\n&quot;, switch_amp_encode(switch_str_nil(gp-&gt;register_contact),xmlbuf,buflen));
+                                stream-&gt;write_function(stream, &quot;    &lt;exten&gt;%s&lt;/exten&gt;\n&quot;, switch_amp_encode(switch_str_nil(gp-&gt;extension),xmlbuf,buflen));
+                                stream-&gt;write_function(stream, &quot;    &lt;to&gt;%s&lt;/to&gt;\n&quot;, switch_str_nil(gp-&gt;register_to));
+                                stream-&gt;write_function(stream, &quot;    &lt;proxy&gt;%s&lt;/proxy&gt;\n&quot;, switch_str_nil(gp-&gt;register_proxy));
+                                stream-&gt;write_function(stream, &quot;    &lt;context&gt;%s&lt;/context&gt;\n&quot;, switch_str_nil(gp-&gt;register_context));
+                                stream-&gt;write_function(stream, &quot;    &lt;expires&gt;%s&lt;/expires&gt;\n&quot;, switch_str_nil(gp-&gt;expires_str));
+                                stream-&gt;write_function(stream, &quot;    &lt;freq&gt;%d&lt;/freq&gt;\n&quot;, gp-&gt;freq);
+                                stream-&gt;write_function(stream, &quot;    &lt;ping&gt;%d&lt;/ping&gt;\n&quot;, gp-&gt;ping);
+                                stream-&gt;write_function(stream, &quot;    &lt;pingfreq&gt;%d&lt;/pingfreq&gt;\n&quot;, gp-&gt;ping_freq);
+                                stream-&gt;write_function(stream, &quot;    &lt;state&gt;%s&lt;/state&gt;\n&quot;, sofia_state_names[gp-&gt;state]);
+                                stream-&gt;write_function(stream, &quot;    &lt;status&gt;%s%s&lt;/status&gt;\n&quot;, status_names[gp-&gt;status], gp-&gt;pinging ? &quot; (ping)&quot; : &quot;&quot;);
+                                stream-&gt;write_function(stream, &quot;    &lt;calls-in&gt;%d&lt;/calls-in&gt;\n&quot;, gp-&gt;ib_calls);
+                                stream-&gt;write_function(stream, &quot;    &lt;calls-out&gt;%d&lt;/calls-out&gt;\n&quot;, gp-&gt;ob_calls);
</ins><span class="cx"> 
</span><del>-        nh = nua_handle(profile-&gt;nua, NULL,        TAG_END());
-        tmp = contact;
-        contact = get_url_from_contact(tmp, 0);
</del><ins>+                                stream-&gt;write_function(stream, &quot;  &lt;/gateway&gt;\n&quot;);
+                                sofia_reg_release_gateway(gp);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;Invalid Gateway!\n&quot;);
+                        }
+                } else if (!strcasecmp(argv[0], &quot;profile&quot;)) {
+                        struct cb_helper cb;
+                        char *sql = NULL;
</ins><span class="cx"> 
</span><del>-        nua_notify(nh,
-                           NUTAG_URL(contact),
-                           SIPTAG_TO_STR(full_from),
-                           SIPTAG_FROM_STR(id),
-                           SIPTAG_CONTACT_STR(profile-&gt;url),
-                           SIPTAG_CALL_ID_STR(callid),
-                           SIPTAG_VIA_STR(full_via),
-                           SIPTAG_SUBSCRIPTION_STATE_STR(&quot;active;expires=3600&quot;),
-                           SIPTAG_EVENT_STR(event),
-                           SIPTAG_CONTENT_TYPE_STR(&quot;application/pidf+xml&quot;),
-                           SIPTAG_PAYLOAD_STR(pl),
-                           TAG_END());
</del><ins>+                        if ((argv[1]) &amp;&amp; (profile = sofia_glue_find_profile(argv[1]))) {
+                                stream-&gt;write_function(stream, &quot;%s\n&quot;, header);
+                                stream-&gt;write_function(stream, &quot;&lt;profile&gt;\n&quot;);
+                                if (!argv[2] || strcasecmp(argv[2], &quot;reg&quot;)) {
+                                        stream-&gt;write_function(stream, &quot;  &lt;profile-info&gt;\n&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;name&gt;%s&lt;/name&gt;\n&quot;, switch_str_nil(argv[1]));
+                                        stream-&gt;write_function(stream, &quot;    &lt;domain-name&gt;%s&lt;/domain-name&gt;\n&quot;, profile-&gt;domain_name ? profile-&gt;domain_name : &quot;N/A&quot;);
+                                        if (strcasecmp(argv[1], profile-&gt;name)) {
+                                                stream-&gt;write_function(stream, &quot;    &lt;alias-of&gt;%s&lt;/alias-of&gt;\n&quot;, switch_str_nil(profile-&gt;name));
+                                        }
+                                        stream-&gt;write_function(stream, &quot;    &lt;db-name&gt;%s&lt;/db-name&gt;\n&quot;, switch_str_nil(profile-&gt;dbname));
+                                        stream-&gt;write_function(stream, &quot;    &lt;pres-hosts&gt;%s&lt;/pres-hosts&gt;\n&quot;, switch_str_nil(profile-&gt;presence_hosts));
+                                        stream-&gt;write_function(stream, &quot;    &lt;dialplan&gt;%s&lt;/dialplan&gt;\n&quot;, switch_str_nil(profile-&gt;dialplan));
+                                        stream-&gt;write_function(stream, &quot;    &lt;context&gt;%s&lt;/context&gt;\n&quot;, switch_str_nil(profile-&gt;context));
+                                        stream-&gt;write_function(stream, &quot;    &lt;challenge-realm&gt;%s&lt;/challenge-realm&gt;\n&quot;, 
+                                                                                   switch_strlen_zero(profile-&gt;challenge_realm) ? &quot;auto_to&quot; : profile-&gt;challenge_realm);
+                                        stream-&gt;write_function(stream, &quot;    &lt;rtp-ip&gt;%s&lt;/rtp-ip&gt;\n&quot;, switch_str_nil(profile-&gt;rtpip));
+                                        stream-&gt;write_function(stream, &quot;    &lt;ext-rtp-ip&gt;%s&lt;/ext-rtp-ip&gt;\n&quot;, profile-&gt;extrtpip);
+                                        stream-&gt;write_function(stream, &quot;    &lt;sip-ip&gt;%s&lt;/sip-ip&gt;\n&quot;, switch_str_nil(profile-&gt;sipip));
+                                        stream-&gt;write_function(stream, &quot;    &lt;ext-sip-ip&gt;%s&lt;/ext-sip-ip&gt;\n&quot;, profile-&gt;extsipip);
+                                        stream-&gt;write_function(stream, &quot;    &lt;url&gt;%s&lt;/url&gt;\n&quot;, switch_str_nil(profile-&gt;url));
+                                        stream-&gt;write_function(stream, &quot;    &lt;bind-url&gt;%s&lt;/bind-url&gt;\n&quot;, switch_str_nil(profile-&gt;bindurl));
+                                        stream-&gt;write_function(stream, &quot;    &lt;tls-url&gt;%s&lt;/tls-url&gt;\n&quot;, switch_str_nil(profile-&gt;tls_url));
+                                        stream-&gt;write_function(stream, &quot;    &lt;tls-bind-url&gt;%s&lt;/tls-bind-url&gt;\n&quot;, switch_str_nil(profile-&gt;tls_bindurl));
+                                        stream-&gt;write_function(stream, &quot;    &lt;hold-music&gt;%s&lt;/hold-music&gt;\n&quot;, switch_strlen_zero(profile-&gt;hold_music) ? &quot;N/A&quot; : profile-&gt;hold_music);
+                                        stream-&gt;write_function(stream, &quot;    &lt;outbound-proxy&gt;%s&lt;/outbound-proxy&gt;\n&quot;, switch_strlen_zero(profile-&gt;outbound_proxy) ? &quot;N/A&quot; : profile-&gt;outbound_proxy);
+                                        stream-&gt;write_function(stream, &quot;    &lt;codecs&gt;%s&lt;/codecs&gt;\n&quot;, switch_str_nil(profile-&gt;codec_string));
+                                        stream-&gt;write_function(stream, &quot;    &lt;tel-event&gt;%d&lt;/tel-event&gt;\n&quot;, profile-&gt;te);
+                                        stream-&gt;write_function(stream, &quot;    &lt;dtmf-mode&gt;rfc2833&lt;/dtmf-mode&gt;\n&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;dtmf-mode&gt;info&lt;/dtmf-mode&gt;\n&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;dtmf-mode&gt;none&lt;/dtmf-mode&gt;\n&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;cng&gt;%d&lt;/cng&gt;\n&quot;, profile-&gt;cng_pt);
+                                        stream-&gt;write_function(stream, &quot;    &lt;session-to&gt;%d&lt;/session-to&gt;\n&quot;, profile-&gt;session_timeout);
+                                        stream-&gt;write_function(stream, &quot;    &lt;max-dialog&gt;%d&lt;/max-dialog&gt;\n&quot;, profile-&gt;max_proceeding);
+                                        stream-&gt;write_function(stream, &quot;    &lt;nomedia&gt;%s&lt;/nomedia&gt;\n&quot;, sofia_test_flag(profile, TFLAG_INB_NOMEDIA) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;late-neg&gt;%s&lt;/late-neg&gt;\n&quot;, sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;proxy-media&gt;%s&lt;/proxy-media&gt;\n&quot;, sofia_test_flag(profile, TFLAG_PROXY_MEDIA) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;aggressive-nat&gt;%s&lt;/aggressive-nat&gt;\n&quot;, 
+                                                                                   sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;stun-enabled&gt;%s&lt;/stun-enabled&gt;\n&quot;, sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;stun-auto-disable&gt;%s&lt;/stun-auto-disable&gt;\n&quot;, 
+                                                                                   sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? &quot;true&quot; : &quot;false&quot;);
+                                        stream-&gt;write_function(stream, &quot;    &lt;calls-in&gt;%d&lt;/calls-in&gt;\n&quot;, profile-&gt;ib_calls);
+                                        stream-&gt;write_function(stream, &quot;    &lt;calls-out&gt;%d&lt;/calls-out&gt;\n&quot;, profile-&gt;ob_calls);
+                                        stream-&gt;write_function(stream, &quot;    &lt;failed-calls-in&gt;%d&lt;/failed-calls-in&gt;\n&quot;, profile-&gt;ib_failed_calls);
+                                        stream-&gt;write_function(stream, &quot;    &lt;failed-calls-out&gt;%d&lt;/failed-calls-out&gt;\n&quot;, profile-&gt;ob_failed_calls);
+                                        stream-&gt;write_function(stream, &quot;  &lt;/profile-info&gt;\n&quot;);
+                                }
+                                stream-&gt;write_function(stream, &quot;  &lt;registrations&gt;\n&quot;);
</ins><span class="cx"> 
</span><del>-        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-&gt;sip_to;
-                        sip_from_t const *from = sip-&gt;sip_from;
-                        sip_contact_t const *contact = sip-&gt;sip_contact;
-                        char *from_user = NULL;
-                        char *from_host = NULL;
-                        char *to_user = NULL;
-                        char *to_host = NULL;
-                        char *sql, *event = NULL;
-                        char *proto = &quot;sip&quot;;
-                        char *d_user = NULL;
-                        char *contact_str = &quot;&quot;;
-                        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 = &quot;\&quot;user\&quot;&quot;;
-                        switch_event_t *sevent;
-
-                        if (contact) {
-                                char *port = (char *) contact-&gt;m_url-&gt;url_port;
-
-                                display = contact-&gt;m_display;
</del><ins>+                                cb.profile = profile;
+                                cb.stream = stream;
</ins><span class="cx">                                 
</span><del>-                                if (switch_strlen_zero(display)) {
-                                        if (from) {
-                                                display = from-&gt;a_display;
-                                                if (switch_strlen_zero(display)) {
-                                                        display = &quot;\&quot;user\&quot;&quot;;
</del><ins>+                                if (argv[3]) {
+                                        if (argv[4]) {
+                                                if (!strcasecmp(argv[3], &quot;pres&quot;)) {
+                                                        sql = switch_mprintf(&quot;select call_id,sip_user,sip_host,contact,status,&quot;
+                                                                                                 &quot;rpid,expires,user_agent,server_user,server_host,profile_name,hostname,&quot;
+                                                                                                 &quot;network_ip,network_port,sip_username,sip_realm&quot;
+                                                                                                 &quot; from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'&quot;, 
+                                                                                                 profile-&gt;name, argv[4]);
</ins><span class="cx">                                                 }
</span><ins>+                                        } else {
+                                                sql = switch_mprintf(&quot;select call_id,sip_user,sip_host,contact,status,&quot;
+                                                                                         &quot;rpid,expires,user_agent,server_user,server_host,profile_name,hostname,&quot;
+                                                                                         &quot;network_ip,network_port,sip_username,sip_realm&quot;
+                                                                                         &quot; from sip_registrations where profile_name='%q' and contact like '%%%q%%'&quot;, 
+                                                                                         profile-&gt;name, argv[3]);
</ins><span class="cx">                                         }
</span><del>-                                } else {
-                                        display = &quot;\&quot;user\&quot;&quot;;
</del><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (!port) {
-                                        port = &quot;5060&quot;;
</del><ins>+                                if (!sql) {
+                                        sql = switch_mprintf(&quot;select call_id,sip_user,sip_host,contact,status,&quot;
+                                                                                 &quot;rpid,expires,user_agent,server_user,server_host,profile_name,hostname,&quot;
+                                                                                 &quot;network_ip,network_port,sip_username,sip_realm&quot;
+                                                                                 &quot; from sip_registrations where profile_name='%q'&quot;, 
+                                                                                 profile-&gt;name);
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (contact-&gt;m_url-&gt;url_params) {
-                                        contact_str = switch_mprintf(&quot;%s &lt;sip:%s@%s:%s;%s&gt;&quot;, 
-                                                                                                 display,
-                                                                                                 contact-&gt;m_url-&gt;url_user,
-                                                                                                 contact-&gt;m_url-&gt;url_host, port, contact-&gt;m_url-&gt;url_params);
-                                } else {
-                                        contact_str = switch_mprintf(&quot;%s &lt;sip:%s@%s:%s&gt;&quot;, 
-                                                                                                 display,
-                                                                                                 contact-&gt;m_url-&gt;url_user,
-                                                                                                 contact-&gt;m_url-&gt;url_host, port);
-                                }
-                        }
-                        
-                        if (to) {
-                                to_str = switch_mprintf(&quot;sip:%s@%s&quot;, to-&gt;a_url-&gt;url_user, to-&gt;a_url-&gt;url_host);//, to-&gt;a_url-&gt;url_port);
-                        }
</del><ins>+                                sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, show_reg_callback_xml, &amp;cb);
+                                free(sql);
</ins><span class="cx"> 
</span><del>-                        if (to) {
-                                to_user = (char *) to-&gt;a_url-&gt;url_user;
-                                to_host = (char *) to-&gt;a_url-&gt;url_host;
</del><ins>+                                stream-&gt;write_function(stream, &quot;  &lt;/registrations&gt;\n&quot;);
+                                stream-&gt;write_function(stream, &quot;&lt;/profile&gt;\n&quot;);
+
+                                sofia_glue_release_profile(profile);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;Invalid Profile!\n&quot;);
</ins><span class="cx">                         }
</span><ins>+                } else {
+                        stream-&gt;write_function(stream, &quot;Invalid Syntax!\n&quot;);
+                }
</ins><span class="cx"> 
</span><ins>+                return SWITCH_STATUS_SUCCESS;
+        }
</ins><span class="cx"> 
</span><del>-                        if (strstr(to_user, &quot;ext+&quot;) || strstr(to_user, &quot;user+&quot;) || strstr(to_user, &quot;conf+&quot;)) {
-                                char proto[80];
-                                char *p;
</del><ins>+  stream-&gt;write_function(stream, &quot;%s\n&quot;, header);
+  stream-&gt;write_function(stream, &quot;&lt;profiles&gt;\n&quot;);
+        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, &amp;vvar, NULL, &amp;val);
+                profile = (sofia_profile_t *) val;
+                if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
</ins><span class="cx"> 
</span><del>-                                switch_copy_string(proto, to_user, sizeof(proto));
-                                if ((p = strchr(proto, '+'))) {
-                                        *p = '\0';
</del><ins>+                        if (strcmp(vvar, profile-&gt;name)) {
+                                ac++;
+                                stream-&gt;write_function(stream, &quot;&lt;alias&gt;\n&lt;name&gt;%s&lt;/name&gt;\n&lt;type&gt;%s&lt;/type&gt;\n&lt;data&gt;%s&lt;/data&gt;\n&lt;state&gt;%s&lt;/state&gt;\n&lt;/alias&gt;\n&quot;, vvar, &quot;alias&quot;, profile-&gt;name, &quot;ALIASED&quot;);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;&lt;profile&gt;\n&lt;name&gt;%s&lt;/name&gt;\n&lt;type&gt;%s&lt;/type&gt;\n&lt;data&gt;%s&lt;/data&gt;\n&lt;state&gt;%s (%u)&lt;/state&gt;\n&lt;/profile&gt;\n&quot;, profile-&gt;name, &quot;profile&quot;, profile-&gt;url,
+                                                                           sofia_test_pflag(profile, PFLAG_RUNNING) ? &quot;RUNNING&quot; : &quot;DOWN&quot;, profile-&gt;inuse);
+
+                                if (sofia_test_pflag(profile, PFLAG_TLS)) {
+                                        stream-&gt;write_function(stream, &quot;&lt;profile&gt;\n&lt;name&gt;%s&lt;/name&gt;\n&lt;type&gt;%s&lt;/type&gt;\n&lt;data&gt;%s&lt;/data&gt;\n&lt;state&gt;%s (%u) (TLS)&lt;/state&gt;\n&lt;/profile&gt;\n&quot;, profile-&gt;name, &quot;profile&quot;, profile-&gt;tls_url,
+                                                                                   sofia_test_pflag(profile, PFLAG_RUNNING) ? &quot;RUNNING&quot; : &quot;DOWN&quot;, profile-&gt;inuse);
</ins><span class="cx">                                 }
</span><del>-                                
-                                if (switch_event_create(&amp;sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-                                        switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
-                                        switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;name);
-                                        switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;,  to_user, to_host);
-                                        switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;unknown&quot;);
-                                        switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;Click To Call&quot;);
-                                        switch_event_fire(&amp;sevent);
-                                }
-                        }
</del><span class="cx"> 
</span><del>-                        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;
</del><ins>+                                c++;
+
+                                for (gp = profile-&gt;gateways; gp; gp = gp-&gt;next) {
+                                        switch_assert(gp-&gt;state &lt; REG_STATE_LAST);
+                                        stream-&gt;write_function(stream, &quot;&lt;gateway&gt;\n&lt;name&gt;%s&lt;/name&gt;\n&lt;type&gt;%s&lt;/type&gt;\n&lt;data&gt;%s&lt;/data&gt;\n&lt;state&gt;%s&lt;/state&gt;\n&lt;/gateway&gt;\n&quot;, gp-&gt;name, &quot;gateway&quot;, gp-&gt;register_to, sofia_state_names[gp-&gt;state]);
+                                        if (gp-&gt;state == REG_STATE_FAILED || gp-&gt;state == REG_STATE_TRYING) {
+                                                time_t now = switch_epoch_time_now(NULL);
+                                                if (gp-&gt;retry &gt; now) {
+                                                        stream-&gt;write_function(stream, &quot; (retry: %ds)&quot;, gp-&gt;retry - now);
+                                                } else {
+                                                        stream-&gt;write_function(stream, &quot; (retry: NEVER)&quot;);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         }
</span><ins>+                                        stream-&gt;write_function(stream, &quot;\n&quot;);
</ins><span class="cx">                                 }
</span><del>-
-                                if (!(proto &amp;&amp; to_user &amp;&amp; to_host)) {
-                                        nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
-                                        goto end;
-                                }
</del><span class="cx">                         }
</span><ins>+                }
+        }
+        switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+        stream-&gt;write_function(stream, &quot;&lt;/profiles&gt;\n&quot;);
+        return SWITCH_STATUS_SUCCESS;
+}
</ins><span class="cx"> 
</span><del>-                        call_id = sip_header_as_string(profile-&gt;home, (void *)sip-&gt;sip_call_id);
-                        event = sip_header_as_string(profile-&gt;home, (void *)sip-&gt;sip_event);
-                        full_from = sip_header_as_string(profile-&gt;home, (void *)sip-&gt;sip_from);
-                        full_via = sip_header_as_string(profile-&gt;home, (void *)sip-&gt;sip_via);
</del><ins>+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;
</ins><span class="cx"> 
</span><del>-                        exp_raw = (sip-&gt;sip_expires ? sip-&gt;sip_expires-&gt;ex_delta : 3600);
-                        exp = (long) time(NULL) + exp_raw;
-                        
-            if (sip &amp;&amp; sip-&gt;sip_from) {
-                from_user = (char *) sip-&gt;sip_from-&gt;a_url-&gt;url_user;
-                from_host = (char *) sip-&gt;sip_from-&gt;a_url-&gt;url_host;
-            } else {
-                from_user = &quot;n/a&quot;;
-                from_host = &quot;n/a&quot;;
-            }
</del><ins>+        if (argc &lt; 2) {
+                stream-&gt;write_function(stream, &quot;Invalid Args!\n&quot;);
+                return SWITCH_STATUS_SUCCESS;
+        }
</ins><span class="cx"> 
</span><del>-                        if ((sql = switch_mprintf(&quot;delete from sip_subscriptions where &quot;
-                                                                                          &quot;proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n&quot;
-                                                                                          &quot;insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)&quot;,
-                                                                                          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-&gt;dbname, sql, profile-&gt;ireg_mutex);
-                                switch_safe_free(sql);
</del><ins>+        if (!strcasecmp(argv[1], &quot;start&quot;)) {
+                if (argc &gt; 2 &amp;&amp; !strcasecmp(argv[2], &quot;reloadxml&quot;)) {
+                        if ((xml_root = switch_xml_open_root(1, &amp;err))) {
+                                switch_xml_free(xml_root);
</ins><span class="cx">                         }
</span><ins>+                        stream-&gt;write_function(stream, &quot;Reload XML [%s]\n&quot;, err);
+                }
+                if (config_sofia(1, argv[0]) == SWITCH_STATUS_SUCCESS) {
+                        stream-&gt;write_function(stream, &quot;%s started successfully\n&quot;, argv[0]);
+                } else {
+                        stream-&gt;write_function(stream, &quot;Failure starting %s\n&quot;, argv[0]);
+                }
+                return SWITCH_STATUS_SUCCESS;
+        }
</ins><span class="cx"> 
</span><del>-                        sstr = switch_mprintf(&quot;active;expires=%ld&quot;, exp_raw);
</del><ins>+        if (argv[1] &amp;&amp; !strcasecmp(argv[0], &quot;restart&quot;) &amp;&amp; !strcasecmp(argv[1], &quot;all&quot;)) {
+                sofia_glue_restart_all_profiles();
+                return SWITCH_STATUS_SUCCESS;
+        }
+        
+        if (switch_strlen_zero(profile_name) || !(profile = sofia_glue_find_profile(profile_name))) {
+                stream-&gt;write_function(stream, &quot;Invalid Profile [%s]&quot;, switch_str_nil(profile_name));
+                return SWITCH_STATUS_SUCCESS;
+        }
</ins><span class="cx"> 
</span><del>-                        nua_respond(nh, SIP_202_ACCEPTED,
-                                                NUTAG_WITH_THIS(nua),
-                                                SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
-                                                SIPTAG_FROM(sip-&gt;sip_to),
-                                                SIPTAG_TO(sip-&gt;sip_from),
-                                                SIPTAG_CONTACT_STR(to_str),
-                                                TAG_END());
</del><ins>+        if (!strcasecmp(argv[1], &quot;killgw&quot;)) {
+                sofia_gateway_t *gateway_ptr;
+                if (argc &lt; 3) {
+                        stream-&gt;write_function(stream, &quot;-ERR missing gw name\n&quot;);
+                        goto done;
+                }
</ins><span class="cx"> 
</span><ins>+                if ((gateway_ptr = sofia_reg_find_gateway(argv[2]))) {                         
+                        sofia_glue_del_gateway(gateway_ptr);
+                        sofia_reg_release_gateway(gateway_ptr);
+                        stream-&gt;write_function(stream, &quot;+OK gateway marked for deletion.\n&quot;);
+                } else {
+                        stream-&gt;write_function(stream, &quot;-ERR no such gateway.\n&quot;);
+                }
</ins><span class="cx"> 
</span><ins>+                goto done;
+        }
</ins><span class="cx"> 
</span><del>-                        switch_safe_free(sstr);
-                        
-                        if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                                goto end;
</del><ins>+        if (!strcasecmp(argv[1], &quot;stun-auto-disable&quot;)) {
+                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);
</ins><span class="cx">                         }
</span><del>-                        if ((sql = switch_mprintf(&quot;select * from sip_subscriptions where user='%q' and host='%q'&quot;, 
-                                                                          to_user, to_host, to_user, to_host))) {
-                                switch_mutex_lock(profile-&gt;ireg_mutex);
-                                switch_core_db_exec(db, sql, sub_reg_callback, profile, &amp;errmsg);
-                                switch_mutex_unlock(profile-&gt;ireg_mutex);
-                                switch_safe_free(sql);
-                        }
-                        switch_core_db_close(db);
-                end:
-                
-                        if (event) {
-                                su_free(profile-&gt;home, event);
-                        }
-                        if (call_id) {
-                                su_free(profile-&gt;home, call_id);
-                        }
-                        if (full_from) {
-                                su_free(profile-&gt;home, full_from);
-                        }
-                        if (full_via) {
-                                su_free(profile-&gt;home, full_via);
-                        }
-
-                        switch_safe_free(d_user);
-                        switch_safe_free(to_str);
-                        switch_safe_free(contact_str);
</del><span class="cx">                 }
</span><del>-}
</del><span class="cx"> 
</span><del>-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-&gt;sip_cseq || !(etmp = switch_mprintf(&quot;refer;id=%u&quot;, sip-&gt;sip_cseq-&gt;cs_seq))) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Memory Error!\n&quot;);
-        goto done;
-    }
-
-
-    if (switch_channel_test_flag(channel_a, CF_NOMEDIA)) {
-        nua_notify(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                   NUTAG_SUBSTATE(nua_substate_terminated),
-                   SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;),
-                   SIPTAG_EVENT_STR(etmp),
-                   TAG_END());
-        goto done;
-    }
</del><ins>+                stream-&gt;write_function(stream, &quot;+OK stun-auto-disable=%s&quot;, sofia_test_pflag(profile, PFLAG_STUN_AUTO_DISABLE) ? &quot;true&quot; : &quot;false&quot;);
</ins><span class="cx">                 
</span><del>-    from = sip-&gt;sip_from;
-    to = sip-&gt;sip_to;
</del><ins>+                goto done;
+        }
</ins><span class="cx"> 
</span><del>-    if ((refer_to = sip-&gt;sip_refer_to)) {
-        if (profile-&gt;pflags &amp; PFLAG_FULL_ID) {
-            exten = switch_mprintf(&quot;%s@%s&quot;, (char *) refer_to-&gt;r_url-&gt;url_user, (char *) refer_to-&gt;r_url-&gt;url_host);
-        } else {
-            exten = (char *) refer_to-&gt;r_url-&gt;url_user;
-        }
-
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Process REFER to [%s@%s]\n&quot;, exten, (char *) refer_to-&gt;r_url-&gt;url_host);
-
-        if (refer_to-&gt;r_url-&gt;url_headers) {
-            sip_replaces_t *replaces;
-            nua_handle_t *bnh;
-            char *rep;
-
-            if ((rep = strchr(refer_to-&gt;r_url-&gt;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, &quot;Replaces: [%s]\n&quot;, rep);
-                } else {
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Memory Error!\n&quot;);
-                    goto done;
-                }
-                if ((replaces = sip_replaces_make(tech_pvt-&gt;home, rep)) &amp;&amp; (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-&gt;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, &quot;Attended Transfer [%s][%s]\n&quot;, br_a, br_b);
-                            
-                        if (br_a &amp;&amp; br_b) {
-                            switch_ivr_uuid_bridge(br_a, br_b);
-                            switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER&quot;);
-                            switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                            switch_set_flag_locked(b_tech_pvt, TFLAG_BYE);
-                            nua_notify(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                       NUTAG_SUBSTATE(nua_substate_terminated),
-                                       SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-                                       SIPTAG_EVENT_STR(etmp),
-                                       TAG_END());
-                                
-                        } else {
-                            if (!br_a &amp;&amp; !br_b) {
-                                switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-                                switch_set_flag_locked(b_tech_pvt, TFLAG_XFER);
-                                b_tech_pvt-&gt;xferto = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session));
-                            } else if (!br_a &amp;&amp; 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-&gt;local_sdp_audio_ip = switch_core_session_strdup(session, b_tech_pvt-&gt;local_sdp_audio_ip);
-                                    tech_pvt-&gt;local_sdp_audio_port = b_tech_pvt-&gt;local_sdp_audio_port;
-
-                                    tech_pvt-&gt;remote_sdp_audio_ip = switch_core_session_strdup(session, br_b_tech_pvt-&gt;remote_sdp_audio_ip);
-                                    tech_pvt-&gt;remote_sdp_audio_port = br_b_tech_pvt-&gt;remote_sdp_audio_port;
-                                    activate_rtp(tech_pvt);
-        
-                                    br_b_tech_pvt-&gt;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-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                       NUTAG_SUBSTATE(nua_substate_terminated),
-                                       SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-                                       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 &amp;&amp; (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(&quot;sofia/%s/%s@%s:%s&quot;, 
-                                                   profile-&gt;name,
-                                                   (char *) refer_to-&gt;r_url-&gt;url_user,
-                                                   (char *) refer_to-&gt;r_url-&gt;url_host,
-                                                   refer_to-&gt;r_url-&gt;url_port
-                                                   );
-
-                            switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
-                                                                
-                            if (switch_ivr_originate(a_session,
-                                                     &amp;tsession,
-                                                     &amp;cause,
-                                                     exten,
-                                                     timeout,
-                                                     &amp;noop_state_handler,
-                                                     NULL,
-                                                     NULL,
-                                                     NULL) != SWITCH_STATUS_SUCCESS) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot Create Outgoing Channel! [%s]\n&quot;, exten);
-                                nua_notify(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                           NUTAG_SUBSTATE(nua_substate_terminated),
-                                           SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;),
-                                           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, &quot;ATTENDED_TRANSFER&quot;);
-                            switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                            nua_notify(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                       NUTAG_SUBSTATE(nua_substate_terminated),
-                                       SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-                                       SIPTAG_EVENT_STR(etmp),
-                                       TAG_END());
-                        } else {
-                            goto error;
-                        }
-
-                    } else { error:
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Transfer! [%s]\n&quot;, br_a);
-                        switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER_ERROR&quot;);
-                        nua_notify(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                   NUTAG_SUBSTATE(nua_substate_terminated),
-                                   SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;),
-                                   SIPTAG_EVENT_STR(etmp),
-                                   TAG_END());
-                    }
-                }
-            } else {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot parse Replaces!\n&quot;);
-            }
-            goto done;
-        }
-
-    } else {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing Refer-To\n&quot;);
-        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, &quot;TRANSFER_FALLBACK&quot;, from-&gt;a_user);
-                switch_ivr_session_transfer(b_session, exten, profile-&gt;dialplan, profile-&gt;context);
-                switch_core_session_rwunlock(b_session);
-            } 
-
-            switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;BLIND_TRANSFER&quot;);
-                
-            /*
-              nua_notify(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-              NUTAG_SUBSTATE(nua_substate_terminated),
-              SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-              SIPTAG_EVENT_STR(etmp),
-              TAG_END());
-            */
-        } else {
-            exten = switch_mprintf(&quot;sip:%s@%s:%s&quot;, 
-                                   (char *) refer_to-&gt;r_url-&gt;url_user,
-                                   (char *) refer_to-&gt;r_url-&gt;url_host,
-                                   refer_to-&gt;r_url-&gt;url_port);
-            tech_pvt-&gt;dest = switch_core_session_strdup(session, exten);
-                                
-                                
-            switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-
-            /*
-              nua_notify(tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-              NUTAG_SUBSTATE(nua_substate_terminated),
-              SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-              SIPTAG_EVENT_STR(etmp),
-              TAG_END());
-            */
-            do_xfer_invite(session);
-
-        }
-    }
-
- done:
-    if (exten &amp;&amp; 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-&gt;sip_from;
-                char *from_user = NULL;
-                char *from_host = NULL;
-                char *rpid = &quot;unknown&quot;;
-                sip_payload_t *payload = sip-&gt;sip_payload;
-                char *event_type;
-
-                if (from) {
-                        from_user = (char *) from-&gt;a_url-&gt;url_user;
-                        from_host = (char *) from-&gt;a_url-&gt;url_host;
</del><ins>+        if (!strcasecmp(argv[1], &quot;stun-enabled&quot;)) {
+                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);
+                        }
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (payload) {
-                        switch_xml_t xml, note, person, tuple, status, basic, act;
-                        switch_event_t *event;
-                        uint8_t in = 0;
-                        char *sql;
</del><ins>+                stream-&gt;write_function(stream, &quot;+OK stun-enabled=%s&quot;, sofia_test_pflag(profile, PFLAG_STUN_ENABLED) ? &quot;true&quot; : &quot;false&quot;);
+                
+                goto done;
+        }
</ins><span class="cx"> 
</span><del>-                        if ((xml = switch_xml_parse_str(payload-&gt;pl_data, strlen(payload-&gt;pl_data)))) {
-                                char *status_txt = &quot;&quot;, *note_txt = &quot;&quot;;
-                                
-                                if ((tuple = switch_xml_child(xml, &quot;tuple&quot;)) &amp;&amp; (status = switch_xml_child(tuple, &quot;status&quot;)) &amp;&amp; (basic = switch_xml_child(status, &quot;basic&quot;))) {
-                                        status_txt = basic-&gt;txt;
-                                }
-                                        
-                                if ((person = switch_xml_child(xml, &quot;dm:person&quot;)) &amp;&amp; (note = switch_xml_child(person, &quot;dm:note&quot;))) {
-                                        note_txt = note-&gt;txt;
-                                }
</del><span class="cx"> 
</span><del>-                                if (person &amp;&amp; (act = switch_xml_child(person, &quot;rpid:activities&quot;))) {
-                                        if ((rpid = strchr(act-&gt;child-&gt;name, ':'))) {
-                                                rpid++;
-                                        } else {
-                                                rpid = act-&gt;child-&gt;name;
-                                        }
-                                }
</del><ins>+        if (!strcasecmp(argv[1], &quot;rescan&quot;)) {
</ins><span class="cx"> 
</span><del>-                                if (!strcasecmp(status_txt, &quot;open&quot;)) {
-                                        if (switch_strlen_zero(note_txt)) {
-                                                note_txt = &quot;Available&quot;;
-                                        }
-                                        in = 1;
-                                } else if (!strcasecmp(status_txt, &quot;closed&quot;)) {
-                                        if (switch_strlen_zero(note_txt)) {
-                                                note_txt = &quot;Unavailable&quot;;
-                                        }
-                                }
-                                
-                                if ((sql = switch_mprintf(&quot;update sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'&quot;, 
-                                                                                  note_txt, rpid, from_user, from_host))) {
-                                        execute_sql(profile-&gt;dbname, sql, profile-&gt;ireg_mutex);
-                                        switch_safe_free(sql);
-                                }
-                                
-                                event_type = sip_header_as_string(profile-&gt;home, (void *)sip-&gt;sip_event);
-
-                                if (in) {
-                                        if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;%s&quot;, rpid);
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;url);
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, from_user, from_host);
-                                                
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;%s&quot;, note_txt);
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;%s&quot;, event_type);
-                                                switch_event_fire(&amp;event);
-                                        }
-                                } else {
-                                        if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;%s&quot;, rpid);
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, &quot;%s&quot;, profile-&gt;url);
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, from_user, from_host);
-
-                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;%s&quot;, event_type);
-                                                switch_event_fire(&amp;event);
-                                        }
-                                }
-
-                                if (event_type) {
-                                        su_free(profile-&gt;home, event_type);
-                                }                                
-
-                                switch_xml_free(xml);
</del><ins>+                if (argc &gt; 2 &amp;&amp; !strcasecmp(argv[2], &quot;reloadxml&quot;)) {
+                        if ((xml_root = switch_xml_open_root(1, &amp;err))) {
+                                switch_xml_free(xml_root);
</ins><span class="cx">                         }
</span><ins>+                        stream-&gt;write_function(stream, &quot;Reload XML [%s]\n&quot;, err);
+                }
</ins><span class="cx">                         
</span><ins>+                if (reconfig_sofia(profile) == SWITCH_STATUS_SUCCESS) {
+                        stream-&gt;write_function(stream, &quot;+OK scan complete\n&quot;);
+                } else {
+                        stream-&gt;write_function(stream, &quot;-ERR cannot find config for profile %s\n&quot;, profile-&gt;name);
</ins><span class="cx">                 }
</span><del>-                
</del><ins>+                goto done;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
</del><ins>+        if (!strcasecmp(argv[1], &quot;flush_inbound_reg&quot;)) {
+                int reboot = 0;
</ins><span class="cx"> 
</span><del>-}
</del><ins>+                if (argc &gt; 2) {
+                        if (!strcasecmp(argv[2], &quot;reboot&quot;)) {
+                                reboot = 1;
+                                argc = 2;
+                        }
+                }
</ins><span class="cx"> 
</span><del>-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[]) {
</del><ins>+                if (argc &gt; 2) {
+                        if (argc &gt; 3 &amp;&amp; !strcasecmp(argv[3], &quot;reboot&quot;)) {
+                                reboot = 1;
+                        }
</ins><span class="cx"> 
</span><del>-        //placeholder for string searching
-        char *signal_ptr;
</del><ins>+                        sofia_reg_expire_call_id(profile, argv[2], reboot);
+                        stream-&gt;write_function(stream, &quot;+OK %s all registrations matching specified call_id\n&quot;, reboot ? &quot;rebooting&quot; : &quot;flushing&quot;);
+                } else {
+                        sofia_reg_check_expire(profile, 0, reboot);
+                        stream-&gt;write_function(stream, &quot;+OK %s all registrations\n&quot;, reboot ? &quot;rebooting&quot; : &quot;flushing&quot;);
+                }
</ins><span class="cx"> 
</span><del>-        //Try and find signal information in the payload
-        signal_ptr = strstr(sip-&gt;sip_payload-&gt;pl_data, &quot;Signal=&quot;);
</del><ins>+                goto done;
+        }
</ins><span class="cx"> 
</span><del>-        //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};
</del><ins>+        if (!strcasecmp(argv[1], &quot;register&quot;)) {
+                char *gname = argv[2];
+                sofia_gateway_t *gateway_ptr;
</ins><span class="cx"> 
</span><del>-                //Get the channel
-                channel = switch_core_session_get_channel(session);
</del><ins>+                if (switch_strlen_zero(gname)) {
+                        stream-&gt;write_function(stream, &quot;No gateway name provided!\n&quot;);
+                        goto done;
+                }
</ins><span class="cx"> 
</span><del>-                //Barf if we didn't get it
-                assert(channel != NULL);
</del><ins>+                if (!strcasecmp(gname, &quot;all&quot;)) {
+                        for (gateway_ptr = profile-&gt;gateways; gateway_ptr; gateway_ptr = gateway_ptr-&gt;next) {
+                                gateway_ptr-&gt;retry = 0;
+                                gateway_ptr-&gt;state = REG_STATE_UNREGED;
+                        }
+                        stream-&gt;write_function(stream, &quot;+OK\n&quot;);
+                } else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
+                        gateway_ptr-&gt;retry = 0;
+                        gateway_ptr-&gt;state = REG_STATE_UNREGED;
+                        stream-&gt;write_function(stream, &quot;+OK\n&quot;);
+                        sofia_reg_release_gateway(gateway_ptr);
+                } else {
+                        stream-&gt;write_function(stream, &quot;Invalid gateway!\n&quot;);
+                }
</ins><span class="cx"> 
</span><del>-                //make sure we have our privates
-                tech_pvt = switch_core_session_get_private(session);
</del><ins>+                goto done;
+        }
</ins><span class="cx"> 
</span><del>-                //Barf if we didn't get it
-                assert(tech_pvt != NULL);
</del><ins>+        if (!strcasecmp(argv[1], &quot;unregister&quot;)) {
+                char *gname = argv[2];
+                sofia_gateway_t *gateway_ptr;
</ins><span class="cx"> 
</span><del>-                //move signal_ptr where we need it (right past Signal=)
-                signal_ptr = signal_ptr + 7;
</del><ins>+                if (switch_strlen_zero(gname)) {
+                        stream-&gt;write_function(stream, &quot;No gateway name provided!\n&quot;);
+                        goto done;
+                }
</ins><span class="cx"> 
</span><del>-                //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, &quot;INFO DTMF(%s)\n&quot;, dtmf_digit);
-
-        } else { //unknown info type
-                sip_from_t const *from;
-
-                from = sip-&gt;sip_from;
-
-                //print in the logs if something comes through we don't understand
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Unknown INFO Recieved: %s%s&quot; URL_PRINT_FORMAT &quot;[%s]\n&quot;,
-                                  from-&gt;a_display ? from-&gt;a_display : &quot;&quot;, from-&gt;a_display ? &quot; &quot; : &quot;&quot;,
-                                  URL_PRINT_ARGS(from-&gt;a_url), sip-&gt;sip_payload-&gt;pl_data);
</del><ins>+                if (!strcasecmp(gname, &quot;all&quot;)) {
+                        for (gateway_ptr = profile-&gt;gateways; gateway_ptr; gateway_ptr = gateway_ptr-&gt;next) {
+                                gateway_ptr-&gt;retry = 0;
+                                gateway_ptr-&gt;state = REG_STATE_UNREGISTER;
+                        }
+                        stream-&gt;write_function(stream, &quot;+OK\n&quot;);
+                } else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
+                        gateway_ptr-&gt;retry = 0;
+                        gateway_ptr-&gt;state = REG_STATE_UNREGISTER;
+                        stream-&gt;write_function(stream, &quot;+OK\n&quot;);
+                        sofia_reg_release_gateway(gateway_ptr);
+                } else {
+                        stream-&gt;write_function(stream, &quot;Invalid gateway!\n&quot;);
+                }
+                goto done;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        return;
-}
</del><ins>+        if (!strcasecmp(argv[1], &quot;stop&quot;) || !strcasecmp(argv[1], &quot;restart&quot;)) {
+                int rsec = 10;
+                int diff = (int) (switch_epoch_time_now(NULL) - profile-&gt;started);
+                int remain = rsec - diff;
+                if (diff &lt; rsec) {
+                        stream-&gt;write_function(stream, &quot;Profile %s must be up for at least %d seconds to stop/restart.\nPlease wait %d second%s\n&quot;,
+                                                                   profile-&gt;name, rsec, remain, remain == 1 ? &quot;&quot; : &quot;s&quot;);
+                } else {
</ins><span class="cx"> 
</span><ins>+                        if (argc &gt; 2 &amp;&amp; !strcasecmp(argv[2], &quot;reloadxml&quot;)) {
+                                if ((xml_root = switch_xml_open_root(1, &amp;err))) {
+                                        switch_xml_free(xml_root);
+                                }
+                                stream-&gt;write_function(stream, &quot;Reload XML [%s]\n&quot;, err);
+                        }
</ins><span class="cx"> 
</span><del>-#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix &quot;_user&quot;, #varprefix &quot;_host&quot;, #varprefix &quot;_port&quot;, #varprefix &quot;_uri&quot;)
-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-&gt;url_user;
-                host = url-&gt;url_host;
-                port = url-&gt;url_port;
</del><ins>+                        if (!strcasecmp(argv[1], &quot;stop&quot;)) {
+                                sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+                                stream-&gt;write_function(stream, &quot;stopping: %s&quot;, profile-&gt;name);
+                        } else {
+                                sofia_set_pflag_locked(profile, PFLAG_RESPAWN);
+                                sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+                                stream-&gt;write_function(stream, &quot;restarting: %s&quot;, profile-&gt;name);
+                        }
+                }
+                goto done;
</ins><span class="cx">         }
</span><del>-
-        if (user) {
-                switch_channel_set_variable(channel, user_var, user);
</del><ins>+        
+        if (!strcasecmp(argv[1], &quot;siptrace&quot;)) {
+                if (argc &gt; 2) {
+                        int value = switch_true(argv[2]);
+                        nua_set_params(profile-&gt;nua, TPTAG_LOG(value), TAG_END());
+                        stream-&gt;write_function(stream, &quot;%s sip debugging on %s&quot;, value ? &quot;Enabled&quot; : &quot;Disabled&quot;, profile-&gt;name);
+                } else {
+                        stream-&gt;write_function(stream, &quot;Usage: sofia profile &lt;name&gt; siptrace &lt;on/off&gt;\n&quot;);
+                }
+                goto done;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!port) {
-                port = &quot;5060&quot;;
-        }
</del><ins>+        stream-&gt;write_function(stream, &quot;-ERR Unknown command!\n&quot;);
</ins><span class="cx"> 
</span><del>-        switch_channel_set_variable(channel, port_var, port);
-        if (host) {
-                if (user) {
-                        uri = switch_core_session_sprintf(session, &quot;%s@%s:%s&quot;, user, host, port);
-                } else {
-                        uri = switch_core_session_sprintf(session, &quot;%s:%s&quot;, host, port);
-                }
-                switch_channel_set_variable_nodup(channel, uri_var, uri);
-                switch_channel_set_variable(channel, host_var, host);
</del><ins>+  done:
+        if (profile) {
+                sofia_glue_release_profile(profile);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        return uri;
</del><ins>+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void process_rpid(sip_unknown_t *un, private_object_t *tech_pvt)
</del><ins>+static int contact_callback(void *pArg, int argc, char **argv, char **columnNames)
</ins><span class="cx"> {
</span><del>-        int argc, x, screen = 1;
-        char *mydata, *argv[10] = { 0 };
-        if (!switch_strlen_zero(un-&gt;un_value)) { 
-                if ((mydata = strdup(un-&gt;un_value))) {
-                        argc = switch_separate_string(mydata, ';', argv, (sizeof(argv) / sizeof(argv[0]))); 
</del><ins>+        struct cb_helper *cb = (struct cb_helper *) pArg;
+        char *contact;
</ins><span class="cx"> 
</span><del>-                        // Do We really need this at this time 
-                        // clid_uri = argv[0];
-
-                        for (x=1; x &lt; argc &amp;&amp; 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], &quot;party&quot;, 5)) {
-                                //        party = argv[x];
-                                // } else 
-                                if (!strncasecmp(argv[x], &quot;privacy=&quot;, 8)) {
-                                        char *arg = argv[x] + 9;
-
-                                        if (!strcasecmp(arg, &quot;yes&quot;)) {
-                                                switch_set_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
-                                        } else if (!strcasecmp(arg, &quot;full&quot;)) {
-                                                switch_set_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
-                                        } else if (!strcasecmp(arg, &quot;name&quot;)) {
-                                                switch_set_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NAME);
-                                        } else if (!strcasecmp(arg, &quot;number&quot;)) {
-                                                switch_set_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NUMBER);
-                                        } else {
-                                                switch_clear_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NAME);
-                                                switch_clear_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NUMBER);
-                                        }
-
-                                } else if (!strncasecmp(argv[x], &quot;screen=&quot;, 7) &amp;&amp; screen &gt; 0) {
-                                        char *arg = argv[x] + 8;
-                                        if (!strcasecmp(arg, &quot;no&quot;)) {
-                                                screen = 0;
-                                                switch_clear_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_SCREEN);
-                                        }
-                                }
-                        }
-                        free(mydata);
-                }
</del><ins>+        if (!switch_strlen_zero(argv[0]) &amp;&amp; (contact = sofia_glue_get_url_from_contact(argv[0], 1)) ) {
+                cb-&gt;stream-&gt;write_function(cb-&gt;stream, &quot;%ssofia/%s/sip:%s,&quot;, argv[2], argv[1], sofia_glue_strip_proto(contact));
+                free(contact);
</ins><span class="cx">         }
</span><ins>+
+        return 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-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[])
</del><ins>+SWITCH_STANDARD_API(sofia_contact_function)
</ins><span class="cx"> {
</span><del>-        switch_core_session_t *session = NULL;
-        char key[128] = &quot;&quot;;
-        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];
</del><ins>+        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 = &quot;error/facility_not_subscribed&quot;;
+        
+        if (!cmd) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, &quot;&quot;);
+                return SWITCH_STATUS_SUCCESS;
+        }
</ins><span class="cx"> 
</span><del>-        if (!sip || !sip-&gt;sip_request || !sip-&gt;sip_request-&gt;rq_method_name) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Received an invalid packet!\n&quot;);
-                nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
-                return;
</del><ins>+        if (session) {
+                switch_channel_t *channel = switch_core_session_get_channel(session);
+                exclude_contact = switch_channel_get_variable(channel, &quot;sip_exclude_contact&quot;);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-        if (!(sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url)) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;NO CONTACT!\n&quot;);
-                nua_respond(nh, 400, &quot;Missing Contact Header&quot;, TAG_END());
-                return;
</del><ins>+        data = strdup(cmd);
+        switch_assert(data);
+
+        if ((p = strchr(data, '/'))) {
+                profile_name = data;
+                *p++ = '\0';
+                user = p;
+        } else {
+                user = data;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if ((profile-&gt;pflags &amp; PFLAG_AUTH_CALLS)) {
-                if (handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key))) {
-                        return;
</del><ins>+        if ((domain = strchr(user, '@'))) {
+                *domain++ = '\0';
+                if ( (concat = strchr( domain, '/')) ) {
+                    *concat++ = '\0';
</ins><span class="cx">                 }
</span><span class="cx">         }
</span><del>-
-        if (!(session = switch_core_session_request(&amp;sofia_endpoint_interface, NULL))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Session Alloc Failed!\n&quot;);
-                nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
-                return;
</del><ins>+        else {
+                if ( (concat = strchr( user, '/')) ) {
+                    *concat++ = '\0';
+                }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Hey where is my memory pool?\n&quot;);
-                terminate_session(&amp;session, SWITCH_CAUSE_SWITCH_CONGESTION, __LINE__);
-                return;
</del><ins>+        if (!profile_name &amp;&amp; domain) {
+                profile_name = domain;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!switch_strlen_zero(key)) {
-                tech_pvt-&gt;key = switch_core_session_strdup(session, key);
-        }
</del><ins>+        if (user &amp;&amp; profile_name) {
+                char *sql;
</ins><span class="cx"> 
</span><del>-        get_addr(network_ip, sizeof(network_ip), &amp;((struct sockaddr_in *)msg_addrinfo(nua_current_request(nua))-&gt;ai_addr)-&gt;sin_addr);
</del><ins>+                if (!(profile = sofia_glue_find_profile(profile_name))) {
+                        profile_name = domain;
+                        domain = NULL;
+                }
</ins><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(session);
</del><ins>+                if (!profile &amp;&amp; profile_name) {
+                        profile = sofia_glue_find_profile(profile_name);
+                }
</ins><span class="cx"> 
</span><del>-        if (sip-&gt;sip_from &amp;&amp; sip-&gt;sip_from-&gt;a_url) {
-                from_user = sip-&gt;sip_from-&gt;a_url-&gt;url_user;
-                from_host = sip-&gt;sip_from-&gt;a_url-&gt;url_host;
-                channel_name = url_set_chanvars(session, sip-&gt;sip_from-&gt;a_url, sip_from);
</del><ins>+                if (profile) {
+                        struct cb_helper cb;
+                        switch_stream_handle_t mystream = { 0 };
</ins><span class="cx"> 
</span><del>-                if (!switch_strlen_zero(from_user)) {
-                        if (*from_user == '+') {
-                                switch_channel_set_variable(channel, &quot;sip_from_user_stripped&quot;, (const char *)(from_user+1));
</del><ins>+                        if (!domain || !strchr(domain, '.')) {
+                                domain = profile-&gt;name;
+                        }
+
+                        SWITCH_STANDARD_STREAM(mystream);
+                        switch_assert(mystream.data);
+                        cb.profile = profile;
+                        cb.stream = &amp;mystream;
+
+                        if (exclude_contact) {
+                                sql = switch_mprintf(&quot;select contact, profile_name, '%q' &quot;
+                                                                         &quot;from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%') &quot;
+                                                                         &quot;and contact not like '%%%s%%'&quot;,
+                                                                         ( concat != NULL ) ? concat : &quot;&quot;, user, domain, domain, exclude_contact);
</ins><span class="cx">                         } else {
</span><del>-                                switch_channel_set_variable(channel, &quot;sip_from_user_stripped&quot;, from_user);
</del><ins>+                                sql = switch_mprintf(&quot;select contact, profile_name, '%q' &quot;
+                                                                         &quot;from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')&quot;, 
+                                                                         ( concat != NULL ) ? concat : &quot;&quot;, user, domain, domain);
</ins><span class="cx">                         }
</span><del>-                }
</del><span class="cx"> 
</span><del>-                if (!switch_strlen_zero(sip-&gt;sip_from-&gt;a_display)) {
-                        char *tmp;
-                        tmp = switch_core_session_strdup(session, sip-&gt;sip_from-&gt;a_display);
-                        if (*tmp == '&quot;') {
-                                char *p;
</del><ins>+                        switch_assert(sql);
+                        sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, contact_callback, &amp;cb);
+                        switch_safe_free(sql);
+                        reply = (char *) mystream.data;
+                        if (!switch_strlen_zero(reply) &amp;&amp; end_of(reply) == ',') {
+                                end_of(reply) = '\0';
+                        }
</ins><span class="cx"> 
</span><del>-                                tmp++;
-                                if ((p = strchr(tmp, '&quot;'))) {
-                                        *p = '\0';
-                                }
</del><ins>+                        if (switch_strlen_zero(reply)) {
+                                reply = &quot;error/user_not_registered&quot;;
</ins><span class="cx">                         }
</span><del>-                        displayname = tmp;
-                } else {
-                        displayname = switch_strlen_zero(from_user) ? &quot;unkonwn&quot; : from_user;
-                }
-        }
</del><span class="cx"> 
</span><del>-        if (sip-&gt;sip_request-&gt;rq_url) {
-                const char * req_uri = url_set_chanvars(session, sip-&gt;sip_request-&gt;rq_url, sip_req);
-                if (profile-&gt;pflags &amp; PFLAG_FULL_ID)  {
-                        destination_number = req_uri;
-                } else {
-                        destination_number = sip-&gt;sip_request-&gt;rq_url-&gt;url_user;
</del><ins>+                        stream-&gt;write_function(stream, &quot;%s&quot;, reply);
+                        reply = NULL;
+                        
+                        switch_safe_free(mystream.data);
</ins><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (sip-&gt;sip_to &amp;&amp; sip-&gt;sip_to-&gt;a_url) {
-                url_set_chanvars(session, sip-&gt;sip_to-&gt;a_url, sip_to);
</del><ins>+        if (reply) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, reply);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url) {
-                const char *contact_uri = url_set_chanvars(session, sip-&gt;sip_contact-&gt;m_url, sip_contact);
-                if (!channel_name) {
-                        channel_name = contact_uri;
-                }
</del><ins>+        switch_safe_free(data);
+
+        if (profile) {
+                sofia_glue_release_profile(profile);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        attach_private(session, profile, tech_pvt, channel_name);
-        tech_set_codecs(tech_pvt);
</del><ins>+        return SWITCH_STATUS_SUCCESS;
+}
</ins><span class="cx"> 
</span><del>-        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;INBOUND CALL&quot;);
-        set_chat_hash(tech_pvt, sip);
</del><ins>+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 = &quot;USAGE:\n&quot;
+                &quot;--------------------------------------------------------------------------------\n&quot;
+                &quot;sofia help\n&quot;
+                &quot;sofia profile &lt;profile_name&gt; [[start|stop|restart|rescan] [reloadxml]|flush_inbound_reg [&lt;call_id&gt;] [reboot]|[register|unregister] [&lt;gateway name&gt;|all]|killgw &lt;gateway name&gt;|[stun-auto-disable|stun-enabled] [true|false]]|siptrace [on|off]\n&quot;
+                &quot;sofia status profile &lt;name&gt; [ reg &lt;contact str&gt; ] | [ pres &lt;pres str&gt; ]\n&quot;
+                &quot;sofia status gateway &lt;name&gt;\n&quot;
+                &quot;sofia loglevel &lt;all|default|tport|iptsec|nea|nta|nth_client|nth_server|nua|soa|sresolv|stun&gt; [0-9]\n&quot;
+                &quot;--------------------------------------------------------------------------------\n&quot;;
</ins><span class="cx"> 
</span><del>-        if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
-                switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-                switch_channel_set_flag(channel, CF_NOMEDIA);
</del><ins>+        if (session) {
+                return SWITCH_STATUS_FALSE;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!tech_pvt-&gt;call_id &amp;&amp; sip-&gt;sip_call_id &amp;&amp; sip-&gt;sip_call_id-&gt;i_id) {
-                tech_pvt-&gt;call_id = switch_core_session_strdup(session, sip-&gt;sip_call_id-&gt;i_id);
-                switch_channel_set_variable(channel, &quot;sip_call_id&quot;, tech_pvt-&gt;call_id);
</del><ins>+        if (switch_strlen_zero(cmd)) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, usage_string);
+                goto done;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (sip-&gt;sip_via) {
-                if (sip-&gt;sip_via-&gt;v_host) {
-                        switch_channel_set_variable(channel, &quot;sip_via_host&quot;, sip-&gt;sip_via-&gt;v_host);
-                }
-                if (sip-&gt;sip_via-&gt;v_port) {
-                        switch_channel_set_variable(channel, &quot;sip_via_port&quot;, sip-&gt;sip_via-&gt;v_port);
-                }
-                if (sip-&gt;sip_via-&gt;v_rport) {
-                        switch_channel_set_variable(channel, &quot;sip_via_rport&quot;, sip-&gt;sip_via-&gt;v_rport);
-                }
</del><ins>+        if (!(mycmd = strdup(cmd))) {
+                status = SWITCH_STATUS_MEMERR;
+                goto done;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (sip-&gt;sip_max_forwards) {
-                char max_forwards[32];
-                snprintf(max_forwards, sizeof(max_forwards), &quot;%u&quot;, sip-&gt;sip_max_forwards-&gt;mf_count);
-                switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
</del><ins>+        if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, usage_string);
+                goto done;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (profile-&gt;context &amp;&amp; !strcasecmp(profile-&gt;context, &quot;_domain_&quot;)) {
-                context = from_host;
</del><ins>+        if (!strcasecmp(argv[0], &quot;profile&quot;)) {
+                func = cmd_profile;
+        } else if (!strcasecmp(argv[0], &quot;status&quot;)) {
+                func = cmd_status;
+        } else if (!strcasecmp(argv[0], &quot;xmlstatus&quot;)) {
+                func = cmd_xml_status;
+        } else if (!strcasecmp(argv[0], &quot;tracelevel&quot;)) {
+                if (argv[1]) {
+                        mod_sofia_globals.tracelevel = switch_log_str2level(argv[1]);
+                }
+                stream-&gt;write_function(stream, &quot;+OK tracelevel is %s&quot;, switch_log_level2str(mod_sofia_globals.tracelevel));
+        goto done;
+        } else if (!strcasecmp(argv[0], &quot;loglevel&quot;)) {
+                if (argc &gt; 2 &amp;&amp; argv[2] &amp;&amp; switch_is_number(argv[2])) {
+                        int level = atoi(argv[2]);
+                        if (sofia_set_loglevel(argv[1], level) == SWITCH_STATUS_SUCCESS) {
+                                stream-&gt;write_function(stream, &quot;Sofia log level for component [%s] has been set to [%d]&quot;, argv[1], level);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;%s&quot;, usage_string);
+                        }
+                } else if (argc &gt; 1 &amp;&amp; argv[1]) {
+                        int level = sofia_get_loglevel(argv[1]);
+                        if (level &gt;= 0) {
+                                stream-&gt;write_function(stream, &quot;Sofia-sip loglevel for [%s] is [%d]&quot;, argv[1], level);
+                        } else {
+                                stream-&gt;write_function(stream, &quot;%s&quot;, usage_string);
+                        }
+                } else {
+                        stream-&gt;write_function(stream, &quot;%s&quot;, usage_string);
+                }
+                goto done;
+        } else if (!strcasecmp(argv[0], &quot;help&quot;)) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, usage_string);
+                goto done;
+        }
+
+        if (func) {
+                status = func(&amp;argv[lead], argc - lead, stream);
</ins><span class="cx">         } else {
</span><del>-                context = profile-&gt;context;
</del><ins>+                stream-&gt;write_function(stream, &quot;Unknown Command [%s]\n&quot;, argv[0]);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        tech_pvt-&gt;caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
-                                                                                                                from_user,
-                                                                                                                profile-&gt;dialplan,
-                                                                                                                displayname,
-                                                                                                                from_user,
-                                                                                                                network_ip,
-                                                                                                                NULL,
-                                                                                                                NULL,
-                                                                                                                NULL,
-                                                                                                                modname,
-                                                                                                                context,
-                                                                                                                destination_number);
</del><ins>+  done:
+        switch_safe_free(mycmd);
+        return status;
+}
</ins><span class="cx"> 
</span><del>-        if (tech_pvt-&gt;caller_profile) {
-                                
-                /* Loop thru unknown Headers Here so we can do something with them */
-                for (un=sip-&gt;sip_unknown; un; un=un-&gt;un_next) {
-                        if (!strncasecmp(un-&gt;un_name, &quot;Alert-Info&quot;, 10)) {
-                                if (!switch_strlen_zero(un-&gt;un_value)) { 
-                                        switch_channel_set_variable(channel, &quot;alert_info&quot;, un-&gt;un_value);
-                                }
-                        } else if (!strncasecmp(un-&gt;un_name, &quot;Remote-Party-ID&quot;, 15)) {
-                                process_rpid(un, tech_pvt);
-                        } else if (!strncasecmp(un-&gt;un_name, &quot;X-&quot;, 2)) {
-                                if (!switch_strlen_zero(un-&gt;un_value)) { 
-                                        char *new_name;
-                                        if ((new_name = switch_mprintf(&quot;%s%s&quot;, SOFIA_SIP_HEADER_PREFIX, un-&gt;un_name))) {
-                                                switch_channel_set_variable(channel, new_name, un-&gt;un_value);
-                                                free(new_name);
-                                        }
-                                }
-                        }
-                }
</del><ins>+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
+};
</ins><span class="cx"> 
</span><del>-                switch_channel_set_caller_profile(channel, tech_pvt-&gt;caller_profile);
-        }
</del><ins>+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
+};
</ins><span class="cx"> 
</span><del>-        if (!(tech_pvt-&gt;sofia_private = malloc(sizeof(*tech_pvt-&gt;sofia_private)))) {
-                abort();
-        }
-        memset(tech_pvt-&gt;sofia_private, 0, sizeof(*tech_pvt-&gt;sofia_private));
-        switch_copy_string(tech_pvt-&gt;sofia_private-&gt;uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt-&gt;sofia_private-&gt;uuid));
-        nua_handle_bind(nh, tech_pvt-&gt;sofia_private);
-        tech_pvt-&gt;nh = nh;
</del><ins>+static switch_status_t sofia_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
+{
+        return SWITCH_STATUS_SUCCESS;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-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[])
</del><ins>+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)
</ins><span class="cx"> {
</span><del>-    char key[128] = &quot;&quot;;
</del><ins>+        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;
</ins><span class="cx"> 
</span><del>-        if (!sip || !sip-&gt;sip_request || !sip-&gt;sip_request-&gt;rq_method_name) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Received an invalid packet!\n&quot;);
-                nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
-                return;
</del><ins>+        *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, &quot;Error Creating Session\n&quot;);
+                goto error;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!(sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url)) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;NO CONTACT!\n&quot;);
-                nua_respond(nh, 400, &quot;Missing Contact Header&quot;, TAG_END());
-                return;
</del><ins>+        if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Error Creating Session\n&quot;);
+                goto error;
</ins><span class="cx">         }
</span><ins>+        switch_mutex_init(&amp;tech_pvt-&gt;flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(nsession));
+        switch_mutex_init(&amp;tech_pvt-&gt;sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(nsession));
</ins><span class="cx"> 
</span><del>-        handle_register(nua, profile, nh, sip, REG_REGISTER, key, sizeof(key));
-}
</del><ins>+        data = switch_core_session_strdup(nsession, outbound_profile-&gt;destination_number);
+        if ((dest_to = strchr(data, '^'))) {
+                *dest_to++ = '\0';
+        }
+        profile_name = data;
</ins><span class="cx"> 
</span><ins>+        nchannel = switch_core_session_get_channel(nsession);
</ins><span class="cx"> 
</span><del>-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-&gt;local_sdp_str),
-                                //SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;),
-                                //NUTAG_INCLUDE_EXTRA_SDP(1),
-                                TAG_END());
-}
</del><ins>+        if ((hval = switch_event_get_header(var_event, &quot;sip_invite_to_uri&quot;))) {
+                dest_to = switch_core_session_strdup(nsession, hval);
+        }
</ins><span class="cx"> 
</span><ins>+        if (!strncasecmp(profile_name, &quot;gateway&quot;, 7)) {
+                char *gw, *params;
+                sofia_gateway_t *gateway_ptr = NULL;
</ins><span class="cx"> 
</span><del>-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 &amp;&amp; sofia_private-&gt;oreg) {
-                if (status == 200) {
-                        sofia_private-&gt;oreg-&gt;state = REG_STATE_REGISTER;
-                } else {
-                        sofia_private-&gt;oreg-&gt;state = REG_STATE_FAILED;
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;received %d on register!\n&quot;, status);
</del><ins>+                if (!(gw = strchr(profile_name, '/'))) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid URL\n&quot;);
+                        cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+                        goto error;
</ins><span class="cx">                 }
</span><del>-        }
-}
</del><span class="cx"> 
</span><del>-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] = &quot;&quot;;
-        int ss_state;
-        
-        if (session) {
-                private_object_t *tech_pvt;
-                if ((tech_pvt = switch_core_session_get_private(session)) &amp;&amp; switch_test_flag(tech_pvt, TFLAG_REFER)) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;received reply from refer\n&quot;);
-                        return;
</del><ins>+                *gw++ = '\0';
+
+                if (!(dest = strchr(gw, '/'))) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid URL\n&quot;);
+                        cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+                        goto error;
</ins><span class="cx">                 }
</span><del>-        }
</del><span class="cx"> 
</span><ins>+                *dest++ = '\0';
</ins><span class="cx"> 
</span><del>-        if (sip-&gt;sip_www_authenticate) {
-                authenticate = sip-&gt;sip_www_authenticate;
-        } else if (sip-&gt;sip_proxy_authenticate) {
-                authenticate = sip-&gt;sip_proxy_authenticate;
-        } else {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Missing Authenticate Header!\n&quot;);
-                return;
-        }
-        scheme = (char const *) authenticate-&gt;au_scheme;
-        if (authenticate-&gt;au_params) {
-                for(indexnum = 0; (cur=(char*)authenticate-&gt;au_params[indexnum]); indexnum++) {
-                        if ((realm = strstr(cur, &quot;realm=&quot;))) {
-                                realm += 6;
-                                break;
-                        }
</del><ins>+                if (!(gateway_ptr = sofia_reg_find_gateway(gw))) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Gateway\n&quot;);
+                        cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+                        goto error;
</ins><span class="cx">                 }
</span><del>-        }
</del><span class="cx"> 
</span><del>-        if (!(scheme &amp;&amp; realm)) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;No scheme and realm!\n&quot;);
-                return;
-        }
</del><ins>+                if (gateway_ptr-&gt;status != SOFIA_GATEWAY_UP) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Gateway is down!\n&quot;);
+                        cause = SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
+                        sofia_reg_release_gateway(gateway_ptr);
+                        gateway_ptr = NULL;
+                        goto error;
+                }
</ins><span class="cx"> 
</span><del>-        if (profile) {
-                outbound_reg_t *oregp;
</del><ins>+                tech_pvt-&gt;transport = gateway_ptr-&gt;register_transport;
</ins><span class="cx"> 
</span><del>-                if ((duprealm = strdup(realm))) {
-                        qrealm = duprealm;
-        
-                        while(*qrealm &amp;&amp; *qrealm == '&quot;') {
-                                qrealm++;
-                        }
</del><ins>+                /*
+                 * 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;
</ins><span class="cx"> 
</span><del>-                        if ((p = strchr(qrealm, '&quot;'))) {
-                                *p = '\0';
-                        }
</del><ins>+                        *params++ = '\0';
</ins><span class="cx"> 
</span><del>-                        for (oregp = profile-&gt;registrations; oregp; oregp = oregp-&gt;next) {
-                                if (scheme &amp;&amp; qrealm &amp;&amp; !strcasecmp(oregp-&gt;register_scheme, scheme) &amp;&amp; !strcasecmp(oregp-&gt;register_realm, qrealm)) {
-                                        oreg = oregp;
-                                        break;
</del><ins>+                        if ((tp_param = (char *) switch_stristr(&quot;port=&quot;, params))) {
+                                tp_param += 5;
+                                tech_pvt-&gt;transport = sofia_glue_str2transport(tp_param);
+                                if (tech_pvt-&gt;transport == SOFIA_TRANSPORT_UNKNOWN) {
+                                        cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                                        goto error;
</ins><span class="cx">                                 }
</span><span class="cx">                         }
</span><del>-                        if (!oreg) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;No Match for Scheme [%s] Realm [%s]\n&quot;, scheme, qrealm);
-                                return;
-                        }
-                        switch_safe_free(duprealm);
-                } else {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Memory Error!\n&quot;);
-                        return;
</del><span class="cx">                 }
</span><del>-        }
-                
-        snprintf(authentication, sizeof(authentication), &quot;%s:%s:%s:%s&quot;, scheme, realm, 
-                         oreg-&gt;register_username,
-                         oreg-&gt;register_password);
-                
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Authenticating '%s' with '%s'.\n&quot;,
-                                          profile-&gt;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-&gt;expires_str), NUTAG_AUTH(authentication), TAG_END());
-        
-}
</del><span class="cx"> 
</span><del>-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;
</del><ins>+                if (tech_pvt-&gt;transport != gateway_ptr-&gt;register_transport) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+                                                          &quot;You are trying to use a different transport type for this gateway (overriding the register-transport), this is unsupported!\n&quot;);
+                        cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                        goto error;
+                }
</ins><span class="cx"> 
</span><del>-    if (sofia_private) {
-        if (!switch_strlen_zero(sofia_private-&gt;uuid)) {
</del><ins>+                profile = gateway_ptr-&gt;profile;
+                tech_pvt-&gt;gateway_name = switch_core_session_strdup(nsession, gateway_ptr-&gt;name);
+                switch_channel_set_variable(nchannel, &quot;sip_gateway_name&quot;, gateway_ptr-&gt;name);
</ins><span class="cx"> 
</span><del>-            if ((session = switch_core_session_locate(sofia_private-&gt;uuid))) {
-                tech_pvt = switch_core_session_get_private(session);
-                channel = switch_core_session_get_channel(tech_pvt-&gt;session);
-                if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
-                    switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
-                }
-                if (!tech_pvt-&gt;call_id &amp;&amp; sip &amp;&amp; sip-&gt;sip_call_id &amp;&amp; sip-&gt;sip_call_id-&gt;i_id) {
-                    tech_pvt-&gt;call_id = switch_core_session_strdup(session, (char *)sip-&gt;sip_call_id-&gt;i_id);
-                    switch_channel_set_variable(channel, &quot;sip_call_id&quot;, tech_pvt-&gt;call_id);
-                }
-            } else {
-                /* too late */
-                return;            
-            }
-        }
-    }
</del><ins>+                if (!sofia_test_flag(gateway_ptr, REG_FLAG_CALLERID)) {
+                        tech_pvt-&gt;gateway_from_str = switch_core_session_strdup(nsession, gateway_ptr-&gt;register_from);
+                }
</ins><span class="cx"> 
</span><ins>+                if (!strchr(dest, '@')) {
+                        tech_pvt-&gt;dest = switch_core_session_sprintf(nsession, &quot;sip:%s@%s&quot;, dest, sofia_glue_strip_proto(gateway_ptr-&gt;register_proxy));
+                } else {
+                        tech_pvt-&gt;dest = switch_core_session_sprintf(nsession, &quot;sip:%s&quot;, dest);
+                }
</ins><span class="cx"> 
</span><del>-        if (status != 100 &amp;&amp; status != 200) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;event [%s] status [%d][%s] session: %s\n&quot;,
-                                                  nua_event_name (event), status, phrase,
-                                                  session ? switch_channel_get_name(channel) : &quot;n/a&quot;
-                                                  );
-        }
</del><ins>+                if (params) {
+                        tech_pvt-&gt;invite_contact = switch_core_session_sprintf(nsession, &quot;%s;%s&quot;, gateway_ptr-&gt;register_contact, params);
+                } else {
+                        tech_pvt-&gt;invite_contact = switch_core_session_strdup(nsession, gateway_ptr-&gt;register_contact);
+                }
+                
+                gateway_ptr-&gt;ob_calls++;
+                
+                if (!switch_strlen_zero(gateway_ptr-&gt;from_domain) &amp;&amp; !switch_channel_get_variable(nchannel, &quot;sip_invite_domain&quot;)) {
+                        switch_channel_set_variable(nchannel, &quot;sip_invite_domain&quot;, gateway_ptr-&gt;from_domain);
+                }
</ins><span class="cx"> 
</span><del>-        if ((profile-&gt;pflags &amp; PFLAG_AUTH_ALL) &amp;&amp; tech_pvt &amp;&amp; tech_pvt-&gt;key &amp;&amp; sip) {
-                sip_authorization_t const *authorization = NULL;
-
-        if (sip-&gt;sip_authorization) {
-                        authorization = sip-&gt;sip_authorization;
-                } else if (sip-&gt;sip_proxy_authorization) {
-                        authorization = sip-&gt;sip_proxy_authorization;
</del><ins>+                if (!switch_strlen_zero(gateway_ptr-&gt;outbound_sticky_proxy) &amp;&amp; !switch_channel_get_variable(nchannel, &quot;sip_route_uri&quot;)) {
+                        switch_channel_set_variable(nchannel, &quot;sip_route_uri&quot;, gateway_ptr-&gt;outbound_sticky_proxy);
</ins><span class="cx">                 }
</span><ins>+                
+                if (gateway_ptr-&gt;ob_vars) {
+                        switch_event_header_t *hp;
+                        for(hp = gateway_ptr-&gt;ob_vars-&gt;headers; hp; hp = hp-&gt;next) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s setting variable [%s]=[%s]\n&quot;,
+                                                                  switch_channel_get_name(nchannel), hp-&gt;name, hp-&gt;value);
+                                switch_channel_set_variable(nchannel, hp-&gt;name, hp-&gt;value);
+                        }
+                }
</ins><span class="cx"> 
</span><del>-                if (authorization) {
-                        auth_res = parse_auth(profile, authorization, (char *)sip-&gt;sip_request-&gt;rq_method_name, tech_pvt-&gt;key, strlen(tech_pvt-&gt;key));
</del><ins>+        } else {
+                if (!(dest = strchr(profile_name, '/'))) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid URL\n&quot;);
+                        cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+                        goto error;
</ins><span class="cx">                 }
</span><ins>+                *dest++ = '\0';
</ins><span class="cx"> 
</span><del>-                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;
</del><ins>+                if (!(profile = sofia_glue_find_profile(profile_name))) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Profile\n&quot;);
+                        cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                        goto error;
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (channel) {
-                        switch_channel_set_variable(channel, &quot;sip_authorized&quot;, &quot;true&quot;);
</del><ins>+                if (profile-&gt;domain_name &amp;&amp; profile-&gt;domain_name != profile-&gt;name) {
+                        profile_name = profile-&gt;domain_name;
</ins><span class="cx">                 }
</span><del>-        }
</del><span class="cx"> 
</span><del>-        if (sip &amp;&amp; (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 &gt; 100) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s: unknown event %d: %03d %s\n&quot;, 
-                                                          nua_event_name (event), event, status, phrase);
-        } else {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s: unknown event %d\n&quot;, 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-&gt;registrations; oregp; oregp = oregp-&gt;next) {
-        if (oregp-&gt;sofia_private) {
-            free(oregp-&gt;sofia_private);
-            nua_handle_bind(oregp-&gt;nh, NULL);
-            oregp-&gt;sofia_private = NULL;
-        }
-                nua_handle_destroy(oregp-&gt;nh);
-        }
-}
-
-static void check_oreg(sofia_profile_t *profile, time_t now)
-{
-        outbound_reg_t *oregp;
-        for (oregp = profile-&gt;registrations; oregp; oregp = oregp-&gt;next) {
-                int ss_state = nua_callstate_authenticating;
-                reg_state_t ostate = oregp-&gt;state;
-
-                switch(ostate) {
-                case REG_STATE_REGISTER:
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,  &quot;registered %s\n&quot;, oregp-&gt;name);
-                        oregp-&gt;expires = now + oregp-&gt;freq;
-                        oregp-&gt;state = REG_STATE_REGED;
-                        break;
-                case REG_STATE_UNREGED:
-                        if ((oregp-&gt;nh = nua_handle(oregp-&gt;profile-&gt;nua, NULL,
-                                                                                NUTAG_URL(oregp-&gt;register_proxy),
-                                                                                SIPTAG_TO_STR(oregp-&gt;register_to),
-                                                                                NUTAG_CALLSTATE_REF(ss_state),
-                                                                                SIPTAG_FROM_STR(oregp-&gt;register_from), TAG_END()))) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,  &quot;registering %s\n&quot;, oregp-&gt;name);        
-                
-                if (!(oregp-&gt;sofia_private = malloc(sizeof(*oregp-&gt;sofia_private)))) {
-                    abort();
-                }
-                memset(oregp-&gt;sofia_private, 0, sizeof(*oregp-&gt;sofia_private));
-
-                                oregp-&gt;sofia_private-&gt;oreg = oregp;
-                                nua_handle_bind(oregp-&gt;nh, oregp-&gt;sofia_private);
-
-                                nua_register(oregp-&gt;nh,
-                                                        SIPTAG_FROM_STR(oregp-&gt;register_from),
-                                                        SIPTAG_CONTACT_STR(oregp-&gt;register_from),
-                                                        SIPTAG_EXPIRES_STR(oregp-&gt;expires_str),
-                                                        NUTAG_REGISTRAR(oregp-&gt;register_proxy),
-                                                        NUTAG_OUTBOUND(&quot;no-options-keepalive&quot;),
-                                                        NUTAG_OUTBOUND(&quot;no-validate&quot;),
-                                                        NUTAG_KEEPALIVE(0),
-                                                        TAG_NULL());
-                                oregp-&gt;retry = now + 10;
-                                oregp-&gt;state = REG_STATE_TRYING;
</del><ins>+                if (!strncasecmp(dest, &quot;sip:&quot;, 4) || !strncasecmp(dest, &quot;sips:&quot;, 5)) {
+                        tech_pvt-&gt;dest = switch_core_session_strdup(nsession, dest);
+                } else if ((host = strchr(dest, '%'))) {
+                        char buf[1024];
+                        *host = '@';
+                        tech_pvt-&gt;e_dest = switch_core_session_strdup(nsession, dest);
+                        *host++ = '\0';
+                        if (sofia_reg_find_reg_url(profile, dest, host, buf, sizeof(buf))) {
+                                tech_pvt-&gt;dest = switch_core_session_strdup(nsession, buf);
+                                tech_pvt-&gt;local_url = switch_core_session_sprintf(nsession, &quot;%s@%s&quot;, dest, host);
</ins><span class="cx">                         } else {
</span><del>-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,  &quot;Error registering %s\n&quot;, oregp-&gt;name);
-                                oregp-&gt;state = REG_STATE_FAILED;
</del><ins>+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Cannot locate registered user %s@%s\n&quot;, dest, host);
+                                cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
+                                goto error;
</ins><span class="cx">                         }
</span><del>-                        break;
-
-                case REG_STATE_TRYING:
-                        if (oregp-&gt;retry &amp;&amp; now &gt;= oregp-&gt;retry) {
-                                oregp-&gt;state = REG_STATE_UNREGED;
-                                oregp-&gt;retry = 0;
</del><ins>+                } else if (!(host = strchr(dest, '@'))) {
+                        char buf[1024];
+                        tech_pvt-&gt;e_dest = switch_core_session_strdup(nsession, dest);
+                        if (sofia_reg_find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) {
+                                tech_pvt-&gt;dest = switch_core_session_strdup(nsession, buf);
+                                tech_pvt-&gt;local_url = switch_core_session_sprintf(nsession, &quot;%s@%s&quot;, dest, profile_name);
+                                host = profile_name;
+                        } else {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Cannot locate registered user %s@%s\n&quot;, dest, profile_name);
+                                cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
+                                goto error;
</ins><span class="cx">                         }
</span><del>-                        break;
-                default:
-                        if (oregp-&gt;expires &amp;&amp; now &gt;= oregp-&gt;expires) {
-                                oregp-&gt;state = REG_STATE_UNREGED;
-                                oregp-&gt;expires = 0;
-                        }
-                        break;
</del><ins>+                } else {
+                        tech_pvt-&gt;dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
+                        switch_snprintf(tech_pvt-&gt;dest, strlen(dest) + 5, &quot;sip:%s&quot;, dest);
</ins><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-}
</del><ins>+        sofia_glue_get_user_host(switch_core_session_strdup(nsession, tech_pvt-&gt;dest), NULL, &amp;tech_pvt-&gt;remote_ip);
</ins><span class="cx"> 
</span><del>-#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-&gt;s_root = su_root_create(NULL);
-        profile-&gt;home = su_home_new(sizeof(*profile-&gt;home));
-
-        profile-&gt;nua = nua_create(profile-&gt;s_root, /* Event loop */
-                                                          event_callback, /* Callback for processing events */
-                                                          profile, /* Additional data to pass to callback */
-                                                          NUTAG_URL(profile-&gt;bindurl),
-                                                          NTATAG_UDP_MTU(65536),
-                                                          TAG_END()); /* Last tag should always finish the sequence */
-
-        nua_set_params(profile-&gt;nua,
-                                   //NUTAG_EARLY_MEDIA(1),                                   
-                                   NUTAG_AUTOANSWER(0),
-                                   NUTAG_AUTOALERT(0),
-                                   NUTAG_ALLOW(&quot;REGISTER&quot;),
-                                   NUTAG_ALLOW(&quot;REFER&quot;),
-                                   NUTAG_ALLOW(&quot;INFO&quot;),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW(&quot;PUBLISH&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW(&quot;NOTIFY&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW(&quot;SUBSCRIBE&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;presence&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;presence.winfo&quot;)),
-                                   SIPTAG_SUPPORTED_STR(&quot;100rel, precondition&quot;),
-                                   SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT),
-                                   TAG_END());
-                                   
-
-        for (node = profile-&gt;aliases; node; node = node-&gt;next) {
-                node-&gt;nua = nua_create(profile-&gt;s_root, /* Event loop */
-                                                           event_callback, /* Callback for processing events */
-                                                           profile, /* Additional data to pass to callback */
-                                                           NUTAG_URL(node-&gt;url),
-                                                           TAG_END()); /* Last tag should always finish the sequence */
-
-                nua_set_params(node-&gt;nua,
-                                   NUTAG_EARLY_MEDIA(1),                                   
-                                           NUTAG_AUTOANSWER(0),
-                                           NUTAG_AUTOALERT(0),
-                                           NUTAG_ALLOW(&quot;REGISTER&quot;),
-                                           NUTAG_ALLOW(&quot;REFER&quot;),
-                                           NUTAG_ALLOW(&quot;INFO&quot;),
-                                           TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW(&quot;PUBLISH&quot;)),
-                                           TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-                                           SIPTAG_SUPPORTED_STR(&quot;100rel, precondition&quot;),
-                                           SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT),
-                                           TAG_END());
-                
</del><ins>+        if (dest_to) {
+                if (strchr(dest_to, '@')) {
+                        tech_pvt-&gt;dest_to = switch_core_session_sprintf(nsession, &quot;sip:%s&quot;, dest_to);
+                } else {
+                        tech_pvt-&gt;dest_to = switch_core_session_sprintf(nsession, &quot;sip:%s@%s&quot;, dest_to, host);
+                }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-        if ((db = switch_core_db_open_file(profile-&gt;dbname))) {
-                switch_core_db_test_reactive(db, &quot;select contact from sip_registrations&quot;, reg_sql);
-                switch_core_db_test_reactive(db, &quot;select contact from sip_subscriptions&quot;, sub_sql);
-                switch_core_db_test_reactive(db, &quot;select * from sip_authentication&quot;, auth_sql);
-        } else {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Cannot Open SQL Database!\n&quot;);
-                return NULL;
</del><ins>+        if (!tech_pvt-&gt;dest_to) {
+                tech_pvt-&gt;dest_to = tech_pvt-&gt;dest;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        sofia_glue_attach_private(nsession, profile, tech_pvt, dest);
</ins><span class="cx"> 
</span><del>-        switch_mutex_init(&amp;profile-&gt;ireg_mutex, SWITCH_MUTEX_NESTED, profile-&gt;pool);
-        switch_mutex_init(&amp;profile-&gt;oreg_mutex, SWITCH_MUTEX_NESTED, profile-&gt;pool);
-
-        ireg_loops = IREG_SECONDS;
-        oreg_loops = OREG_SECONDS;
-
-        if (switch_event_create(&amp;s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;service&quot;, &quot;_sip._udp&quot;);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;port&quot;, &quot;%d&quot;, profile-&gt;sip_port);
-                switch_event_fire(&amp;s_event);
</del><ins>+        if (tech_pvt-&gt;local_url) {
+                switch_channel_set_variable(nchannel, &quot;sip_local_url&quot;, tech_pvt-&gt;local_url);
+                if (profile-&gt;pres_type) {
+                        switch_channel_set_variable(nchannel, &quot;presence_id&quot;, tech_pvt-&gt;local_url);
+                }
</ins><span class="cx">         }
</span><ins>+        switch_channel_set_variable(nchannel, &quot;sip_destination_url&quot;, tech_pvt-&gt;dest);
</ins><span class="cx"> 
</span><del>-        if (switch_event_create(&amp;s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;service&quot;, &quot;_sip._tcp&quot;);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;port&quot;, &quot;%d&quot;, profile-&gt;sip_port);
-                switch_event_fire(&amp;s_event);
</del><ins>+        caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
+        caller_profile-&gt;destination_number = switch_core_strdup(caller_profile-&gt;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);
</ins><span class="cx">         }
</span><ins>+        tech_pvt-&gt;caller_profile = caller_profile;
+        *new_session = nsession;
+        cause = SWITCH_CAUSE_SUCCESS;
</ins><span class="cx"> 
</span><del>-        if (switch_event_create(&amp;s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;service&quot;, &quot;_sip._sctp&quot;);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;port&quot;, &quot;%d&quot;, profile-&gt;sip_port);
-                switch_event_fire(&amp;s_event);
</del><ins>+        if ((hval = switch_event_get_header(var_event, &quot;sip_auto_answer&quot;)) &amp;&amp; switch_true(hval)) {
+                switch_channel_set_variable_printf(nchannel, &quot;sip_h_Call-Info&quot;, &quot;&lt;sip:%s&gt;;answer-after=0&quot;, profile-&gt;sipip);
+                switch_channel_set_variable(nchannel, &quot;sip_invite_params&quot;, &quot;intercom=true&quot;);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (session) {
+                switch_channel_t *o_channel = switch_core_session_get_channel(session);
+                const char *vval = NULL;
</ins><span class="cx"> 
</span><del>-        switch_mutex_lock(globals.hash_mutex);
-        switch_core_hash_insert(globals.profile_hash, profile-&gt;name, profile);
-        switch_mutex_unlock(globals.hash_mutex);
</del><ins>+                if ((vval = switch_channel_get_variable(o_channel, &quot;sip_auto_answer&quot;)) &amp;&amp; switch_true(vval)) {
+                        switch_channel_set_variable_printf(nchannel, &quot;sip_h_Call-Info&quot;, &quot;&lt;sip:%s&gt;;answer-after=0&quot;, profile-&gt;sipip);
+                        switch_channel_set_variable(nchannel, &quot;sip_invite_params&quot;, &quot;intercom=true&quot;);
+                }
+                
+                switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
+                switch_ivr_transfer_variable(session, nsession, &quot;sip_auto_answer&quot;);
+                switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T);
+                switch_ivr_transfer_variable(session, nsession, &quot;sip_video_fmtp&quot;);
+                switch_ivr_transfer_variable(session, nsession, &quot;sip-force-contact&quot;);
+                switch_ivr_transfer_variable(session, nsession, &quot;sip_sticky_contact&quot;);
+                switch_ivr_transfer_variable(session, nsession, &quot;sip_cid_type&quot;);
</ins><span class="cx"> 
</span><del>-        if (profile-&gt;pflags &amp; PFLAG_PRESENCE) {
-                establish_presence(profile);
-        }
</del><ins>+                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-&gt;bte = ctech_pvt-&gt;te;
+                        tech_pvt-&gt;bcng_pt = ctech_pvt-&gt;cng_pt;
+                }
</ins><span class="cx"> 
</span><ins>+                if (switch_channel_test_flag(o_channel, CF_PROXY_MEDIA)) {
+                        const char *r_sdp = switch_channel_get_variable(o_channel, SWITCH_R_SDP_VARIABLE);
</ins><span class="cx"> 
</span><del>-
-
-        while(globals.running == 1) {
-                if (++ireg_loops &gt;= IREG_SECONDS) {
-                        check_expire(db, profile, time(NULL));
-                        ireg_loops = 0;
</del><ins>+                        if (switch_stristr(&quot;m=video&quot;, r_sdp)) {
+                                sofia_glue_tech_choose_video_port(tech_pvt, 1);
+                                tech_pvt-&gt;video_rm_encoding = &quot;PROXY-VID&quot;;
+                                tech_pvt-&gt;video_rm_rate = 90000;
+                                tech_pvt-&gt;video_codec_ms = 0;
+                                switch_channel_set_flag(tech_pvt-&gt;channel, CF_VIDEO);
+                                sofia_set_flag(tech_pvt, TFLAG_VIDEO);
+                        }
</ins><span class="cx">                 }
</span><ins>+        }
</ins><span class="cx"> 
</span><del>-                if (++oreg_loops &gt;= OREG_SECONDS) {
-                        check_oreg(profile, time(NULL));
-                        oreg_loops = 0;
-                }
</del><ins>+        goto done;
</ins><span class="cx"> 
</span><del>-                su_root_step(profile-&gt;s_root, 1000);
</del><ins>+  error:
+        if (nsession) {
+                switch_core_session_destroy(&amp;nsession);
</ins><span class="cx">         }
</span><ins>+        *pool = NULL;
</ins><span class="cx"> 
</span><del>-        switch_core_db_close(db);
-        unreg(profile);
-        su_home_unref(profile-&gt;home);
-        
</del><ins>+  done:
</ins><span class="cx"> 
</span><del>-        if (switch_event_create(&amp;s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;service&quot;, &quot;_sip._udp&quot;);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;port&quot;, &quot;%d&quot;, profile-&gt;sip_port);
-                switch_event_fire(&amp;s_event);
</del><ins>+        if (profile) {
+                if (cause == SWITCH_CAUSE_SUCCESS) {
+                        profile-&gt;ob_calls++;
+                } else {
+                        profile-&gt;ob_failed_calls++;
+                }
+                sofia_glue_release_profile(profile);
</ins><span class="cx">         }
</span><del>-
-        su_root_destroy(profile-&gt;s_root);
-        pool = profile-&gt;pool;
-        switch_core_destroy_memory_pool(&amp;pool);
-        switch_mutex_lock(globals.mutex);
-        globals.running = 0;
-        switch_mutex_unlock(globals.mutex);
-        
-        return NULL;
</del><ins>+        return cause;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void launch_profile_thread(sofia_profile_t *profile)
</del><ins>+
+static int notify_callback(void *pArg, int argc, char **argv, char **columnNames)
</ins><span class="cx"> {
</span><del>-        switch_thread_t *thread;
-        switch_threadattr_t *thd_attr = NULL;
-        
-        switch_threadattr_create(&amp;thd_attr, profile-&gt;pool);
-        switch_threadattr_detach_set(thd_attr, 1);
-        switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
-        switch_thread_create(&amp;thread, thd_attr, profile_thread_run, profile, profile-&gt;pool);
-}
</del><span class="cx"> 
</span><ins>+        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;
</ins><span class="cx"> 
</span><ins>+        
+        if (profile_name &amp;&amp; strcasecmp(profile_name, profile-&gt;name)) {
+        if ((ext_profile = sofia_glue_find_profile(profile_name))) {
+            profile = ext_profile;
+        }
+    }
</ins><span class="cx"> 
</span><del>-static switch_status_t config_sofia(int reload)
-{
-        char *cf = &quot;sofia.conf&quot;;
-        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] = &quot;&quot;;
-        switch_mutex_lock(globals.mutex);
-        globals.running = 1;
-        switch_mutex_unlock(globals.mutex);
-
-        if (!(xml = switch_xml_open_cfg(cf, &amp;cfg, NULL))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;open of %s failed\n&quot;, cf);
-                status = SWITCH_STATUS_FALSE;
-                goto done;
</del><ins>+        id = switch_mprintf(&quot;sip:%s@%s&quot;, user, host);
+        switch_assert(id);
+        contact = sofia_glue_get_url_from_contact(contact_in, 1);
+                                
+        if ((p = strstr(contact, &quot;;fs_&quot;))) {
+                *p = '\0';
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if ((settings = switch_xml_child(cfg, &quot;global_settings&quot;))) {
-                for (param = switch_xml_child(settings, &quot;param&quot;); param; param = param-&gt;next) {
-                        char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
-                        char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
-                        if (!strcasecmp(var, &quot;log-level&quot;)) {
-                                su_log_set_level(NULL, atoi(val));
-                        } else if (!strcasecmp(var, &quot;log-level-trace&quot;)) {
-                                su_log_set_level(tport_log, atoi(val));
-                        }
-                }
-        }
</del><ins>+        nh = nua_handle(profile-&gt;nua, 
+                                        NULL, 
+                                        NUTAG_URL(contact), 
+                                        SIPTAG_FROM_STR(id), 
+                                        SIPTAG_TO_STR(id), 
+                                        SIPTAG_CONTACT_STR(profile-&gt;url), 
+                                        TAG_END());
+                                
+        nua_handle_bind(nh, &amp;mod_sofia_globals.destroy_private);
</ins><span class="cx"> 
</span><del>-        if ((profiles = switch_xml_child(cfg, &quot;profiles&quot;))) {
-                for (xprofile = switch_xml_child(profiles, &quot;profile&quot;); xprofile; xprofile = xprofile-&gt;next) {
-                        if (!(settings = switch_xml_child(xprofile, &quot;settings&quot;))) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;No Settings, check the new config!\n&quot;, cf);
-                        } else {
-                                char *xprofilename = (char *) switch_xml_attr_soft(xprofile, &quot;name&quot;);
-                                switch_memory_pool_t *pool = NULL;
</del><ins>+        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());
</ins><span class="cx"> 
</span><span class="cx">                                 
</span><del>-                                /* Setup the pool */
-                                if ((status = switch_core_new_memory_pool(&amp;pool)) != SWITCH_STATUS_SUCCESS) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Memory Error!\n&quot;);
-                                        goto done;
-                                }
</del><ins>+        free(id);
+        free(contact);
</ins><span class="cx"> 
</span><del>-                                if (!(profile = (sofia_profile_t *) switch_core_alloc(pool, sizeof(*profile)))) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Memory Error!\n&quot;);
-                                        goto done;
-                                }
</del><ins>+        if (ext_profile) {
+                sofia_glue_release_profile(ext_profile);
+        }        
</ins><span class="cx"> 
</span><del>-                                if (!xprofilename) {
-                                        xprofilename = &quot;unnamed&quot;;
-                                }
-                
-                                profile-&gt;pool = pool;
</del><ins>+        return 0;
+}
</ins><span class="cx"> 
</span><del>-                                profile-&gt;name = switch_core_strdup(profile-&gt;pool, xprofilename);
-                                snprintf(url, sizeof(url), &quot;sofia_reg_%s&quot;, xprofilename);
-                                profile-&gt;dbname = switch_core_strdup(profile-&gt;pool, url);
-                                switch_core_hash_init(&amp;profile-&gt;chat_hash, profile-&gt;pool);
</del><ins>+static void general_event_handler(switch_event_t *event)
+{
+        switch (event-&gt;event_id) {
+        case SWITCH_EVENT_NOTIFY:
+                {
+                        const char *profile_name = switch_event_get_header(event, &quot;profile&quot;);
+                        const char *ct = switch_event_get_header(event, &quot;content-type&quot;);
+                        const char *es = switch_event_get_header(event, &quot;event-string&quot;);
+                        const char *user = switch_event_get_header(event, &quot;user&quot;);
+                        const char *host = switch_event_get_header(event, &quot;host&quot;);
+                        const char *call_id = switch_event_get_header(event, &quot;call-id&quot;);
+                        const char *uuid = switch_event_get_header(event, &quot;uuid&quot;);
+                        const char *body = switch_event_get_body(event);
+                        const char *to_uri = switch_event_get_header(event, &quot;to-uri&quot;);
+                        const char *from_uri = switch_event_get_header(event, &quot;from-uri&quot;);
+                        sofia_profile_t *profile;
</ins><span class="cx"> 
</span><del>-                                profile-&gt;dtmf_duration = 100;                
-                                profile-&gt;codec_ms = 20;
</del><span class="cx"> 
</span><del>-                                for (param = switch_xml_child(settings, &quot;param&quot;); param; param = param-&gt;next) {
-                                        char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
-                                        char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
-
-                                        if (!strcasecmp(var, &quot;debug&quot;)) {
-                                                profile-&gt;debug = atoi(val);
-                                        } else if (!strcasecmp(var, &quot;use-rtp-timer&quot;) &amp;&amp; switch_true(val)) {
-                                                switch_set_flag(profile, TFLAG_TIMER);
-                                        } else if (!strcasecmp(var, &quot;inbound-no-media&quot;) &amp;&amp; switch_true(val)) {
-                                                switch_set_flag(profile, TFLAG_INB_NOMEDIA);
-                                        } else if (!strcasecmp(var, &quot;inbound-late-negotiation&quot;) &amp;&amp; switch_true(val)) {
-                                                switch_set_flag(profile, TFLAG_LATE_NEGOTIATION);
-                                        } else if (!strcasecmp(var, &quot;rfc2833-pt&quot;)) {
-                                                profile-&gt;te = (switch_payload_t) atoi(val);
-                                        } else if (!strcasecmp(var, &quot;sip-port&quot;)) {
-                                                profile-&gt;sip_port = atoi(val);
-                                        } else if (!strcasecmp(var, &quot;vad&quot;)) {
-                                                if (!strcasecmp(val, &quot;in&quot;)) {
-                                                        switch_set_flag(profile, TFLAG_VAD_IN);
-                                                } else if (!strcasecmp(val, &quot;out&quot;)) {
-                                                        switch_set_flag(profile, TFLAG_VAD_OUT);
-                                                } else if (!strcasecmp(val, &quot;both&quot;)) {
-                                                        switch_set_flag(profile, TFLAG_VAD_IN);
-                                                        switch_set_flag(profile, TFLAG_VAD_OUT);
-                                                } else {
-                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invald option %s for VAD\n&quot;, val);
-                                                }
-                                        } else if (!strcasecmp(var, &quot;ext-rtp-ip&quot;)) {
-                                                profile-&gt;extrtpip = switch_core_strdup(profile-&gt;pool, strcasecmp(val, &quot;auto&quot;) ? val : globals.guess_ip);
-                                        } else if (!strcasecmp(var, &quot;rtp-ip&quot;)) {
-                                                profile-&gt;rtpip = switch_core_strdup(profile-&gt;pool, strcasecmp(val, &quot;auto&quot;) ? val : globals.guess_ip);
-                                        } else if (!strcasecmp(var, &quot;sip-ip&quot;)) {
-                                                profile-&gt;sipip = switch_core_strdup(profile-&gt;pool, strcasecmp(val, &quot;auto&quot;) ? val : globals.guess_ip);
-                                        } else if (!strcasecmp(var, &quot;sip-domain&quot;)) {
-                                                profile-&gt;sipdomain = switch_core_strdup(profile-&gt;pool, val);
-                                        } else if (!strcasecmp(var, &quot;rtp-timer-name&quot;)) {
-                                                profile-&gt;timer_name = switch_core_strdup(profile-&gt;pool, val);
-                                        } else if (!strcasecmp(var, &quot;manage-presence&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_PRESENCE;
-                                                }
-                                        } else if (!strcasecmp(var, &quot;pass-rfc2833&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_PASS_RFC2833;
-                                                }
-                                        } else if (!strcasecmp(var, &quot;disable-transcoding&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_DISABLE_TRANSCODING;
-                                                }
-                                        } else if (!strcasecmp(var, &quot;auth-calls&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_AUTH_CALLS;
-                                                }
-                                        } else if (!strcasecmp(var, &quot;nonce-ttl&quot;)) {
-                        profile-&gt;nonce_ttl = atoi(val);
-                                        } else if (!strcasecmp(var, &quot;accept-blind-reg&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_BLIND_REG;
-                                                }
-                                        } else if (!strcasecmp(var, &quot;auth-all-packets&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_AUTH_ALL;
-                                                }
-                                        } else if (!strcasecmp(var, &quot;full-id-in-dialplan&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_FULL_ID;
-                                                }
-                                        } else if (!strcasecmp(var, &quot;ext-sip-ip&quot;)) {
-                                                profile-&gt;extsipip = switch_core_strdup(profile-&gt;pool, strcasecmp(val, &quot;auto&quot;) ? val : globals.guess_ip);
-                                        } else if (!strcasecmp(var, &quot;bitpacking&quot;)) {
-                                                if (!strcasecmp(val, &quot;aal2&quot;)) {
-                                                        profile-&gt;codec_flags = SWITCH_CODEC_FLAG_AAL2;
-                                                } 
-                                        } else if (!strcasecmp(var, &quot;username&quot;)) {
-                                                profile-&gt;username = switch_core_strdup(profile-&gt;pool, val);
-                                        } else if (!strcasecmp(var, &quot;context&quot;)) {
-                                                profile-&gt;context = switch_core_strdup(profile-&gt;pool, val);
-                                        } else if (!strcasecmp(var, &quot;alias&quot;)) {
-                                                sip_alias_node_t *node;
-                                                if ((node = switch_core_alloc(profile-&gt;pool, sizeof(*node)))) {
-                                                        if ((node-&gt;url = switch_core_strdup(profile-&gt;pool, val))) {
-                                                                node-&gt;next = profile-&gt;aliases;
-                                                                profile-&gt;aliases = node;
-                                                        }
-                                                }
-                                        } else if (!strcasecmp(var, &quot;dialplan&quot;)) {
-                                                profile-&gt;dialplan = switch_core_strdup(profile-&gt;pool, val);
-                                        } else if (!strcasecmp(var, &quot;max-calls&quot;)) {
-                                                profile-&gt;max_calls = atoi(val);
-                                        } else if (!strcasecmp(var, &quot;codec-prefs&quot;)) {
-                                                profile-&gt;codec_string = switch_core_strdup(profile-&gt;pool, val);
-                                        } else if (!strcasecmp(var, &quot;codec-ms&quot;)) {
-                                                profile-&gt;codec_ms = atoi(val);
-                                        } else if (!strcasecmp(var, &quot;dtmf-duration&quot;)) {
-                                                int dur = atoi(val);
-                                                if (dur &gt; 10 &amp;&amp; dur &lt; 8000) {
-                                                        profile-&gt;dtmf_duration = dur;
-                                                } else {
-                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Duration out of bounds!\n&quot;);
-                                                }
-                                        }
</del><ins>+                        if (to_uri || from_uri) {
+                                
+                                if (!to_uri) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing To-URI header\n&quot;);
+                                        return;
</ins><span class="cx">                                 }
</span><del>-
-                if (!profile-&gt;sipip) {
-                    profile-&gt;sipip = switch_core_strdup(profile-&gt;pool, globals.guess_ip);
-                }
-
-                if (!profile-&gt;rtpip) {
-                    profile-&gt;rtpip = switch_core_strdup(profile-&gt;pool, globals.guess_ip);
-                }
-
-                if (profile-&gt;nonce_ttl &lt; 60) {
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Setting nonce TTL to 60 seconds\n&quot;);
-                    profile-&gt;nonce_ttl = 60;
-                }
-
-                                if (switch_test_flag(profile, TFLAG_TIMER) &amp;&amp; !profile-&gt;timer_name) {
-                                        profile-&gt;timer_name = switch_core_strdup(profile-&gt;pool, &quot;soft&quot;);                        
</del><ins>+                                
+                                if (!from_uri) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing From-URI header\n&quot;);
+                                        return;
</ins><span class="cx">                                 }
</span><del>-
-                                if (!profile-&gt;username) {
-                                        profile-&gt;username = switch_core_strdup(profile-&gt;pool, &quot;FreeSWITCH&quot;);
</del><ins>+                                
+                                if (!es) {
+                                        es = &quot;message-summary&quot;;
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (!profile-&gt;rtpip) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Setting ip to '127.0.0.1'\n&quot;);
-                                        profile-&gt;rtpip = switch_core_strdup(profile-&gt;pool, &quot;127.0.0.1&quot;);
</del><ins>+                                if (!ct) {
+                                        ct = &quot;application/simple-message-summary&quot;;
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (!profile-&gt;sip_port) {
-                                        profile-&gt;sip_port = 5060;
</del><ins>+                                if (!profile_name) {
+                                        profile_name = &quot;default&quot;;
</ins><span class="cx">                                 }
</span><del>-
-                                if (!profile-&gt;dialplan) {
-                                        profile-&gt;dialplan = switch_core_strdup(profile-&gt;pool, &quot;XML&quot;);
</del><ins>+                                
+                                if (!(profile = sofia_glue_find_profile(profile_name))) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't find profile %s\n&quot;, profile_name);
+                                        return;
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (!profile-&gt;sipdomain) {
-                                        profile-&gt;sipdomain = switch_core_strdup(profile-&gt;pool, profile-&gt;sipip);
</del><ins>+                                
+                                if (to_uri &amp;&amp; from_uri &amp;&amp; ct &amp;&amp; es &amp;&amp; profile_name &amp;&amp; (profile = sofia_glue_find_profile(profile_name))) {
+                                        nua_handle_t *nh = nua_handle(profile-&gt;nua, 
+                                                                                                  NULL, 
+                                                                                                  NUTAG_URL(to_uri), 
+                                                                                                  SIPTAG_FROM_STR(from_uri), 
+                                                                                                  SIPTAG_TO_STR(to_uri), 
+                                                                                                  SIPTAG_CONTACT_STR(profile-&gt;url), 
+                                                                                                  TAG_END());
+                                
+                                        nua_handle_bind(nh, &amp;mod_sofia_globals.destroy_private);
+                                
+                                        nua_notify(nh,
+                                                           NUTAG_NEWSUB(1),
+                                                           NUTAG_WITH_THIS(profile-&gt;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);
</ins><span class="cx">                                 }
</span><del>-                                if (profile-&gt;extsipip) {
-                                        profile-&gt;url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:%d&quot;, profile-&gt;extsipip, profile-&gt;sip_port);
-                                        profile-&gt;bindurl = switch_core_sprintf(profile-&gt;pool, &quot;%s;maddr=%s&quot;, profile-&gt;url, profile-&gt;sipip);
-                                } else {
-                                        profile-&gt;url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:%d&quot;, profile-&gt;sipip, profile-&gt;sip_port);
-                                        profile-&gt;bindurl = profile-&gt;url;
-                                }
</del><ins>+
+                                return;
</ins><span class="cx">                         }
</span><del>-                        if (profile) {
-                                if ((registrations = switch_xml_child(xprofile, &quot;registrations&quot;))) {
-                                        for (registration = switch_xml_child(registrations, &quot;registration&quot;); registration; registration = registration-&gt;next) {
-                                                char *name = (char *) switch_xml_attr_soft(registration, &quot;name&quot;);
-                                                outbound_reg_t *oreg;
</del><span class="cx"> 
</span><del>-                                                if (switch_strlen_zero(name)) {
-                                                        name = &quot;anonymous&quot;;
-                                                }
</del><ins>+                        if (uuid &amp;&amp; ct &amp;&amp; es) {
+                                switch_core_session_t *session;
+                                private_object_t *tech_pvt;
</ins><span class="cx"> 
</span><del>-                                                if ((oreg = switch_core_alloc(profile-&gt;pool, sizeof(*oreg)))) {
-                                                        oreg-&gt;pool = profile-&gt;pool;
-                                                        oreg-&gt;profile = profile;
-                                                        oreg-&gt;name = switch_core_strdup(oreg-&gt;pool, name);
-                                                        oreg-&gt;freq = 0;
-
-                                                        for (param = switch_xml_child(registration, &quot;param&quot;); param; param = param-&gt;next) {
-                                                                char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
-                                                                char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
-                                                                
-                                                                if (!strcmp(var, &quot;register-scheme&quot;)) {
-                                                                        oreg-&gt;register_scheme = switch_core_strdup(oreg-&gt;pool, val);
-                                                                } else if (!strcmp(var, &quot;register-realm&quot;)) {
-                                                                        oreg-&gt;register_realm = switch_core_strdup(oreg-&gt;pool, val);
-                                                                } else if (!strcmp(var, &quot;register-username&quot;)) {
-                                                                        oreg-&gt;register_username = switch_core_strdup(oreg-&gt;pool, val);
-                                                                } else if (!strcmp(var, &quot;register-password&quot;)) {
-                                                                        oreg-&gt;register_password = switch_core_strdup(oreg-&gt;pool, val);
-                                                                } else if (!strcmp(var, &quot;register-from&quot;)) {
-                                                                        oreg-&gt;register_from = switch_core_strdup(oreg-&gt;pool, val);
-                                                                } else if (!strcmp(var, &quot;register-to&quot;)) {
-                                                                        oreg-&gt;register_to = switch_core_strdup(oreg-&gt;pool, val);
-                                                                } else if (!strcmp(var, &quot;register-proxy&quot;)) {
-                                                                        oreg-&gt;register_proxy = switch_core_strdup(oreg-&gt;pool, val);
-                                                                } else if (!strcmp(var, &quot;register-frequency&quot;)) {
-                                                                        oreg-&gt;expires_str = switch_core_strdup(oreg-&gt;pool, val);
-                                                                }
-                                                        }
-                                                        if (switch_strlen_zero(oreg-&gt;register_scheme)) {
-                                                                oreg-&gt;register_scheme = switch_core_strdup(oreg-&gt;pool, &quot;Digest&quot;);
-                                                        }
-                                                        if (switch_strlen_zero(oreg-&gt;register_realm)) {
-                                                                oreg-&gt;register_realm = switch_core_strdup(oreg-&gt;pool, &quot;freeswitch.org&quot;);
-                                                        }
-                                                        if (switch_strlen_zero(oreg-&gt;register_username)) {
-                                                                oreg-&gt;register_username = switch_core_strdup(oreg-&gt;pool, &quot;freeswitch&quot;);
-                                                        }
-                                                        if (switch_strlen_zero(oreg-&gt;register_password)) {
-                                                                oreg-&gt;register_password = switch_core_strdup(oreg-&gt;pool, &quot;works&quot;);
-                                                        }                                                        
-                                                        if (switch_strlen_zero(oreg-&gt;register_from)) {
-                                                                oreg-&gt;register_from = switch_core_strdup(oreg-&gt;pool, &quot;FreeSWITCH &lt;sip:freeswitch@freeswitch.org&gt;&quot;);
-                                                        }
-                                                        if (switch_strlen_zero(oreg-&gt;register_to)) {
-                                                                oreg-&gt;register_to = switch_core_strdup(oreg-&gt;pool, &quot;sip:freeswitch@freeswitch.org&quot;);
-                                                        }
-                                                        if (switch_strlen_zero(oreg-&gt;register_proxy)) {
-                                                                oreg-&gt;register_proxy = switch_core_strdup(oreg-&gt;pool, &quot;sip:freeswitch@freeswitch.org&quot;);
-                                                        }
-
-                                                        if (switch_strlen_zero(oreg-&gt;expires_str)) {
-                                                                oreg-&gt;expires_str = switch_core_strdup(oreg-&gt;pool, &quot;300&quot;);
-                                                        }
-
-                                                        if ((oreg-&gt;freq = atoi(oreg-&gt;expires_str)) &lt; 5) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid Freq: %d.  Setting Register-Frequency to 5\n&quot;, oreg-&gt;freq);
-                                oreg-&gt;freq = 5;
-                            }
-                            oreg-&gt;freq -= 2;
-
-                                                        oreg-&gt;next = profile-&gt;registrations;
-                                                        profile-&gt;registrations = oreg;
-
-                                                }
</del><ins>+                                if ((session = switch_core_session_locate(uuid))) {
+                                        if ((tech_pvt = switch_core_session_get_private(session))) {
+                                                nua_notify(tech_pvt-&gt;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());
</ins><span class="cx">                                         }
</span><ins>+                                        switch_core_session_rwunlock(session);
</ins><span class="cx">                                 }
</span><ins>+                        } else if (profile_name &amp;&amp; ct &amp;&amp; es &amp;&amp; user &amp;&amp; host &amp;&amp; (profile = sofia_glue_find_profile(profile_name))) {
+                                char *sql;
</ins><span class="cx"> 
</span><del>-                                if (profile-&gt;sipip) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Started Profile %s [%s]\n&quot;, profile-&gt;name, url);
-                                        launch_profile_thread(profile);
</del><ins>+                                if (call_id) {
+                                        sql = switch_mprintf(&quot;select sip_user,sip_host,contact,profile_name,'%q','%q','%q' &quot;
+                                                                                 &quot;from sip_registrations where call_id='%q'&quot;, ct, es, switch_str_nil(body), call_id
+                                                                                 );
</ins><span class="cx">                                 } else {
</span><del>-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Unable to start Profile %s due to no configured sip-ip\n&quot;, profile-&gt;name);
</del><ins>+                                        sql = switch_mprintf(&quot;select sip_user,sip_host,contact,profile_name,'%q','%q','%q' &quot;
+                                                                                 &quot;from sip_registrations where sip_user='%s' and sip_host='%q'&quot;,
+                                                                                 ct, es, switch_str_nil(body), switch_str_nil(user), switch_str_nil(host)
+                                                                                 );
</ins><span class="cx">                                 }
</span><del>-                                profile = NULL;
-                        }
-                }
-        }
- done:
-        if (xml) {
-                switch_xml_free(xml);
-        }
</del><ins>+                                
</ins><span class="cx"> 
</span><del>-        return status;
</del><ins>+                                switch_mutex_lock(profile-&gt;ireg_mutex);
+                                sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, notify_callback, profile);
+                                switch_mutex_unlock(profile-&gt;ireg_mutex);
+                                sofia_glue_release_profile(profile);
</ins><span class="cx"> 
</span><del>-}
-
-static void event_handler(switch_event_t *event)
-{
-        char *subclass, *sql;
-
-        if ((subclass = switch_event_get_header(event, &quot;orig-event-subclass&quot;)) &amp;&amp; !strcasecmp(subclass, MY_EVENT_REGISTER)) {
-                char *from_user = switch_event_get_header(event, &quot;orig-from-user&quot;);
-                char *from_host = switch_event_get_header(event, &quot;orig-from-host&quot;);
-                char *contact_str = switch_event_get_header(event, &quot;orig-contact&quot;);
-                char *exp_str = switch_event_get_header(event, &quot;orig-expires&quot;);
-                char *rpid = switch_event_get_header(event, &quot;orig-rpid&quot;);
-                long expires = (long)time(NULL) + atol(exp_str);
-                char *profile_name = switch_event_get_header(event, &quot;orig-profile-name&quot;);
-                sofia_profile_t *profile;
-                char buf[512];
-
-                if (!rpid) {
-                        rpid = &quot;unknown&quot;;
-                }
-
-                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, &quot;Invalid Profile\n&quot;);
-                        return;
-                }
-
-
-                if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
-                        sql = switch_mprintf(&quot;insert into sip_registrations values ('%q','%q','%q','Regestered', '%q', %ld)&quot;, 
-                                                                 from_user,
-                                                                 from_host,
-                                                                 contact_str,
-                                                                 rpid,
-                                                                 expires);
-                } else {
-                        sql = switch_mprintf(&quot;update sip_registrations set contact='%q', rpid='%q', expires=%ld where user='%q' and host='%q'&quot;,
-                                                                 contact_str,
-                                                                 rpid,
-                                                                 expires,
-                                                                 from_user,
-                                                                 from_host);
</del><ins>+                                free(sql);
+                        }
</ins><span class="cx">                         
</span><span class="cx">                 }
</span><del>-        
-                if (sql) {
-                        execute_sql(profile-&gt;dbname, sql, profile-&gt;ireg_mutex);
-                        switch_safe_free(sql);
-                        sql = NULL;
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Propagating registration for %s@%s-&gt;%s\n&quot;, 
-                                                          from_user, from_host, contact_str);
</del><ins>+                break;
+        case SWITCH_EVENT_SEND_MESSAGE:
+                {
+                        const char *profile_name = switch_event_get_header(event, &quot;profile&quot;);
+                        const char *ct = switch_event_get_header(event, &quot;content-type&quot;);
+                        const char *user = switch_event_get_header(event, &quot;user&quot;);
+                        const char *host = switch_event_get_header(event, &quot;host&quot;);
+                        const char *body = switch_event_get_body(event);
+                        sofia_profile_t *profile;
+                        nua_handle_t *nh;
</ins><span class="cx"> 
</span><del>-                }
</del><ins>+                        if (profile_name &amp;&amp; ct &amp;&amp; user &amp;&amp; host) {
+                                char *id = NULL;
+                                char *contact, *p;
+                                char buf[512] = &quot;&quot;;
</ins><span class="cx"> 
</span><del>-        }
-}
</del><ins>+                                if (!(profile = sofia_glue_find_profile(profile_name))) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't find profile %s\n&quot;, profile_name);
+                                        return;
+                                }
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-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;
</del><ins>+                                if (!sofia_reg_find_reg_url(profile, user, host, buf, sizeof(buf))) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't find user %s@%s\n&quot;, user, host);
+                                        return;
+                                }
</ins><span class="cx"> 
</span><del>-        if (to &amp;&amp; (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, &quot;Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n&quot;, 
-                              proto,
-                              from,
-                              to,
-                              body ? body : &quot;[no body]&quot;,
-                              host ? host : &quot;NULL&quot;);
-                        return SWITCH_STATUS_FALSE;
-                }
</del><ins>+                                id = switch_mprintf(&quot;sip:%s@%s&quot;, user, host);
</ins><span class="cx"> 
</span><del>-        if (!find_reg_url(profile, user, host, buf, sizeof(buf))) {
-                        return SWITCH_STATUS_FALSE;
-                }
</del><ins>+                                switch_assert(id);
+                                contact = sofia_glue_get_url_from_contact(buf, 0);
+                                
+                                if ((p = strstr(contact, &quot;;fs_&quot;))) {
+                                        *p = '\0';
+                                }
+                                
+                                nh = nua_handle(profile-&gt;nua, 
+                                                                NULL, 
+                                                                NUTAG_URL(contact), 
+                                                                SIPTAG_FROM_STR(id), 
+                                                                SIPTAG_TO_STR(id), 
+                                                                SIPTAG_CONTACT_STR(profile-&gt;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());
</ins><span class="cx"> 
</span><del>-                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, &quot;Memory Error!\n&quot;);
-                                return SWITCH_STATUS_FALSE;
</del><ins>+                                
+                                free(id);
+                                sofia_glue_release_profile(profile);
</ins><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        if ((p = strchr(fp, '@'))) {
-                                *p = '\0';
-                                fu = strdup(fp);
-                                *p = '+';
-                        }
-                        
-                        ffrom = switch_mprintf(&quot;\&quot;%s\&quot; &lt;sip:%s+%s@%s&gt;&quot;, fu, proto, fp, profile-&gt;name);                        
-                        from = ffrom;
-                        switch_safe_free(fu);
-                        switch_safe_free(fp);
</del><span class="cx">                 }
</span><ins>+                break;
+        case SWITCH_EVENT_SEND_INFO:
+                {
+                        const char *profile_name = switch_event_get_header(event, &quot;profile&quot;);
+                        const char *ct = switch_event_get_header(event, &quot;content-type&quot;);
+                        const char *to_uri = switch_event_get_header(event, &quot;to-uri&quot;);
+                        const char *local_user_full = switch_event_get_header(event, &quot;local-user&quot;);
+                        const char *from_uri = switch_event_get_header(event, &quot;from-uri&quot;);
+                        const char *call_info = switch_event_get_header(event, &quot;call-info&quot;);
+                        const char *alert_info = switch_event_get_header(event, &quot;alert-info&quot;);
+                        const char *call_id = switch_event_get_header(event, &quot;call-id&quot;);
+                        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] = &quot;&quot;;
+                        char *p;
</ins><span class="cx"> 
</span><del>-                contact = get_url_from_contact(buf, 1);
-                msg_nh = nua_handle(profile-&gt;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-&gt;url),
-                                                        TAG_END());
</del><ins>+                        if (!profile_name) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing Profile Name\n&quot;);
+                goto done;
+            }
</ins><span class="cx"> 
</span><del>-                switch_safe_free(contact);
</del><ins>+            if (!call_id &amp;&amp; !to_uri &amp;&amp; !local_user_full) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing To-URI header\n&quot;);
+                goto done;
+            }
</ins><span class="cx"> 
</span><ins>+            if (!call_id &amp;&amp; !from_uri) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing From-URI header\n&quot;);
+                goto done;
+            }
</ins><span class="cx"> 
</span><del>-                nua_message(msg_nh,
-                                        SIPTAG_CONTENT_TYPE_STR(&quot;text/html&quot;),
-                                        SIPTAG_PAYLOAD_STR(body),
-                                        TAG_END());
-                
-                
-                switch_safe_free(ffrom);
-                free(user);
-        }
-                
-        return SWITCH_STATUS_SUCCESS;
-}
</del><span class="cx"> 
</span><del>-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;
</del><ins>+            if (!(profile = sofia_glue_find_profile(profile_name))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't find profile %s\n&quot;, profile_name);
+                goto done;
+            }
</ins><span class="cx"> 
</span><del>-        if ((sql = switch_mprintf(&quot;select 0,'unavailable','unavailable',* from sip_subscriptions where event='presence'&quot;))) {
-                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, &amp;val);
-                        profile = (sofia_profile_t *) val;
-                        if (!(profile-&gt;pflags &amp; PFLAG_PRESENCE)) {
-                                continue;
-                        }
</del><ins>+                        if (call_id) {
+                                nh = nua_handle_by_call_id(profile-&gt;nua, call_id);
</ins><span class="cx"> 
</span><del>-                        if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                                continue;
</del><ins>+                                if (!nh) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Call-ID %s\n&quot;, call_id);
+                                        goto done;
+                                }
</ins><span class="cx">                         }
</span><del>-                        switch_mutex_lock(profile-&gt;ireg_mutex);
-                        switch_core_db_exec(db, sql, sub_callback, profile, &amp;errmsg);
-                        switch_mutex_unlock(profile-&gt;ireg_mutex);
-                        switch_core_db_close(db);
-                }
-                switch_safe_free(sql);
-        }
</del><span class="cx"> 
</span><del>-}
</del><ins>+                        else {
+                                if (local_user_full) {
+                                        local_dup = strdup(local_user_full);
+                                        local_user = local_dup;
+                                        if ((local_host = strchr(local_user, '@'))) {
+                                                *local_host++ = '\0';
+                                        }
</ins><span class="cx"> 
</span><del>-static void establish_presence(sofia_profile_t *profile) 
-{
-        char *sql, *errmsg = NULL;
-        switch_core_db_t *db;
</del><ins>+                                        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, &quot;Can't find local user\n&quot;);
+                                                goto done;
+                                        }
</ins><span class="cx"> 
</span><del>-        if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                return;
-        }
</del><ins>+                                        to_uri = sofia_glue_get_url_from_contact(buf, 0);
+                                        
+                                        if ((p = strstr(to_uri, &quot;;fs_&quot;))) {
+                                                *p = '\0';
+                                        }
</ins><span class="cx"> 
</span><del>-        if ((sql = switch_mprintf(&quot;select user,host,'Registered','unknown','' from sip_registrations&quot;))) {
-                switch_mutex_lock(profile-&gt;ireg_mutex);
-                switch_core_db_exec(db, sql, resub_callback, profile, &amp;errmsg);
-                switch_mutex_unlock(profile-&gt;ireg_mutex);
-                switch_safe_free(sql);
-        }
</del><ins>+                                }
</ins><span class="cx"> 
</span><del>-        if ((sql = switch_mprintf(&quot;select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions &quot;
-                                                          &quot;where proto='ext' or proto='user' or proto='conf'&quot;))) {
-                switch_mutex_lock(profile-&gt;ireg_mutex);
-                switch_core_db_exec(db, sql, resub_callback, profile, &amp;errmsg);
-                switch_mutex_unlock(profile-&gt;ireg_mutex);
-                switch_safe_free(sql);
-        }
</del><span class="cx"> 
</span><del>-        switch_core_db_close(db);
-
-}
-
-
-
-static char *translate_rpid(char *in, char *ext)
-{
-        char *r = NULL;
-
-        if (in &amp;&amp; (strstr(in, &quot;null&quot;) || strstr(in, &quot;NULL&quot;))) {
-                in = NULL;
-        }
-
-        if (!in) {
-                in = ext;
-        }
-
-        if (!in) {
-                return NULL;
-        }
-        
-        if (!strcasecmp(in, &quot;dnd&quot;)) {
-                r = &quot;busy&quot;;
-        }
-
-        if (ext &amp;&amp; !strcasecmp(ext, &quot;away&quot;)) {
-                r = &quot;idle&quot;;
-        }
-        
-        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, &quot;from&quot;);
-        char *proto = switch_event_get_header(event, &quot;proto&quot;);
-        char *rpid = switch_event_get_header(event, &quot;rpid&quot;);
-        char *status= switch_event_get_header(event, &quot;status&quot;);
-        char *event_type = switch_event_get_header(event, &quot;event_type&quot;);
-        //char *event_subtype = switch_event_get_header(event, &quot;event_subtype&quot;);
-        char *sql = NULL;
-        char *euser = NULL, *user = NULL, *host = NULL;
-        char *errmsg;
-        switch_core_db_t *db;
-
-
-        if (rpid &amp;&amp; !strcasecmp(rpid, &quot;n/a&quot;)) {
-                rpid = NULL;
-        }
-
-        if (status &amp;&amp; !strcasecmp(status, &quot;n/a&quot;)) {
-                status = NULL;
-        }
-
-        if (rpid) {
-                rpid = translate_rpid(rpid, status);
-        } 
-
-        if (!status) {
-                status = &quot;Available&quot;;
-
-                if (rpid) {
-                        if (!strcasecmp(rpid, &quot;busy&quot;)) {
-                                status = &quot;Busy&quot;;
-                        } else if (!strcasecmp(rpid, &quot;unavailable&quot;)) {
-                                status = &quot;Idle&quot;;
-                        } else if (!strcasecmp(rpid, &quot;away&quot;)) {
-                                status = &quot;Idle&quot;;
</del><ins>+                                nh = nua_handle(profile-&gt;nua, 
+                                                                NULL, 
+                                                                NUTAG_URL(to_uri), 
+                                                                SIPTAG_FROM_STR(from_uri), 
+                                                                SIPTAG_TO_STR(to_uri), 
+                                                                SIPTAG_CONTACT_STR(profile-&gt;url), 
+                                                                TAG_END());
+                                
+                                nua_handle_bind(nh, &amp;mod_sofia_globals.destroy_private);
</ins><span class="cx">                         }
</span><del>-                }
-        }
</del><span class="cx"> 
</span><del>-        if (!rpid) {
-                rpid = &quot;unknown&quot;;
-        }
</del><ins>+                        nua_info(nh,
+                                         NUTAG_WITH_THIS(profile-&gt;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());
</ins><span class="cx"> 
</span><del>-        if (event-&gt;event_id == SWITCH_EVENT_ROSTER) {
-
-                if (from) {
-                        sql = switch_mprintf(&quot;select 1,'%q','%q',* from sip_subscriptions where event='presence' and full_from like '%%%q%%'&quot;, status, rpid, from);
-                } else {
-                        sql = switch_mprintf(&quot;select 1,'%q','%q',* from sip_subscriptions where event='presence'&quot;, 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, &amp;val);
-                        profile = (sofia_profile_t *) val;
-                        if (!(profile-&gt;pflags &amp; PFLAG_PRESENCE)) {
-                                continue;
</del><ins>+                        if (call_id &amp;&amp; nh) {
+                                nua_handle_unref(nh);
</ins><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        if (sql) {
-                                if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                                        continue;
-                                }
-                                switch_mutex_lock(profile-&gt;ireg_mutex);
-                                switch_core_db_exec(db, sql, sub_callback, profile, &amp;errmsg);
-                                switch_mutex_unlock(profile-&gt;ireg_mutex);
-                                switch_core_db_close(db);
</del><ins>+                        if (profile) {
+                                sofia_glue_release_profile(profile);
</ins><span class="cx">                         }
</span><ins>+                        
+                done:
</ins><span class="cx"> 
</span><ins>+                        switch_safe_free(local_dup);
+                        
</ins><span class="cx">                 }
</span><ins>+                break;
+        case SWITCH_EVENT_TRAP:
+                {
+                        const char *cond = switch_event_get_header(event, &quot;condition&quot;);
</ins><span class="cx"> 
</span><del>-                return;
-        }
</del><ins>+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;EVENT_TRAP: IP change detected\n&quot;);
</ins><span class="cx"> 
</span><del>-        if (switch_strlen_zero(event_type)) {
-                event_type=&quot;presence&quot;;
-        }
</del><ins>+                        if (cond &amp;&amp; !strcmp(cond, &quot;network-address-change&quot;) &amp;&amp; mod_sofia_globals.auto_restart) {
+                                const char *old_ip4 = switch_event_get_header_nil(event, &quot;network-address-previous-v4&quot;);
+                                const char *new_ip4 = switch_event_get_header_nil(event, &quot;network-address-change-v4&quot;);
+                                const char *old_ip6 = switch_event_get_header_nil(event, &quot;network-address-previous-v6&quot;);
+                                const char *new_ip6 = switch_event_get_header_nil(event, &quot;network-address-change-v6&quot;);
+                                switch_hash_index_t *hi;
+                                const void *var;
+                                void *val;
+                                sofia_profile_t *profile;
</ins><span class="cx"> 
</span><del>-        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;
-        }
</del><ins>+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;IP change detected [%s]-&gt;[%s] [%s]-&gt;[%s]\n&quot;, old_ip4, new_ip4, old_ip6, new_ip6);
</ins><span class="cx"> 
</span><ins>+                                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, &amp;var, NULL, &amp;val);
+                                                if ((profile = (sofia_profile_t *) val) &amp;&amp; profile-&gt;auto_restart) {
+                                                        if (!strcmp(profile-&gt;sipip, old_ip4)) {
+                                                                profile-&gt;sipip = switch_core_strdup(profile-&gt;pool, new_ip4);
+                                                                rb++;
+                                                        }
+                                                        if (!strcmp(profile-&gt;rtpip, old_ip4)) {
+                                                                profile-&gt;rtpip = switch_core_strdup(profile-&gt;pool, new_ip4);
+                                                                rb++;
+                                                        }
+                                                        if (!strcmp(profile-&gt;sipip, old_ip6)) {
+                                                                profile-&gt;sipip = switch_core_strdup(profile-&gt;pool, new_ip6);
+                                                                rb++;
+                                                        }
+                                                        if (!strcmp(profile-&gt;rtpip, old_ip6)) {
+                                                                profile-&gt;rtpip = switch_core_strdup(profile-&gt;pool, new_ip6);
+                                                                rb++;
+                                                        }
</ins><span class="cx"> 
</span><del>-        switch(event-&gt;event_id) {
-    case SWITCH_EVENT_PRESENCE_PROBE: 
-        if (proto) {
-            switch_core_db_t *db = NULL;
-            char *to = switch_event_get_header(event, &quot;to&quot;);
-            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 &amp;&amp; host &amp;&amp; 
-                (sql = switch_mprintf(&quot;select user,host,status,rpid,'' from sip_registrations where user='%q' and host='%q'&quot;, euser, host)) &amp;&amp;
-                (profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, host))) {
-                if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
-                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                    switch_safe_free(user);
-                    switch_safe_free(sql);
-                    return;
-                }
-
-                switch_mutex_lock(profile-&gt;ireg_mutex);
-                switch_core_db_exec(db, sql, resub_callback, profile, &amp;errmsg);
-                switch_mutex_unlock(profile-&gt;ireg_mutex);
-                switch_safe_free(sql);
-            }
-            switch_safe_free(user);
-            switch_core_db_close(db);
-        }
-        return;
-        case SWITCH_EVENT_PRESENCE_IN:
-                sql = switch_mprintf(&quot;select 1,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'&quot;, 
-                                                         status , rpid, proto, event_type, euser, host);
</del><ins>+                                                        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();
+                        }
+                        
+                }
</ins><span class="cx">                 break;
</span><del>-        case SWITCH_EVENT_PRESENCE_OUT:
-                sql = switch_mprintf(&quot;select 0,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'&quot;, 
-                                                         status, rpid, proto, event_type, euser, host);
-                break;
</del><span class="cx">         default:
</span><span class="cx">                 break;
</span><span class="cx">         }
</span><del>-
-    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, &amp;val);
-        profile = (sofia_profile_t *) val;
-        if (!(profile-&gt;pflags &amp; PFLAG_PRESENCE)) {
-                        continue;
-        }
-
-                if (sql) {
-                        if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
-                                continue;
-                        }
-                        switch_mutex_lock(profile-&gt;ireg_mutex);
-                        switch_core_db_exec(db, sql, sub_callback, profile, &amp;errmsg);
-                        switch_mutex_unlock(profile-&gt;ireg_mutex);
-                        
-                        switch_core_db_close(db);
-                }
-        }
-
-        switch_safe_free(sql);
-        switch_safe_free(user);
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
</del><ins>+SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
</ins><span class="cx"> {
</span><ins>+        switch_chat_interface_t *chat_interface;
+        switch_api_interface_t *api_interface;
+        switch_management_interface_t *management_interface;
+        struct in_addr in;
</ins><span class="cx"> 
</span><span class="cx">         silence_frame.data = silence_data;
</span><span class="cx">         silence_frame.datalen = sizeof(silence_data);
</span><span class="cx">         silence_frame.buflen = sizeof(silence_data);
</span><span class="cx">         silence_frame.flags = SFF_CNG;
</span><span class="cx"> 
</span><ins>+        memset(&amp;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(&amp;mod_sofia_globals.mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool);
</ins><span class="cx"> 
</span><del>-        if (switch_core_new_memory_pool(&amp;module_pool) != SWITCH_STATUS_SUCCESS) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;OH OH no pool\n&quot;);
-                return SWITCH_STATUS_TERM;
-        }
</del><ins>+        switch_find_local_ip(mod_sofia_globals.guess_ip, sizeof(mod_sofia_globals.guess_ip), &amp;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));
</ins><span class="cx"> 
</span><del>-        memset(&amp;globals, 0, sizeof(globals));
-        switch_mutex_init(&amp;globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
</del><span class="cx"> 
</span><del>-    switch_find_local_ip(globals.guess_ip, sizeof(globals.guess_ip), AF_INET);
</del><ins>+        switch_core_hash_init(&amp;mod_sofia_globals.profile_hash, mod_sofia_globals.pool);
+        switch_core_hash_init(&amp;mod_sofia_globals.gateway_hash, mod_sofia_globals.pool);
+        switch_mutex_init(&amp;mod_sofia_globals.hash_mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool);
</ins><span class="cx"> 
</span><del>-        if (switch_event_bind((char *) modname, SWITCH_EVENT_CUSTOM, MULTICAST_EVENT, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</del><ins>+        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(&quot;nat_type&quot;) ? 1 : 0);
+
+        switch_queue_create(&amp;mod_sofia_globals.presence_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
+        switch_queue_create(&amp;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, &quot;Waiting for profiles to start\n&quot;);
+        switch_yield(1500000);
+
+        if (switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, MULTICAST_EVENT, event_handler, NULL,
+                                                                        &amp;mod_sofia_globals.custom_node) != SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
</span><span class="cx">                 return SWITCH_STATUS_TERM;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        su_init();
-        su_log_redirect(NULL, logger, NULL);
-        su_log_redirect(tport_log, logger, NULL);
</del><ins>+        if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+                                                                        &amp;mod_sofia_globals.in_node) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
+                return SWITCH_STATUS_GENERR;
+        }
</ins><span class="cx"> 
</span><del>-        switch_core_hash_init(&amp;globals.profile_hash, module_pool);
-        switch_mutex_init(&amp;globals.hash_mutex, SWITCH_MUTEX_NESTED, module_pool);
</del><ins>+        if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+                                                                        &amp;mod_sofia_globals.out_node) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
+                return SWITCH_STATUS_GENERR;
+        }
</ins><span class="cx"> 
</span><del>-        config_sofia(0);
</del><ins>+        if (switch_event_bind_removable(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+                                                                        &amp;mod_sofia_globals.probe_node) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
+                return SWITCH_STATUS_GENERR;
+        }
</ins><span class="cx"> 
</span><ins>+        if (switch_event_bind_removable(modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL,
+                                                                        &amp;mod_sofia_globals.roster_node) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
+                return SWITCH_STATUS_GENERR;
+        }
</ins><span class="cx"> 
</span><del>-        if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</del><ins>+        if (switch_event_bind_removable(modname, SWITCH_EVENT_MESSAGE_WAITING, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_mwi_event_handler, NULL,
+                                                                        &amp;mod_sofia_globals.mwi_node) != SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
</span><span class="cx">                 return SWITCH_STATUS_GENERR;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</del><ins>+        if (switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
</span><span class="cx">                 return SWITCH_STATUS_GENERR;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</del><ins>+        if (switch_event_bind(modname, SWITCH_EVENT_NOTIFY, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
</span><span class="cx">                 return SWITCH_STATUS_GENERR;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_event_bind((char *) modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</del><ins>+        if (switch_event_bind(modname, SWITCH_EVENT_SEND_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't bind!\n&quot;);
</span><span class="cx">                 return SWITCH_STATUS_GENERR;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        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, &quot;Couldn't bind!\n&quot;);
+                return SWITCH_STATUS_GENERR;
+        }
+
</ins><span class="cx">         /* connect my internal structure to the blank pointer passed to me */
</span><del>-        *module_interface = &amp;sofia_module_interface;
</del><ins>+        *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-&gt;interface_name = &quot;sofia&quot;;
+        sofia_endpoint_interface-&gt;io_routines = &amp;sofia_io_routines;
+        sofia_endpoint_interface-&gt;state_handler = &amp;sofia_event_handlers;
</ins><span class="cx"> 
</span><ins>+        management_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_MANAGEMENT_INTERFACE);
+        management_interface-&gt;relative_oid = &quot;1&quot;;
+        management_interface-&gt;management_function = sofia_manage;
+
+        SWITCH_ADD_API(api_interface, &quot;sofia&quot;, &quot;Sofia Controls&quot;, sofia_function, &quot;&lt;cmd&gt; &lt;args&gt;&quot;);
+        switch_console_set_complete(&quot;add sofia help&quot;);
+        switch_console_set_complete(&quot;add sofia status&quot;);
+        switch_console_set_complete(&quot;add sofia loglevel&quot;);
+        switch_console_set_complete(&quot;add sofia profile&quot;);
+        switch_console_set_complete(&quot;add sofia profile restart all&quot;);
+
+        SWITCH_ADD_API(api_interface, &quot;sofia_contact&quot;, &quot;Sofia Contacts&quot;, sofia_contact_function, &quot;[profile/]&lt;user&gt;@&lt;domain&gt;&quot;);
+        SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
+
</ins><span class="cx">         /* indicate that the module should continue to be loaded */
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><del>-
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
</del><ins>+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown)
</ins><span class="cx"> {
</span><ins>+        int sanity = 0;
</ins><span class="cx"> 
</span><del>-        cancel_presence();
-
-        switch_mutex_lock(globals.mutex);
-        if (globals.running == 1) {
-                globals.running = -1;
</del><ins>+        switch_mutex_lock(mod_sofia_globals.mutex);
+        if (mod_sofia_globals.running == 1) {
+                mod_sofia_globals.running = 0;
</ins><span class="cx">         }
</span><del>-        switch_mutex_unlock(globals.mutex);
</del><ins>+        switch_mutex_unlock(mod_sofia_globals.mutex);
</ins><span class="cx"> 
</span><del>-        while(globals.running) {
-                switch_yield(1000);
</del><ins>+        switch_event_unbind(&amp;mod_sofia_globals.in_node);
+        switch_event_unbind(&amp;mod_sofia_globals.probe_node);
+        switch_event_unbind(&amp;mod_sofia_globals.out_node);
+        switch_event_unbind(&amp;mod_sofia_globals.roster_node);
+        switch_event_unbind(&amp;mod_sofia_globals.custom_node);
+        switch_event_unbind(&amp;mod_sofia_globals.mwi_node);
+        switch_event_unbind_callback(general_event_handler);
+        
+        while (mod_sofia_globals.threads) {
+                switch_cond_next();
+                if (++sanity &gt;= 60000) {
+                        break;
+                }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        //switch_yield(1000000);
</ins><span class="cx">         su_deinit();
</span><span class="cx"> 
</span><ins>+        switch_mutex_lock(mod_sofia_globals.hash_mutex);
+        switch_core_hash_destroy(&amp;mod_sofia_globals.profile_hash);
+        switch_core_hash_destroy(&amp;mod_sofia_globals.gateway_hash);
+        switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
</ins><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -5897,5 +3394,5 @@
</span><span class="cx">  * c-basic-offset:4
</span><span class="cx">  * End:
</span><span class="cx">  * For VIM:
</span><del>- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
</del><ins>+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
</ins><span class="cx">  */
</span><span class="cx">Property changes on: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.c
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:eol-style
</span><span class="cx">   + native
</span></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiah"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.h (14389 => 14390)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /* 
</span><span class="cx">  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
</span><del>- * Copyright (C) 2005/2006, Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Copyright (C) 2005-2009, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  *
</span><span class="cx">  * Version: MPL 1.1
</span><span class="cx">  *
</span><span class="lines">@@ -17,13 +17,13 @@
</span><span class="cx">  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
</span><span class="cx">  *
</span><span class="cx">  * The Initial Developer of the Original Code is
</span><del>- * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  * Portions created by the Initial Developer are Copyright (C)
</span><span class="cx">  * the Initial Developer. All Rights Reserved.
</span><span class="cx">  *
</span><span class="cx">  * Contributor(s):
</span><span class="cx">  * 
</span><del>- * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  * Ken Rice, Asteria Solutions Group, Inc &lt;ken@asteriasgi.com&gt;
</span><span class="cx">  * Paul D. Tinsley &lt;pdt at jackhammer.org&gt;
</span><span class="cx">  * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
</span><span class="lines">@@ -36,23 +36,33 @@
</span><span class="cx"> 
</span><span class="cx"> /*Defines etc..*/
</span><span class="cx"> /*************************************************************************************************************************************************************/
</span><ins>+#define MANUAL_BYE
+
</ins><span class="cx"> #define IREG_SECONDS 30
</span><span class="cx"> #define GATEWAY_SECONDS 1
</span><del>-
</del><ins>+#define SOFIA_QUEUE_SIZE 50000
</ins><span class="cx"> #define HAVE_APR
</span><span class="cx"> #include &lt;switch.h&gt;
</span><span class="cx"> #include &lt;switch_version.h&gt;
</span><del>-#ifdef SWITCH_HAVE_ODBC
-#include &lt;switch_odbc.h&gt;
</del><ins>+#define SOFIA_NAT_SESSION_TIMEOUT 20
+#define SOFIA_MAX_ACL 100
+#ifdef _MSC_VER
+#define HAVE_FUNCTION 1
+#else
+#define HAVE_FUNC 1
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-#define SOFIA_MAX_ACL 100
-
</del><ins>+#define MAX_CODEC_CHECK_FRAMES 50
+#define MAX_MISMATCH_FRAMES 3
</ins><span class="cx"> #define MODNAME &quot;mod_sofia&quot;
</span><ins>+#define SOFIA_DEFAULT_CONTACT_USER MODNAME
</ins><span class="cx"> static const switch_state_handler_table_t noop_state_handler = { 0 };
</span><span class="cx"> struct sofia_gateway;
</span><span class="cx"> typedef struct sofia_gateway sofia_gateway_t;
</span><span class="cx"> 
</span><ins>+struct sofia_gateway_subscription;
+typedef struct sofia_gateway_subscription sofia_gateway_subscription_t;
+
</ins><span class="cx"> struct sofia_profile;
</span><span class="cx"> typedef struct sofia_profile sofia_profile_t;
</span><span class="cx"> #define NUA_MAGIC_T sofia_profile_t
</span><span class="lines">@@ -65,12 +75,17 @@
</span><span class="cx"> 
</span><span class="cx"> #define SOFIA_SESSION_TIMEOUT &quot;sofia_session_timeout&quot;
</span><span class="cx"> #define MY_EVENT_REGISTER &quot;sofia::register&quot;
</span><ins>+#define MY_EVENT_UNREGISTER &quot;sofia::unregister&quot;
</ins><span class="cx"> #define MY_EVENT_EXPIRE &quot;sofia::expire&quot;
</span><ins>+#define MY_EVENT_GATEWAY_STATE &quot;sofia::gateway_state&quot;
+#define MY_EVENT_NOTIFY_REFER &quot;sofia::notify_refer&quot;
+
</ins><span class="cx"> #define MULTICAST_EVENT &quot;multicast::event&quot;
</span><span class="cx"> #define SOFIA_REPLACES_HEADER &quot;_sofia_replaces_&quot;
</span><span class="cx"> #define SOFIA_USER_AGENT &quot;FreeSWITCH-mod_sofia/&quot; SWITCH_VERSION_MAJOR &quot;.&quot; SWITCH_VERSION_MINOR &quot;.&quot; SWITCH_VERSION_MICRO &quot;-&quot; SWITCH_VERSION_REVISION
</span><span class="cx"> #define SOFIA_CHAT_PROTO &quot;sip&quot;
</span><span class="cx"> #define SOFIA_SIP_HEADER_PREFIX &quot;sip_h_&quot;
</span><ins>+#define SOFIA_SIP_BYE_HEADER_PREFIX &quot;sip_bye_h_&quot;
</ins><span class="cx"> #define SOFIA_SIP_HEADER_PREFIX_T &quot;~sip_h_&quot;
</span><span class="cx"> #define SOFIA_DEFAULT_PORT &quot;5060&quot;
</span><span class="cx"> #define SOFIA_DEFAULT_TLS_PORT &quot;5061&quot;
</span><span class="lines">@@ -79,7 +94,6 @@
</span><span class="cx"> #define SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE &quot;sip_secure_media_confirmed&quot;
</span><span class="cx"> #define SOFIA_HAS_CRYPTO_VARIABLE &quot;sip_has_crypto&quot;
</span><span class="cx"> #define SOFIA_CRYPTO_MANDATORY_VARIABLE &quot;sip_crypto_mandatory&quot;
</span><del>-#define SOFIA_AUTO_PORT -1
</del><span class="cx"> 
</span><span class="cx"> #include &lt;sofia-sip/nua.h&gt;
</span><span class="cx"> #include &lt;sofia-sip/sip_status.h&gt;
</span><span class="lines">@@ -90,7 +104,14 @@
</span><span class="cx"> #include &lt;sofia-sip/su_log.h&gt;
</span><span class="cx"> #include &lt;sofia-sip/nea.h&gt;
</span><span class="cx"> #include &lt;sofia-sip/msg_addr.h&gt;
</span><ins>+#include &lt;sofia-sip/tport_tag.h&gt;
+#include &lt;sofia-sip/sip_extra.h&gt;
+#include &quot;nua_stack.h&quot;
+#include &quot;sofia-sip/msg_parser.h&quot;
+#include &quot;sofia-sip/sip_parser.h&quot;
+#include &quot;sofia-sip/tport_tag.h&quot;
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> typedef enum {
</span><span class="cx">         DTMF_2833,
</span><span class="cx">         DTMF_INFO,
</span><span class="lines">@@ -100,10 +121,17 @@
</span><span class="cx"> struct sofia_private {
</span><span class="cx">         char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
</span><span class="cx">         sofia_gateway_t *gateway;
</span><ins>+        char gateway_name[256];
+        char auth_gateway_name[256];
+        int destroy_nh;
+        int destroy_me;
+        int is_call;
+        int is_static;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> #define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);}
</span><span class="cx"> #define set_anchor(t,m) if (t-&gt;Anchor) {delete t-&gt;Anchor;} t-&gt;Anchor = new SipMessage(m);
</span><ins>+#define sofia_private_free(_pvt) if (_pvt &amp;&amp; ! _pvt-&gt;is_static) {free(_pvt); _pvt = NULL;}
</ins><span class="cx"> 
</span><span class="cx"> /* Local Structures */
</span><span class="cx"> /*************************************************************************************************************************************************************/
</span><span class="lines">@@ -121,63 +149,102 @@
</span><span class="cx"> } MFLAGS;
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><del>-        PFLAG_AUTH_CALLS = (1 &lt;&lt; 0),
-        PFLAG_BLIND_REG = (1 &lt;&lt; 1),
-        PFLAG_AUTH_ALL = (1 &lt;&lt; 2),
-        PFLAG_FULL_ID = (1 &lt;&lt; 3),
-        PFLAG_PRESENCE = (1 &lt;&lt; 4),
-        PFLAG_PASS_RFC2833 = (1 &lt;&lt; 5),
-        PFLAG_DISABLE_TRANSCODING = (1 &lt;&lt; 6),
-        PFLAG_REWRITE_TIMESTAMPS = (1 &lt;&lt; 7),
-        PFLAG_RUNNING = (1 &lt;&lt; 8),
-        PFLAG_RESPAWN = (1 &lt;&lt; 9),
-        PFLAG_GREEDY = (1 &lt;&lt; 10),
-        PFLAG_MULTIREG = (1 &lt;&lt; 11),
-        PFLAG_SUPRESS_CNG = (1 &lt;&lt; 12),
-        PFLAG_TLS = (1 &lt;&lt; 13),
-        PFLAG_CHECKUSER = (1 &lt;&lt; 14),
-        PFLAG_SECURE = (1 &lt;&lt; 15),
-        PFLAG_BLIND_AUTH = (1 &lt;&lt; 16),
-        PFLAG_WORKER_RUNNING = (1 &lt;&lt; 17),
-        PFLAG_UNREG_OPTIONS_FAIL = (1 &lt;&lt; 18)
</del><ins>+        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
</ins><span class="cx"> } PFLAGS;
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><span class="cx">         PFLAG_NDLB_TO_IN_200_CONTACT = (1 &lt;&lt; 0),
</span><del>-        PFLAG_NDLB_BROKEN_AUTH_HASH = (1 &lt;&lt; 1)
</del><ins>+        PFLAG_NDLB_BROKEN_AUTH_HASH = (1 &lt;&lt; 1),
+        PFLAG_NDLB_SENDRECV_IN_SESSION = (1 &lt;&lt; 2)
</ins><span class="cx"> } sofia_NDLB_t;
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><del>-        TFLAG_IO = (1 &lt;&lt; 0),
-        TFLAG_CHANGE_MEDIA = (1 &lt;&lt; 1),
-        TFLAG_OUTBOUND = (1 &lt;&lt; 2),
-        TFLAG_READING = (1 &lt;&lt; 3),
-        TFLAG_WRITING = (1 &lt;&lt; 4),
-        TFLAG_HUP = (1 &lt;&lt; 5),
-        TFLAG_RTP = (1 &lt;&lt; 6),
-        TFLAG_BYE = (1 &lt;&lt; 7),
-        TFLAG_ANS = (1 &lt;&lt; 8),
-        TFLAG_EARLY_MEDIA = (1 &lt;&lt; 9),
-        TFLAG_SECURE = (1 &lt;&lt; 10),
-        TFLAG_VAD_IN = (1 &lt;&lt; 11),
-        TFLAG_VAD_OUT = (1 &lt;&lt; 12),
-        TFLAG_VAD = (1 &lt;&lt; 13),
-        TFLAG_TIMER = (1 &lt;&lt; 14),
-        TFLAG_READY = (1 &lt;&lt; 15),
-        TFLAG_REINVITE = (1 &lt;&lt; 16),
-        TFLAG_REFER = (1 &lt;&lt; 17),
-        TFLAG_NOHUP = (1 &lt;&lt; 18),
-        TFLAG_XFER = (1 &lt;&lt; 19),
-        TFLAG_RESERVED = (1 &lt;&lt; 20),
-        TFLAG_BUGGY_2833 = (1 &lt;&lt; 21),
-        TFLAG_SIP_HOLD = (1 &lt;&lt; 22),
-        TFLAG_INB_NOMEDIA = (1 &lt;&lt; 23),
-        TFLAG_LATE_NEGOTIATION = (1 &lt;&lt; 24),
-        TFLAG_SDP = (1 &lt;&lt; 25),
-        TFLAG_VIDEO = (1 &lt;&lt; 26),
-        TFLAG_TPORT_LOG = (1 &lt;&lt; 27),
-        TFLAG_SENT_UPDATE = (1 &lt;&lt; 28),
-        TFLAG_PROXY_MEDIA = (1 &lt;&lt; 29)
</del><ins>+        STUN_FLAG_SET = (1 &lt;&lt; 0),
+        STUN_FLAG_PING = (1 &lt;&lt; 1),
+        STUN_FLAG_FUNNY = (1 &lt;&lt; 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
</ins><span class="cx"> } TFLAGS;
</span><span class="cx"> 
</span><span class="cx"> struct mod_sofia_globals {
</span><span class="lines">@@ -190,14 +257,33 @@
</span><span class="cx">         int32_t threads;
</span><span class="cx">         switch_mutex_t *mutex;
</span><span class="cx">         char guess_ip[80];
</span><ins>+        char hostname[512];
</ins><span class="cx">         switch_queue_t *presence_queue;
</span><span class="cx">         switch_queue_t *mwi_queue;
</span><ins>+        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;
</ins><span class="cx"> };
</span><span class="cx"> extern struct mod_sofia_globals mod_sofia_globals;
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><del>-        REG_FLAG_AUTHED = (1 &lt;&lt; 0),
-        REG_FLAG_CALLERID = (1 &lt;&lt; 1)
</del><ins>+        REG_FLAG_AUTHED,
+        REG_FLAG_CALLERID,
+
+        /* No new flags below this line */
+        REG_FLAG_MAX
</ins><span class="cx"> } reg_flags_t;
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><span class="lines">@@ -207,6 +293,7 @@
</span><span class="cx">         REG_STATE_REGED,
</span><span class="cx">         REG_STATE_UNREGISTER,
</span><span class="cx">         REG_STATE_FAILED,
</span><ins>+        REG_STATE_FAIL_WAIT,
</ins><span class="cx">         REG_STATE_EXPIRED,
</span><span class="cx">         REG_STATE_NOREG,
</span><span class="cx">         REG_STATE_LAST
</span><span class="lines">@@ -220,33 +307,99 @@
</span><span class="cx">         SOFIA_TRANSPORT_SCTP
</span><span class="cx"> } sofia_transport_t;
</span><span class="cx"> 
</span><ins>+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;
+};
+
</ins><span class="cx"> struct sofia_gateway {
</span><span class="cx">         sofia_private_t *sofia_private;
</span><span class="cx">         nua_handle_t *nh;
</span><ins>+        nua_handle_t *sub_nh;
</ins><span class="cx">         sofia_profile_t *profile;
</span><span class="cx">         char *name;
</span><span class="cx">         char *register_scheme;
</span><span class="cx">         char *register_realm;
</span><span class="cx">         char *register_username;
</span><ins>+        char *auth_username;
</ins><span class="cx">         char *register_password;
</span><span class="cx">         char *register_from;
</span><span class="cx">         char *register_contact;
</span><ins>+        char *extension;
</ins><span class="cx">         char *register_to;
</span><span class="cx">         char *register_proxy;
</span><ins>+        char *register_sticky_proxy;
+        char *outbound_sticky_proxy;
</ins><span class="cx">         char *register_context;
</span><span class="cx">         char *expires_str;
</span><span class="cx">         char *register_url;
</span><ins>+        char *from_domain;
</ins><span class="cx">         sofia_transport_t register_transport;
</span><span class="cx">         uint32_t freq;
</span><span class="cx">         time_t expires;
</span><span class="cx">         time_t retry;
</span><del>-        uint32_t flags;
</del><ins>+        time_t ping;
+        int pinging;
+        sofia_gateway_status_t status;
+        uint32_t ping_freq;
+        uint8_t flags[REG_FLAG_MAX];
</ins><span class="cx">         int32_t retry_seconds;
</span><span class="cx">         reg_state_t state;
</span><span class="cx">         switch_memory_pool_t *pool;
</span><ins>+        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;
</ins><span class="cx">         struct sofia_gateway *next;
</span><ins>+        sofia_gateway_subscription_t *subscriptions;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+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 &lt;&lt; 0),
+        MEDIA_OPT_BYPASS_AFTER_ATT_XFER = (1 &lt;&lt; 1)
+} sofia_media_options_t;
+
+typedef enum {
+        CID_TYPE_RPID,
+        CID_TYPE_PID,
+        CID_TYPE_NONE
+} sofia_cid_type_t;
+
</ins><span class="cx"> struct sofia_profile {
</span><span class="cx">         int debug;
</span><span class="cx">         char *name;
</span><span class="lines">@@ -260,27 +413,40 @@
</span><span class="cx">         char *extsipip;
</span><span class="cx">         char *username;
</span><span class="cx">         char *url;
</span><ins>+        char *public_url;
</ins><span class="cx">         char *bindurl;
</span><span class="cx">         char *tls_url;
</span><ins>+        char *tls_public_url;
</ins><span class="cx">         char *tls_bindurl;
</span><ins>+        char *tcp_public_contact;
+        char *tls_public_contact;
+        char *tcp_contact;
+        char *tls_contact;
+        char *sla_contact;
</ins><span class="cx">         char *sipdomain;
</span><span class="cx">         char *timer_name;
</span><span class="cx">         char *hold_music;
</span><ins>+        char *outbound_proxy;
</ins><span class="cx">         char *bind_params;
</span><span class="cx">         char *tls_bind_params;
</span><span class="cx">         char *tls_cert_dir;
</span><span class="cx">         char *reg_domain;
</span><ins>+        char *reg_db_domain;
</ins><span class="cx">         char *user_agent;
</span><span class="cx">         char *record_template;
</span><ins>+        char *presence_hosts;
+        char *challenge_realm;
+        sofia_cid_type_t cid_type;
</ins><span class="cx">         sofia_dtmf_t dtmf_type;
</span><del>-        int sip_port;
-        int tls_sip_port;
</del><ins>+        int auto_restart;
+        switch_port_t sip_port;
+        switch_port_t tls_sip_port;
</ins><span class="cx">         int tls_version;
</span><span class="cx">         char *codec_string;
</span><span class="cx">         int running;
</span><span class="cx">         int dtmf_duration;
</span><del>-        unsigned int flags;
-        unsigned int pflags;
</del><ins>+        uint8_t flags[TFLAG_MAX];
+        uint8_t pflags[PFLAG_MAX];
</ins><span class="cx">         unsigned int mflags;
</span><span class="cx">         unsigned int ndlb;
</span><span class="cx">         uint32_t max_calls;
</span><span class="lines">@@ -296,7 +462,6 @@
</span><span class="cx">         switch_mutex_t *gateway_mutex;
</span><span class="cx">         sofia_gateway_t *gateways;
</span><span class="cx">         su_home_t *home;
</span><del>-        switch_hash_t *sub_hash;
</del><span class="cx">         switch_hash_t *chat_hash;
</span><span class="cx">         switch_core_db_t *master_db;
</span><span class="cx">         switch_thread_rwlock_t *rwlock;
</span><span class="lines">@@ -304,6 +469,7 @@
</span><span class="cx">         uint32_t inuse;
</span><span class="cx">         time_t started;
</span><span class="cx">         uint32_t session_timeout;
</span><ins>+        uint32_t minimum_session_expires;
</ins><span class="cx">         uint32_t max_proceeding;
</span><span class="cx">         uint32_t rtp_timeout_sec;
</span><span class="cx">         uint32_t rtp_hold_timeout_sec;
</span><span class="lines">@@ -316,12 +482,28 @@
</span><span class="cx">         uint32_t acl_count;
</span><span class="cx">         char *reg_acl[SOFIA_MAX_ACL];
</span><span class="cx">         uint32_t reg_acl_count;
</span><del>-
</del><ins>+        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;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct private_object {
</span><span class="cx">         sofia_private_t *sofia_private;
</span><del>-        uint32_t flags;
</del><ins>+        uint8_t flags[TFLAG_MAX];
</ins><span class="cx">         switch_payload_t agreed_pt;
</span><span class="cx">         switch_core_session_t *session;
</span><span class="cx">         switch_channel_t *channel;
</span><span class="lines">@@ -352,18 +534,25 @@
</span><span class="cx">         char *from_address;
</span><span class="cx">         char *to_address;
</span><span class="cx">         char *callid;
</span><del>-        char *far_end_contact;
</del><span class="cx">         char *contact_url;
</span><span class="cx">         char *from_str;
</span><span class="cx">         char *rpid;
</span><ins>+        char *asserted_id;
+        char *preferred_id;
+        char *privacy;
</ins><span class="cx">         char *gateway_from_str;
</span><span class="cx">         char *rm_encoding;
</span><span class="cx">         char *iananame;
</span><span class="cx">         char *rm_fmtp;
</span><span class="cx">         char *fmtp_out;
</span><span class="cx">         char *remote_sdp_str;
</span><ins>+        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;
</ins><span class="cx">         char *local_sdp_str;
</span><del>-        char *orig_local_sdp_str;
</del><span class="cx">         char *dest;
</span><span class="cx">         char *dest_to;
</span><span class="cx">         char *key;
</span><span class="lines">@@ -380,15 +569,16 @@
</span><span class="cx">         char *gateway_name;
</span><span class="cx">         char *local_crypto_key;
</span><span class="cx">         char *remote_crypto_key;
</span><del>-        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;
</del><ins>+        char *record_route;
+        char *extrtpip;
+        char *stun_ip;
+        char *route_uri;
+        switch_port_t stun_port;
+        uint32_t stun_flags;
</ins><span class="cx">         unsigned long rm_rate;
</span><span class="cx">         switch_payload_t pt;
</span><span class="cx">         switch_mutex_t *flag_mutex;
</span><ins>+        switch_mutex_t *sofia_mutex;
</ins><span class="cx">         switch_payload_t te;
</span><span class="cx">         switch_payload_t bte;
</span><span class="cx">         switch_payload_t cng_pt;
</span><span class="lines">@@ -420,6 +610,21 @@
</span><span class="cx">         uint32_t video_count;
</span><span class="cx">         sofia_dtmf_t dtmf_type;
</span><span class="cx">         int q850_cause;
</span><ins>+        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;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct callback_t {
</span><span class="lines">@@ -430,7 +635,8 @@
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><span class="cx">         REG_REGISTER,
</span><del>-        REG_INVITE
</del><ins>+        REG_AUTO_REGISTER,
+        REG_INVITE,
</ins><span class="cx"> } sofia_regtype_t;
</span><span class="cx"> 
</span><span class="cx"> typedef enum {
</span><span class="lines">@@ -439,16 +645,31 @@
</span><span class="cx">         AUTH_STALE,
</span><span class="cx"> } auth_res_t;
</span><span class="cx"> 
</span><del>-#define sofia_test_pflag(obj, flag) ((obj)-&gt;pflags &amp; flag)
-#define sofia_set_pflag(obj, flag) (obj)-&gt;pflags |= (flag)
</del><ins>+typedef struct {
+        char *to;
+        char *contact;
+        char *route;
+        char *route_uri;
+} sofia_destination_t;
+
+#define sofia_test_pflag(obj, flag) ((obj)-&gt;pflags[flag] ? 1 : 0)
+#define sofia_set_pflag(obj, flag) (obj)-&gt;pflags[flag] = 1
</ins><span class="cx"> #define sofia_set_pflag_locked(obj, flag) assert(obj-&gt;flag_mutex != NULL);\
</span><span class="cx"> switch_mutex_lock(obj-&gt;flag_mutex);\
</span><del>-(obj)-&gt;pflags |= (flag);\
</del><ins>+(obj)-&gt;pflags[flag] = 1;\
</ins><span class="cx"> switch_mutex_unlock(obj-&gt;flag_mutex);
</span><del>-#define sofia_clear_pflag_locked(obj, flag) switch_mutex_lock(obj-&gt;flag_mutex); (obj)-&gt;pflags &amp;= ~(flag); switch_mutex_unlock(obj-&gt;flag_mutex);
-#define sofia_clear_pflag(obj, flag) (obj)-&gt;pflags &amp;= ~(flag)
-#define sofia_copy_pflags(dest, src, flags) (dest)-&gt;pflags &amp;= ~(flags);        (dest)-&gt;pflags |= ((src)-&gt;pflags &amp; (flags))
</del><ins>+#define sofia_clear_pflag_locked(obj, flag) switch_mutex_lock(obj-&gt;flag_mutex); (obj)-&gt;pflags[flag] = 0; switch_mutex_unlock(obj-&gt;flag_mutex);
+#define sofia_clear_pflag(obj, flag) (obj)-&gt;pflags[flag] = 0
</ins><span class="cx"> 
</span><ins>+#define sofia_set_flag_locked(obj, flag) assert(obj-&gt;flag_mutex != NULL);\
+switch_mutex_lock(obj-&gt;flag_mutex);\
+(obj)-&gt;flags[flag] = 1;\
+switch_mutex_unlock(obj-&gt;flag_mutex);
+#define sofia_set_flag(obj, flag) (obj)-&gt;flags[flag] = 1
+#define sofia_clear_flag(obj, flag) (obj)-&gt;flags[flag] = 0
+#define sofia_clear_flag_locked(obj, flag) switch_mutex_lock(obj-&gt;flag_mutex); (obj)-&gt;flags[flag] = 0; switch_mutex_unlock(obj-&gt;flag_mutex);
+#define sofia_test_flag(obj, flag) ((obj)-&gt;flags[flag] ? 1 : 0)
+
</ins><span class="cx"> /* Function Prototypes */
</span><span class="cx"> /*************************************************************************************************************************************************************/
</span><span class="cx"> 
</span><span class="lines">@@ -487,8 +708,17 @@
</span><span class="cx"> 
</span><span class="cx"> void launch_sofia_profile_thread(sofia_profile_t *profile);
</span><span class="cx"> 
</span><del>-switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint);
</del><ins>+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);
</ins><span class="cx"> void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt);
</span><ins>+
+/*
+ * \brief Sets the &quot;ep_codec_string&quot; 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);
</ins><span class="cx"> switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_sdp);
</span><span class="cx"> char *sofia_reg_find_reg_url(sofia_profile_t *profile, const char *user, const char *host, char *val, switch_size_t len);
</span><span class="cx"> void event_handler(switch_event_t *event);
</span><span class="lines">@@ -496,14 +726,17 @@
</span><span class="cx"> void sofia_presence_mwi_event_handler(switch_event_t *event);
</span><span class="cx"> void sofia_presence_cancel(void);
</span><span class="cx"> switch_status_t config_sofia(int reload, char *profile_name);
</span><del>-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);
</del><ins>+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);
+                                                                
</ins><span class="cx"> 
</span><span class="cx"> void sofia_reg_handle_sip_r_challenge(int status,
</span><span class="cx">                                                                           char const *phrase,
</span><del>-                                                                          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[]);
</del><ins>+                                                                          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[]);
</ins><span class="cx"> void sofia_reg_handle_sip_r_register(int status,
</span><span class="cx">                                         char const *phrase,
</span><span class="cx">                                         nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
</span><span class="lines">@@ -523,17 +756,18 @@
</span><span class="cx"> 
</span><span class="cx"> void sofia_glue_execute_sql(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic);
</span><span class="cx"> void sofia_glue_actually_execute_sql(sofia_profile_t *profile, switch_bool_t master, char *sql, switch_mutex_t *mutex);
</span><del>-void sofia_reg_check_expire(sofia_profile_t *profile, time_t now);
</del><ins>+void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot);
</ins><span class="cx"> void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now);
</span><ins>+void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now);
</ins><span class="cx"> void sofia_reg_unregister(sofia_profile_t *profile);
</span><del>-switch_status_t sofia_glue_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool);
</del><ins>+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);
</ins><span class="cx"> 
</span><span class="cx"> void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp);
</span><span class="cx"> int sofia_glue_get_user_host(char *in, char **user, char **host);
</span><span class="cx"> switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status);
</span><span class="cx"> void sofia_glue_do_xfer_invite(switch_core_session_t *session);
</span><span class="cx"> uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, 
</span><del>-                                                                  sofia_regtype_t regtype, char *key, uint32_t keylen, switch_event_t **v_event);
</del><ins>+                                                                  sofia_regtype_t regtype, char *key, uint32_t keylen, switch_event_t **v_event, const char *is_nat);
</ins><span class="cx"> extern switch_endpoint_interface_t *sofia_endpoint_interface;
</span><span class="cx"> void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip);
</span><span class="cx"> switch_status_t sofia_on_hangup(switch_core_session_t *session);
</span><span class="lines">@@ -556,13 +790,15 @@
</span><span class="cx"> void sofia_glue_release_profile__(const char *file, const char *func, int line, sofia_profile_t *profile);
</span><span class="cx"> #define sofia_glue_release_profile(x) sofia_glue_release_profile__(__FILE__, __SWITCH_FUNC__, __LINE__,  x)
</span><span class="cx"> 
</span><del>-sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, char *key);
</del><ins>+sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, const char *key);
</ins><span class="cx"> #define sofia_glue_find_profile(x) sofia_glue_find_profile__(__FILE__, __SWITCH_FUNC__, __LINE__,  x)
</span><span class="cx"> 
</span><span class="cx"> switch_status_t sofia_reg_add_gateway(char *key, sofia_gateway_t *gateway);
</span><del>-sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, int line, char *key);
</del><ins>+sofia_gateway_t *sofia_reg_find_gateway__(const char *file, const char *func, int line, const char *key);
</ins><span class="cx"> #define sofia_reg_find_gateway(x) sofia_reg_find_gateway__(__FILE__, __SWITCH_FUNC__, __LINE__,  x)
</span><span class="cx"> 
</span><ins>+sofia_gateway_subscription_t *sofia_find_gateway_subscription(sofia_gateway_t *gateway_ptr, const char *event);
+
</ins><span class="cx"> void sofia_reg_release_gateway__(const char *file, const char *func, int line, sofia_gateway_t *gateway);
</span><span class="cx"> #define sofia_reg_release_gateway(x) sofia_reg_release_gateway__(__FILE__, __SWITCH_FUNC__, __LINE__, x);
</span><span class="cx"> 
</span><span class="lines">@@ -591,7 +827,7 @@
</span><span class="cx">                         }                                                                                                                        \
</span><span class="cx">                 }                                                                                                                                \
</span><span class="cx">                                                                                                                                                 \
</span><del>-                if(_session) break;                                                                                                \
</del><ins>+                if (_session) break;                                                                                        \
</ins><span class="cx">         } while(!_session)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -604,11 +840,64 @@
</span><span class="cx"> 
</span><span class="cx"> const char *sofia_glue_transport2str(const sofia_transport_t tp);
</span><span class="cx"> char * sofia_glue_find_parameter(const char *str, const char *param);
</span><del>-
</del><ins>+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);
</ins><span class="cx"> int sofia_glue_transport_has_tls(const sofia_transport_t tp);
</span><span class="cx"> const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name);
</span><span class="cx"> 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);
</span><span class="cx"> void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt);
</span><span class="cx"> switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt);
</span><span class="cx"> void sofia_presence_event_thread_start(void);
</span><del>-void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id);
</del><ins>+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 &quot;all&quot; to change them all
+ * \note Valid components are &quot;all&quot;, &quot;default&quot; (sofia's default logger), &quot;tport&quot;, &quot;iptsec&quot;, &quot;nea&quot;, &quot;nta&quot;, &quot;nth_client&quot;, &quot;nth_server&quot;, &quot;nua&quot;, &quot;soa&quot;, &quot;sresolv&quot;, &quot;stun&quot;
+ * \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 &quot;default&quot; (sofia's default logger), &quot;tport&quot;, &quot;iptsec&quot;, &quot;nea&quot;, &quot;nta&quot;, &quot;nth_client&quot;, &quot;nth_server&quot;, &quot;nua&quot;, &quot;soa&quot;, &quot;sresolv&quot;, &quot;stun&quot;
+ * \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);
</ins></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiamod_sofiavcproj"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj (14389 => 14390)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -17,15 +17,12 @@
</span><span class="cx">         &lt;Configurations&gt;
</span><span class="cx">                 &lt;Configuration
</span><span class="cx">                         Name=&quot;Debug|Win32&quot;
</span><del>-                        OutputDirectory=&quot;$(ConfigurationName)&quot;
-                        IntermediateDirectory=&quot;$(ConfigurationName)&quot;
</del><span class="cx">                         ConfigurationType=&quot;2&quot;
</span><del>-                        InheritedPropertySheets=&quot;$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops&quot;
</del><ins>+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_debug.vsprops&quot;
</ins><span class="cx">                         CharacterSet=&quot;2&quot;
</span><span class="cx">                         &gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCPreBuildEventTool&quot;
</span><del>-                                CommandLine=&quot;&quot;
</del><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCCustomBuildTool&quot;
</span><span class="lines">@@ -41,17 +38,9 @@
</span><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCCLCompilerTool&quot;
</span><del>-                                Optimization=&quot;0&quot;
-                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\include&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\include&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;&quot;
-                                PreprocessorDefinitions=&quot;WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
-                                MinimalRebuild=&quot;true&quot;
-                                BasicRuntimeChecks=&quot;3&quot;
-                                RuntimeLibrary=&quot;3&quot;
</del><ins>+                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&amp;quot;&quot;
+                                PreprocessorDefinitions=&quot;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
</ins><span class="cx">                                 UsePrecompiledHeader=&quot;0&quot;
</span><del>-                                WarningLevel=&quot;4&quot;
-                                WarnAsError=&quot;true&quot;
-                                Detect64BitPortabilityProblems=&quot;true&quot;
-                                DebugInformationFormat=&quot;3&quot;
</del><span class="cx">                                 DisableSpecificWarnings=&quot;4201&quot;
</span><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="lines">@@ -66,14 +55,7 @@
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCLinkerTool&quot;
</span><span class="cx">                                 AdditionalDependencies=&quot;ws2_32.lib advapi32.lib iphlpapi.lib&quot;
</span><del>-                                OutputFile=&quot;$(SolutionDir)$(OutDir)/mod/$(InputName).dll&quot;
-                                LinkIncremental=&quot;1&quot;
-                                AdditionalLibraryDirectories=&quot;&amp;quot;..\..\..\..\w32\vsnet\$(OutDir)&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
-                                GenerateDebugInformation=&quot;true&quot;
-                                ProgramDatabaseFile=&quot;$(OutDir)$(TargetName).pdb&quot;
-                                SubSystem=&quot;2&quot;
-                                ImportLibrary=&quot;$(OutDir)/mod_sofia.lib&quot;
-                                TargetMachine=&quot;1&quot;
</del><ins>+                                AdditionalLibraryDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
</ins><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCALinkTool&quot;
</span><span class="lines">@@ -102,15 +84,12 @@
</span><span class="cx">                 &lt;/Configuration&gt;
</span><span class="cx">                 &lt;Configuration
</span><span class="cx">                         Name=&quot;Release|Win32&quot;
</span><del>-                        OutputDirectory=&quot;$(ConfigurationName)&quot;
-                        IntermediateDirectory=&quot;$(ConfigurationName)&quot;
</del><span class="cx">                         ConfigurationType=&quot;2&quot;
</span><del>-                        InheritedPropertySheets=&quot;$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops&quot;
</del><ins>+                        InheritedPropertySheets=&quot;..\..\..\..\w32\module_release.vsprops&quot;
</ins><span class="cx">                         CharacterSet=&quot;2&quot;
</span><span class="cx">                         &gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCPreBuildEventTool&quot;
</span><del>-                                CommandLine=&quot;&quot;
</del><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCCustomBuildTool&quot;
</span><span class="lines">@@ -126,14 +105,10 @@
</span><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCCLCompilerTool&quot;
</span><del>-                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\include&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\include&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;&quot;
-                                PreprocessorDefinitions=&quot;WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
-                                RuntimeLibrary=&quot;2&quot;
</del><ins>+                                Optimization=&quot;0&quot;
+                                AdditionalIncludeDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\su&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nua&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\url&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sip&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\msg&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\sdp&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nta&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\nea&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\soa&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\iptsec&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\bnf&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\libsofia-sip-ua\tport&amp;quot;&quot;
+                                PreprocessorDefinitions=&quot;LIBSOFIA_SIP_UA_STATIC;PTW32_STATIC_LIB&quot;
</ins><span class="cx">                                 UsePrecompiledHeader=&quot;0&quot;
</span><del>-                                WarningLevel=&quot;4&quot;
-                                WarnAsError=&quot;true&quot;
-                                Detect64BitPortabilityProblems=&quot;true&quot;
-                                DebugInformationFormat=&quot;3&quot;
</del><span class="cx">                                 DisableSpecificWarnings=&quot;4201&quot;
</span><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="lines">@@ -148,17 +123,7 @@
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCLinkerTool&quot;
</span><span class="cx">                                 AdditionalDependencies=&quot;ws2_32.lib advapi32.lib iphlpapi.lib&quot;
</span><del>-                                OutputFile=&quot;$(SolutionDir)$(OutDir)/mod/$(InputName).dll&quot;
-                                LinkIncremental=&quot;1&quot;
-                                AdditionalLibraryDirectories=&quot;&amp;quot;..\..\..\..\w32\vsnet\$(OutDir)&amp;quot;;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
-                                GenerateDebugInformation=&quot;true&quot;
-                                ProgramDatabaseFile=&quot;$(OutDir)$(TargetName).pdb&quot;
-                                SubSystem=&quot;2&quot;
-                                OptimizeReferences=&quot;2&quot;
-                                EnableCOMDATFolding=&quot;2&quot;
-                                LinkTimeCodeGeneration=&quot;1&quot;
-                                ImportLibrary=&quot;$(OutDir)/mod_sofia.lib&quot;
-                                TargetMachine=&quot;1&quot;
</del><ins>+                                AdditionalLibraryDirectories=&quot;&amp;quot;$(InputDir)..\..\..\..\libs\sofia-sip\win32\pthread&amp;quot;&quot;
</ins><span class="cx">                         /&gt;
</span><span class="cx">                         &lt;Tool
</span><span class="cx">                                 Name=&quot;VCALinkTool&quot;
</span><span class="lines">@@ -189,28 +154,34 @@
</span><span class="cx">         &lt;References&gt;
</span><span class="cx">         &lt;/References&gt;
</span><span class="cx">         &lt;Files&gt;
</span><del>-                &lt;Filter
-                        Name=&quot;Source Files&quot;
-                        Filter=&quot;cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx&quot;
-                        UniqueIdentifier=&quot;{4FC737F1-C7A5-4376-A066-2A32D752A2FF}&quot;
</del><ins>+                &lt;File
+                        RelativePath=&quot;.\mod_sofia.c&quot;
</ins><span class="cx">                         &gt;
</span><del>-                        &lt;File
-                                RelativePath=&quot;.\mod_sofia.c&quot;
-                                &gt;
-                        &lt;/File&gt;
-                &lt;/Filter&gt;
-                &lt;Filter
-                        Name=&quot;Header Files&quot;
-                        Filter=&quot;h;hpp;hxx;hm;inl;inc;xsd&quot;
-                        UniqueIdentifier=&quot;{93995380-89BD-4b04-88EB-625FBE52EBFB}&quot;
</del><ins>+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\mod_sofia.h&quot;
</ins><span class="cx">                         &gt;
</span><del>-                &lt;/Filter&gt;
-                &lt;Filter
-                        Name=&quot;Resource Files&quot;
-                        Filter=&quot;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx&quot;
-                        UniqueIdentifier=&quot;{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}&quot;
</del><ins>+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia.c&quot;
</ins><span class="cx">                         &gt;
</span><del>-                &lt;/Filter&gt;
</del><ins>+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_glue.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_presence.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_reg.c&quot;
+                        &gt;
+                &lt;/File&gt;
+                &lt;File
+                        RelativePath=&quot;.\sofia_sla.c&quot;
+                        &gt;
+                &lt;/File&gt;
</ins><span class="cx">         &lt;/Files&gt;
</span><span class="cx">         &lt;Globals&gt;
</span><span class="cx">         &lt;/Globals&gt;
</span><span class="cx">Property changes on: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/mod_sofia.vcproj
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:eol-style
</span><span class="cx">   + CRLF
</span></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiasofiac"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c (14389 => 14390)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /* 
</span><span class="cx">  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
</span><del>- * Copyright (C) 2005/2006, Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Copyright (C) 2005-2009, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  *
</span><span class="cx">  * Version: MPL 1.1
</span><span class="cx">  *
</span><span class="lines">@@ -17,13 +17,13 @@
</span><span class="cx">  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
</span><span class="cx">  *
</span><span class="cx">  * The Initial Developer of the Original Code is
</span><del>- * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  * Portions created by the Initial Developer are Copyright (C)
</span><span class="cx">  * the Initial Developer. All Rights Reserved.
</span><span class="cx">  *
</span><span class="cx">  * Contributor(s):
</span><span class="cx">  * 
</span><del>- * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
</del><ins>+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
</ins><span class="cx">  * Ken Rice, Asteria Solutions Group, Inc &lt;ken@asteriasgi.com&gt;
</span><span class="cx">  * Paul D. Tinsley &lt;pdt at jackhammer.org&gt;
</span><span class="cx">  * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
</span><span class="lines">@@ -35,10 +35,8 @@
</span><span class="cx">  *
</span><span class="cx">  */
</span><span class="cx"> #include &quot;mod_sofia.h&quot;
</span><del>-#include &quot;sofia-sip/msg_parser.h&quot;
-#include &quot;sofia-sip/sip_extra.h&quot;
-#include &quot;sofia-sip/tport_tag.h&quot;
</del><span class="cx"> 
</span><ins>+
</ins><span class="cx"> extern su_log_t tport_log[];
</span><span class="cx"> extern su_log_t iptsec_log[];
</span><span class="cx"> extern su_log_t nea_log[];
</span><span class="lines">@@ -49,6 +47,7 @@
</span><span class="cx"> extern su_log_t soa_log[];
</span><span class="cx"> extern su_log_t sresolv_log[];
</span><span class="cx"> extern su_log_t stun_log[];
</span><ins>+extern su_log_t su_log_default[];
</ins><span class="cx"> 
</span><span class="cx"> static void set_variable_sip_param(switch_channel_t *channel, char *header_type, sip_param_t const *params);
</span><span class="cx"> 
</span><span class="lines">@@ -56,145 +55,340 @@
</span><span class="cx"> 
</span><span class="cx"> static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
</span><span class="cx">                                                                          char const *phrase,
</span><del>-                                                                         nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[]);
</del><ins>+                                                                         nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+                                                                         tagi_t tags[]);
</ins><span class="cx"> 
</span><span class="cx"> static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status,
</span><del>-                                                                         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[]);
</del><ins>+                                                                          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[]);
</ins><span class="cx"> 
</span><span class="cx"> void sofia_handle_sip_r_notify(switch_core_session_t *session, int status,
</span><span class="cx">                                                            char const *phrase,
</span><span class="cx">                                                            nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
</span><span class="cx"> {
</span><del>-        if (status &gt;= 300 &amp;&amp; sip) {
-                const char *call_id = sip-&gt;sip_call_id-&gt;i_id;
</del><ins>+#if 0
+        if (status &gt;= 300 &amp;&amp; sip &amp;&amp; sip-&gt;sip_call_id) {
</ins><span class="cx">                 char *sql;
</span><del>-                switch_core_hash_delete(profile-&gt;sub_hash, call_id);
-                
-                sql = switch_mprintf(&quot;delete from sip_subscriptions where call_id='%q'&quot;, call_id);
</del><ins>+                sql = switch_mprintf(&quot;delete from sip_subscriptions where call_id='%q'&quot;, sip-&gt;sip_call_id-&gt;i_id);
</ins><span class="cx">                 switch_assert(sql != NULL);
</span><span class="cx">                 sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
</span><del>-                nua_handle_destroy(nh);
</del><span class="cx">         }
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
</span><del>-                                                          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[])
</del><ins>+                                                           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[])
</ins><span class="cx"> {
</span><span class="cx">         switch_channel_t *channel = NULL;
</span><del>-        
</del><ins>+        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());
+
</ins><span class="cx">         /* make sure we have a proper event */
</span><span class="cx">         if (!sip || !sip-&gt;sip_event) {
</span><span class="cx">                 goto error;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        /* 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(&quot;NOTIFY&quot;) when creating
+         * nua, and also pick them off special elsewhere here in sofia.c - MTK
+         * *and* for Linksys, I believe they use &quot;sa&quot; 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-&gt;sip_request-&gt;rq_url-&gt;url_user &amp;&amp; !strncmp(sip-&gt;sip_request-&gt;rq_url-&gt;url_user, &quot;sla-agent&quot;, sizeof(&quot;sla-agent&quot;))) {
+                        sofia_sla_handle_sip_i_notify(nua, profile, nh, sip, tags);
+                        goto end;
+                }
+        }
+
</ins><span class="cx">         /* Automatically return a 200 OK for Event: keep-alive */
</span><span class="cx">         if (!strcasecmp(sip-&gt;sip_event-&gt;o_type, &quot;keep-alive&quot;)) {
</span><ins>+                /* XXX MTK - is this right? in this case isn't sofia is already sending a 200 itself also? */
</ins><span class="cx">                 nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
</span><del>-                return;
</del><ins>+                goto end;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        /* make sure we have a proper &quot;talk&quot; event */
-        if (!session || strcasecmp(sip-&gt;sip_event-&gt;o_type, &quot;talk&quot;)) {
-                goto error;
</del><ins>+        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);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        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, &quot;auto_answer_destination&quot;, switch_channel_get_variable(channel, &quot;destination_number&quot;));
-                switch_ivr_session_transfer(session, &quot;auto_answer&quot;, NULL , NULL);
</del><ins>+        /* For additional NOTIFY event packages see http://www.iana.org/assignments/sip-events. */
+        if (sip-&gt;sip_content_type &amp;&amp;
+                sip-&gt;sip_content_type-&gt;c_type &amp;&amp;
+                sip-&gt;sip_payload &amp;&amp;
+                sip-&gt;sip_payload-&gt;pl_data &amp;&amp;
+                !strcasecmp(sip-&gt;sip_event-&gt;o_type, &quot;refer&quot;)) {
+                if (switch_event_create_subclass(&amp;s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_NOTIFY_REFER) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;content-type&quot;, sip-&gt;sip_content_type-&gt;c_type);
+                        switch_event_add_body(s_event, &quot;%s&quot;, sip-&gt;sip_payload-&gt;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, &quot;event-package&quot;, sip-&gt;sip_event-&gt;o_type);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;event-id&quot;, sip-&gt;sip_event-&gt;o_id);
+
+                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;contact&quot;, &quot;%s@%s&quot;, 
+                                                                sip-&gt;sip_contact-&gt;m_url-&gt;url_user, sip-&gt;sip_contact-&gt;m_url-&gt;url_host);
+                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, 
+                                                                sip-&gt;sip_from-&gt;a_url-&gt;url_user, sip-&gt;sip_from-&gt;a_url-&gt;url_host);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;from-tag&quot;, sip-&gt;sip_from-&gt;a_tag);
+                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;to&quot;, &quot;%s@%s&quot;, 
+                                                                sip-&gt;sip_to-&gt;a_url-&gt;url_user, sip-&gt;sip_to-&gt;a_url-&gt;url_host);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;to-tag&quot;, sip-&gt;sip_to-&gt;a_tag);
+
+                if (sip-&gt;sip_call_id &amp;&amp; sip-&gt;sip_call_id-&gt;i_id) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;call-id&quot;, sip-&gt;sip_call_id-&gt;i_id);
+                }
+                if (sip-&gt;sip_subscription_state &amp;&amp; sip-&gt;sip_subscription_state-&gt;ss_substate) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;subscription-substate&quot;, sip-&gt;sip_subscription_state-&gt;ss_substate);
+                }
+                if (sip-&gt;sip_subscription_state &amp;&amp; sip-&gt;sip_subscription_state-&gt;ss_reason) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;subscription-reason&quot;, sip-&gt;sip_subscription_state-&gt;ss_reason);
+                }
+                if (sip-&gt;sip_subscription_state &amp;&amp; sip-&gt;sip_subscription_state-&gt;ss_retry_after) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;subscription-retry-after&quot;, sip-&gt;sip_subscription_state-&gt;ss_retry_after);
+                }
+                if (sip-&gt;sip_subscription_state &amp;&amp; sip-&gt;sip_subscription_state-&gt;ss_expires) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;subscription-expires&quot;, sip-&gt;sip_subscription_state-&gt;ss_expires);
+                }
+                if (session) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;UniqueID&quot;, switch_core_session_get_uuid(session));
+                }
+                switch_event_fire(&amp;s_event);
+        }
+
+        if (!strcasecmp(sip-&gt;sip_event-&gt;o_type, &quot;refer&quot;)) {
+                if (session &amp;&amp; channel &amp;&amp; tech_pvt) {
+                        if (sip-&gt;sip_payload &amp;&amp; sip-&gt;sip_payload-&gt;pl_data) {
+                                char *p;
+                                int status_val = 0;
+                                if ((p = strchr(sip-&gt;sip_payload-&gt;pl_data, ' '))) {
+                                        p++;
+                                        if (p) {
+                                                status_val = atoi(p);
+                                        }
+                                }
+                                if (!status_val || status_val &gt;= 200) {
+                                        switch_channel_set_variable(channel, &quot;sip_refer_reply&quot;, sip-&gt;sip_payload-&gt;pl_data);
+                                        if (status_val == 200) {
+                                                switch_channel_hangup(channel, SWITCH_CAUSE_BLIND_TRANSFER);
+                                        }
+                                        if (tech_pvt-&gt;want_event == 9999) {
+                                                tech_pvt-&gt;want_event = 0;
+                                        }
+                                }
+                        }
+                }
</ins><span class="cx">                 nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
</span><del>-                return;
</del><span class="cx">         }
</span><span class="cx"> 
</span><del>-error:
-        nua_respond(nh, 481, &quot;Subscription Does Not Exist&quot;, NUTAG_WITH_THIS(nua), TAG_END());
-        return;
</del><ins>+        /* if no session, assume it could be an incoming notify from a gateway subscription */
+        if (session) {
+                /* make sure we have a proper &quot;talk&quot; event */
+                if (strcasecmp(sip-&gt;sip_event-&gt;o_type, &quot;talk&quot;)) {
+                        goto error;
+                }
+
+                if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+                        switch_channel_answer(channel);
+                        switch_channel_set_variable(channel, &quot;auto_answer_destination&quot;, switch_channel_get_variable(channel, &quot;destination_number&quot;));
+                        switch_ivr_session_transfer(session, &quot;auto_answer&quot;, NULL, NULL);
+                        nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+                        goto end;
+                }
+        }
+        
+        if (!sofia_private || !sofia_private-&gt;gateway) {
+                if (profile-&gt;debug) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Gateway information missing Subscription Event: %s\n&quot;, sip-&gt;sip_event-&gt;o_type);
+                }
+                goto error;        
+        }
+                                
+        /* find the corresponding gateway subscription (if any) */
+        if (!(gw_sub_ptr = sofia_find_gateway_subscription(sofia_private-&gt;gateway, sip-&gt;sip_event-&gt;o_type))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+                                                  &quot;Could not find gateway subscription.  Gateway: %s.  Subscription Event: %s\n&quot;,
+                                                  sofia_private-&gt;gateway-&gt;name, sip-&gt;sip_event-&gt;o_type);
+                goto error;        
+        }
+
+        if (!(gw_sub_ptr-&gt;state == SUB_STATE_SUBED || gw_sub_ptr-&gt;state == SUB_STATE_SUBSCRIBE)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+                                                  &quot;Ignoring notify due to subscription state: %d\n&quot;,
+                                                  gw_sub_ptr-&gt;state);
+                goto error;        
+        }
+
+        /* dispatch freeswitch event */
+        if (switch_event_create(&amp;s_event, SWITCH_EVENT_NOTIFY_IN) == SWITCH_STATUS_SUCCESS) {
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;event&quot;, sip-&gt;sip_event-&gt;o_type);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;pl_data&quot;, sip-&gt;sip_payload-&gt;pl_data);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;sip_content_type&quot;, sip-&gt;sip_content_type-&gt;c_type);
+                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;port&quot;, &quot;%d&quot;, sofia_private-&gt;gateway-&gt;profile-&gt;sip_port);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;module_name&quot;, &quot;mod_sofia&quot;);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_name&quot;, sofia_private-&gt;gateway-&gt;profile-&gt;name);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_uri&quot;, sofia_private-&gt;gateway-&gt;profile-&gt;url);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;gateway_name&quot;, sofia_private-&gt;gateway-&gt;name);
+                switch_event_fire(&amp;s_event);
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;dispatched freeswitch event for message-summary NOTIFY\n&quot;);
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Failed to create event\n&quot;);
+                goto error;        
+        }
+
+        goto end;
+
+  error:
+
+
+        if (sip &amp;&amp; sip-&gt;sip_event &amp;&amp; sip-&gt;sip_event-&gt;o_type &amp;&amp; !strcasecmp(sip-&gt;sip_event-&gt;o_type, &quot;message-summary&quot;)) {
+                /* unsolicited mwi, just say ok */
+                nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+        } else {
+                nua_respond(nh, 481, &quot;Subscription Does Not Exist&quot;, NUTAG_WITH_THIS(nua), TAG_END());
+        }
+        
+ end:
+        
+        if (sub_state == nua_substate_terminated &amp;&amp; sofia_private &amp;&amp; sofia_private != &amp;mod_sofia_globals.destroy_private &amp;&amp; 
+                sofia_private != &amp;mod_sofia_globals.keep_private) {
+                sofia_private-&gt;destroy_nh = 1;
+                sofia_private-&gt;destroy_me = 1;
+        }
+
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void sofia_handle_sip_i_bye(switch_core_session_t *session, int status,
</span><del>-                                                          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[])
</del><ins>+                                                        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[])
</ins><span class="cx"> {
</span><span class="cx">         const char *tmp;
</span><span class="cx">         switch_channel_t *channel;
</span><ins>+        private_object_t *tech_pvt;
+#ifdef MANUAL_BYE
+        int cause;
+        char st[80] = &quot;&quot;;
+#endif
</ins><span class="cx"> 
</span><del>-        if (!session) return;
</del><ins>+        if (!session)
+                return;
</ins><span class="cx"> 
</span><del>-        channel = switch_core_session_get_channel(session); 
</del><ins>+        channel = switch_core_session_get_channel(session);
+        tech_pvt = switch_core_session_get_private(session);
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    if (sip-&gt;sip_reason &amp;&amp; sip-&gt;sip_reason-&gt;re_protocol &amp;&amp; 
-        (!strcasecmp(sip-&gt;sip_reason-&gt;re_protocol, &quot;Q.850&quot;) || !strcasecmp(sip-&gt;sip_reason-&gt;re_protocol, &quot;FreeSWITCH&quot;)) &amp;&amp;
-        sip-&gt;sip_reason-&gt;re_cause) {
-        private_object_t *tech_pvt = switch_core_session_get_private(session);
-        tech_pvt-&gt;q850_cause = atoi(sip-&gt;sip_reason-&gt;re_cause);
</del><ins>+#ifdef MANUAL_BYE
+        status = 200;
+        phrase = &quot;OK&quot;;
+        
+        sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+
+        if (sip-&gt;sip_reason &amp;&amp; sip-&gt;sip_reason-&gt;re_protocol &amp;&amp;
+                (!strcasecmp(sip-&gt;sip_reason-&gt;re_protocol, &quot;Q.850&quot;) 
+                        || !strcasecmp(sip-&gt;sip_reason-&gt;re_protocol, &quot;FreeSWITCH&quot;)
+                        || !strcasecmp(sip-&gt;sip_reason-&gt;re_protocol, profile-&gt;username)) &amp;&amp; sip-&gt;sip_reason-&gt;re_cause) {
+                tech_pvt-&gt;q850_cause = atoi(sip-&gt;sip_reason-&gt;re_cause);
+                cause = tech_pvt-&gt;q850_cause;
+        } else {
+                cause = sofia_glue_sip_cause_to_freeswitch(status);
+        }
+
+        switch_snprintf(st, sizeof(st), &quot;%d&quot;, status);
+        switch_channel_set_variable(channel, &quot;sip_term_status&quot;, st);
+        switch_snprintf(st, sizeof(st), &quot;sip:%d&quot;, status);
+
+        if (phrase) {
+                switch_channel_set_variable_partner(channel, &quot;sip_hangup_phrase&quot;, phrase);
+        }
+
+        switch_snprintf(st, sizeof(st), &quot;%d&quot;, cause);
+        switch_channel_set_variable(channel, &quot;sip_term_cause&quot;, st);
+        switch_channel_hangup(channel, cause);
+        nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+
+        if (sofia_private) {
+        sofia_private-&gt;destroy_me = 1;
+        sofia_private-&gt;destroy_nh = 1;
</ins><span class="cx">     }
</span><ins>+#endif
</ins><span class="cx"> 
</span><del>-        if (sip-&gt;sip_user_agent &amp;&amp; !switch_strlen_zero(sip-&gt;sip_user_agent-&gt;g_string)){
</del><ins>+
+        if (sip-&gt;sip_user_agent &amp;&amp; !switch_strlen_zero(sip-&gt;sip_user_agent-&gt;g_string)) {
</ins><span class="cx">                 switch_channel_set_variable(channel, &quot;sip_user_agent&quot;, sip-&gt;sip_user_agent-&gt;g_string);
</span><ins>+        } else if (sip-&gt;sip_server &amp;&amp; !switch_strlen_zero(sip-&gt;sip_server-&gt;g_string)) {
+                switch_channel_set_variable(channel, &quot;sip_user_agent&quot;, sip-&gt;sip_server-&gt;g_string);
</ins><span class="cx">         }
</span><ins>+
</ins><span class="cx">         if ((tmp = sofia_glue_get_unknown_header(sip, &quot;rtp-txstat&quot;))) {
</span><span class="cx">                 switch_channel_set_variable(channel, &quot;sip_rtp_txstat&quot;, tmp);
</span><span class="cx">         }
</span><span class="cx">         if ((tmp = sofia_glue_get_unknown_header(sip, &quot;rtp-rxstat&quot;))) {
</span><span class="cx">                 switch_channel_set_variable(channel, &quot;sip_rtp_rxstat&quot;, tmp);
</span><span class="cx">         }
</span><ins>+        if ((tmp = sofia_glue_get_unknown_header(sip, &quot;P-RTP-Stat&quot;))) {
+                switch_channel_set_variable(channel, &quot;sip_p_rtp_stat&quot;, tmp);
+        }
+        
+        tech_pvt-&gt;got_bye = 1;
+        switch_channel_set_variable(channel, &quot;sip_hangup_disposition&quot;, &quot;recv_bye&quot;);        
+
</ins><span class="cx">         return;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void sofia_handle_sip_r_message(int status, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip)
</span><span class="cx"> {
</span><del>-        if (status == 503) {
-                const char *user = NULL, *host = NULL;
-                char *sql;
</del><ins>+}
</ins><span class="cx"> 
</span><del>-                if (sip-&gt;sip_to &amp;&amp; sip-&gt;sip_to-&gt;a_url) {
-                        user = sip-&gt;sip_to-&gt;a_url-&gt;url_user;
-                        host = sip-&gt;sip_to-&gt;a_url-&gt;url_host;
</del><ins>+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-&gt;want_event = event;
</ins><span class="cx"> 
</span><del>-                        sql = switch_mprintf(&quot;delete from sip_registrations where sip_user='%q' and sip_host='%q'&quot;, user, host);
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Deleting registration for %s@%s\n&quot;, user, host);
-                        sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
-                }
</del><ins>+        while(switch_channel_ready(tech_pvt-&gt;channel) &amp;&amp; tech_pvt-&gt;want_event &amp;&amp; switch_epoch_time_now(NULL) &lt; exp) {
+                switch_yield(100000);
</ins><span class="cx">         }
</span><del>-
-        nua_handle_destroy(nh);
</del><ins>+        
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void sofia_event_callback(nua_event_t event,
</span><span class="cx">                                                   int status,
</span><span class="cx">                                                   char const *phrase,
</span><del>-                                                  nua_t *nua,
-                                                  sofia_profile_t *profile,
-                                                  nua_handle_t *nh,
-                                                  sofia_private_t *sofia_private,
-                                                  sip_t const *sip,
-                                                  tagi_t tags[])
</del><ins>+                                                  nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
</ins><span class="cx"> {
</span><span class="cx">         struct private_object *tech_pvt = NULL;
</span><span class="cx">         auth_res_t auth_res = AUTH_FORBIDDEN;
</span><span class="cx">         switch_core_session_t *session = NULL;
</span><span class="cx">         switch_channel_t *channel = NULL;
</span><span class="cx">         sofia_gateway_t *gateway = NULL;
</span><ins>+        int locked = 0;
+        int check_destroy = 1;
</ins><span class="cx"> 
</span><del>-        if (sofia_private) {
</del><ins>+        if (nh &amp;&amp; sofia_private == &amp;mod_sofia_globals.keep_private) {
+                if (status &gt;= 300) {
+                        nua_handle_bind(nh, NULL);
+                        nua_handle_destroy(nh);
+                        return;
+                }
+        }
+
+        if (sofia_private &amp;&amp; sofia_private != &amp;mod_sofia_globals.destroy_private &amp;&amp; sofia_private != &amp;mod_sofia_globals.keep_private) {
</ins><span class="cx">                 if ((gateway = sofia_private-&gt;gateway)) {
</span><span class="cx">                         if (switch_thread_rwlock_tryrdlock(gateway-&gt;profile-&gt;rwlock) != SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Profile %s is locked\n&quot;, gateway-&gt;profile-&gt;name);
</span><span class="lines">@@ -203,38 +397,44 @@
</span><span class="cx">                 } else if (!switch_strlen_zero(sofia_private-&gt;uuid)) {
</span><span class="cx">                         if ((session = switch_core_session_locate(sofia_private-&gt;uuid))) {
</span><span class="cx">                                 tech_pvt = switch_core_session_get_private(session);
</span><del>-                                channel = switch_core_session_get_channel(tech_pvt-&gt;session);
</del><ins>+                                channel = switch_core_session_get_channel(session);
+                                if (tech_pvt) {
+                                        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+                                        locked = 1;                                                                                
+                                } else {
+                                        switch_core_session_rwunlock(session);
+                                        return;
+                                }
+
+                                if (status &gt;= 180 &amp;&amp; !*sofia_private-&gt;auth_gateway_name) {
+                                        const char *gwname = switch_channel_get_variable(channel, &quot;sip_use_gateway&quot;);
+                                        if (!switch_strlen_zero(gwname)) {
+                                                switch_set_string(sofia_private-&gt;auth_gateway_name, gwname);
+                                        }
+                                }
</ins><span class="cx">                                 if (!tech_pvt-&gt;call_id &amp;&amp; sip &amp;&amp; sip-&gt;sip_call_id &amp;&amp; sip-&gt;sip_call_id-&gt;i_id) {
</span><span class="cx">                                         tech_pvt-&gt;call_id = switch_core_session_strdup(session, sip-&gt;sip_call_id-&gt;i_id);
</span><span class="cx">                                         switch_channel_set_variable(channel, &quot;sip_call_id&quot;, tech_pvt-&gt;call_id);
</span><span class="cx">                                 }
</span><ins>+
</ins><span class="cx">                                 if (tech_pvt-&gt;gateway_name) {
</span><span class="cx">                                         gateway = sofia_reg_find_gateway(tech_pvt-&gt;gateway_name);
</span><span class="cx">                                 }
</span><ins>+
+                                if (channel &amp;&amp; switch_channel_down(channel)) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Channel is already hungup.\n&quot;);
+                                        goto done;
+                                }
</ins><span class="cx">                         } else {
</span><del>-                                /* too late */
</del><ins>+                                /* we can't find the session it must be hanging up or something else, its too late to do anything with it. */
</ins><span class="cx">                                 return;
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><del>-        
-        if (status != 100 &amp;&amp; status != 200) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;event [%s] status [%d][%s] session: %s\n&quot;,
-                                                  nua_event_name(event), status, phrase, session ? switch_channel_get_name(channel) : &quot;n/a&quot;);
-        }
</del><span class="cx"> 
</span><del>-        if (session) {
-                switch_core_session_signal_lock(session);
</del><ins>+        if (sofia_test_pflag(profile, PFLAG_AUTH_ALL) &amp;&amp; tech_pvt &amp;&amp; tech_pvt-&gt;key &amp;&amp; sip) {
+                sip_authorization_t const *authorization = NULL;
</ins><span class="cx"> 
</span><del>-                if (channel &amp;&amp; switch_channel_get_state(channel) &gt;= CS_HANGUP) {
-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Channel is already hungup.\n&quot;);
-                        goto done;
-                }
-        }
-
-        if ((profile-&gt;pflags &amp; PFLAG_AUTH_ALL) &amp;&amp; tech_pvt &amp;&amp; tech_pvt-&gt;key &amp;&amp; sip) {
-                sip_authorization_t const *authorization = NULL;
-                
</del><span class="cx">                 if (sip-&gt;sip_authorization) {
</span><span class="cx">                         authorization = sip-&gt;sip_authorization;
</span><span class="cx">                 } else if (sip-&gt;sip_proxy_authorization) {
</span><span class="lines">@@ -243,13 +443,14 @@
</span><span class="cx"> 
</span><span class="cx">                 if (authorization) {
</span><span class="cx">                         char network_ip[80];
</span><del>-                        get_addr(network_ip, sizeof(network_ip), &amp;((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))-&gt;ai_addr)-&gt;sin_addr);
-                        auth_res = sofia_reg_parse_auth(profile, authorization, sip, 
-                                                                                        (char *) sip-&gt;sip_request-&gt;rq_method_name, tech_pvt-&gt;key, strlen(tech_pvt-&gt;key), network_ip, NULL, 0, REG_INVITE, NULL);
</del><ins>+                        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-&gt;sip_request-&gt;rq_method_name, tech_pvt-&gt;key, strlen(tech_pvt-&gt;key), network_ip, NULL, 0,
+                                                                                        REG_INVITE, NULL, NULL);
</ins><span class="cx">                 }
</span><del>-
</del><ins>+                
</ins><span class="cx">                 if (auth_res != AUTH_OK) {
</span><del>-                        switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</del><ins>+                        //switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</ins><span class="cx">                         nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
</span><span class="cx">                         goto done;
</span><span class="cx">                 }
</span><span class="lines">@@ -260,17 +461,31 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (sip &amp;&amp; (status == 401 || status == 407)) {
</span><del>-                sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, session, gateway, sip, tags);
</del><ins>+                sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, sofia_private, session, gateway, sip, tags);
</ins><span class="cx">                 goto done;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         switch (event) {
</span><ins>+        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;
</ins><span class="cx">         case nua_r_shutdown:
</span><del>-                if (status &gt;= 200) {
-                        su_root_break(profile-&gt;s_root);
-                }
</del><ins>+                if (status &gt;= 200) su_root_break(profile-&gt;s_root);
</ins><span class="cx">                 break;
</span><del>-
</del><span class="cx">         case nua_r_message:
</span><span class="cx">                 sofia_handle_sip_r_message(status, profile, nh, sip);
</span><span class="cx">                 break;
</span><span class="lines">@@ -280,24 +495,9 @@
</span><span class="cx">         case nua_r_options:
</span><span class="cx">                 sofia_handle_sip_r_options(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
</span><span class="cx">                 break;
</span><del>-        case nua_r_get_params:
-        case nua_r_unregister:
-        case nua_i_fork:
-        case nua_r_info:
-        case nua_r_bye:
-                break;
</del><span class="cx">         case nua_i_bye:
</span><span class="cx">                 sofia_handle_sip_i_bye(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
</span><span class="cx">                 break;
</span><del>-        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;
</del><span class="cx">         case nua_r_notify:
</span><span class="cx">                 sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
</span><span class="cx">                 break;
</span><span class="lines">@@ -311,18 +511,16 @@
</span><span class="cx">                 sofia_handle_sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, tags);
</span><span class="cx">                 break;
</span><span class="cx">         case nua_i_invite:
</span><del>-                if (!session) {
-                        sofia_handle_sip_i_invite(nua, profile, nh, sofia_private, sip, tags);
-                }
</del><ins>+                if (!session) sofia_handle_sip_i_invite(nua, profile, nh, sofia_private, sip, tags);
</ins><span class="cx">                 break;
</span><span class="cx">         case nua_i_publish:
</span><span class="cx">                 sofia_presence_handle_sip_i_publish(nua, profile, nh, sofia_private, sip, tags);
</span><span class="cx">                 break;
</span><span class="cx">         case nua_i_register:
</span><ins>+                //nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip-&gt;sip_contact), NUTAG_WITH_THIS(nua), TAG_END());
+                //nua_handle_destroy(nh);
</ins><span class="cx">                 sofia_reg_handle_sip_i_register(nua, profile, nh, sofia_private, sip, tags);
</span><span class="cx">                 break;
</span><del>-        case nua_i_prack:
-                break;
</del><span class="cx">         case nua_i_state:
</span><span class="cx">                 sofia_handle_sip_i_state(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
</span><span class="cx">                 break;
</span><span class="lines">@@ -332,12 +530,12 @@
</span><span class="cx">         case nua_i_info:
</span><span class="cx">                 sofia_handle_sip_i_info(nua, profile, nh, session, sip, tags);
</span><span class="cx">                 break;
</span><ins>+        case nua_r_update:
+                break;
</ins><span class="cx">         case nua_r_refer:
</span><span class="cx">                 break;
</span><span class="cx">         case nua_i_refer:
</span><del>-                if (session) {
-                        sofia_handle_sip_i_refer(nua, profile, nh, session, sip, tags);
-                }
</del><ins>+                if (session) sofia_handle_sip_i_refer(nua, profile, nh, session, sip, tags);
</ins><span class="cx">                 break;
</span><span class="cx">         case nua_r_subscribe:
</span><span class="cx">                 sofia_presence_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
</span><span class="lines">@@ -356,12 +554,64 @@
</span><span class="cx"> 
</span><span class="cx">   done:
</span><span class="cx"> 
</span><ins>+        if (tech_pvt &amp;&amp; tech_pvt-&gt;want_event &amp;&amp; event == tech_pvt-&gt;want_event) {
+                tech_pvt-&gt;want_event = 0;
+        }
+
+        switch (event) {
+        case nua_i_subscribe:
+        case nua_r_notify:
+                check_destroy = 0;
+                break;
+
+        case nua_i_notify:
+                
+                if (sip &amp;&amp; sip-&gt;sip_event &amp;&amp; !strcmp(sip-&gt;sip_event-&gt;o_type, &quot;dialog&quot;) &amp;&amp; sip-&gt;sip_event-&gt;o_params &amp;&amp; !strcmp(sip-&gt;sip_event-&gt;o_params[0], &quot;sla&quot;)) {
+                        check_destroy = 0;
+                }
+
+                break;
+        default:
+                break;
+        }
+
+        if ((sofia_private &amp;&amp; sofia_private == &amp;mod_sofia_globals.destroy_private)) {
+                nua_handle_bind(nh, NULL);
+                nua_handle_destroy(nh);
+                nh = NULL;
+        }
+
+        if (check_destroy) {
+                if (nh &amp;&amp; ((sofia_private &amp;&amp; sofia_private-&gt;destroy_nh) || !nua_handle_magic(nh))) {
+                        if (sofia_private) {
+                                nua_handle_bind(nh, NULL);
+                        }
+                        nua_handle_destroy(nh);
+                        nh = NULL;
+                }
+        }
+        
+        if (sofia_private &amp;&amp; sofia_private-&gt;destroy_me) {
+                if (tech_pvt) {
+            tech_pvt-&gt;sofia_private = NULL;
+        }
+
+                if (nh) {
+                        nua_handle_bind(nh, NULL);
+                }
+                sofia_private-&gt;destroy_me = 12;
+                sofia_private_free(sofia_private);
+        }
+
</ins><span class="cx">         if (gateway) {
</span><span class="cx">                 sofia_reg_release_gateway(gateway);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (locked &amp;&amp; tech_pvt) {
+                switch_mutex_unlock(tech_pvt-&gt;sofia_mutex);
+        }
+        
</ins><span class="cx">         if (session) {
</span><del>-                switch_core_session_signal_unlock(session);
</del><span class="cx">                 switch_core_session_rwunlock(session);
</span><span class="cx">         }
</span><span class="cx"> }
</span><span class="lines">@@ -373,15 +623,26 @@
</span><span class="cx">         if ((subclass = switch_event_get_header(event, &quot;orig-event-subclass&quot;)) &amp;&amp; !strcasecmp(subclass, MY_EVENT_REGISTER)) {
</span><span class="cx">                 char *from_user = switch_event_get_header(event, &quot;orig-from-user&quot;);
</span><span class="cx">                 char *from_host = switch_event_get_header(event, &quot;orig-from-host&quot;);
</span><ins>+                char *to_host = switch_event_get_header(event, &quot;orig-to-host&quot;);
</ins><span class="cx">                 char *contact_str = switch_event_get_header(event, &quot;orig-contact&quot;);
</span><span class="cx">                 char *exp_str = switch_event_get_header(event, &quot;orig-expires&quot;);
</span><span class="cx">                 char *rpid = switch_event_get_header(event, &quot;orig-rpid&quot;);
</span><span class="cx">                 char *call_id = switch_event_get_header(event, &quot;orig-call-id&quot;);
</span><del>-                char *user_agent = switch_event_get_header(event, &quot;user-agent&quot;);
-                long expires = (long) switch_timestamp(NULL);
</del><ins>+                char *user_agent = switch_event_get_header(event, &quot;orig-user-agent&quot;);
+                long expires = (long) switch_epoch_time_now(NULL);
</ins><span class="cx">                 char *profile_name = switch_event_get_header(event, &quot;orig-profile-name&quot;);
</span><ins>+                char *to_user = switch_event_get_header(event, &quot;orig-to-user&quot;);
+                char *presence_hosts = switch_event_get_header(event, &quot;orig-presence-hosts&quot;);
+                char *network_ip = switch_event_get_header(event, &quot;orig-network-ip&quot;);
+                char *network_port = switch_event_get_header(event, &quot;orig-network-port&quot;);
+                char *username = switch_event_get_header(event, &quot;orig-username&quot;);
+                char *realm = switch_event_get_header(event, &quot;orig-realm&quot;);
+                char *fixed_contact_str = NULL;
+
</ins><span class="cx">                 sofia_profile_t *profile = NULL;
</span><span class="cx"> 
</span><ins>+                char guess_ip4[256];
+
</ins><span class="cx">                 if (exp_str) {
</span><span class="cx">                         expires += atol(exp_str);
</span><span class="cx">                 }
</span><span class="lines">@@ -400,11 +661,38 @@
</span><span class="cx">                         sql = switch_mprintf(&quot;delete from sip_registrations where sip_user='%q' and sip_host='%q'&quot;, from_user, from_host);
</span><span class="cx">                 }
</span><span class="cx"> 
</span><ins>+                if (mod_sofia_globals.rewrite_multicasted_fs_path &amp;&amp; contact_str) {
+                        const char *needle = &quot;;fs_path=&quot;;
+                        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), &quot;;fs_path=sip:%s%s&quot;, to_host, eptr ? eptr : &quot;&gt;&quot;);
+
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Rewrote contact string from '%s' to '%s'\n&quot;, contact_str, fixed_contact_str);
+                        contact_str = fixed_contact_str;
+                }
+
</ins><span class="cx">                 switch_mutex_lock(profile-&gt;ireg_mutex);
</span><span class="cx">                 sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
</span><span class="cx">                 
</span><del>-                sql = switch_mprintf(&quot;insert into sip_registrations values ('%q', '%q','%q','%q','Registered', '%q', %ld, '%q')&quot;,
-                                                          call_id, from_user, from_host, contact_str, rpid, expires, user_agent);
</del><ins>+                switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET);
+                sql = switch_mprintf(&quot;insert into sip_registrations &quot;
+                                                         &quot;(call_id, sip_user, sip_host, presence_hosts, contact, status, rpid, expires,&quot;
+                                                         &quot;user_agent, server_user, server_host, profile_name, hostname, network_ip, network_port, sip_username, sip_realm) &quot;
+                                                         &quot;values ('%q','%q','%q','%q','%q','Registered','%q',%ld, '%q','%q','%q','%q','%q','%q','%q','%q','%q')&quot;,
+                                                         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);
</ins><span class="cx"> 
</span><span class="cx">                 if (sql) {
</span><span class="cx">                         sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
</span><span class="lines">@@ -412,10 +700,11 @@
</span><span class="cx">                 }
</span><span class="cx">                 switch_mutex_unlock(profile-&gt;ireg_mutex);
</span><span class="cx"> 
</span><del>-
</del><span class="cx">                 if (profile) {
</span><span class="cx">                         sofia_glue_release_profile(profile);
</span><span class="cx">                 }
</span><ins>+
+                switch_safe_free(fixed_contact_str);
</ins><span class="cx">         }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -426,19 +715,19 @@
</span><span class="cx">         uint32_t gateway_loops = 0;
</span><span class="cx">         int loops = 0;
</span><span class="cx">         uint32_t qsize;
</span><del>-
</del><ins>+        void *pop;
+        
</ins><span class="cx">         ireg_loops = IREG_SECONDS;
</span><span class="cx">         gateway_loops = GATEWAY_SECONDS;
</span><span class="cx"> 
</span><span class="cx">         sofia_set_pflag_locked(profile, PFLAG_WORKER_RUNNING);
</span><del>-        
-        switch_queue_create(&amp;profile-&gt;sql_queue, 500000, profile-&gt;pool);
-        
</del><ins>+
+        switch_queue_create(&amp;profile-&gt;sql_queue, SOFIA_QUEUE_SIZE, profile-&gt;pool);
+
</ins><span class="cx">         qsize = switch_queue_size(profile-&gt;sql_queue);
</span><span class="cx"> 
</span><span class="cx">         while ((mod_sofia_globals.running == 1 &amp;&amp; sofia_test_pflag(profile, PFLAG_RUNNING)) || qsize) {
</span><span class="cx">                 if (qsize) {
</span><del>-                        void *pop;
</del><span class="cx">                         switch_mutex_lock(profile-&gt;ireg_mutex);
</span><span class="cx">                         while (switch_queue_trypop(profile-&gt;sql_queue, &amp;pop) == SWITCH_STATUS_SUCCESS &amp;&amp; pop) {
</span><span class="cx">                                 sofia_glue_actually_execute_sql(profile, SWITCH_TRUE, (char *) pop, NULL);
</span><span class="lines">@@ -449,45 +738,53 @@
</span><span class="cx"> 
</span><span class="cx">                 if (++loops &gt;= 100) {
</span><span class="cx">                         if (++ireg_loops &gt;= IREG_SECONDS) {
</span><del>-                                sofia_reg_check_expire(profile, switch_timestamp(NULL));
</del><ins>+                                sofia_reg_check_expire(profile, switch_epoch_time_now(NULL), 0);
</ins><span class="cx">                                 ireg_loops = 0;
</span><span class="cx">                         }
</span><span class="cx"> 
</span><span class="cx">                         if (++gateway_loops &gt;= GATEWAY_SECONDS) {
</span><del>-                                sofia_reg_check_gateway(profile, switch_timestamp(NULL));
</del><ins>+                                sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
</ins><span class="cx">                                 gateway_loops = 0;
</span><span class="cx">                         }
</span><ins>+                        sofia_sub_check_gateway(profile, time(NULL));
</ins><span class="cx">                         loops = 0;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                switch_yield(10000);
</del><ins>+                switch_cond_next();
</ins><span class="cx">                 qsize = switch_queue_size(profile-&gt;sql_queue);
</span><span class="cx">         }
</span><del>-        
</del><ins>+
+        switch_mutex_lock(profile-&gt;ireg_mutex);
+        while (switch_queue_trypop(profile-&gt;sql_queue, &amp;pop) == SWITCH_STATUS_SUCCESS &amp;&amp; pop) {
+                sofia_glue_actually_execute_sql(profile, SWITCH_TRUE, (char *) pop, NULL);
+                free(pop);
+        }
+        switch_mutex_unlock(profile-&gt;ireg_mutex);
+
</ins><span class="cx">         sofia_clear_pflag_locked(profile, PFLAG_WORKER_RUNNING);
</span><del>-        
</del><ins>+
</ins><span class="cx">         return NULL;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-void launch_sofia_worker_thread(sofia_profile_t *profile)
</del><ins>+switch_thread_t *launch_sofia_worker_thread(sofia_profile_t *profile)
</ins><span class="cx"> {
</span><span class="cx">         switch_thread_t *thread;
</span><span class="cx">         switch_threadattr_t *thd_attr = NULL;
</span><span class="cx">         int x = 0;
</span><span class="cx"> 
</span><span class="cx">         switch_threadattr_create(&amp;thd_attr, profile-&gt;pool);
</span><del>-        switch_threadattr_detach_set(thd_attr, 1);
</del><span class="cx">         switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
</span><span class="cx">         switch_threadattr_priority_increase(thd_attr);
</span><span class="cx">         switch_thread_create(&amp;thread, thd_attr, sofia_profile_worker_thread_run, profile, profile-&gt;pool);
</span><span class="cx"> 
</span><del>-        while(!sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
</del><ins>+        while (!sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
</ins><span class="cx">                 switch_yield(100000);
</span><span class="cx">                 if (++x &gt;= 100) {
</span><span class="cx">                         break;
</span><span class="cx">                 }
</span><span class="cx">         }
</span><ins>+
+        return thread;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void *obj)
</span><span class="lines">@@ -496,8 +793,15 @@
</span><span class="cx">         switch_memory_pool_t *pool;
</span><span class="cx">         sip_alias_node_t *node;
</span><span class="cx">         switch_event_t *s_event;
</span><del>-        int tportlog = 0;
</del><ins>+        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;
</ins><span class="cx"> 
</span><ins>+        
+
</ins><span class="cx">         switch_mutex_lock(mod_sofia_globals.mutex);
</span><span class="cx">         mod_sofia_globals.threads++;
</span><span class="cx">         switch_mutex_unlock(mod_sofia_globals.mutex);
</span><span class="lines">@@ -513,20 +817,46 @@
</span><span class="cx">                 goto end;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_test_flag(profile, TFLAG_TPORT_LOG)) {
-                tportlog = 1;
</del><ins>+        supported = switch_core_sprintf(profile-&gt;pool, &quot;%s%sprecondition, path, replaces&quot;, 
+                                                                        use_100rel ? &quot;100rel, &quot; : &quot;&quot;,
+                                                                        use_timer ? &quot;timer, &quot; : &quot;&quot;
+                                                                        );
+
+        if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) &amp;&amp; switch_core_get_variable(&quot;nat_type&quot;)) {
+                if (switch_nat_add_mapping(profile-&gt;sip_port, SWITCH_NAT_UDP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Created UDP nat mapping for %s port %d\n&quot;, profile-&gt;name, profile-&gt;sip_port);
+                }
+                if (switch_nat_add_mapping(profile-&gt;sip_port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Created TCP nat mapping for %s port %d\n&quot;, profile-&gt;name, profile-&gt;sip_port);
+                }
+                if(sofia_test_pflag(profile, PFLAG_TLS) &amp;&amp; switch_nat_add_mapping(profile-&gt;tls_sip_port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Created TCP/TLS nat mapping for %s port %d\n&quot;, profile-&gt;name, profile-&gt;tls_sip_port);
+                }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         profile-&gt;nua = nua_create(profile-&gt;s_root,        /* Event loop */
</span><del>-                                                        sofia_event_callback,        /* Callback for processing events */
-                                                        profile,        /* Additional data to pass to callback */
-                                                        NUTAG_URL(profile-&gt;bindurl),
-                                                        TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_SIPS_URL(profile-&gt;tls_bindurl)),
-                                                        TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_CERTIFICATE_DIR(profile-&gt;tls_cert_dir)),
-                                                        TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), TPTAG_TLS_VERSION(profile-&gt;tls_version)),
-                                                        NTATAG_UDP_MTU(65536),
-                                                        TAG_IF(tportlog, TPTAG_LOG(1)),
-                                                        TAG_END());        /* Last tag should always finish the sequence */
</del><ins>+                                                          sofia_event_callback,        /* Callback for processing events */
+                                                          profile,        /* Additional data to pass to callback */
+                                                          NUTAG_URL(profile-&gt;bindurl),
+                                                          NTATAG_USER_VIA(1),
+                                                          TAG_IF(!strchr(profile-&gt;sipip, ':'), SOATAG_AF(SOA_AF_IP4_ONLY)),
+                                                          TAG_IF(strchr(profile-&gt;sipip, ':'), SOATAG_AF(SOA_AF_IP6_ONLY)),
+                                                          TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_SIPS_URL(profile-&gt;tls_bindurl)), 
+                                                          TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_CERTIFICATE_DIR(profile-&gt;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-&gt;tls_version)), 
+                                                          TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), TPTAG_KEEPALIVE(20000)),
+                                                          TAG_IF(!strchr(profile-&gt;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-&gt;outbound_proxy),
+                                                          NTATAG_SERVER_RPORT(profile-&gt;rport_level),
+                                                          TPTAG_LOG(sofia_test_flag(profile, TFLAG_TPORT_LOG)), 
+                                                          TAG_IF(profile-&gt;timer_t1, NTATAG_SIP_T1(profile-&gt;timer_t1)),
+                                                          TAG_IF(profile-&gt;timer_t1x64, NTATAG_SIP_T1X64(profile-&gt;timer_t1x64)),
+                                                          TAG_IF(profile-&gt;timer_t2, NTATAG_SIP_T2(profile-&gt;timer_t2)),
+                                                          TAG_IF(profile-&gt;timer_t4, NTATAG_SIP_T4(profile-&gt;timer_t4)),
+                                                          TAG_END());        /* Last tag should always finish the sequence */
</ins><span class="cx"> 
</span><span class="cx">         if (!profile-&gt;nua) {
</span><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Creating SIP UA for profile: %s\n&quot;, profile-&gt;name);
</span><span class="lines">@@ -540,49 +870,54 @@
</span><span class="cx">                                    NUTAG_APPL_METHOD(&quot;OPTIONS&quot;),
</span><span class="cx">                                    NUTAG_APPL_METHOD(&quot;NOTIFY&quot;),
</span><span class="cx">                                    NUTAG_APPL_METHOD(&quot;INFO&quot;),
</span><ins>+#ifdef MANUAL_BYE
+                                   NUTAG_APPL_METHOD(&quot;BYE&quot;),
+#endif
</ins><span class="cx">                                    NUTAG_AUTOANSWER(0),
</span><span class="cx">                                    NUTAG_AUTOALERT(0),
</span><ins>+                                   NUTAG_ENABLEMESSENGER(1),
</ins><span class="cx">                                    TAG_IF((profile-&gt;mflags &amp; MFLAG_REGISTER), NUTAG_ALLOW(&quot;REGISTER&quot;)),
</span><span class="cx">                                    TAG_IF((profile-&gt;mflags &amp; MFLAG_REFER), NUTAG_ALLOW(&quot;REFER&quot;)),
</span><span class="cx">                                    NUTAG_ALLOW(&quot;INFO&quot;),
</span><span class="cx">                                    NUTAG_ALLOW(&quot;NOTIFY&quot;),
</span><span class="cx">                                    NUTAG_ALLOW_EVENTS(&quot;talk&quot;),
</span><span class="cx">                                    NUTAG_SESSION_TIMER(profile-&gt;session_timeout),
</span><ins>+                                   TAG_IF(profile-&gt;minimum_session_expires, NUTAG_MIN_SE(profile-&gt;minimum_session_expires)),
</ins><span class="cx">                                    NTATAG_MAX_PROCEEDING(profile-&gt;max_proceeding),
</span><del>-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW(&quot;PUBLISH&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW(&quot;SUBSCRIBE&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;presence&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;dialog&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;call-info&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;sla&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;include-session-description&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;presence.winfo&quot;)),
-                                   TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS(&quot;message-summary&quot;)),
-                                   SIPTAG_SUPPORTED_STR(&quot;100rel, precondition, timer&quot;), SIPTAG_USER_AGENT_STR(profile-&gt;user_agent), TAG_END());
</del><ins>+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW(&quot;PUBLISH&quot;)),
+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW(&quot;SUBSCRIBE&quot;)),
+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ENABLEMESSAGE(1)),
+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW_EVENTS(&quot;presence&quot;)),
+                                   TAG_IF((profile-&gt;pres_type || sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)), NUTAG_ALLOW_EVENTS(&quot;dialog&quot;)),
+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW_EVENTS(&quot;call-info&quot;)),
+                                   TAG_IF((profile-&gt;pres_type || sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)), NUTAG_ALLOW_EVENTS(&quot;sla&quot;)),
+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW_EVENTS(&quot;include-session-description&quot;)),
+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW_EVENTS(&quot;presence.winfo&quot;)),
+                                   TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW_EVENTS(&quot;message-summary&quot;)),
+                                   NUTAG_ALLOW_EVENTS(&quot;refer&quot;),
+                                   SIPTAG_SUPPORTED_STR(supported), SIPTAG_USER_AGENT_STR(profile-&gt;user_agent), TAG_END());
</ins><span class="cx"> 
</span><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set params for %s\n&quot;, profile-&gt;name);
</span><span class="cx"> 
</span><span class="cx">         for (node = profile-&gt;aliases; node; node = node-&gt;next) {
</span><span class="cx">                 node-&gt;nua = nua_create(profile-&gt;s_root,        /* Event loop */
</span><del>-                                                                sofia_event_callback,        /* Callback for processing events */
-                                                                profile,        /* Additional data to pass to callback */
-                                                                NUTAG_URL(node-&gt;url), TAG_END());        /* Last tag should always finish the sequence */
</del><ins>+                                                           sofia_event_callback,        /* Callback for processing events */
+                                                           profile,        /* Additional data to pass to callback */
+                                                           NTATAG_SERVER_RPORT(profile-&gt;rport_level), NUTAG_URL(node-&gt;url), TAG_END());        /* Last tag should always finish the sequence */
</ins><span class="cx"> 
</span><span class="cx">                 nua_set_params(node-&gt;nua,
</span><span class="cx">                                            NUTAG_APPL_METHOD(&quot;OPTIONS&quot;),
</span><del>-                                           NUTAG_EARLY_MEDIA(1),
</del><span class="cx">                                            NUTAG_AUTOANSWER(0),
</span><span class="cx">                                            NUTAG_AUTOALERT(0),
</span><span class="cx">                                            TAG_IF((profile-&gt;mflags &amp; MFLAG_REGISTER), NUTAG_ALLOW(&quot;REGISTER&quot;)),
</span><span class="cx">                                            TAG_IF((profile-&gt;mflags &amp; MFLAG_REFER), NUTAG_ALLOW(&quot;REFER&quot;)),
</span><span class="cx">                                            NUTAG_ALLOW(&quot;INFO&quot;),
</span><del>-                                           TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ALLOW(&quot;PUBLISH&quot;)),
-                                           TAG_IF((profile-&gt;pflags &amp; PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
-                                           SIPTAG_SUPPORTED_STR(&quot;100rel, precondition&quot;), SIPTAG_USER_AGENT_STR(profile-&gt;user_agent), TAG_END());
</del><ins>+                                           TAG_IF(profile-&gt;pres_type, NUTAG_ALLOW(&quot;PUBLISH&quot;)),
+                                           TAG_IF(profile-&gt;pres_type, NUTAG_ENABLEMESSAGE(1)),
+                                           SIPTAG_SUPPORTED_STR(supported), SIPTAG_USER_AGENT_STR(profile-&gt;user_agent), TAG_END());
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;activated db for %s\n&quot;, profile-&gt;name);
</del><ins>+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Activated db for %s\n&quot;, profile-&gt;name);
</ins><span class="cx"> 
</span><span class="cx">         switch_mutex_init(&amp;profile-&gt;ireg_mutex, SWITCH_MUTEX_NESTED, profile-&gt;pool);
</span><span class="cx">         switch_mutex_init(&amp;profile-&gt;gateway_mutex, SWITCH_MUTEX_NESTED, profile-&gt;pool);
</span><span class="lines">@@ -592,29 +927,29 @@
</span><span class="cx">                                                                 (sofia_test_pflag(profile, PFLAG_TLS)) ? &quot;,_sips._tcp&quot; : &quot;&quot;);
</span><span class="cx"> 
</span><span class="cx">                 switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;port&quot;, &quot;%d&quot;, profile-&gt;sip_port);
</span><del>-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;module_name&quot;, &quot;%s&quot;, &quot;mod_sofia&quot;);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile_name&quot;, &quot;%s&quot;, profile-&gt;name);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile_uri&quot;, &quot;%s&quot;, profile-&gt;url);
</del><ins>+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;module_name&quot;, &quot;mod_sofia&quot;);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_name&quot;, profile-&gt;name);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_uri&quot;, profile-&gt;url);
</ins><span class="cx"> 
</span><span class="cx">                 if (sofia_test_pflag(profile, PFLAG_TLS)) {
</span><span class="cx">                         switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;tls_port&quot;, &quot;%d&quot;, profile-&gt;tls_sip_port);
</span><del>-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile_tls_uri&quot;, &quot;%s&quot;, profile-&gt;tls_url);
</del><ins>+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_tls_uri&quot;, profile-&gt;tls_url);
</ins><span class="cx">                 }
</span><span class="cx">                 switch_event_fire(&amp;s_event);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         sofia_glue_add_profile(profile-&gt;name, profile);
</span><span class="cx"> 
</span><del>-        if (profile-&gt;pflags &amp; PFLAG_PRESENCE) {
</del><ins>+        if (profile-&gt;pres_type) {
</ins><span class="cx">                 sofia_presence_establish_presence(profile);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Starting thread for %s\n&quot;, profile-&gt;name);
</span><span class="cx"> 
</span><del>-        profile-&gt;started = switch_timestamp(NULL);
</del><ins>+        profile-&gt;started = switch_epoch_time_now(NULL);
</ins><span class="cx"> 
</span><span class="cx">         sofia_set_pflag_locked(profile, PFLAG_RUNNING);
</span><del>-        launch_sofia_worker_thread(profile);
</del><ins>+        worker_thread = launch_sofia_worker_thread(profile);
</ins><span class="cx"> 
</span><span class="cx">         switch_yield(1000000);
</span><span class="cx"> 
</span><span class="lines">@@ -622,25 +957,42 @@
</span><span class="cx">                 su_root_step(profile-&gt;s_root, 1000);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+
+        switch_core_session_hupall_matching_var(&quot;sofia_profile_name&quot;, profile-&gt;name, SWITCH_CAUSE_MANAGER_REQUEST);
+        sanity = 10;
+        while (profile-&gt;inuse) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Waiting for %d session(s)\n&quot;, profile-&gt;inuse);
+                su_root_step(profile-&gt;s_root, 1000);
+                if (!--sanity) {
+                        break;
+                } else if (sanity == 5) {
+                        switch_core_session_hupall_matching_var(&quot;sofia_profile_name&quot;, profile-&gt;name, SWITCH_CAUSE_MANAGER_REQUEST);
+                }
+        }
+
</ins><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Write lock %s\n&quot;, profile-&gt;name);
</span><span class="cx">         switch_thread_rwlock_wrlock(profile-&gt;rwlock);
</span><span class="cx">         sofia_reg_unregister(profile);
</span><span class="cx">         nua_shutdown(profile-&gt;nua);
</span><span class="cx">         su_root_run(profile-&gt;s_root);
</span><del>-
</del><ins>+        
</ins><span class="cx">         sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
</span><del>-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;waiting for worker thread\n&quot;);
</del><ins>+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Waiting for worker thread\n&quot;);
</ins><span class="cx"> 
</span><del>-        while(sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
-                switch_yield(100000);
</del><ins>+        switch_thread_join(&amp;st, worker_thread);
+        
+        sanity = 4;
+        while (profile-&gt;inuse) {
+                switch_core_session_hupall_matching_var(&quot;sofia_profile_name&quot;, profile-&gt;name, SWITCH_CAUSE_MANAGER_REQUEST);
+                switch_yield(5000000);
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Waiting for %d session(s)\n&quot;, profile-&gt;inuse);
+                if (!--sanity) {
+                        break;
+                }
</ins><span class="cx">         }
</span><del>-
-        while(profile-&gt;inuse) {
-                switch_yield(100000);
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;waiting for %d session(s)\n&quot;, profile-&gt;inuse);
-        }
</del><span class="cx">         nua_destroy(profile-&gt;nua);
</span><del>-
</del><ins>+        
</ins><span class="cx">         switch_mutex_lock(profile-&gt;ireg_mutex);
</span><span class="cx">         switch_mutex_unlock(profile-&gt;ireg_mutex);
</span><span class="cx"> 
</span><span class="lines">@@ -649,20 +1001,32 @@
</span><span class="cx"> 
</span><span class="cx">         if (switch_event_create(&amp;s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                 switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;service&quot;, &quot;_sip._udp,_sip._tcp,_sip._sctp%s&quot;,
</span><del>-                                                        (sofia_test_pflag(profile, PFLAG_TLS)) ? &quot;,_sips._tcp&quot; : &quot;&quot;);
</del><ins>+                                                                (sofia_test_pflag(profile, PFLAG_TLS)) ? &quot;,_sips._tcp&quot; : &quot;&quot;);
</ins><span class="cx"> 
</span><span class="cx">                 switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;port&quot;, &quot;%d&quot;, profile-&gt;sip_port);
</span><del>-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;module_name&quot;, &quot;%s&quot;, &quot;mod_sofia&quot;);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile_name&quot;, &quot;%s&quot;, profile-&gt;name);
-                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile_uri&quot;, &quot;%s&quot;, profile-&gt;url);
</del><ins>+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;module_name&quot;, &quot;mod_sofia&quot;);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_name&quot;, profile-&gt;name);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_uri&quot;, profile-&gt;url);
</ins><span class="cx"> 
</span><span class="cx">                 if (sofia_test_pflag(profile, PFLAG_TLS)) {
</span><span class="cx">                         switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;tls_port&quot;, &quot;%d&quot;, profile-&gt;tls_sip_port);
</span><del>-                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;profile_tls_uri&quot;, &quot;%s&quot;, profile-&gt;tls_url);
</del><ins>+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile_tls_uri&quot;, profile-&gt;tls_url);
</ins><span class="cx">                 }
</span><span class="cx">                 switch_event_fire(&amp;s_event);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) &amp;&amp; switch_core_get_variable(&quot;nat_type&quot;)) {
+                if (switch_nat_del_mapping(profile-&gt;sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Deleted UDP nat mapping for %s port %d\n&quot;, profile-&gt;name, profile-&gt;sip_port);
+                }
+                if (switch_nat_del_mapping(profile-&gt;sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Deleted TCP nat mapping for %s port %d\n&quot;, profile-&gt;name, profile-&gt;sip_port);
+                }
+                if(sofia_test_pflag(profile, PFLAG_TLS) &amp;&amp; switch_nat_del_mapping(profile-&gt;tls_sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Deleted TCP/TLS nat mapping for %s port %d\n&quot;, profile-&gt;name, profile-&gt;tls_sip_port);
+                }
+        }
+
</ins><span class="cx">         sofia_glue_sql_close(profile);
</span><span class="cx">         su_home_unref(profile-&gt;home);
</span><span class="cx">         su_root_destroy(profile-&gt;s_root);
</span><span class="lines">@@ -670,7 +1034,6 @@
</span><span class="cx"> 
</span><span class="cx">         sofia_glue_del_profile(profile);
</span><span class="cx">         switch_core_hash_destroy(&amp;profile-&gt;chat_hash);
</span><del>-        switch_core_hash_destroy(&amp;profile-&gt;sub_hash);
</del><span class="cx"> 
</span><span class="cx">         switch_thread_rwlock_unlock(profile-&gt;rwlock);
</span><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Write unlock %s\n&quot;, profile-&gt;name);
</span><span class="lines">@@ -701,37 +1064,135 @@
</span><span class="cx">         switch_thread_create(&amp;thread, thd_attr, sofia_profile_thread_run, profile, profile-&gt;pool);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void logger(void *logarg, char const *fmt, va_list ap)
+{
+        if (fmt &amp;&amp; ap) {
+                switch_log_vprintf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, fmt, ap);
+        } else if (fmt &amp;&amp; !ap) {
+                switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, &quot;%s&quot;, fmt);
+        }
+}
</ins><span class="cx"> 
</span><ins>+static su_log_t *sofia_get_logger(const char *name) 
+{
+        if (!strcasecmp(name, &quot;tport&quot;)) {
+                return tport_log;
+        } else if (!strcasecmp(name, &quot;iptsec&quot;)) {
+                return iptsec_log;
+        } else if (!strcasecmp(name, &quot;nea&quot;)) {
+                return nea_log;
+        } else if (!strcasecmp(name, &quot;nta&quot;)) {
+                return nta_log;
+        } else if (!strcasecmp(name, &quot;nth_client&quot;)) {
+                return nth_client_log;
+        } else if (!strcasecmp(name, &quot;nth_server&quot;)) {
+                return nth_server_log;
+        } else if (!strcasecmp(name, &quot;nua&quot;)) {
+                return nua_log;
+        } else if (!strcasecmp(name, &quot;sresolv&quot;)) {
+                return sresolv_log;
+        } else if (!strcasecmp(name, &quot;stun&quot;)) {
+                return stun_log;
+        } else if (!strcasecmp(name, &quot;default&quot;)) {
+                return su_log_default;
+        } else {
+                return NULL;
+        }
+}
</ins><span class="cx"> 
</span><del>-static void logger(void *logarg, char const *fmt, va_list ap)
</del><ins>+switch_status_t sofia_set_loglevel(const char *name, int level)
</ins><span class="cx"> {
</span><del>-        char *data = NULL;
</del><ins>+        su_log_t *log = NULL;
+        
+        if (level &lt; 0 || level &gt; 9) {
+                return SWITCH_STATUS_FALSE;
+        }
+                
+        if (!strcasecmp(name, &quot;all&quot;)) {
+                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;
+}
</ins><span class="cx"> 
</span><del>-        if (fmt) {
-#ifdef HAVE_VASPRINTF
-                int ret;
-                ret = vasprintf(&amp;data, fmt, ap);
-                if ((ret == -1) || !data) {
-                        return;
</del><ins>+int sofia_get_loglevel(const char *name)
+{
+        su_log_t *log = NULL;
+        
+        if ((log = sofia_get_logger(name))) {
+                return log-&gt;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, &quot;subscription&quot;); subscription_tag; subscription_tag = subscription_tag-&gt;next) {
+                sofia_gateway_subscription_t *gw_sub;
+
+                if ((gw_sub = switch_core_alloc(profile-&gt;pool, sizeof(*gw_sub)))) {
+                        char *expire_seconds = &quot;3600&quot;, *retry_seconds = &quot;30&quot;, *content_type = &quot;NO_CONTENT_TYPE&quot;;
+                        char *event = (char *) switch_xml_attr_soft(subscription_tag, &quot;event&quot;);
+                        gw_sub-&gt;event = switch_core_strdup(gateway-&gt;pool, event);                        
+                        gw_sub-&gt;gateway = gateway;
+                        gw_sub-&gt;next = NULL;
+                        
+                        for (param = switch_xml_child(subscription_tag, &quot;param&quot;); param; param = param-&gt;next) {
+                                char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
+                                char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
+                                if (!strcmp(var, &quot;expire-seconds&quot;)) {
+                                        expire_seconds = val;
+                                } else if (!strcmp(var, &quot;retry-seconds&quot;)) {
+                                        retry_seconds = val;
+                                } else if (!strcmp(var, &quot;content-type&quot;)) {
+                                        content_type = val;
+                                }
+                        }
+                        
+                        gw_sub-&gt;retry_seconds = atoi(retry_seconds);
+                        if (gw_sub-&gt;retry_seconds &lt; 10) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;INVALID: retry_seconds correcting the value to 30\n&quot;);
+                                gw_sub-&gt;retry_seconds = 30;
+                        }
+                        
+                        gw_sub-&gt;expires_str = switch_core_strdup(gateway-&gt;pool, expire_seconds);  
+                        
+                        if ((gw_sub-&gt;freq = atoi(gw_sub-&gt;expires_str)) &lt; 5) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+                                &quot;Invalid Freq: %d.  Setting Register-Frequency to 3600\n&quot;, gw_sub-&gt;freq);
+                                gw_sub-&gt;freq = 3600;
+                        }
+                        gw_sub-&gt;freq -= 2;
+                        gw_sub-&gt;content_type = switch_core_strdup(gateway-&gt;pool, content_type);
+                        gw_sub-&gt;next = gateway-&gt;subscriptions;                
</ins><span class="cx">                 }
</span><del>-#else
-                data = (char *) malloc(2048);
-                if (data) {
-                        vsnprintf(data, 2048, fmt, ap);
-                } else {
-                        return;
-                }
-#endif
</del><ins>+                gateway-&gt;subscriptions = gw_sub;
</ins><span class="cx">         }
</span><del>-        if (data) {
-                switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, (char *) &quot;%s&quot;, data);
-                free(data);
-        }
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag)
</span><span class="cx"> {
</span><del>-        switch_xml_t gateway_tag, param;
</del><ins>+        switch_xml_t gateway_tag, param = NULL, x_params, gw_subs_tag;
</ins><span class="cx">         sofia_gateway_t *gp;
</span><span class="cx"> 
</span><span class="cx">         for (gateway_tag = switch_xml_child(gateways_tag, &quot;gateway&quot;); gateway_tag; gateway_tag = gateway_tag-&gt;next) {
</span><span class="lines">@@ -751,34 +1212,90 @@
</span><span class="cx">                 switch_mutex_unlock(mod_sofia_globals.hash_mutex);
</span><span class="cx"> 
</span><span class="cx">                 if ((gateway = switch_core_alloc(profile-&gt;pool, sizeof(*gateway)))) {
</span><ins>+                        const char *sipip, *format;
+                        switch_uuid_t uuid;
+                        uint32_t ping_freq = 0, extension_in_contact = 0;
</ins><span class="cx">                         char *register_str = &quot;true&quot;, *scheme = &quot;Digest&quot;,
</span><span class="cx">                                 *realm = NULL,
</span><span class="cx">                                 *username = NULL,
</span><ins>+                                *auth_username = NULL,
</ins><span class="cx">                                 *password = NULL,
</span><span class="cx">                                 *caller_id_in_from = &quot;false&quot;,
</span><span class="cx">                                 *extension = NULL,
</span><span class="cx">                                 *proxy = NULL,
</span><del>-                                *context = &quot;default&quot;,
</del><ins>+                                *context = profile-&gt;context,
</ins><span class="cx">                                 *expire_seconds = &quot;3600&quot;,
</span><span class="cx">                                 *retry_seconds = &quot;30&quot;,
</span><del>-                                *from_user = &quot;&quot;,
-                                *from_domain = &quot;&quot;,
-                                *register_proxy = NULL,
-                                *contact_params = NULL,
-                                *params = NULL,
-                                *register_transport = NULL;
-
</del><ins>+                                *from_user = &quot;&quot;, *from_domain = NULL, *outbound_proxy = NULL, *register_proxy = NULL, *contact_host = NULL,
+                                *contact_params = NULL, *params = NULL, *register_transport = NULL;
+                        
+                        if (!context) {
+                                context = &quot;default&quot;;
+                        }
+                        
+                        switch_uuid_get(&amp;uuid);
+                        switch_uuid_format(gateway-&gt;uuid_str, &amp;uuid);
+                        
</ins><span class="cx">                         gateway-&gt;register_transport = SOFIA_TRANSPORT_UDP;
</span><span class="cx">                         gateway-&gt;pool = profile-&gt;pool;
</span><span class="cx">                         gateway-&gt;profile = profile;
</span><span class="cx">                         gateway-&gt;name = switch_core_strdup(gateway-&gt;pool, name);
</span><span class="cx">                         gateway-&gt;freq = 0;
</span><span class="cx">                         gateway-&gt;next = NULL;
</span><ins>+                        gateway-&gt;ping = 0;
+                        gateway-&gt;ping_freq = 0;
+                        
+                        
+                        if ((x_params = switch_xml_child(gateway_tag, &quot;variables&quot;))) {
+                                param = switch_xml_child(x_params, &quot;variable&quot;);
+                        } else {
+                                param = switch_xml_child(gateway_tag, &quot;variable&quot;);
+                        }
+                        
+                        
+                        for (; param; param = param-&gt;next) {
+                                const char *var = switch_xml_attr(param, &quot;name&quot;);
+                                const char *val = switch_xml_attr(param, &quot;value&quot;);
+                                const char *direction = switch_xml_attr(param, &quot;direction&quot;);
+                                int in = 0, out = 0;
+                                
+                                if (var &amp;&amp; val) {
+                                        if (direction) {
+                                                if (!strcasecmp(direction, &quot;inbound&quot;)) {
+                                                        in = 1;
+                                                } else if (!strcasecmp(direction, &quot;outbound&quot;)) {
+                                                        out = 1;
+                                                }
+                                        } else {
+                                                in = out = 1;
+                                        }
</ins><span class="cx"> 
</span><del>-                        for (param = switch_xml_child(gateway_tag, &quot;param&quot;); param; param = param-&gt;next) {
</del><ins>+                                        if (in) {
+                                                if (!gateway-&gt;ib_vars) {
+                                                        switch_event_create_plain(&amp;gateway-&gt;ib_vars, SWITCH_EVENT_GENERAL);
+                                                }
+                                                switch_event_add_header_string(gateway-&gt;ib_vars, SWITCH_STACK_BOTTOM, var, val);
+                                        }
+
+                                        if (out) {
+                                                if (!gateway-&gt;ob_vars) {
+                                                        switch_event_create_plain(&amp;gateway-&gt;ob_vars, SWITCH_EVENT_GENERAL);
+                                                }
+                                                switch_event_add_header_string(gateway-&gt;ob_vars, SWITCH_STACK_BOTTOM, var, val);
+                                        }
+                                }
+                        }
+
+                        if ((x_params = switch_xml_child(gateway_tag, &quot;params&quot;))) {
+                                param = switch_xml_child(x_params, &quot;param&quot;);
+                        } else {
+                                param = switch_xml_child(gateway_tag, &quot;param&quot;);
+                        }
+                        
+                        for (; param; param = param-&gt;next) {
</ins><span class="cx">                                 char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
</span><span class="cx">                                 char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
</span><del>-
</del><ins>+                                
</ins><span class="cx">                                 if (!strcmp(var, &quot;register&quot;)) {
</span><span class="cx">                                         register_str = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;scheme&quot;)) {
</span><span class="lines">@@ -787,12 +1304,18 @@
</span><span class="cx">                                         realm = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;username&quot;)) {
</span><span class="cx">                                         username = val;
</span><ins>+                                } else if (!strcmp(var, &quot;extension-in-contact&quot;)) {
+                                        extension_in_contact = switch_true(val);
+                                } else if (!strcmp(var, &quot;auth-username&quot;)) {
+                                        auth_username = val;
</ins><span class="cx">                                 } else if (!strcmp(var, &quot;password&quot;)) {
</span><span class="cx">                                         password = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;caller-id-in-from&quot;)) {
</span><span class="cx">                                         caller_id_in_from = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;extension&quot;)) {
</span><span class="cx">                                         extension = val;
</span><ins>+                                } else if (!strcmp(var, &quot;ping&quot;)) {
+                                        ping_freq = atoi(val);
</ins><span class="cx">                                 } else if (!strcmp(var, &quot;proxy&quot;)) {
</span><span class="cx">                                         proxy = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;context&quot;)) {
</span><span class="lines">@@ -801,12 +1324,18 @@
</span><span class="cx">                                         expire_seconds = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;retry-seconds&quot;)) {
</span><span class="cx">                                         retry_seconds = val;
</span><ins>+                                } else if (!strcmp(var, &quot;retry_seconds&quot;)) { // support typo for back compat
+                                        retry_seconds = val;
</ins><span class="cx">                                 } else if (!strcmp(var, &quot;from-user&quot;)) {
</span><span class="cx">                                         from_user = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;from-domain&quot;)) {
</span><span class="cx">                                         from_domain = val;
</span><ins>+                                } else if (!strcmp(var, &quot;contact-host&quot;)) {
+                                        contact_host = val;
</ins><span class="cx">                                 } else if (!strcmp(var, &quot;register-proxy&quot;)) {
</span><span class="cx">                                         register_proxy = val;
</span><ins>+                                } else if (!strcmp(var, &quot;outbound-proxy&quot;)) {
+                                        outbound_proxy = val;
</ins><span class="cx">                                 } else if (!strcmp(var, &quot;contact-params&quot;)) {
</span><span class="cx">                                         contact_params = val;
</span><span class="cx">                                 } else if (!strcmp(var, &quot;register-transport&quot;)) {
</span><span class="lines">@@ -821,8 +1350,25 @@
</span><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx"> 
</span><ins>+                        if (ping_freq) {
+                                if (ping_freq &gt;= 5) {
+                                        gateway-&gt;ping_freq = ping_freq;
+                                        gateway-&gt;ping = switch_epoch_time_now(NULL) + ping_freq;
+                                } else {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;ERROR: invalid ping!\n&quot;);
+                                }
+                        }
+
+                        if ((gw_subs_tag = switch_xml_child(gateway_tag, &quot;subscriptions&quot;))) {
+                                parse_gateway_subscriptions(profile, gateway, gw_subs_tag);
+                        }
+                        
</ins><span class="cx">                         if (switch_strlen_zero(realm)) {
</span><del>-                                realm = name;
</del><ins>+                                if (switch_strlen_zero(proxy)) {
+                                        realm = name;
+                                } else {
+                                        realm = proxy;
+                                }
</ins><span class="cx">                         }
</span><span class="cx"> 
</span><span class="cx">                         if (switch_strlen_zero(username)) {
</span><span class="lines">@@ -849,46 +1395,86 @@
</span><span class="cx"> 
</span><span class="cx">                         if (!switch_true(register_str)) {
</span><span class="cx">                                 gateway-&gt;state = REG_STATE_NOREG;
</span><ins>+                                gateway-&gt;status = SOFIA_GATEWAY_UP;
</ins><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        if (switch_strlen_zero(from_domain)) {
-                                from_domain = realm;
</del><ins>+                        if (switch_strlen_zero(auth_username)) {
+                                auth_username = username;
</ins><span class="cx">                         }
</span><ins>+                        
+                        if (!switch_strlen_zero(register_proxy)) {
+                                if (strncasecmp(register_proxy, &quot;sip:&quot;, 4) &amp;&amp; strncasecmp(register_proxy, &quot;sips:&quot;, 5)) {
+                                        gateway-&gt;register_sticky_proxy = switch_core_sprintf(gateway-&gt;pool, &quot;sip:%s&quot;, register_proxy);
+                                } else {
+                                        gateway-&gt;register_sticky_proxy = switch_core_strdup(gateway-&gt;pool, register_proxy);
+                                }
+                        }
</ins><span class="cx"> 
</span><del>-                        if (switch_strlen_zero(register_proxy)) {
-                                register_proxy = proxy;
</del><ins>+                        if (!switch_strlen_zero(outbound_proxy)) {
+                                if (strncasecmp(outbound_proxy, &quot;sip:&quot;, 4) &amp;&amp; strncasecmp(outbound_proxy, &quot;sips:&quot;, 5)) {
+                                        gateway-&gt;outbound_sticky_proxy = switch_core_sprintf(gateway-&gt;pool, &quot;sip:%s&quot;, outbound_proxy);
+                                } else {
+                                        gateway-&gt;outbound_sticky_proxy = switch_core_strdup(gateway-&gt;pool, outbound_proxy);
+                                }
</ins><span class="cx">                         }
</span><span class="cx"> 
</span><span class="cx">                         gateway-&gt;retry_seconds = atoi(retry_seconds);
</span><del>-                        if (gateway-&gt;retry_seconds &lt; 10) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;INVALID: retry_seconds correcting the value to 30\n&quot;);
</del><ins>+
+                        if (gateway-&gt;retry_seconds &lt; 5) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid retry-seconds of %d on gateway %s, using the value of 30 instead.\n&quot;,
+                                                                  gateway-&gt;retry_seconds, name);
</ins><span class="cx">                                 gateway-&gt;retry_seconds = 30;
</span><span class="cx">                         }
</span><ins>+
</ins><span class="cx">                         gateway-&gt;register_scheme = switch_core_strdup(gateway-&gt;pool, scheme);
</span><span class="cx">                         gateway-&gt;register_context = switch_core_strdup(gateway-&gt;pool, context);
</span><span class="cx">                         gateway-&gt;register_realm = switch_core_strdup(gateway-&gt;pool, realm);
</span><span class="cx">                         gateway-&gt;register_username = switch_core_strdup(gateway-&gt;pool, username);
</span><ins>+                        gateway-&gt;auth_username = switch_core_strdup(gateway-&gt;pool, auth_username);
</ins><span class="cx">                         gateway-&gt;register_password = switch_core_strdup(gateway-&gt;pool, password);
</span><ins>+
</ins><span class="cx">                         if (switch_true(caller_id_in_from)) {
</span><del>-                                switch_set_flag(gateway, REG_FLAG_CALLERID);
</del><ins>+                                sofia_set_flag(gateway, REG_FLAG_CALLERID);
</ins><span class="cx">                         }
</span><del>-                        register_transport = (char *)sofia_glue_transport2str(gateway-&gt;register_transport);
</del><ins>+
+                        register_transport = (char *) sofia_glue_transport2str(gateway-&gt;register_transport);
+
</ins><span class="cx">                         if (contact_params) {
</span><span class="cx">                                 if (*contact_params == ';') {
</span><del>-                                        params = switch_core_sprintf(gateway-&gt;pool, &quot;%s&amp;transport=%s&quot;, contact_params, register_transport);
</del><ins>+                                        params = switch_core_sprintf(gateway-&gt;pool, &quot;%s;transport=%s&quot;, contact_params, register_transport);
</ins><span class="cx">                                 } else {
</span><del>-                                        params = switch_core_sprintf(gateway-&gt;pool, &quot;;%s&amp;transport=%s&quot;, contact_params, register_transport);
</del><ins>+                                        params = switch_core_sprintf(gateway-&gt;pool, &quot;;%s;transport=%s&quot;, contact_params, register_transport);
</ins><span class="cx">                                 }
</span><span class="cx">                         } else {
</span><span class="cx">                                 params = switch_core_sprintf(gateway-&gt;pool, &quot;;transport=%s&quot;, register_transport);
</span><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        gateway-&gt;register_url = switch_core_sprintf(gateway-&gt;pool, &quot;sip:%s;transport=%s&quot;, register_proxy, register_transport);
-                        gateway-&gt;register_from = switch_core_sprintf(gateway-&gt;pool, &quot;&lt;sip:%s@%s;transport=%s&gt;&quot;, from_user, from_domain, register_transport);
-                        gateway-&gt;register_contact = switch_core_sprintf(gateway-&gt;pool, &quot;&lt;sip:%s@%s:%d%s&gt;&quot;, extension,
-                                                                                                 profile-&gt;extsipip ? profile-&gt;extsipip : profile-&gt;sipip,
-                                                                                                 sofia_glue_transport_has_tls(gateway-&gt;register_transport) ? profile-&gt;tls_sip_port : profile-&gt;sip_port, params);
</del><ins>+                        if (!switch_strlen_zero(from_domain)) {
+                                gateway-&gt;from_domain = switch_core_strdup(gateway-&gt;pool, from_domain);
+                        }
</ins><span class="cx"> 
</span><ins>+                        gateway-&gt;register_url = switch_core_sprintf(gateway-&gt;pool, &quot;sip:%s&quot;, proxy);
+                        gateway-&gt;register_from = switch_core_sprintf(gateway-&gt;pool, &quot;&lt;sip:%s@%s;transport=%s&gt;&quot;, 
+                                                                                                                 from_user, from_domain ? from_domain : proxy, register_transport);
+
+                        sipip = contact_host ? contact_host : profile-&gt;extsipip ?  profile-&gt;extsipip : profile-&gt;sipip;
+
+                        if (extension_in_contact) {
+                                format = strchr(sipip, ':') ? &quot;&lt;sip:%s@[%s]:%d%s&gt;&quot; : &quot;&lt;sip:%s@%s:%d%s&gt;&quot;;
+                                gateway-&gt;register_contact = switch_core_sprintf(gateway-&gt;pool, format, extension,
+                                                                                                                                sipip,
+                                                                                                                                sofia_glue_transport_has_tls(gateway-&gt;register_transport) ?
+                                                                                                                                profile-&gt;tls_sip_port : profile-&gt;sip_port, params);
+                        } else {
+                                format = strchr(sipip, ':') ? &quot;&lt;sip:gw+%s@[%s]:%d%s&gt;&quot; : &quot;&lt;sip:gw+%s@%s:%d%s&gt;&quot;;
+                                gateway-&gt;register_contact = switch_core_sprintf(gateway-&gt;pool, format, gateway-&gt;name,
+                                                                                                                                sipip,
+                                                                                                                                sofia_glue_transport_has_tls(gateway-&gt;register_transport) ?
+                                                                                                                                profile-&gt;tls_sip_port : profile-&gt;sip_port, params);
+                        }
+
+                        gateway-&gt;extension = switch_core_strdup(gateway-&gt;pool, extension);
+                        
</ins><span class="cx">                         if (!strncasecmp(proxy, &quot;sip:&quot;, 4)) {
</span><span class="cx">                                 gateway-&gt;register_proxy = switch_core_strdup(gateway-&gt;pool, proxy);
</span><span class="cx">                                 gateway-&gt;register_to = switch_core_sprintf(gateway-&gt;pool, &quot;sip:%s@%s&quot;, username, proxy + 4);
</span><span class="lines">@@ -900,46 +1486,530 @@
</span><span class="cx">                         gateway-&gt;expires_str = switch_core_strdup(gateway-&gt;pool, expire_seconds);
</span><span class="cx"> 
</span><span class="cx">                         if ((gateway-&gt;freq = atoi(gateway-&gt;expires_str)) &lt; 5) {
</span><del>-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-                                                                   &quot;Invalid Freq: %d.  Setting Register-Frequency to 3600\n&quot;, gateway-&gt;freq);
</del><ins>+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid register-frequency of %d on gateway %s, using the value of 3600 instead\n&quot;,
+                                                                  gateway-&gt;freq, name);
</ins><span class="cx">                                 gateway-&gt;freq = 3600;
</span><span class="cx">                         }
</span><del>-                        gateway-&gt;freq -= 2;
</del><span class="cx"> 
</span><span class="cx">                         gateway-&gt;next = profile-&gt;gateways;
</span><span class="cx">                         profile-&gt;gateways = gateway;
</span><span class="cx">                         sofia_reg_add_gateway(gateway-&gt;name, gateway);
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-        skip:
</del><ins>+          skip:
</ins><span class="cx">                 switch_assert(gateway_tag);
</span><span class="cx">         }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> static void parse_domain_tag(sofia_profile_t *profile, switch_xml_t x_domain_tag, const char *dname, const char *parse, const char *alias)
</span><span class="cx"> {
</span><del>-
</del><span class="cx">         if (switch_true(alias)) {
</span><span class="cx">                 if (sofia_glue_add_profile(switch_core_strdup(profile-&gt;pool, dname), profile) == SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Adding Alias [%s] for profile [%s]\n&quot;, dname, profile-&gt;name);
</span><span class="cx">                 } else {
</span><del>-                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Adding Alias [%s] for profile [%s] (name in use)\n&quot;, 
</del><ins>+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Alias [%s] for profile [%s] (already exists)\n&quot;,                         
</ins><span class="cx">                                                           dname, profile-&gt;name);
</span><span class="cx">                 }
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         if (switch_true(parse)) {
</span><del>-                switch_xml_t ut, gateways_tag;
</del><ins>+                switch_xml_t gts, gt, uts, ut, gateways_tag;
+                /* Backwards Compatibility */
</ins><span class="cx">                 for (ut = switch_xml_child(x_domain_tag, &quot;user&quot;); ut; ut = ut-&gt;next) {
</span><span class="cx">                         if (((gateways_tag = switch_xml_child(ut, &quot;gateways&quot;)))) {
</span><span class="cx">                                 parse_gateways(profile, gateways_tag);
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><ins>+                /* New Method with &lt;groups&gt; tags and users are now inside a &lt;users&gt; tag */
+                for (gts = switch_xml_child(x_domain_tag, &quot;groups&quot;); gts; gts = gts-&gt;next) {
+                        for (gt = switch_xml_child(gts, &quot;group&quot;); gt; gt = gt-&gt;next) {
+                                for (uts = switch_xml_child(gt, &quot;users&quot;); uts; uts = uts-&gt;next) {
+                                        for (ut = switch_xml_child(uts, &quot;user&quot;); ut; ut = ut-&gt;next) {
+                                                if (((gateways_tag = switch_xml_child(ut, &quot;gateways&quot;)))) {
+                                                        parse_gateways(profile, gateways_tag);
+                                                }
+                                        }
+                                }
+                        }
+                }
</ins><span class="cx">         }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void parse_rtp_bugs(sofia_profile_t *profile, const char *str)
+{
+        if (switch_stristr(&quot;clear&quot;, str)) {
+                profile-&gt;auto_rtp_bugs = 0;
+        }
</ins><span class="cx"> 
</span><ins>+        if (switch_stristr(&quot;CISCO_SKIP_MARK_BIT_2833&quot;, str)) {
+                profile-&gt;auto_rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
+        }
+
+        if (switch_stristr(&quot;~CISCO_SKIP_MARK_BIT_2833&quot;, str)) {
+                profile-&gt;auto_rtp_bugs &amp;= ~RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
+        }
+        
+        if (switch_stristr(&quot;SONUS_SEND_INVALID_TIMESTAMP_2833&quot;, str)) {
+                profile-&gt;auto_rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+        }
+
+        if (switch_stristr(&quot;~SONUS_SEND_INVALID_TIMESTAMP_2833&quot;, str)) {
+                profile-&gt;auto_rtp_bugs &amp;= ~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 = &quot;sofia.conf&quot;;
+        switch_event_t *params = NULL;
+        switch_status_t status = SWITCH_STATUS_FALSE;
+
+        switch_event_create(&amp;params, SWITCH_EVENT_REQUEST_PARAMS);
+        switch_assert(params);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;profile&quot;, profile-&gt;name);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;reconfig&quot;, &quot;true&quot;);
+
+        if (!(xml = switch_xml_open_cfg(cf, &amp;cfg, params))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Open of %s failed\n&quot;, cf);
+                status = SWITCH_STATUS_FALSE;
+                goto done;
+        }
+        
+        if ((profiles = switch_xml_child(cfg, &quot;profiles&quot;))) {
+                for (xprofile = switch_xml_child(profiles, &quot;profile&quot;); xprofile; xprofile = xprofile-&gt;next) {
+                        char *xprofilename = (char *) switch_xml_attr_soft(xprofile, &quot;name&quot;);
+                        char *xprofiledomain = (char *) switch_xml_attr(xprofile, &quot;domain&quot;);
+
+                        if (strcasecmp(profile-&gt;name, xprofilename)) {
+                                continue;
+                        }
+
+                        /* you could change profile-&gt;foo here if it was a minor change like context or dialplan ... */
+                        profile-&gt;rport_level = 1; /* default setting */
+                        profile-&gt;acl_count = 0;
+                        sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+                        profile-&gt;ib_calls = 0;
+                        profile-&gt;ob_calls = 0;
+                        profile-&gt;ib_failed_calls = 0;
+                        profile-&gt;ob_failed_calls = 0;
+
+                        if (xprofiledomain) {
+                                profile-&gt;domain_name = switch_core_strdup(profile-&gt;pool, xprofiledomain);
+                        }
+
+                        if ((settings = switch_xml_child(xprofile, &quot;settings&quot;))) {
+                                for (param = switch_xml_child(settings, &quot;param&quot;); param; param = param-&gt;next) {
+                                        char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
+                                        char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
+                                        if (!strcasecmp(var, &quot;debug&quot;)) {
+                                                profile-&gt;debug = atoi(val);
+                                        } else if (!strcasecmp(var, &quot;tracelevel&quot;)) {
+                                                mod_sofia_globals.tracelevel = switch_log_str2level(val);
+                                        } else if (!strcasecmp(var, &quot;sip-trace&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_flag(profile, TFLAG_TPORT_LOG);
+                                                } else {
+                                                        sofia_clear_flag(profile, TFLAG_TPORT_LOG);
+                                                }
+                                                nua_set_params(profile-&gt;nua, TPTAG_LOG(sofia_test_flag(profile, TFLAG_TPORT_LOG)), TAG_END());
+                                        } else if (!strcasecmp(var, &quot;send-message-query-on-register&quot;)) {
+                                                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, &quot;auto-rtp-bugs&quot;)) {
+                                                parse_rtp_bugs(profile, val);
+                                        } else if (!strcasecmp(var, &quot;user-agent-string&quot;)) { 
+                                                profile-&gt;user_agent = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;auto-restart&quot;)) {
+                                                profile-&gt;auto_restart = switch_true(val);
+                                        } else if (!strcasecmp(var, &quot;dtmf-type&quot;)) {
+                                                if (!strcasecmp(val, &quot;rfc2833&quot;)) {
+                                                        profile-&gt;dtmf_type = DTMF_2833;
+                                                } else if (!strcasecmp(val, &quot;info&quot;)) {
+                                                        profile-&gt;dtmf_type = DTMF_INFO;
+                                                } else {
+                                                        profile-&gt;dtmf_type = DTMF_NONE;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;NDLB-force-rport&quot;)) {
+                                                if (switch_true(val)) {
+                                                        profile-&gt;rport_level = 2;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;caller-id-type&quot;)) {
+                                                profile-&gt;cid_type = sofia_cid_name2type(val);
+                                        } else if (!strcasecmp(var, &quot;record-template&quot;)) {
+                                                profile-&gt;record_template = switch_core_strdup(profile-&gt;pool, val);;
+                                        } else if ((!strcasecmp(var, &quot;inbound-no-media&quot;) || !strcasecmp(var, &quot;inbound-bypass-media&quot;))) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_flag(profile, TFLAG_INB_NOMEDIA);
+                                                } else {
+                                                        sofia_clear_flag(profile, TFLAG_INB_NOMEDIA);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;force-subscription-expires&quot;)) {
+                                                int tmp = atoi(val);
+                                                if (tmp &gt; 0) {
+                                                        profile-&gt;force_subscription_expires = tmp;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;inbound-late-negotiation&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION);
+                                                } else {
+                                                        sofia_clear_flag(profile, TFLAG_LATE_NEGOTIATION);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;inbound-proxy-media&quot;)) {
+                                                if (switch_true(val)) { 
+                                                        sofia_set_flag(profile, TFLAG_PROXY_MEDIA);
+                                                } else {
+                                                        sofia_clear_flag(profile, TFLAG_PROXY_MEDIA);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;inbound-use-callid-as-uuid&quot;)) {
+                                                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, &quot;rtp-autoflush-during-bridge&quot;)) {
+                                                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, &quot;manual-redirect&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_MANUAL_REDIRECT);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;outbound-use-uuid-as-callid&quot;)) {
+                                                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, &quot;NDLB-received-in-nat-reg-contact&quot;)) {
+                                                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, &quot;aggressive-nat-detection&quot;)) {
+                                                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, &quot;disable-rtp-auto-adjust&quot;)) {
+                                                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, &quot;NDLB-support-asterisk-missing-srtp-auth&quot;)) {
+                                                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, &quot;NDLB-funny-stun&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_FUNNY_STUN); 
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_FUNNY_STUN); 
+                                                }
+                                        } else if (!strcasecmp(var, &quot;stun-enabled&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_STUN_ENABLED);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;stun-auto-disable&quot;)) {
+                                                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, &quot;apply-nat-acl&quot;)) {
+                                                if (profile-&gt;acl_count &lt; SOFIA_MAX_ACL) {
+                                                        if (!profile-&gt;extsipip &amp;&amp; switch_check_network_list_ip(profile-&gt;sipip, val)) {
+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Not adding acl %s because it's the local network\n&quot;, val);
+                                                        } else {
+                                                                profile-&gt;nat_acl[profile-&gt;nat_acl_count++] = switch_core_strdup(profile-&gt;pool, val);
+                                                        }
+                                                } else {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Max acl records of %d reached\n&quot;, SOFIA_MAX_ACL);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;apply-inbound-acl&quot;)) {
+                                                if (profile-&gt;acl_count &lt; SOFIA_MAX_ACL) {
+                                                        profile-&gt;acl[profile-&gt;acl_count++] = switch_core_strdup(profile-&gt;pool, val);
+                                                } else {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Max acl records of %d reached\n&quot;, SOFIA_MAX_ACL);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;apply-register-acl&quot;)) {
+                                                if (profile-&gt;reg_acl_count &lt; SOFIA_MAX_ACL) {
+                                                        profile-&gt;reg_acl[profile-&gt;reg_acl_count++] = switch_core_strdup(profile-&gt;pool, val);
+                                                } else {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Max acl records of %d reached\n&quot;, SOFIA_MAX_ACL);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;rfc2833-pt&quot;)) {
+                                                profile-&gt;te = (switch_payload_t) atoi(val);
+                                        } else if (!strcasecmp(var, &quot;cng-pt&quot;) &amp;&amp; !(sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG))) {
+                                                profile-&gt;cng_pt = (switch_payload_t) atoi(val);
+                                        } else if (!strcasecmp(var, &quot;vad&quot;)) {
+                                                if (!strcasecmp(val, &quot;in&quot;)) {
+                                                        sofia_set_flag(profile, TFLAG_VAD_IN);
+                                                } else if (!strcasecmp(val, &quot;out&quot;)) {
+                                                        sofia_set_flag(profile, TFLAG_VAD_OUT);
+                                                } else if (!strcasecmp(val, &quot;both&quot;)) {
+                                                        sofia_set_flag(profile, TFLAG_VAD_IN);
+                                                        sofia_set_flag(profile, TFLAG_VAD_OUT);
+                                                } else if (strcasecmp(val, &quot;none&quot;)) {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid option %s for VAD\n&quot;, val);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;unregister-on-options-fail&quot;)) {
+                                                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, &quot;require-secure-rtp&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_SECURE);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_SECURE);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;multiple-registrations&quot;)) {
+                                                if (!strcasecmp(val, &quot;call-id&quot;)) {
+                                                        sofia_set_pflag(profile, PFLAG_MULTIREG);
+                                                } else if (!strcasecmp(val, &quot;contact&quot;) || 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, &quot;supress-cng&quot;) || !strcasecmp(var, &quot;suppress-cng&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_SUPPRESS_CNG);
+                                                        profile-&gt;cng_pt = 0;
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_SUPPRESS_CNG);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;NDLB-broken-auth-hash&quot;)) {
+                                                if (switch_true(val)) {
+                                                        profile-&gt;ndlb |= PFLAG_NDLB_BROKEN_AUTH_HASH;
+                                                } else {
+                                                        profile-&gt;ndlb &amp;= ~PFLAG_NDLB_BROKEN_AUTH_HASH;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;NDLB-sendrecv-in-session&quot;)) {
+                                                if (switch_true(val)) {
+                                                        profile-&gt;ndlb |= PFLAG_NDLB_SENDRECV_IN_SESSION;
+                                                } else {
+                                                        profile-&gt;ndlb &amp;= ~PFLAG_NDLB_SENDRECV_IN_SESSION;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;pass-rfc2833&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_PASS_RFC2833);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_PASS_RFC2833);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;rtp-autoflush&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_AUTOFLUSH);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_AUTOFLUSH);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;rtp-autofix-timing&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_AUTOFIX_TIMING);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_AUTOFIX_TIMING);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;nat-options-ping&quot;)) {
+                                                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, &quot;inbound-codec-negotiation&quot;)) {
+                                                if (!strcasecmp(val, &quot;greedy&quot;)) {
+                                                        sofia_set_pflag(profile, PFLAG_GREEDY);
+                                                } else if (!strcasecmp(val, &quot;scrooge&quot;)) {
+                                                        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, &quot;disable-transcoding&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_DISABLE_TRANSCODING);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_DISABLE_TRANSCODING);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;rtp-rewrite-timestamps&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_REWRITE_TIMESTAMPS);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_REWRITE_TIMESTAMPS);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;auth-calls&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_AUTH_CALLS);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_AUTH_CALLS);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;context&quot;)) {
+                                                profile-&gt;context = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;local-network-acl&quot;)) {
+                                                profile-&gt;local_network = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;force-register-domain&quot;)) {
+                                                profile-&gt;reg_domain = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;force-register-db-domain&quot;)) {
+                                                profile-&gt;reg_db_domain = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;hold-music&quot;)) {
+                                                profile-&gt;hold_music = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;outbound-proxy&quot;)) {
+                                                profile-&gt;outbound_proxy = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;session-timeout&quot;)) {
+                                                int v_session_timeout = atoi(val);
+                                                if (v_session_timeout &gt;= 0) {
+                                                        profile-&gt;session_timeout = v_session_timeout;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;rtp-timeout-sec&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt;= 0) {
+                                                        profile-&gt;rtp_timeout_sec = v;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;rtp-hold-timeout-sec&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt;= 0) {
+                                                        profile-&gt;rtp_hold_timeout_sec = v;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;nonce-ttl&quot;)) {
+                                                profile-&gt;nonce_ttl = atoi(val);
+                                        } else if (!strcasecmp(var, &quot;dialplan&quot;)) {
+                                                profile-&gt;dialplan = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;max-calls&quot;)) {
+                                                profile-&gt;max_calls = atoi(val);
+                                        } else if (!strcasecmp(var, &quot;codec-prefs&quot;)) {
+                                                profile-&gt;codec_string = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;challenge-realm&quot;)) {
+                                                profile-&gt;challenge_realm = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;dtmf-duration&quot;)) {
+                                                int dur = atoi(val);
+                                                if (dur &gt; 10 &amp;&amp; dur &lt; 8000) {
+                                                        profile-&gt;dtmf_duration = dur;
+                                                } else {
+                                                        profile-&gt;dtmf_duration = SWITCH_DEFAULT_DTMF_DURATION;
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Duration out of bounds, using default of %d!\n&quot;, SWITCH_DEFAULT_DTMF_DURATION);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;timer-T1&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t1 = v;
+                                                } else {
+                                                        profile-&gt;timer_t1 = 500;
+                                                }
+                                                nua_set_params(profile-&gt;nua, NTATAG_SIP_T1(profile-&gt;timer_t1), TAG_END());
+                                        } else if (!strcasecmp(var, &quot;timer-T1X64&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t1x64 = v;
+                                                } else {
+                                                        profile-&gt;timer_t1x64 = 32000;
+                                                }
+                                                nua_set_params(profile-&gt;nua, NTATAG_SIP_T1X64(profile-&gt;timer_t1x64), TAG_END());
+                                        } else if (!strcasecmp(var, &quot;timer-T2&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t2 = v;
+                                                } else {
+                                                        profile-&gt;timer_t2 = 4000;
+                                                }
+                                                nua_set_params(profile-&gt;nua, NTATAG_SIP_T2(profile-&gt;timer_t2), TAG_END());
+                                        } else if (!strcasecmp(var, &quot;timer-T4&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t4 = v;
+                                                } else {
+                                                        profile-&gt;timer_t4 = 4000;
+                                                }
+                                                nua_set_params(profile-&gt;nua, NTATAG_SIP_T4(profile-&gt;timer_t4), TAG_END());
+                                        }
+                                }
+                        }
+
+                        if ((gateways_tag = switch_xml_child(xprofile, &quot;gateways&quot;))) {
+                                parse_gateways(profile, gateways_tag);
+                        }
+                        
+                        status = SWITCH_STATUS_SUCCESS;
+
+                        if ((domains_tag = switch_xml_child(xprofile, &quot;domains&quot;))) {
+                                switch_event_t *xml_params;
+                                switch_event_create(&amp;xml_params, SWITCH_EVENT_REQUEST_PARAMS);
+                                switch_assert(xml_params);
+                                switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, &quot;purpose&quot;, &quot;gateways&quot;);
+                                switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, &quot;profile&quot;, profile-&gt;name);
+                                
+                                for (domain_tag = switch_xml_child(domains_tag, &quot;domain&quot;); domain_tag; domain_tag = domain_tag-&gt;next) {
+                                        switch_xml_t droot, x_domain_tag;
+                                        const char *dname = switch_xml_attr_soft(domain_tag, &quot;name&quot;);
+                                        const char *parse = switch_xml_attr_soft(domain_tag, &quot;parse&quot;);
+                                        const char *alias = switch_xml_attr_soft(domain_tag, &quot;alias&quot;);
+
+                                        if (!switch_strlen_zero(dname)) {
+                                                if (!strcasecmp(dname, &quot;all&quot;)) {
+                                                        switch_xml_t xml_root, x_domains;
+                                                        if (switch_xml_locate(&quot;directory&quot;, NULL, NULL, NULL, &amp;xml_root, &amp;x_domains, xml_params, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+                                                                for (x_domain_tag = switch_xml_child(x_domains, &quot;domain&quot;); x_domain_tag; x_domain_tag = x_domain_tag-&gt;next) {
+                                                                        dname = switch_xml_attr_soft(x_domain_tag, &quot;name&quot;);
+                                                                        parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
+                                                                }
+                                                                switch_xml_free(xml_root);
+                                                        }
+                                                } else if (switch_xml_locate_domain(dname, xml_params, &amp;droot, &amp;x_domain_tag) == SWITCH_STATUS_SUCCESS) {
+                                                        parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
+                                                        switch_xml_free(droot);
+                                                }
+                                        }
+                                }
+                                
+                                switch_event_destroy(&amp;xml_params);
+                        }
+
+                        if ((aliases_tag = switch_xml_child(xprofile, &quot;aliases&quot;))) {
+                                for (alias_tag = switch_xml_child(aliases_tag, &quot;alias&quot;); alias_tag; alias_tag = alias_tag-&gt;next) {
+                                        char *aname = (char *) switch_xml_attr_soft(alias_tag, &quot;name&quot;);
+                                        if (!switch_strlen_zero(aname)) {
+                                                
+                                                if (sofia_glue_add_profile(switch_core_strdup(profile-&gt;pool, aname), profile) == SWITCH_STATUS_SUCCESS) {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Adding Alias [%s] for profile [%s]\n&quot;, aname, profile-&gt;name);
+                                                } else {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Alias [%s] for profile [%s] (already exists)\n&quot;,
+                                                                                          aname, profile-&gt;name);
+                                                }
+                                        }
+                                }
+                        }
+                }
+        }
+
+ done:
+
+        if (xml) {
+        switch_xml_free(xml);
+    }
+
+        switch_event_destroy(&amp;params);
+
+        return status;
+}
+
</ins><span class="cx"> switch_status_t config_sofia(int reload, char *profile_name)
</span><span class="cx"> {
</span><span class="cx">         char *cf = &quot;sofia.conf&quot;;
</span><span class="lines">@@ -949,41 +2019,60 @@
</span><span class="cx">         char url[512] = &quot;&quot;;
</span><span class="cx">         int profile_found = 0;
</span><span class="cx">         switch_event_t *params = NULL;;
</span><del>-        
</del><ins>+
</ins><span class="cx">         if (!reload) {
</span><span class="cx">                 su_init();
</span><span class="cx">                 if (sip_update_default_mclass(sip_extend_mclass(NULL)) &lt; 0) {
</span><span class="cx">                         su_deinit();
</span><span class="cx">                         return SWITCH_STATUS_FALSE;
</span><span class="cx">                 }
</span><del>-
-                su_log_redirect(NULL, logger, NULL);
</del><ins>+                
+                /* Redirect loggers in sofia */
+                su_log_redirect(su_log_default, logger, NULL);
</ins><span class="cx">                 su_log_redirect(tport_log, logger, NULL);
</span><ins>+                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);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!switch_strlen_zero(profile_name) &amp;&amp; (profile = sofia_glue_find_profile(profile_name))) {
</span><del>-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Profile [%s] Already exists.\n&quot;, switch_str_nil(profile_name));
</del><ins>+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Profile [%s] Already exists.\n&quot;, switch_str_nil(profile_name));
</ins><span class="cx">                 status = SWITCH_STATUS_FALSE;
</span><span class="cx">                 sofia_glue_release_profile(profile);
</span><span class="cx">                 return status;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        switch_event_create(&amp;params, SWITCH_EVENT_MESSAGE);
</del><ins>+        switch_event_create(&amp;params, SWITCH_EVENT_REQUEST_PARAMS);
</ins><span class="cx">         switch_assert(params);
</span><span class="cx">         switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;profile&quot;, profile_name);
</span><del>-        
</del><ins>+
</ins><span class="cx">         if (!(xml = switch_xml_open_cfg(cf, &amp;cfg, params))) {
</span><del>-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;open of %s failed\n&quot;, cf);
</del><ins>+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Open of %s failed\n&quot;, cf);
</ins><span class="cx">                 status = SWITCH_STATUS_FALSE;
</span><span class="cx">                 goto done;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        mod_sofia_globals.auto_restart = SWITCH_TRUE;
+        mod_sofia_globals.rewrite_multicasted_fs_path = SWITCH_FALSE;
+
</ins><span class="cx">         if ((settings = switch_xml_child(cfg, &quot;global_settings&quot;))) {
</span><span class="cx">                 for (param = switch_xml_child(settings, &quot;param&quot;); param; param = param-&gt;next) {
</span><span class="cx">                         char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
</span><span class="cx">                         char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
</span><span class="cx">                         if (!strcasecmp(var, &quot;log-level&quot;)) {
</span><span class="cx">                                 su_log_set_level(NULL, atoi(val));
</span><ins>+                        } else if (!strcasecmp(var, &quot;debug-presence&quot;)) {
+                                mod_sofia_globals.debug_presence = atoi(val);
+                        } else if (!strcasecmp(var, &quot;auto-restart&quot;)) {
+                                mod_sofia_globals.auto_restart = switch_true(val);
+                        } else if (!strcasecmp(var, &quot;rewrite-multicasted-fs-path&quot;)) {
+                                mod_sofia_globals.rewrite_multicasted_fs_path = switch_true(val);
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="lines">@@ -1020,6 +2109,8 @@
</span><span class="cx">                                         goto done;
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><ins>+                                profile-&gt;auto_rtp_bugs = RTP_BUG_CISCO_SKIP_MARK_BIT_2833 | RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+
</ins><span class="cx">                                 profile-&gt;pool = pool;
</span><span class="cx">                                 profile-&gt;user_agent = SOFIA_USER_AGENT;
</span><span class="cx"> 
</span><span class="lines">@@ -1028,44 +2119,48 @@
</span><span class="cx"> 
</span><span class="cx">                                 if (xprofiledomain) {
</span><span class="cx">                                         profile-&gt;domain_name = switch_core_strdup(profile-&gt;pool, xprofiledomain);
</span><del>-                                } else {
-                                        profile-&gt;domain_name = profile-&gt;name;
</del><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 profile-&gt;dbname = switch_core_strdup(profile-&gt;pool, url);
</span><span class="cx">                                 switch_core_hash_init(&amp;profile-&gt;chat_hash, profile-&gt;pool);
</span><del>-                                switch_core_hash_init(&amp;profile-&gt;sub_hash, profile-&gt;pool);
</del><span class="cx">                                 switch_thread_rwlock_create(&amp;profile-&gt;rwlock, profile-&gt;pool);
</span><span class="cx">                                 switch_mutex_init(&amp;profile-&gt;flag_mutex, SWITCH_MUTEX_NESTED, profile-&gt;pool);
</span><span class="cx">                                 profile-&gt;dtmf_duration = 100;
</span><span class="cx">                                 profile-&gt;tls_version = 0;
</span><span class="cx">                                 profile-&gt;mflags = MFLAG_REFER | MFLAG_REGISTER;
</span><del>-                                
</del><ins>+                                profile-&gt;rport_level = 1;
+                                sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+                                sofia_set_pflag(profile, PFLAG_DISABLE_100REL);
+                                profile-&gt;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-&gt;contact_user = SOFIA_DEFAULT_CONTACT_USER;
+
</ins><span class="cx">                                 for (param = switch_xml_child(settings, &quot;param&quot;); param; param = param-&gt;next) {
</span><span class="cx">                                         char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
</span><span class="cx">                                         char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
</span><span class="cx"> 
</span><span class="cx">                                         if (!strcasecmp(var, &quot;debug&quot;)) {
</span><span class="cx">                                                 profile-&gt;debug = atoi(val);
</span><del>-                                        } else if (!strcasecmp(var, &quot;use-rtp-timer&quot;) &amp;&amp; switch_true(val)) {
-                                                switch_set_flag(profile, TFLAG_TIMER);
</del><span class="cx">                                         } else if (!strcasecmp(var, &quot;sip-trace&quot;) &amp;&amp; switch_true(val)) {
</span><del>-                                                switch_set_flag(profile, TFLAG_TPORT_LOG);
</del><ins>+                                                sofia_set_flag(profile, TFLAG_TPORT_LOG);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;odbc-dsn&quot;) &amp;&amp; !switch_strlen_zero(val)) {
</span><del>-#ifdef SWITCH_HAVE_ODBC
-                                                profile-&gt;odbc_dsn = switch_core_strdup(profile-&gt;pool, val);
-                                                if ((profile-&gt;odbc_user = strchr(profile-&gt;odbc_dsn, ':'))) {
-                                                        *profile-&gt;odbc_user++ = '\0';
-                                                        if ((profile-&gt;odbc_pass = strchr(profile-&gt;odbc_user, ':'))) {
-                                                                *profile-&gt;odbc_pass++ = '\0';
</del><ins>+                                                if (switch_odbc_available()) {
+                                                        profile-&gt;odbc_dsn = switch_core_strdup(profile-&gt;pool, val);
+                                                        if ((profile-&gt;odbc_user = strchr(profile-&gt;odbc_dsn, ':'))) {
+                                                                *profile-&gt;odbc_user++ = '\0';
+                                                                if ((profile-&gt;odbc_pass = strchr(profile-&gt;odbc_user, ':'))) {
+                                                                        *profile-&gt;odbc_pass++ = '\0';
+                                                                }
</ins><span class="cx">                                                         }
</span><ins>+                                                } else {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;ODBC IS NOT AVAILABLE!\n&quot;);
</ins><span class="cx">                                                 }
</span><del>-
-#else
-                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;ODBC IS NOT AVAILABLE!\n&quot;);
-#endif
</del><span class="cx">                                         } else if (!strcasecmp(var, &quot;user-agent-string&quot;)) {
</span><del>-                                                profile-&gt;user_agent = switch_core_strdup(profile-&gt;pool, val);;
</del><ins>+                                                profile-&gt;user_agent = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;auto-restart&quot;)) {
+                                                profile-&gt;auto_restart = switch_true(val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;dtmf-type&quot;)) {
</span><span class="cx">                                                 if (!strcasecmp(val, &quot;rfc2833&quot;)) {
</span><span class="cx">                                                         profile-&gt;dtmf_type = DTMF_2833;
</span><span class="lines">@@ -1074,53 +2169,169 @@
</span><span class="cx">                                                 } else {
</span><span class="cx">                                                         profile-&gt;dtmf_type = DTMF_NONE;
</span><span class="cx">                                                 }
</span><ins>+                                        } else if (!strcasecmp(var, &quot;NDLB-force-rport&quot;)) {
+                                                if (switch_true(val)) {
+                                                        profile-&gt;rport_level = 2;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;auto-rtp-bugs&quot;)) {
+                                                parse_rtp_bugs(profile, val);
+                                        } else if (!strcasecmp(var, &quot;dbname&quot;)) {
+                                                profile-&gt;dbname = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;presence-hosts&quot;)) {
+                                                profile-&gt;presence_hosts = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;caller-id-type&quot;)) {
+                                                profile-&gt;cid_type = sofia_cid_name2type(val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;record-template&quot;)) {
</span><del>-                                                profile-&gt;record_template = switch_core_strdup(profile-&gt;pool, val);;
-                                        } else if (!strcasecmp(var, &quot;inbound-no-media&quot;) &amp;&amp; switch_true(val)) {
-                                                switch_set_flag(profile, TFLAG_INB_NOMEDIA);
-                                        } else if (!strcasecmp(var, &quot;inbound-bypass-media&quot;) &amp;&amp; switch_true(val)) {
-                                                switch_set_flag(profile, TFLAG_INB_NOMEDIA);
</del><ins>+                                                profile-&gt;record_template = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if ((!strcasecmp(var, &quot;inbound-no-media&quot;) || !strcasecmp(var, &quot;inbound-bypass-media&quot;)) &amp;&amp; switch_true(val)) {
+                                                sofia_set_flag(profile, TFLAG_INB_NOMEDIA);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;inbound-late-negotiation&quot;) &amp;&amp; switch_true(val)) {
</span><del>-                                                switch_set_flag(profile, TFLAG_LATE_NEGOTIATION);
</del><ins>+                                                sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION);
+                                        } else if (!strcasecmp(var, &quot;rtp-autoflush-during-bridge&quot;)) {
+                                                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, &quot;manual-redirect&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_MANUAL_REDIRECT);
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;inbound-proxy-media&quot;) &amp;&amp; switch_true(val)) {
</span><del>-                                                switch_set_flag(profile, TFLAG_PROXY_MEDIA);
</del><ins>+                                                sofia_set_flag(profile, TFLAG_PROXY_MEDIA);
+                                        } else if (!strcasecmp(var, &quot;force-subscription-expires&quot;)) {
+                                                int tmp = atoi(val);
+                                                if (tmp &gt; 0) {
+                                                        profile-&gt;force_subscription_expires = tmp;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;send-message-query-on-register&quot;)) {
+                                                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, &quot;inbound-use-callid-as-uuid&quot;)) {
+                                                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, &quot;outbound-use-uuid-as-callid&quot;)) {
+                                                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, &quot;NDLB-received-in-nat-reg-contact&quot;) &amp;&amp; switch_true(val)) {
+                                                sofia_set_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT);
+                                        } else if (!strcasecmp(var, &quot;aggressive-nat-detection&quot;) &amp;&amp; switch_true(val)) {
+                                                sofia_set_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION);
+                                        } else if (!strcasecmp(var, &quot;disable-rtp-auto-adjust&quot;) &amp;&amp; switch_true(val)) {
+                                                sofia_set_pflag(profile, PFLAG_DISABLE_RTP_AUTOADJ);
+                                        } else if (!strcasecmp(var, &quot;NDLB-support-asterisk-missing-srtp-auth&quot;) &amp;&amp; switch_true(val)) {
+                                                sofia_set_pflag(profile, PFLAG_DISABLE_SRTP_AUTH);
+                                        } else if (!strcasecmp(var, &quot;NDLB-funny-stun&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_FUNNY_STUN); 
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_FUNNY_STUN); 
+                                                }
+                                        } else if (!strcasecmp(var, &quot;stun-enabled&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_STUN_ENABLED);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_STUN_ENABLED); 
+                                                }
+                                        } else if (!strcasecmp(var, &quot;stun-auto-disable&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_STUN_AUTO_DISABLE);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_STUN_AUTO_DISABLE); 
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;rfc2833-pt&quot;)) {
</span><span class="cx">                                                 profile-&gt;te = (switch_payload_t) atoi(val);
</span><del>-                                        } else if (!strcasecmp(var, &quot;cng-pt&quot;)) {
</del><ins>+                                        } else if (!strcasecmp(var, &quot;cng-pt&quot;) &amp;&amp; !sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG)) {
</ins><span class="cx">                                                 profile-&gt;cng_pt = (switch_payload_t) atoi(val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;sip-port&quot;)) {
</span><del>-                                                profile-&gt;sip_port = strcasecmp(val, &quot;auto&quot;) ? atoi(val) : SOFIA_AUTO_PORT;
</del><ins>+                                                profile-&gt;sip_port = (switch_port_t)atoi(val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;vad&quot;)) {
</span><span class="cx">                                                 if (!strcasecmp(val, &quot;in&quot;)) {
</span><del>-                                                        switch_set_flag(profile, TFLAG_VAD_IN);
</del><ins>+                                                        sofia_set_flag(profile, TFLAG_VAD_IN);
</ins><span class="cx">                                                 } else if (!strcasecmp(val, &quot;out&quot;)) {
</span><del>-                                                        switch_set_flag(profile, TFLAG_VAD_OUT);
</del><ins>+                                                        sofia_set_flag(profile, TFLAG_VAD_OUT);
</ins><span class="cx">                                                 } else if (!strcasecmp(val, &quot;both&quot;)) {
</span><del>-                                                        switch_set_flag(profile, TFLAG_VAD_IN);
-                                                        switch_set_flag(profile, TFLAG_VAD_OUT);
</del><ins>+                                                        sofia_set_flag(profile, TFLAG_VAD_IN);
+                                                        sofia_set_flag(profile, TFLAG_VAD_OUT);
+                                                } else if (strcasecmp(val, &quot;none&quot;)) {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid option %s for VAD\n&quot;, val);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;ext-rtp-ip&quot;)) {
+                                                if (!switch_strlen_zero(val)) {
+                                                        char *ip = mod_sofia_globals.guess_ip;
+                                                        
+                                                        if (!strcmp(val, &quot;0.0.0.0&quot;)) {
+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid IP 0.0.0.0 replaced with %s\n&quot;, mod_sofia_globals.guess_ip);
+                                                        } else if (!strcasecmp(val, &quot;auto-nat&quot;)) {
+                                                                ip = mod_sofia_globals.auto_nat ? switch_core_get_variable(&quot;nat_public_addr&quot;) : mod_sofia_globals.guess_ip; 
+                                                        } else {
+                                                                ip = strcasecmp(val, &quot;auto&quot;) ? val : mod_sofia_globals.guess_ip;
+                                                        }
+                                                        sofia_set_pflag(profile, PFLAG_AUTO_NAT);
+                                                        profile-&gt;extrtpip = switch_core_strdup(profile-&gt;pool, ip);
</ins><span class="cx">                                                 } else {
</span><del>-                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invald option %s for VAD\n&quot;, val);
</del><ins>+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid ext-rtp-ip\n&quot;);
</ins><span class="cx">                                                 }
</span><del>-                                        } else if (!strcasecmp(var, &quot;ext-rtp-ip&quot;)) {
-                                                profile-&gt;extrtpip = switch_core_strdup(profile-&gt;pool, strcasecmp(val, &quot;auto&quot;) ? val : mod_sofia_globals.guess_ip);
</del><span class="cx">                                         } else if (!strcasecmp(var, &quot;rtp-ip&quot;)) {
</span><del>-                                                profile-&gt;rtpip = switch_core_strdup(profile-&gt;pool, strcasecmp(val, &quot;auto&quot;) ? val : mod_sofia_globals.guess_ip);
</del><ins>+                                                char *ip = mod_sofia_globals.guess_ip;
+
+                                                if (!strcmp(val, &quot;0.0.0.0&quot;)) {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid IP 0.0.0.0 replaced with %s\n&quot;, mod_sofia_globals.guess_ip);
+                                                } else {
+                                                        ip = strcasecmp(val, &quot;auto&quot;) ? val : mod_sofia_globals.guess_ip;
+                                                }
+                                                profile-&gt;rtpip = switch_core_strdup(profile-&gt;pool, ip);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;sip-ip&quot;)) {
</span><del>-                                                profile-&gt;sipip = switch_core_strdup(profile-&gt;pool, strcasecmp(val, &quot;auto&quot;) ? val : mod_sofia_globals.guess_ip);
</del><ins>+                                                char *ip = mod_sofia_globals.guess_ip;
+
+                                                if (!strcmp(val, &quot;0.0.0.0&quot;)) {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid IP 0.0.0.0 replaced with %s\n&quot;, mod_sofia_globals.guess_ip);
+                                                } else {
+                                                        ip = strcasecmp(val, &quot;auto&quot;) ? val : mod_sofia_globals.guess_ip;
+                                                }
+                                                profile-&gt;sipip = switch_core_strdup(profile-&gt;pool, ip);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;ext-sip-ip&quot;)) {
</span><del>-                                                if (!strcasecmp(val, &quot;auto&quot;)) {
-                                                        profile-&gt;extsipip = switch_core_strdup(profile-&gt;pool, mod_sofia_globals.guess_ip);
-                                                } else {
</del><ins>+                                                if (!switch_strlen_zero(val)) {
</ins><span class="cx">                                                         char *ip = mod_sofia_globals.guess_ip;
</span><del>-                                                        switch_port_t port = 0;
-                                                        if (sofia_glue_ext_address_lookup(&amp;ip, &amp;port, val, profile-&gt;pool) == SWITCH_STATUS_SUCCESS) {
-                                                                profile-&gt;extsipip = switch_core_strdup(profile-&gt;pool, ip);
-                                                        } else {
-                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Failed to get external ip.\n&quot;);
</del><ins>+                                                        char stun_ip[50] = &quot;&quot;;
+                                                        char *myip = stun_ip;
+                                                        
+                                                        switch_copy_string(stun_ip, ip, sizeof(stun_ip));
+                                                        
+                                                        if (!strcasecmp(val, &quot;0.0.0.0&quot;)) {
+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Invalid IP 0.0.0.0 replaced with %s\n&quot;, mod_sofia_globals.guess_ip);
+                                                        } else if (!strcasecmp(val, &quot;auto-nat&quot;)) {
+                                                                ip = mod_sofia_globals.auto_nat ? switch_core_get_variable(&quot;nat_public_addr&quot;) : mod_sofia_globals.guess_ip;
+                                                        } else if (strcasecmp(val, &quot;auto&quot;)) {
+                                                                switch_port_t port = 0;
+                                                                if (sofia_glue_ext_address_lookup(profile, NULL, &amp;myip, &amp;port, val, profile-&gt;pool) == SWITCH_STATUS_SUCCESS) {
+                                                                        ip = myip;
+                                                                } else {
+                                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Failed to get external ip.\n&quot;);
+                                                                }
</ins><span class="cx">                                                         }
</span><ins>+                                                        sofia_set_pflag(profile, PFLAG_AUTO_NAT);
+                                                        profile-&gt;extsipip = switch_core_strdup(profile-&gt;pool, ip);
+                                                } else {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid ext-sip-ip\n&quot;);
</ins><span class="cx">                                                 }
</span><ins>+                                        } else if (!strcasecmp(var, &quot;local-network-acl&quot;)) {
+                                                profile-&gt;local_network = switch_core_strdup(profile-&gt;pool, val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;force-register-domain&quot;)) {
</span><span class="cx">                                                 profile-&gt;reg_domain = switch_core_strdup(profile-&gt;pool, val);
</span><ins>+                                        } else if (!strcasecmp(var, &quot;force-register-db-domain&quot;)) {
+                                                profile-&gt;reg_db_domain = switch_core_strdup(profile-&gt;pool, val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;bind-params&quot;)) {
</span><span class="cx">                                                 profile-&gt;bind_params = switch_core_strdup(profile-&gt;pool, val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;sip-domain&quot;)) {
</span><span class="lines">@@ -1129,6 +2340,8 @@
</span><span class="cx">                                                 profile-&gt;timer_name = switch_core_strdup(profile-&gt;pool, val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;hold-music&quot;)) {
</span><span class="cx">                                                 profile-&gt;hold_music = switch_core_strdup(profile-&gt;pool, val);
</span><ins>+                                        } else if (!strcasecmp(var, &quot;outbound-proxy&quot;)) {
+                                                profile-&gt;outbound_proxy = switch_core_strdup(profile-&gt;pool, val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;session-timeout&quot;)) {
</span><span class="cx">                                                 int v_session_timeout = atoi(val);
</span><span class="cx">                                                 if (v_session_timeout &gt;= 0) {
</span><span class="lines">@@ -1153,76 +2366,154 @@
</span><span class="cx">                                                 profile-&gt;mflags &amp;= ~MFLAG_REFER;
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;disable-register&quot;) &amp;&amp; switch_true(val)) {
</span><span class="cx">                                                 profile-&gt;mflags &amp;= ~MFLAG_REGISTER;
</span><ins>+                                        } else if (!strcasecmp(var, &quot;media-option&quot;)) {
+                                                if (!strcasecmp(val, &quot;resume-media-on-hold&quot;)) {
+                                                        profile-&gt;media_options |= MEDIA_OPT_MEDIA_ON_HOLD;
+                                                } else if (!strcasecmp(val, &quot;bypass-media-after-att-xfer&quot;)) {
+                                                        profile-&gt;media_options |= MEDIA_OPT_BYPASS_AFTER_ATT_XFER;
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;manage-presence&quot;)) {
</span><ins>+                                                if (!strcasecmp(val, &quot;passive&quot;)) {
+                                                        profile-&gt;pres_type = PRES_TYPE_PASSIVE;
+                                                
+                                                } else if (switch_true(val)) {
+                                                        profile-&gt;pres_type = PRES_TYPE_FULL;
+                                                } 
+                                        } else if (!strcasecmp(var, &quot;manage-shared-appearance&quot;)) {
</ins><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_PRESENCE;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE);
+                                                        profile-&gt;sla_contact = switch_core_sprintf(profile-&gt;pool, &quot;sla-agent&quot;);
</ins><span class="cx">                                                 }
</span><ins>+                                        } else if (!strcasecmp(var, &quot;disable-srv&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_DISABLE_SRV);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;disable-naptr&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_DISABLE_NAPTR);
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;unregister-on-options-fail&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_UNREG_OPTIONS_FAIL;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;require-secure-rtp&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_SECURE;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_SECURE);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;multiple-registrations&quot;)) {
</span><del>-                                                if (switch_true(val)) {
-                                                        profile-&gt;pflags |= PFLAG_MULTIREG;
</del><ins>+                                                if (!strcasecmp(val, &quot;call-id&quot;)) {
+                                                        sofia_set_pflag(profile, PFLAG_MULTIREG);
+                                                } else if (!strcasecmp(val, &quot;contact&quot;) || 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);
</ins><span class="cx">                                                 }
</span><del>-                                        } else if (!strcasecmp(var, &quot;supress-cng&quot;)) {
</del><ins>+                                        } else if (!strcasecmp(var, &quot;supress-cng&quot;) || !strcasecmp(var, &quot;suppress-cng&quot;)) {
</ins><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_SUPRESS_CNG;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_SUPPRESS_CNG);
+                                                        profile-&gt;cng_pt = 0;
</ins><span class="cx">                                                 }
</span><del>-                                        } else if (!strcasecmp(var, &quot;NDLB-to-in-200-contact&quot;)) {
-                                                if (switch_true(val)) {
-                                                        profile-&gt;ndlb |= PFLAG_NDLB_TO_IN_200_CONTACT;
-                                                }
</del><span class="cx">                                         } else if (!strcasecmp(var, &quot;NDLB-broken-auth-hash&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><span class="cx">                                                         profile-&gt;ndlb |= PFLAG_NDLB_BROKEN_AUTH_HASH;
</span><span class="cx">                                                 }
</span><ins>+                                        } else if (!strcasecmp(var, &quot;NDLB-sendrecv-in-session&quot;)) {
+                                                if (switch_true(val)) {
+                                                        profile-&gt;ndlb |= PFLAG_NDLB_SENDRECV_IN_SESSION;
+                                                } else {
+                                                        profile-&gt;ndlb &amp;= ~PFLAG_NDLB_SENDRECV_IN_SESSION;
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;pass-rfc2833&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_PASS_RFC2833;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_PASS_RFC2833);
</ins><span class="cx">                                                 }
</span><ins>+                                        } else if (!strcasecmp(var, &quot;rtp-autoflush&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_AUTOFLUSH);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_AUTOFLUSH);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;rtp-autofix-timing&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_AUTOFIX_TIMING);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_AUTOFIX_TIMING);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;contact-user&quot;)) {
+                                                profile-&gt;contact_user = switch_core_strdup(profile-&gt;pool, val);
+                                        } else if (!strcasecmp(var, &quot;nat-options-ping&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_NAT_OPTIONS_PING);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_NAT_OPTIONS_PING);
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;inbound-codec-negotiation&quot;)) {
</span><span class="cx">                                                 if (!strcasecmp(val, &quot;greedy&quot;)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_GREEDY;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_GREEDY);
+                                                } else if (!strcasecmp(val, &quot;scrooge&quot;)) {
+                                                        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);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;disable-transcoding&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_DISABLE_TRANSCODING;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_DISABLE_TRANSCODING);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;rtp-rewrite-timestamps&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_REWRITE_TIMESTAMPS;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_REWRITE_TIMESTAMPS);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;auth-calls&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_AUTH_CALLS;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_AUTH_CALLS);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;nonce-ttl&quot;)) {
</span><span class="cx">                                                 profile-&gt;nonce_ttl = atoi(val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;accept-blind-reg&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_BLIND_REG;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_BLIND_REG);
</ins><span class="cx">                                                 }
</span><ins>+                                        } else if (!strcasecmp(var, &quot;enable-3pcc&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_3PCC);
+                                                }
+                                                else if (!strcasecmp(val, &quot;proxy&quot;)){
+                                                        sofia_set_pflag(profile, PFLAG_3PCC_PROXY);
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;accept-blind-auth&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_BLIND_AUTH;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_BLIND_AUTH);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;auth-all-packets&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_AUTH_ALL;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_AUTH_ALL);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;full-id-in-dialplan&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_FULL_ID;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_FULL_ID);
</ins><span class="cx">                                                 }
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;inbound-reg-force-matching-username&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><del>-                                                        profile-&gt;pflags |= PFLAG_CHECKUSER;
</del><ins>+                                                        sofia_set_pflag(profile, PFLAG_CHECKUSER);
</ins><span class="cx">                                                 }
</span><ins>+                                        } else if (!strcasecmp(var, &quot;enable-timer&quot;)) {
+                                                if (!switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_DISABLE_TIMER);
+                                                }
+                                        } else if (!strcasecmp(var, &quot;minimum-session-expires&quot;)) {
+                                                profile-&gt;minimum_session_expires = atoi(val);
+                                                /* per RFC 4028: minimum_session_expires must be &gt; 90 */
+                                                if (profile-&gt;minimum_session_expires &lt; 90) {
+                                                        profile-&gt;minimum_session_expires = 90;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;enable-100rel&quot;)) {
+                                                if (switch_true(val)) {
+                                                        sofia_clear_pflag(profile, PFLAG_DISABLE_100REL);
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;bitpacking&quot;)) {
</span><span class="cx">                                                 if (!strcasecmp(val, &quot;aal2&quot;)) {
</span><span class="cx">                                                         profile-&gt;codec_flags = SWITCH_CODEC_FLAG_AAL2;
</span><span class="lines">@@ -1231,6 +2522,16 @@
</span><span class="cx">                                                 profile-&gt;username = switch_core_strdup(profile-&gt;pool, val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;context&quot;)) {
</span><span class="cx">                                                 profile-&gt;context = switch_core_strdup(profile-&gt;pool, val);
</span><ins>+                                        } else if (!strcasecmp(var, &quot;apply-nat-acl&quot;)) {
+                                                if (profile-&gt;acl_count &lt; SOFIA_MAX_ACL) {
+                                                        if (!profile-&gt;extsipip &amp;&amp; profile-&gt;sipip &amp;&amp; switch_check_network_list_ip(profile-&gt;sipip, val)) {
+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Not adding acl %s because it's the local network\n&quot;, val);
+                                                        } else {
+                                                                profile-&gt;nat_acl[profile-&gt;nat_acl_count++] = switch_core_strdup(profile-&gt;pool, val);
+                                                        }
+                                                } else {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Max acl records of %d reached\n&quot;, SOFIA_MAX_ACL);
+                                                }
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;apply-inbound-acl&quot;)) {
</span><span class="cx">                                                 if (profile-&gt;acl_count &lt; SOFIA_MAX_ACL) {
</span><span class="cx">                                                         profile-&gt;acl[profile-&gt;acl_count++] = switch_core_strdup(profile-&gt;pool, val);
</span><span class="lines">@@ -1257,17 +2558,21 @@
</span><span class="cx">                                                 profile-&gt;max_calls = atoi(val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;codec-prefs&quot;)) {
</span><span class="cx">                                                 profile-&gt;codec_string = switch_core_strdup(profile-&gt;pool, val);
</span><ins>+                                        } else if (!strcasecmp(var, &quot;challenge-realm&quot;)) {
+                                                profile-&gt;challenge_realm = switch_core_strdup(profile-&gt;pool, val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;dtmf-duration&quot;)) {
</span><span class="cx">                                                 int dur = atoi(val);
</span><span class="cx">                                                 if (dur &gt; 10 &amp;&amp; dur &lt; 8000) {
</span><span class="cx">                                                         profile-&gt;dtmf_duration = dur;
</span><span class="cx">                                                 } else {
</span><del>-                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Duration out of bounds!\n&quot;);
</del><ins>+                                                        profile-&gt;dtmf_duration = SWITCH_DEFAULT_DTMF_DURATION;
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Duration out of bounds, using default of %d!\n&quot;, 
+                                                                                          SWITCH_DEFAULT_DTMF_DURATION);
</ins><span class="cx">                                                 }
</span><span class="cx"> 
</span><del>-                                        /*
-                                         * handle TLS params #1
-                                         */
</del><ins>+                                                /*
+                                                 * handle TLS params #1
+                                                 */
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;tls&quot;)) {
</span><span class="cx">                                                 if (switch_true(val)) {
</span><span class="cx">                                                         sofia_set_pflag(profile, PFLAG_TLS);
</span><span class="lines">@@ -1275,7 +2580,7 @@
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;tls-bind-params&quot;)) {
</span><span class="cx">                                                 profile-&gt;tls_bind_params = switch_core_strdup(profile-&gt;pool, val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;tls-sip-port&quot;)) {
</span><del>-                                                profile-&gt;tls_sip_port = strcasecmp(val, &quot;auto&quot;) ? atoi(val) : SOFIA_AUTO_PORT;
</del><ins>+                                                profile-&gt;tls_sip_port = (switch_port_t)atoi(val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, &quot;tls-cert-dir&quot;)) {
</span><span class="cx">                                                 profile-&gt;tls_cert_dir = switch_core_strdup(profile-&gt;pool, val);
</span><span class="cx">                                         } else if (!strcasecmp(var, &quot;tls-version&quot;)) {
</span><span class="lines">@@ -1285,10 +2590,38 @@
</span><span class="cx">                                                 } else {
</span><span class="cx">                                                         profile-&gt;tls_version = 0;
</span><span class="cx">                                                 }
</span><del>-                                         }
</del><ins>+                                        } else if (!strcasecmp(var, &quot;timer-T1&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t1 = v;
+                                                } else {
+                                                        profile-&gt;timer_t1 = 500;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;timer-T1X64&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t1x64 = v;
+                                                } else {
+                                                        profile-&gt;timer_t1x64 = 32000;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;timer-T2&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t2 = v;
+                                                } else {
+                                                        profile-&gt;timer_t2 = 4000;
+                                                }
+                                        } else if (!strcasecmp(var, &quot;timer-T4&quot;)) {
+                                                int v = atoi(val);
+                                                if (v &gt; 0) {
+                                                        profile-&gt;timer_t4 = v;
+                                                } else {
+                                                        profile-&gt;timer_t4 = 4000;
+                                                }
+                                        }
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (!profile-&gt;cng_pt) {
</del><ins>+                                if ((!profile-&gt;cng_pt) &amp;&amp; (!sofia_test_pflag(profile, PFLAG_SUPPRESS_CNG))) {
</ins><span class="cx">                                         profile-&gt;cng_pt = SWITCH_RTP_CNG_PAYLOAD;
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="lines">@@ -1305,10 +2638,6 @@
</span><span class="cx">                                         profile-&gt;nonce_ttl = 60;
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (switch_test_flag(profile, TFLAG_TIMER) &amp;&amp; !profile-&gt;timer_name) {
-                                        profile-&gt;timer_name = switch_core_strdup(profile-&gt;pool, &quot;soft&quot;);
-                                }
-
</del><span class="cx">                                 if (!profile-&gt;username) {
</span><span class="cx">                                         profile-&gt;username = switch_core_strdup(profile-&gt;pool, &quot;FreeSWITCH&quot;);
</span><span class="cx">                                 }
</span><span class="lines">@@ -1319,61 +2648,119 @@
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 if (!profile-&gt;sip_port) {
</span><del>-                                        profile-&gt;sip_port = atoi(SOFIA_DEFAULT_PORT);
</del><ins>+                                        profile-&gt;sip_port = (switch_port_t)atoi(SOFIA_DEFAULT_PORT);
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 if (!profile-&gt;dialplan) {
</span><span class="cx">                                         profile-&gt;dialplan = switch_core_strdup(profile-&gt;pool, &quot;XML&quot;);
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><ins>+                                if (!profile-&gt;context) {
+                                        profile-&gt;context = switch_core_strdup(profile-&gt;pool, &quot;default&quot;);
+                                }
+
</ins><span class="cx">                                 if (!profile-&gt;sipdomain) {
</span><span class="cx">                                         profile-&gt;sipdomain = switch_core_strdup(profile-&gt;pool, profile-&gt;sipip);
</span><span class="cx">                                 }
</span><del>-                                if (profile-&gt;extsipip) {
-                                        if (profile-&gt;sip_port == SOFIA_AUTO_PORT) {
-                                                profile-&gt;url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:*&quot;, profile-&gt;extsipip);
-                                        } else {
-                                                profile-&gt;url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:%d&quot;, profile-&gt;extsipip, profile-&gt;sip_port);
-                                        }
</del><ins>+                                if (profile-&gt;extsipip &amp;&amp; sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+                                        char *ipv6 = strchr(profile-&gt;extsipip, ':');
+                                        profile-&gt;public_url = switch_core_sprintf(profile-&gt;pool,
+                                                                                                                          &quot;sip:%s@%s%s%s:%d&quot;,
+                                                                                                                          profile-&gt;contact_user,
+                                                                                                                          ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                                          profile-&gt;extsipip,
+                                                                                                                          ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                                          profile-&gt;sip_port);
+                                }
+
+                                if (profile-&gt;extsipip &amp;&amp; !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+                                        char *ipv6 = strchr(profile-&gt;extsipip, ':');
+                                        profile-&gt;url = switch_core_sprintf(profile-&gt;pool,
+                                                                                                                &quot;sip:%s@%s%s%s:%d&quot;,
+                                                                                                                profile-&gt;contact_user,
+                                                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                                profile-&gt;extsipip,
+                                                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                                profile-&gt;sip_port);
</ins><span class="cx">                                         profile-&gt;bindurl = switch_core_sprintf(profile-&gt;pool, &quot;%s;maddr=%s&quot;, profile-&gt;url, profile-&gt;sipip);
</span><span class="cx">                                 } else {
</span><del>-                                        if (profile-&gt;sip_port == SOFIA_AUTO_PORT) {
-                                                profile-&gt;url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:*&quot;, profile-&gt;sipip);
-                                        } else {
-                                                profile-&gt;url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:%d&quot;, profile-&gt;sipip, profile-&gt;sip_port);
-                                        }
</del><ins>+                                        char *ipv6 = strchr(profile-&gt;sipip, ':');
+                                        profile-&gt;url = switch_core_sprintf(profile-&gt;pool,
+                                                                                                                &quot;sip:%s@%s%s%s:%d&quot;,
+                                                                                                                profile-&gt;contact_user,
+                                                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                                profile-&gt;sipip,
+                                                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                                profile-&gt;sip_port);
</ins><span class="cx">                                         profile-&gt;bindurl = profile-&gt;url;
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><ins>+                                profile-&gt;tcp_contact = switch_core_sprintf(profile-&gt;pool, &quot;%s;transport=tcp&quot;, profile-&gt;url);
+
+                                if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+                                        profile-&gt;tcp_public_contact = switch_core_sprintf(profile-&gt;pool, &quot;%s;transport=tcp&quot;, profile-&gt;public_url);
+                                }
+
</ins><span class="cx">                                 if (profile-&gt;bind_params) {
</span><span class="cx">                                         char *bindurl = profile-&gt;bindurl;
</span><span class="cx">                                         profile-&gt;bindurl = switch_core_sprintf(profile-&gt;pool, &quot;%s;%s&quot;, bindurl, profile-&gt;bind_params);
</span><span class="cx">                                 }
</span><del>-
</del><ins>+                                
</ins><span class="cx">                                 /*
</span><span class="cx">                                  * handle TLS params #2
</span><span class="cx">                                  */
</span><span class="cx">                                 if (sofia_test_pflag(profile, PFLAG_TLS)) {
</span><span class="cx">                                         if (!profile-&gt;tls_sip_port) {
</span><del>-                                                profile-&gt;tls_sip_port = atoi(SOFIA_DEFAULT_TLS_PORT);
</del><ins>+                                                profile-&gt;tls_sip_port = (switch_port_t)atoi(SOFIA_DEFAULT_TLS_PORT);
</ins><span class="cx">                                         }
</span><span class="cx"> 
</span><del>-                                        if (profile-&gt;extsipip) {
-                                                if (profile-&gt;tls_sip_port == SOFIA_AUTO_PORT) {
-                                                        profile-&gt;tls_url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:*&quot;, profile-&gt;extsipip);
-                                                        profile-&gt;tls_bindurl = switch_core_sprintf(profile-&gt;pool, &quot;sips:mod_sofia@%s:*;maddr=%s&quot;, profile-&gt;extsipip, profile-&gt;sipip);
-                                                } else {
-                                                        profile-&gt;tls_url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:%d&quot;, profile-&gt;extsipip, profile-&gt;tls_sip_port);
-                                                        profile-&gt;tls_bindurl = switch_core_sprintf(profile-&gt;pool, &quot;sips:mod_sofia@%s:%d;maddr=%s&quot;, profile-&gt;extsipip, profile-&gt;tls_sip_port, profile-&gt;sipip);
-                                                }
</del><ins>+                                        if (profile-&gt;extsipip &amp;&amp; sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+                                                char *ipv6 = strchr(profile-&gt;extsipip, ':');
+                                                profile-&gt;tls_public_url = switch_core_sprintf(profile-&gt;pool,
+                                                                                                                                  &quot;sip:%s@%s%s%s:%d&quot;,
+                                                                                                                                  profile-&gt;contact_user,
+                                                                                                                                  ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                                                  profile-&gt;extsipip,
+                                                                                                                                  ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                                                  profile-&gt;tls_sip_port);
+                                        }
+                                        
+                                        if (profile-&gt;extsipip &amp;&amp; !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+                                                char *ipv6 = strchr(profile-&gt;extsipip, ':');
+                                                profile-&gt;tls_url = 
+                                                        switch_core_sprintf(profile-&gt;pool,
+                                                                                                &quot;sip:%s@%s%s%s:%d&quot;,
+                                                                                                profile-&gt;contact_user,
+                                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                profile-&gt;extsipip, ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                profile-&gt;tls_sip_port);
+                                                profile-&gt;tls_bindurl =
+                                                        switch_core_sprintf(profile-&gt;pool,
+                                                                                                &quot;sips:%s@%s%s%s:%d;maddr=%s&quot;,
+                                                                                                profile-&gt;contact_user,
+                                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                profile-&gt;extsipip,
+                                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                profile-&gt;tls_sip_port,
+                                                                                                profile-&gt;sipip);
</ins><span class="cx">                                         } else {
</span><del>-                                                if (profile-&gt;tls_sip_port == SOFIA_AUTO_PORT) {
-                                                        profile-&gt;tls_url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:*&quot;, profile-&gt;sipip);
-                                                        profile-&gt;tls_bindurl = switch_core_sprintf(profile-&gt;pool, &quot;sips:mod_sofia@%s:*&quot;, profile-&gt;sipip);
-                                                } else {
-                                                        profile-&gt;tls_url = switch_core_sprintf(profile-&gt;pool, &quot;sip:mod_sofia@%s:%d&quot;, profile-&gt;sipip, profile-&gt;tls_sip_port);
-                                                        profile-&gt;tls_bindurl = switch_core_sprintf(profile-&gt;pool, &quot;sips:mod_sofia@%s:%d&quot;, profile-&gt;sipip, profile-&gt;tls_sip_port);
-                                                }
</del><ins>+                                                char *ipv6 = strchr(profile-&gt;sipip, ':');
+                                                profile-&gt;tls_url = 
+                                                        switch_core_sprintf(profile-&gt;pool,
+                                                                                                &quot;sip:%s@%s%s%s:%d&quot;,
+                                                                                                profile-&gt;contact_user,
+                                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                profile-&gt;sipip,
+                                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                profile-&gt;tls_sip_port);
+                                                profile-&gt;tls_bindurl =
+                                                        switch_core_sprintf(profile-&gt;pool,
+                                                                                                &quot;sips:%s@%s%s%s:%d&quot;,
+                                                                                                profile-&gt;contact_user,
+                                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                                profile-&gt;sipip,
+                                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                                profile-&gt;tls_sip_port);
</ins><span class="cx">                                         }
</span><span class="cx"> 
</span><span class="cx">                                         if (profile-&gt;tls_bind_params) {
</span><span class="lines">@@ -1384,41 +2771,50 @@
</span><span class="cx">                                         if (!profile-&gt;tls_cert_dir) {
</span><span class="cx">                                                 profile-&gt;tls_cert_dir = switch_core_sprintf(profile-&gt;pool, &quot;%s/ssl&quot;, SWITCH_GLOBAL_dirs.conf_dir);
</span><span class="cx">                                         }
</span><ins>+                                        profile-&gt;tls_contact = switch_core_sprintf(profile-&gt;pool, &quot;%s;transport=tls&quot;, profile-&gt;tls_url);
+                                        if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+                                                profile-&gt;tls_public_contact = switch_core_sprintf(profile-&gt;pool, &quot;%s;transport=tls&quot;, profile-&gt;tls_public_url);
+                                        }
</ins><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx">                         if (profile) {
</span><span class="cx">                                 switch_xml_t aliases_tag, alias_tag;
</span><span class="cx"> 
</span><del>-                                if ((gateways_tag = switch_xml_child(xprofile, &quot;registrations&quot;))) {
-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
-                                                                          &quot;The &lt;registrations&gt; syntax has been discontinued, please see the new syntax in the default configuration examples\n&quot;);
-                                } else if ((gateways_tag = switch_xml_child(xprofile, &quot;gateways&quot;))) {
</del><ins>+                                if ((gateways_tag = switch_xml_child(xprofile, &quot;gateways&quot;))) {
</ins><span class="cx">                                         parse_gateways(profile, gateways_tag);
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 if ((domains_tag = switch_xml_child(xprofile, &quot;domains&quot;))) {
</span><ins>+                                        switch_event_t *xml_params;
+                                        switch_event_create(&amp;xml_params, SWITCH_EVENT_REQUEST_PARAMS);
+                                        switch_assert(xml_params);
+                                        switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, &quot;purpose&quot;, &quot;gateways&quot;);
+                                        switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, &quot;profile&quot;, profile-&gt;name);
+                                        
</ins><span class="cx">                                         for (domain_tag = switch_xml_child(domains_tag, &quot;domain&quot;); domain_tag; domain_tag = domain_tag-&gt;next) {
</span><span class="cx">                                                 switch_xml_t droot, x_domain_tag;
</span><span class="cx">                                                 const char *dname = switch_xml_attr_soft(domain_tag, &quot;name&quot;);
</span><span class="cx">                                                 const char *parse = switch_xml_attr_soft(domain_tag, &quot;parse&quot;);
</span><span class="cx">                                                 const char *alias = switch_xml_attr_soft(domain_tag, &quot;alias&quot;);
</span><del>-                                                
-                                                if (!switch_strlen_zero(dname)) { 
</del><ins>+
+                                                if (!switch_strlen_zero(dname)) {
</ins><span class="cx">                                                         if (!strcasecmp(dname, &quot;all&quot;)) {
</span><span class="cx">                                                                 switch_xml_t xml_root, x_domains;
</span><del>-                                                                if (switch_xml_locate(&quot;directory&quot;, NULL, NULL, NULL, &amp;xml_root, &amp;x_domains, NULL) == SWITCH_STATUS_SUCCESS) {
-                                                                        for(x_domain_tag = switch_xml_child(x_domains, &quot;domain&quot;); x_domain_tag; x_domain_tag = x_domain_tag-&gt;next) {
</del><ins>+                                                                if (switch_xml_locate(&quot;directory&quot;, NULL, NULL, NULL, &amp;xml_root, &amp;x_domains, xml_params, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+                                                                        for (x_domain_tag = switch_xml_child(x_domains, &quot;domain&quot;); x_domain_tag; x_domain_tag = x_domain_tag-&gt;next) {
</ins><span class="cx">                                                                                 dname = switch_xml_attr_soft(x_domain_tag, &quot;name&quot;);
</span><span class="cx">                                                                                 parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
</span><span class="cx">                                                                         }
</span><span class="cx">                                                                         switch_xml_free(xml_root);
</span><span class="cx">                                                                 }
</span><del>-                                                        } else if (switch_xml_locate_domain(dname, NULL, &amp;droot, &amp;x_domain_tag) == SWITCH_STATUS_SUCCESS) {
</del><ins>+                                                        } else if (switch_xml_locate_domain(dname, xml_params, &amp;droot, &amp;x_domain_tag) == SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                                                                 parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
</span><del>-                                                                switch_xml_free(droot);                                                                        
</del><ins>+                                                                switch_xml_free(droot);
</ins><span class="cx">                                                         }
</span><span class="cx">                                                 }
</span><span class="cx">                                         }
</span><ins>+                                        
+                                        switch_event_destroy(&amp;xml_params);
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 if ((aliases_tag = switch_xml_child(xprofile, &quot;aliases&quot;))) {
</span><span class="lines">@@ -1429,16 +2825,21 @@
</span><span class="cx">                                                         if (sofia_glue_add_profile(switch_core_strdup(profile-&gt;pool, aname), profile) == SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Adding Alias [%s] for profile [%s]\n&quot;, aname, profile-&gt;name);
</span><span class="cx">                                                         } else {
</span><del>-                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Adding Alias [%s] for profile [%s] (name in use)\n&quot;, 
-                                                                                                   aname, profile-&gt;name);
</del><ins>+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Adding Alias [%s] for profile [%s] (name in use)\n&quot;,
+                                                                                                  aname, profile-&gt;name);
</ins><span class="cx">                                                         }
</span><span class="cx">                                                 }
</span><span class="cx">                                         }
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 if (profile-&gt;sipip) {
</span><del>-                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Started Profile %s [%s]\n&quot;, profile-&gt;name, url);
</del><span class="cx">                                         launch_sofia_profile_thread(profile);
</span><ins>+                                        if (profile-&gt;odbc_dsn) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Connecting ODBC Profile %s [%s]\n&quot;, profile-&gt;name, url);
+                                                switch_yield(1000000);
+                                        } else {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Started Profile %s [%s]\n&quot;, profile-&gt;name, url);
+                                        }
</ins><span class="cx">                                 } else {
</span><span class="cx">                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Unable to start Profile %s due to no configured sip-ip\n&quot;, profile-&gt;name);
</span><span class="cx">                                 }
</span><span class="lines">@@ -1466,58 +2867,100 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void sofia_handle_sip_r_options(switch_core_session_t *session, int status,
</span><del>-                                                                          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[])
</del><ins>+                                                                           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[])
</ins><span class="cx"> {
</span><del>-        if ((profile-&gt;pflags &amp; PFLAG_UNREG_OPTIONS_FAIL) &amp;&amp; status != 200 &amp;&amp; sip &amp;&amp; sip-&gt;sip_to) {
</del><ins>+        sofia_gateway_t *gateway = NULL;
+
+        if (sofia_private &amp;&amp; !switch_strlen_zero(sofia_private-&gt;gateway_name)) {
+                gateway = sofia_reg_find_gateway(sofia_private-&gt;gateway_name);
+                sofia_private-&gt;destroy_me = 1;
+        }
+
+        if (gateway) {
+                if (status &gt;= 200 &amp;&amp; status &lt; 600) {
+                        if (gateway-&gt;state == REG_STATE_FAILED) {
+                                gateway-&gt;state = REG_STATE_UNREGED;
+                        }
+                        gateway-&gt;status = SOFIA_GATEWAY_UP;
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Ping failed %s\n&quot;, gateway-&gt;name);
+                        gateway-&gt;status = SOFIA_GATEWAY_DOWN;
+                        if (gateway-&gt;state == REG_STATE_REGED) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Unregister %s\n&quot;, gateway-&gt;name);
+                                gateway-&gt;state = REG_STATE_FAILED;
+                        }
+                }
+                gateway-&gt;ping = switch_epoch_time_now(NULL) + gateway-&gt;ping_freq;
+                sofia_reg_release_gateway(gateway);
+                gateway-&gt;pinging = 0;
+        } else if (sofia_test_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL) &amp;&amp; status != 200 &amp;&amp; sip &amp;&amp; sip-&gt;sip_to) {
</ins><span class="cx">                 char *sql;
</span><del>-                time_t now = switch_timestamp(NULL);
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Expire registration '%s@%s' due to options failure\n&quot;, 
-                                                  sip-&gt;sip_to-&gt;a_url-&gt;url_user,
-                                                  sip-&gt;sip_to-&gt;a_url-&gt;url_host
-                                                  );
</del><ins>+                time_t now = switch_epoch_time_now(NULL);
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Expire registration '%s@%s' due to options failure\n&quot;,
+                                                  sip-&gt;sip_to-&gt;a_url-&gt;url_user, sip-&gt;sip_to-&gt;a_url-&gt;url_host);
</ins><span class="cx"> 
</span><del>-                sql = switch_mprintf(&quot;update sip_registrations set expired=%ld where sip_user='%s' and sip_host='%s'&quot;, 
-                                                                   (long)now,
-                                                                   sip-&gt;sip_to-&gt;a_url-&gt;url_user,
-                                                                   sip-&gt;sip_to-&gt;a_url-&gt;url_host
-                                                                   );
</del><ins>+                sql = switch_mprintf(&quot;update sip_registrations set expires=%ld where sip_user='%s' and sip_host='%s'&quot;,
+                                                         (long) now, sip-&gt;sip_to-&gt;a_url-&gt;url_user, sip-&gt;sip_to-&gt;a_url-&gt;url_host);
</ins><span class="cx">                 sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
</span><span class="cx">         }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status,
</span><span class="cx">                                                                           char const *phrase,
</span><del>-                                                                          nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
</del><ins>+                                                                          nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+                                                                          tagi_t tags[])
</ins><span class="cx"> {
</span><span class="cx">         if (sip &amp;&amp; session) {
</span><span class="cx">                 switch_channel_t *channel = switch_core_session_get_channel(session);
</span><span class="cx">                 const char *uuid;
</span><span class="cx">                 switch_core_session_t *other_session;
</span><span class="cx">                 private_object_t *tech_pvt = switch_core_session_get_private(session);
</span><ins>+                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), &amp;network_port);
+
+                switch_channel_set_variable(channel, &quot;sip_reply_host&quot;, network_ip);
+                switch_channel_set_variable_printf(channel, &quot;sip_reply_port&quot;, &quot;%d&quot;, network_port);
</ins><span class="cx">                 
</span><ins>+                if ((caller_profile = switch_channel_get_caller_profile(channel))) {
+                        caller_profile-&gt;network_addr = switch_core_strdup(caller_profile-&gt;pool, network_ip);
+                }
+
</ins><span class="cx">                 switch_channel_clear_flag(channel, CF_REQ_MEDIA);
</span><ins>+                
+                if ((status == 180 || status == 183 || status == 200)) { 
+                        if (sip-&gt;sip_user_agent &amp;&amp; sip-&gt;sip_user_agent-&gt;g_string) {
+                                switch_channel_set_variable(channel, &quot;sip_user_agent&quot;, sip-&gt;sip_user_agent-&gt;g_string);
+                        } else if (sip-&gt;sip_server &amp;&amp; sip-&gt;sip_server-&gt;g_string) {
+                                switch_channel_set_variable(channel, &quot;sip_user_agent&quot;, sip-&gt;sip_server-&gt;g_string);
+                        }
+                }
</ins><span class="cx"> 
</span><span class="cx">                 if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
</span><span class="cx"> 
</span><del>-                        if (!switch_test_flag(tech_pvt, TFLAG_SENT_UPDATE)) {
</del><ins>+                        if (!sofia_test_flag(tech_pvt, TFLAG_SENT_UPDATE)) {
</ins><span class="cx">                                 return;
</span><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        switch_clear_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
</del><ins>+                        sofia_clear_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
</ins><span class="cx"> 
</span><span class="cx">                         if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) &amp;&amp; (other_session = switch_core_session_locate(uuid))) {
</span><span class="cx">                                 const char *r_sdp = NULL;
</span><span class="cx">                                 switch_core_session_message_t msg = { 0 };
</span><del>-                        
-                                if (sip-&gt;sip_payload &amp;&amp; sip-&gt;sip_payload-&gt;pl_data &amp;&amp; 
</del><ins>+
+                                if (sip-&gt;sip_payload &amp;&amp; sip-&gt;sip_payload-&gt;pl_data &amp;&amp;
</ins><span class="cx">                                         sip-&gt;sip_content_type &amp;&amp; sip-&gt;sip_content_type-&gt;c_subtype &amp;&amp; switch_stristr(&quot;sdp&quot;, sip-&gt;sip_content_type-&gt;c_subtype)) {
</span><del>-                                        r_sdp = sip-&gt;sip_payload-&gt;pl_data;
</del><ins>+                                        tech_pvt-&gt;remote_sdp_str = switch_core_session_strdup(tech_pvt-&gt;session, sip-&gt;sip_payload-&gt;pl_data);
+                                        r_sdp = tech_pvt-&gt;remote_sdp_str;
+                                        sofia_glue_tech_proxy_remote_addr(tech_pvt);
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Passing %d %s to other leg\n&quot;, status, phrase);
</span><del>-                                
</del><ins>+
</ins><span class="cx">                                 msg.message_id = SWITCH_MESSAGE_INDICATE_RESPOND;
</span><span class="cx">                                 msg.from = __FILE__;
</span><span class="cx">                                 msg.numeric_arg = status;
</span><span class="lines">@@ -1553,7 +2996,7 @@
</span><span class="cx">                                 astate = &quot;confirmed&quot;;
</span><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        if (!switch_channel_test_flag(channel, CF_EARLY_MEDIA) &amp;&amp; !switch_channel_test_flag(channel, CF_ANSWERED) &amp;&amp; 
</del><ins>+                        if (!switch_channel_test_flag(channel, CF_EARLY_MEDIA) &amp;&amp; !switch_channel_test_flag(channel, CF_ANSWERED) &amp;&amp;
</ins><span class="cx">                                 !switch_channel_test_flag(channel, CF_RING_READY)) {
</span><span class="cx">                                 const char *from_user = &quot;&quot;, *from_host = &quot;&quot;, *to_user = &quot;&quot;, *to_host = &quot;&quot;, *contact_user = &quot;&quot;, *contact_host = &quot;&quot;;
</span><span class="cx">                                 const char *user_agent = &quot;&quot;, *call_id = &quot;&quot;;
</span><span class="lines">@@ -1582,39 +3025,217 @@
</span><span class="cx">                                         contact_host = switch_str_nil(contact-&gt;url_host);
</span><span class="cx">                                 }
</span><span class="cx"> 
</span><del>-                                if (profile-&gt;pflags &amp; PFLAG_PRESENCE) {
-                                        sql = switch_mprintf(
-                                                                                 &quot;insert into sip_dialogs values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')&quot;,
</del><ins>+                                if (profile-&gt;pres_type) {
+                                        sql = switch_mprintf(&quot;insert into sip_dialogs &quot;
+                                                                                 &quot;(call_id,uuid,sip_to_user,sip_to_host,sip_from_user,sip_from_host,contact_user,&quot;
+                                                                                 &quot;contact_host,state,direction,user_agent,profile_name,hostname) &quot;
+                                                                                 &quot;values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')&quot;,
</ins><span class="cx">                                                                                  call_id,
</span><span class="cx">                                                                                  switch_core_session_get_uuid(session),
</span><del>-                                                                                 to_user,
-                                                                                 to_host,
-                                                                                 from_user,
-                                                                                 from_host,
-                                                                                 contact_user,
-                                                                                 contact_host,
-                                                                                 astate,
-                                                                                 &quot;outbound&quot;,
-                                                                                 user_agent
-                                                                                 );
</del><ins>+                                                                                 to_user, to_host, from_user, from_host, contact_user, 
+                                                                                 contact_host, astate, &quot;outbound&quot;, user_agent,
+                                                                                 profile-&gt;name, mod_sofia_globals.hostname);
</ins><span class="cx"> 
</span><span class="cx">                                         switch_assert(sql);
</span><del>-                                        
</del><ins>+
</ins><span class="cx">                                         sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
</span><span class="cx">                                 }
</span><del>-                        } else if (status == 200 &amp;&amp; (profile-&gt;pflags &amp; PFLAG_PRESENCE)) { 
</del><ins>+                        } else if (status == 200 &amp;&amp; (profile-&gt;pres_type)) {
</ins><span class="cx">                                 char *sql = NULL;
</span><span class="cx">                                 sql = switch_mprintf(&quot;update sip_dialogs set state='%s' where uuid='%s';\n&quot;, astate, switch_core_session_get_uuid(session));
</span><del>-                                switch_assert(sql); 
-                                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE); 
</del><ins>+                                switch_assert(sql);
+                                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><ins>+
+                if (channel &amp;&amp; sip &amp;&amp; (status == 300 || status == 302 || status == 305) &amp;&amp; switch_channel_test_flag(channel, CF_OUTBOUND)) {
+                        sip_contact_t * p_contact = sip-&gt;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)) &amp;&amp; (a_channel = switch_core_session_get_channel(a_session))) { 
+                                        switch_stream_handle_t stream = { 0 };
+                                        char separator[2] = &quot;|&quot;;
+                                        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, &quot;sip_redirect_profile&quot;))) {
+                                                sip_redirect_profile = profile-&gt;name;
+                                        }
+                                        if (!(sip_redirect_context = switch_channel_get_variable(channel, &quot;sip_redirect_context&quot;))) {
+                                                sip_redirect_context = &quot;redirected&quot;;
+                                        }
+                                        if (!(sip_redirect_dialplan = switch_channel_get_variable(channel, &quot;sip_redirect_dialplan&quot;))) {
+                                                sip_redirect_dialplan = &quot;XML&quot;;
+                                        }
+
+                                        sip_redirect_fork = switch_channel_get_variable(channel, &quot;sip_redirect_fork&quot;);
+                                        
+                                        if (switch_true(sip_redirect_fork)) {
+                                                *separator = ',';
+                                        }
+
+                                        for (p_contact = sip-&gt;sip_contact; p_contact; p_contact = p_contact-&gt;m_next) {
+                                                if (p_contact-&gt;m_url) {
+                                                        full_contact = sip_header_as_string(home, (void *) sip-&gt;sip_contact);
+                                                        invite_contact = sofia_glue_strip_uri(full_contact);
+                                                        
+                                                        switch_snprintf(var_name, sizeof(var_name), &quot;sip_redirect_contact_%d&quot;, i);
+                                                        switch_channel_set_variable(a_channel, var_name, full_contact);
+                                                        
+                                                        if (i == 0) {
+                                                                switch_channel_set_variable(channel, &quot;sip_redirected_to&quot;, full_contact);
+                                                                switch_channel_set_variable(a_channel, &quot;sip_redirected_to&quot;, full_contact);
+                                                        }
+                                                        
+                                                        if (p_contact-&gt;m_url-&gt;url_user) {
+                                                                switch_snprintf(var_name, sizeof(var_name), &quot;sip_redirect_contact_user_%d&quot;, i);
+                                                                switch_channel_set_variable(channel, var_name, p_contact-&gt;m_url-&gt;url_user);
+                                                                switch_channel_set_variable(a_channel, var_name, p_contact-&gt;m_url-&gt;url_user);
+                                                        }
+                                                        if (p_contact-&gt;m_url-&gt;url_host) {
+                                                                switch_snprintf(var_name, sizeof(var_name), &quot;sip_redirect_contact_host_%d&quot;, i);
+                                                                switch_channel_set_variable(channel, var_name, p_contact-&gt;m_url-&gt;url_host);
+                                                                switch_channel_set_variable(a_channel, var_name, p_contact-&gt;m_url-&gt;url_host);
+                                                        }
+                                                        if (p_contact-&gt;m_url-&gt;url_params) {
+                                                                switch_snprintf(var_name, sizeof(var_name), &quot;sip_redirect_contact_params_%d&quot;, i);
+                                                                switch_channel_set_variable(channel, var_name, p_contact-&gt;m_url-&gt;url_params);
+                                                                switch_channel_set_variable(a_channel, var_name, p_contact-&gt;m_url-&gt;url_params);
+                                                        }
+                                                        
+                                                        switch_snprintf(var_name, sizeof(var_name), &quot;sip_redirect_dialstring_%d&quot;, i);
+                                                        switch_channel_set_variable_printf(channel, var_name, &quot;sofia/%s/%s&quot;, sip_redirect_profile, invite_contact);
+                                                        switch_channel_set_variable_printf(a_channel, var_name, &quot;sofia/%s/%s&quot;, sip_redirect_profile, invite_contact);
+                                                        stream.write_function(&amp;stream, &quot;%ssofia/%s/%s&quot;, i ? separator : &quot;&quot;, sip_redirect_profile, invite_contact);
+                                                        free(invite_contact);
+                                                        i++;
+                                                }
+                                        }
+                                        
+                                        redirect_dialstring = stream.data;
+                                        
+                                        switch_channel_set_variable(channel, &quot;sip_redirect_dialstring&quot;, redirect_dialstring);
+                                        switch_channel_set_variable(a_channel, &quot;sip_redirect_dialstring&quot;, redirect_dialstring);
+                                        
+                                        p_contact = sip-&gt;sip_contact;
+                                        full_contact = sip_header_as_string(home, (void *) sip-&gt;sip_contact);
+                                        
+                                        if ((diversion_header = sofia_glue_get_unknown_header(sip, &quot;diversion&quot;))) {
+                                                switch_channel_set_variable(channel, &quot;sip_redirected_by&quot;, diversion_header);
+                                                switch_channel_set_variable(a_channel, &quot;sip_redirected_by&quot;, diversion_header);
+                                        }
+                                        
+                                        if (sofia_test_pflag(profile, PFLAG_MANUAL_REDIRECT)) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Redirect: Transfering to %s %s %s\n&quot;, 
+                                                                                  p_contact-&gt;m_url-&gt;url_user, sip_redirect_dialplan, sip_redirect_context);
+                                                switch_ivr_session_transfer(a_session, p_contact-&gt;m_url-&gt;url_user, sip_redirect_dialplan, sip_redirect_context);                                        
+                                        } else if ((!strcmp(profile-&gt;sipip, p_contact-&gt;m_url-&gt;url_host))
+                                                           || (profile-&gt;extsipip &amp;&amp; !strcmp(profile-&gt;extsipip, p_contact-&gt;m_url-&gt;url_host))
+                                                           || (switch_xml_locate_domain(p_contact-&gt;m_url-&gt;url_host, NULL, &amp;root, &amp;domain) == SWITCH_STATUS_SUCCESS)) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Redirect: Transfering to %s\n&quot;, p_contact-&gt;m_url-&gt;url_user);
+                                                switch_ivr_session_transfer(a_session, p_contact-&gt;m_url-&gt;url_user, NULL, NULL);
+                                                switch_xml_free(root);
+                                        } else {
+                                                invite_contact = sofia_glue_strip_uri(full_contact);
+                                                tech_pvt-&gt;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-&gt;sip_contact);
+                                invite_contact = sofia_glue_strip_uri(full_contact);
+
+                                tech_pvt-&gt;redirected = switch_core_session_strdup(session, invite_contact);
+
+                                free(invite_contact);
+
+                                if (home) {
+                                        su_home_unref(home);
+                                        home = NULL;
+                                }
+                        }
+                }
</ins><span class="cx">         }
</span><ins>+
+        if (!session &amp;&amp; (status == 180 || status == 183 || status == 200)) {
+                /* nevermind */
+                nua_handle_bind(nh, NULL);
+                nua_handle_destroy(nh);
+        }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+/* 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)) &amp;&amp; (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-&gt;rtp_session) {
+                                        switch_rtp_clear_flag(tech_pvt-&gt;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(&amp;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(&amp;thread, thd_attr, media_on_hold_thread_run, session, switch_core_session_get_pool(session));
+}
+
</ins><span class="cx"> static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
</span><span class="cx">                                                                          char const *phrase,
</span><del>-                                                                         nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, tagi_t tags[])
</del><ins>+                                                                         nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
+                                                                         tagi_t tags[])
</ins><span class="cx"> {
</span><span class="cx">         const char *l_sdp = NULL, *r_sdp = NULL;
</span><span class="cx">         int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
</span><span class="lines">@@ -1634,20 +3255,54 @@
</span><span class="cx">                         NUTAG_OFFER_SENT_REF(offer_sent),
</span><span class="cx">                         NUTAG_ANSWER_SENT_REF(answer_sent),
</span><span class="cx">                         SIPTAG_REPLACES_STR_REF(replaces_str), SOATAG_LOCAL_SDP_STR_REF(l_sdp), SOATAG_REMOTE_SDP_STR_REF(r_sdp), TAG_END());
</span><ins>+        
+        if (ss_state == nua_callstate_terminated) {
</ins><span class="cx"> 
</span><ins>+                if ((status == 300 || status == 302 || status == 305) &amp;&amp; session) {
+                        channel = switch_core_session_get_channel(session);
+                        tech_pvt = switch_core_session_get_private(session);
+                        
+                        if (!tech_pvt || !tech_pvt-&gt;nh) {
+                                goto done;
+                        }
+                        
+
+                        if (tech_pvt-&gt;redirected) {
+                                sofia_glue_do_invite(session);
+                                goto done;
+                        }
+                }
+
+                if (sofia_private) {
+                        sofia_private-&gt;destroy_me = 1;
+                }
+        }
+
</ins><span class="cx">         if (session) {
</span><span class="cx">                 channel = switch_core_session_get_channel(session);
</span><span class="cx">                 tech_pvt = switch_core_session_get_private(session);
</span><del>-                switch_assert(tech_pvt != NULL);
-                switch_assert(tech_pvt-&gt;nh != NULL);
</del><span class="cx"> 
</span><del>-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Channel %s entering state [%s]\n&quot;,
-                                                  switch_channel_get_name(channel), nua_callstate_name(ss_state));
</del><ins>+                if (!tech_pvt || !tech_pvt-&gt;nh) {
+                        goto done;
+                }
</ins><span class="cx"> 
</span><ins>+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Channel %s entering state [%s][%d]\n&quot;,
+                                                  switch_channel_get_name(channel), nua_callstate_name(ss_state), status);
+                
</ins><span class="cx">                 if (r_sdp) {
</span><ins>+                        sdp_parser_t *parser;
+                        sdp_session_t *sdp;
+
</ins><span class="cx">                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Remote SDP:\n%s\n&quot;, r_sdp);
</span><span class="cx">                         tech_pvt-&gt;remote_sdp_str = switch_core_session_strdup(session, r_sdp);
</span><span class="cx">                         switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
</span><ins>+
+                        if ( sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) &amp;&amp; (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-&gt;profile?tech_pvt-&gt;profile-&gt;codec_string:NULL), sdp);
+                                }
+                                sdp_parser_free(parser);
+                        }
</ins><span class="cx">                         sofia_glue_pass_sdp(tech_pvt, (char *) r_sdp);
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="lines">@@ -1658,8 +3313,12 @@
</span><span class="cx"> 
</span><span class="cx">         if (status == 183 &amp;&amp; !r_sdp) {
</span><span class="cx">                 status = 180;
</span><ins>+        } 
+        
+        if (status == 180 &amp;&amp; r_sdp) {
+                status = 183;
</ins><span class="cx">         }
</span><del>-
</del><ins>+        
</ins><span class="cx">         if (channel &amp;&amp; (status == 180 || status == 183) &amp;&amp; switch_channel_test_flag(channel, CF_OUTBOUND)) {
</span><span class="cx">                 const char *val;
</span><span class="cx">                 if ((val = switch_channel_get_variable(channel, &quot;sip_auto_answer&quot;)) &amp;&amp; switch_true(val)) {
</span><span class="lines">@@ -1667,9 +3326,22 @@
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>- state_process:
-        
</del><ins>+  state_process:
+
</ins><span class="cx">         switch ((enum nua_callstate) ss_state) {
</span><ins>+        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 &amp;&amp; channel &amp;&amp; tech_pvt)) goto done;
+                break;
+        default:
+                break;
+        }
+
+        switch ((enum nua_callstate) ss_state) {
</ins><span class="cx">         case nua_callstate_init:
</span><span class="cx">                 break;
</span><span class="cx">         case nua_callstate_authenticating:
</span><span class="lines">@@ -1677,61 +3349,59 @@
</span><span class="cx">         case nua_callstate_calling:
</span><span class="cx">                 break;
</span><span class="cx">         case nua_callstate_proceeding:
</span><del>-                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))
-                                                        &amp;&amp; (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, &amp;msg);
-                                                        switch_core_session_rwunlock(other_session);
-                                                }
</del><ins>+                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))
+                                                &amp;&amp; (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, &amp;msg);
+                                                switch_core_session_rwunlock(other_session);
+                                        }
</ins><span class="cx"> 
</span><del>-                                        } else {
-                                                switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
-                                        }
</del><ins>+                                } else {
+                                        switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
</ins><span class="cx">                                 }
</span><span class="cx">                         }
</span><del>-
-                        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;
-                                                }
</del><ins>+                }
+                        
+                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) &amp;&amp; !switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND)) {
+                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;PROXY MEDIA&quot;);
+                                }
+                                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;
</ins><span class="cx">                                         }
</span><del>-                                        if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) &amp;&amp; (uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
-                                                &amp;&amp; (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);
</del><ins>+                                }
+                                if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) &amp;&amp; (uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+                                        &amp;&amp; (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);
</ins><span class="cx">                                         }
</span><del>-                                        goto done;
</del><ins>+                                        switch_channel_pre_answer(other_channel);
+                                        switch_core_session_rwunlock(other_session);
+                                }
+                                goto done;
+                        } else {
+                                if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) &amp;&amp; !switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND)) {
+                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;DELAYED NEGOTIATION&quot;);
</ins><span class="cx">                                 } else {
</span><del>-                                        if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) &amp;&amp; !switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND)) {
-                                                switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;PROXY MEDIA&quot;);
-                                        } else if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) &amp;&amp; !switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND)) {
-                                                switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;DELAYED NEGOTIATION&quot;);
-                                        } else {
-                                                if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
-                                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;CODEC NEGOTIATION ERROR&quot;);
-                                                        nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
-                                                        switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
-                                                }
</del><ins>+                                        if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
+                                                switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;CODEC NEGOTIATION ERROR&quot;);
+                                                nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+                                                switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
</ins><span class="cx">                                         }
</span><del>-                                        goto done;
</del><span class="cx">                                 }
</span><ins>+                                goto done;
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">                 break;
</span><span class="lines">@@ -1739,29 +3409,29 @@
</span><span class="cx">                 nua_ack(nh, TAG_END());
</span><span class="cx">                 break;
</span><span class="cx">         case nua_callstate_received:
</span><del>-                if (tech_pvt &amp;&amp; !switch_test_flag(tech_pvt, TFLAG_SDP)) {
-                        if (r_sdp &amp;&amp; !switch_test_flag(tech_pvt, TFLAG_SDP)) {
</del><ins>+                if (!sofia_test_flag(tech_pvt, TFLAG_SDP)) {
+                        if (r_sdp &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
</ins><span class="cx">                                 if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
</span><span class="cx">                                         switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;RECEIVED_NOMEDIA&quot;);
</span><del>-                                        switch_set_flag_locked(tech_pvt, TFLAG_READY);
</del><ins>+                                        sofia_set_flag_locked(tech_pvt, TFLAG_READY);
</ins><span class="cx">                                         if (switch_channel_get_state(channel) == CS_NEW) {
</span><span class="cx">                                                 switch_channel_set_state(channel, CS_INIT);
</span><span class="cx">                                         }
</span><del>-                                        switch_set_flag(tech_pvt, TFLAG_SDP);
</del><ins>+                                        sofia_set_flag(tech_pvt, TFLAG_SDP);
</ins><span class="cx">                                         goto done;
</span><span class="cx">                                 } else if (switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA)) {
</span><del>-                    switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;PROXY MEDIA&quot;);
-                    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, &quot;DELAYED NEGOTIATION&quot;);
-                    switch_set_flag_locked(tech_pvt, TFLAG_READY);
-                    if (switch_channel_get_state(channel) == CS_NEW) {
-                        switch_channel_set_state(channel, CS_INIT);
-                    }
-                } else {
</del><ins>+                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;PROXY MEDIA&quot;);
+                                        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, &quot;DELAYED NEGOTIATION&quot;);
+                                        sofia_set_flag_locked(tech_pvt, TFLAG_READY);
+                                        if (switch_channel_get_state(channel) == CS_NEW) {
+                                                switch_channel_set_state(channel, CS_INIT);
+                                        }
+                                } else {
</ins><span class="cx">                                         sdp_parser_t *parser;
</span><span class="cx">                                         sdp_session_t *sdp;
</span><span class="cx">                                         uint8_t match = 0;
</span><span class="lines">@@ -1774,17 +3444,17 @@
</span><span class="cx">                                                         sdp_parser_free(parser);
</span><span class="cx">                                                 }
</span><span class="cx">                                         }
</span><del>-                                        
</del><ins>+
</ins><span class="cx">                                         if (match) {
</span><span class="cx">                                                 nua_handle_t *bnh;
</span><span class="cx">                                                 sip_replaces_t *replaces;
</span><span class="cx">                                                 su_home_t *home = NULL;
</span><span class="cx">                                                 switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;RECEIVED&quot;);
</span><del>-                                                switch_set_flag_locked(tech_pvt, TFLAG_READY);
</del><ins>+                                                sofia_set_flag_locked(tech_pvt, TFLAG_READY);
</ins><span class="cx">                                                 if (switch_channel_get_state(channel) == CS_NEW) {
</span><span class="cx">                                                         switch_channel_set_state(channel, CS_INIT);
</span><span class="cx">                                                 }
</span><del>-                                                switch_set_flag(tech_pvt, TFLAG_SDP);
</del><ins>+                                                sofia_set_flag(tech_pvt, TFLAG_SDP);
</ins><span class="cx">                                                 if (replaces_str) {
</span><span class="cx">                                                         home = su_home_new(sizeof(*home));
</span><span class="cx">                                                         switch_assert(home != NULL);
</span><span class="lines">@@ -1796,15 +3466,16 @@
</span><span class="cx">                                                                 while (switch_channel_get_state(channel) &lt; CS_EXECUTE) {
</span><span class="cx">                                                                         switch_yield(10000);
</span><span class="cx">                                                                 }
</span><del>-                                                                
</del><ins>+
</ins><span class="cx">                                                                 if ((b_private = nua_handle_magic(bnh))) {
</span><span class="cx">                                                                         const char *br_b = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
</span><span class="cx">                                                                         char *br_a = b_private-&gt;uuid;
</span><del>-                                                                        
</del><ins>+
</ins><span class="cx">                                                                         if (br_b) {
</span><span class="cx">                                                                                 switch_ivr_uuid_bridge(br_a, br_b);
</span><span class="cx">                                                                                 switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER&quot;);
</span><del>-                                                                                switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
</del><ins>+                                                                                sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                                                                                sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
</ins><span class="cx">                                                                                 switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
</span><span class="cx">                                                                         } else {
</span><span class="cx">                                                                                 switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER_ERROR&quot;);
</span><span class="lines">@@ -1830,22 +3501,39 @@
</span><span class="cx">                                 if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
</span><span class="cx">                                         goto done;
</span><span class="cx">                                 } else {
</span><del>-                                        switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;RECEIVED_NOSDP&quot;);
-                                        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-&gt;nh, SIP_200_OK,
-                                                                SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
-                                                                SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
-                                                                SOATAG_REUSE_REJECTED(1),
-                                                                SOATAG_ORDERED_USER(1),
-                                                                SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;),
-                                                                NUTAG_INCLUDE_EXTRA_SDP(1),
-                                                                TAG_END());
</del><ins>+                                        if (sofia_test_pflag(profile, PFLAG_3PCC)) {
+                                                switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;RECEIVED_NOSDP&quot;);
+                                                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-&gt;nh, SIP_200_OK,
+                                                                        SIPTAG_CONTACT_STR(tech_pvt-&gt;profile-&gt;url),
+                                                                        SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
+                                                                        SOATAG_REUSE_REJECTED(1),
+                                                                        SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), 
+                                                                        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, &quot;RECEIVED_NOSDP&quot;);
+                                                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, &quot;3PCC DISABLED&quot;);
+                                                switch_channel_hangup(channel, SWITCH_CAUSE_MANDATORY_IE_MISSING);
+                                        }
</ins><span class="cx">                                         goto done;
</span><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx"> 
</span><ins>+                } else if (tech_pvt &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_SDP) &amp;&amp; !r_sdp) {
+                        nua_respond(tech_pvt-&gt;nh, SIP_200_OK, TAG_END());
+                        sofia_set_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE);
+                        goto done;
</ins><span class="cx">                 } else {
</span><span class="cx">                         ss_state = nua_callstate_completed;
</span><span class="cx">                         goto state_process;
</span><span class="lines">@@ -1855,28 +3543,92 @@
</span><span class="cx">         case nua_callstate_early:
</span><span class="cx">                 break;
</span><span class="cx">         case nua_callstate_completed:
</span><del>-                if (tech_pvt &amp;&amp; r_sdp) {
-                        sdp_parser_t *parser; 
</del><ins>+                if (r_sdp) {
+                        sdp_parser_t *parser;
</ins><span class="cx">                         sdp_session_t *sdp;
</span><del>-                        uint8_t match = 0;
</del><ins>+                        uint8_t match = 0, is_ok = 1;
+                        tech_pvt-&gt;hold_laps = 0;
</ins><span class="cx"> 
</span><del>-                        if (r_sdp) { 
</del><ins>+                        if (r_sdp) {
+                                const char *var;
+                                
+                                if ((var = switch_channel_get_variable(channel, &quot;sip_ignore_reinvites&quot;)) &amp;&amp; switch_true(var)) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Ignoring Re-invite\n&quot;);
+                                        nua_respond(tech_pvt-&gt;nh, SIP_200_OK, TAG_END());
+                                        goto done;
+                                }
+
</ins><span class="cx">                                 if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
</span><ins>+                                        
</ins><span class="cx">                                         if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
</span><span class="cx">                                                 &amp;&amp; (other_session = switch_core_session_locate(uuid))) {
</span><span class="cx">                                                 switch_core_session_message_t msg = { 0 };
</span><ins>+                                                
+                                                if (profile-&gt;media_options &amp; MEDIA_OPT_MEDIA_ON_HOLD) {
+                                                        tech_pvt-&gt;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-&gt;channel, CF_OUTBOUND)) {
+                                                                        //const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
</ins><span class="cx"> 
</span><ins>+                                                                        tech_pvt-&gt;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, &quot;CODEC NEGOTIATION ERROR&quot;);
+                                                                                status = SWITCH_STATUS_FALSE;
+                                                                                goto done;
+                                                                        }
+                                                                }
+                                                        }
+
+                                                        if (!switch_rtp_ready(tech_pvt-&gt;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-&gt;nh, SIP_200_OK,
+                                                                                SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
+                                                                                SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
+                                                                                SOATAG_REUSE_REJECTED(1),
+                                                                                SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), 
+                                                                                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;
+                                                }
+                                                
</ins><span class="cx">                                                 msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT;
</span><span class="cx">                                                 msg.from = __FILE__;
</span><span class="cx">                                                 msg.string_arg = (char *) r_sdp;
</span><span class="cx">                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Passing SDP to other leg.\n%s\n&quot;, r_sdp);
</span><ins>+                                                
+                                                if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+                                                        if (!switch_stristr(&quot;sendonly&quot;, r_sdp)) {
+                                                                sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                                                                switch_channel_presence(tech_pvt-&gt;channel, &quot;unknown&quot;, &quot;unhold&quot;, NULL);
+                                                        }
+                                                } else if (switch_stristr(&quot;sendonly&quot;, r_sdp)) {
+                                                        sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                                                        switch_channel_presence(tech_pvt-&gt;channel, &quot;unknown&quot;, &quot;hold&quot;, NULL);
+                                                }
+                                        
+
</ins><span class="cx">                                                 if (switch_core_session_receive_message(other_session, &amp;msg) != SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Other leg is not available\n&quot;);
</span><span class="cx">                                                         nua_respond(tech_pvt-&gt;nh, 403, &quot;Hangup in progress&quot;, TAG_END());
</span><del>-                                                }                                        
</del><ins>+                                                }
</ins><span class="cx">                                                 switch_core_session_rwunlock(other_session);
</span><span class="cx">                                         } else {
</span><span class="cx">                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Re-INVITE to a no-media channel that is not in a bridge.\n&quot;);
</span><ins>+                                                is_ok = 0;
</ins><span class="cx">                                                 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</span><span class="cx">                                         }
</span><span class="cx">                                         goto done;
</span><span class="lines">@@ -1894,37 +3646,81 @@
</span><span class="cx">                                                         goto done;
</span><span class="cx">                                                 }
</span><span class="cx">                                                 sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
</span><del>-                                                switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
</del><ins>+                                                sofia_set_flag_locked(tech_pvt, TFLAG_REINVITE);
</ins><span class="cx">                                                 if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Reinvite RTP Error!\n&quot;);
</span><ins>+                                                        is_ok = 0;
</ins><span class="cx">                                                         switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</span><span class="cx">                                                 }
</span><span class="cx">                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Processing Reinvite\n&quot;);
</span><span class="cx">                                         } else {
</span><span class="cx">                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Reinvite Codec Error!\n&quot;);
</span><del>-                                                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</del><ins>+                                                is_ok = 0;
</ins><span class="cx">                                         }
</span><span class="cx">                                 }
</span><ins>+                                
+                                if (is_ok) {
+                                        if (tech_pvt-&gt;local_crypto_key) {
+                                                sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+                                        }
+                                        nua_respond(tech_pvt-&gt;nh, SIP_200_OK,
+                                                                SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
+                                                                SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
+                                                                SOATAG_REUSE_REJECTED(1),
+                                                                SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;), 
+                                                                TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
+                                } else {
+                                        nua_respond(tech_pvt-&gt;nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+                                }
+                        }
+                }
+                break;
+        case nua_callstate_ready:
</ins><span class="cx"> 
</span><ins>+                if (r_sdp &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_NOSDP_REINVITE)) {
+                        sdp_parser_t *parser;
+                        sdp_session_t *sdp;
+                        uint8_t match = 0;
+                        int is_ok = 1;
</ins><span class="cx"> 
</span><del>-                                nua_respond(tech_pvt-&gt;nh, SIP_200_OK,
-                                                        SIPTAG_CONTACT_STR(tech_pvt-&gt;reply_contact),
-                                                        SOATAG_USER_SDP_STR(tech_pvt-&gt;local_sdp_str),
-                                                        SOATAG_REUSE_REJECTED(1),
-                                                        SOATAG_ORDERED_USER(1),
-                                                        SOATAG_AUDIO_AUX(&quot;cn telephone-event&quot;),
-                                                        NUTAG_INCLUDE_EXTRA_SDP(1),
-                                                        TAG_END());
</del><ins>+                        sofia_clear_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE);
+
+                        if (tech_pvt-&gt;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);
+                                }
</ins><span class="cx">                         }
</span><ins>+
+                        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, &quot;RTP Error!\n&quot;);
+                                        switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;RTP ERROR&quot;);
+                                        is_ok = 0;
+                                }
+                                sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+                        } else {
+                                switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;CODEC NEGOTIATION ERROR&quot;);
+                                is_ok = 0;
+                        }
+
+                        if (!is_ok) {
+                                nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+                                switch_channel_hangup(tech_pvt-&gt;channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
+                        }
+
+                        goto done;
</ins><span class="cx">                 }
</span><del>-                break;
-        case nua_callstate_ready:
</del><ins>+
</ins><span class="cx">                 if (channel) {
</span><span class="cx">                         switch_channel_clear_flag(channel, CF_REQ_MEDIA);
</span><span class="cx">                 }
</span><span class="cx">                 if (tech_pvt &amp;&amp; nh == tech_pvt-&gt;nh2) {
</span><span class="cx">                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Cheater Reinvite!\n&quot;);
</span><del>-                        switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
</del><ins>+                        sofia_set_flag_locked(tech_pvt, TFLAG_REINVITE);
</ins><span class="cx">                         tech_pvt-&gt;nh = tech_pvt-&gt;nh2;
</span><span class="cx">                         tech_pvt-&gt;nh2 = NULL;
</span><span class="cx">                         if (sofia_glue_tech_choose_port(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
</span><span class="lines">@@ -1935,34 +3731,38 @@
</span><span class="cx">                         }
</span><span class="cx">                         goto done;
</span><span class="cx">                 }
</span><del>-
</del><ins>+                
</ins><span class="cx">                 if (channel) {
</span><del>-                        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))
-                                        &amp;&amp; (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);
</del><ins>+            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))
+                                                &amp;&amp; (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);
+                                        }
</ins><span class="cx">                                 }
</span><del>-                                goto done;
</del><ins>+                goto done;
+            }
+                        
+                        if (!r_sdp &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
+                                r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
</ins><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        if (!r_sdp &amp;&amp; !switch_test_flag(tech_pvt, TFLAG_SDP)) {
-                                r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
-                        }
-                        if (r_sdp &amp;&amp; !switch_test_flag(tech_pvt, TFLAG_SDP)) {
</del><ins>+                        if (r_sdp &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
</ins><span class="cx">                                 if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
</span><del>-                                        switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-                                        switch_set_flag_locked(tech_pvt, TFLAG_SDP);
</del><ins>+                                        sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
+                                        sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
</ins><span class="cx">                                         switch_channel_mark_answered(channel);
</span><span class="cx">                                         if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
</span><span class="cx">                                                 if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                                                         goto done;
</span><span class="cx">                                                 }
</span><span class="cx">                                         }
</span><ins>+
</ins><span class="cx">                                         if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
</span><span class="cx">                                                 &amp;&amp; (other_session = switch_core_session_locate(uuid))) {
</span><span class="cx">                                                 other_channel = switch_core_session_get_channel(other_session);
</span><span class="lines">@@ -1988,7 +3788,7 @@
</span><span class="cx">                                         }
</span><span class="cx"> 
</span><span class="cx">                                         if (match) {
</span><del>-                                                switch_set_flag_locked(tech_pvt, TFLAG_ANS);
</del><ins>+                                                sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
</ins><span class="cx">                                                 if (sofia_glue_tech_choose_port(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                                                         if (sofia_glue_activate_rtp(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                                                                 switch_channel_mark_answered(channel);
</span><span class="lines">@@ -1996,12 +3796,17 @@
</span><span class="cx">                                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;RTP Error!\n&quot;);
</span><span class="cx">                                                                 switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</span><span class="cx">                                                         }
</span><del>-                                                        if (switch_channel_get_state(channel) == CS_HIBERNATE) {
-                                                                switch_set_flag_locked(tech_pvt, TFLAG_READY);
-                                                                if (switch_channel_get_state(channel) == CS_NEW) {
</del><ins>+
+                                                        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, &quot;3PCC-PROXY, Got my ACK\n&quot;);
+                                                                        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);
</ins><span class="cx">                                                                         switch_channel_set_state(channel, CS_INIT);
</span><ins>+                                                                        sofia_set_flag(tech_pvt, TFLAG_SDP);
</ins><span class="cx">                                                                 }
</span><del>-                                                                switch_set_flag(tech_pvt, TFLAG_SDP);
</del><span class="cx">                                                         }
</span><span class="cx">                                                         goto done;
</span><span class="cx">                                                 }
</span><span class="lines">@@ -2015,58 +3820,127 @@
</span><span class="cx"> 
</span><span class="cx">                 break;
</span><span class="cx">         case nua_callstate_terminating:
</span><del>-                if (session) {
-                        if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
-                                switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                        }
</del><ins>+                if (status == 488 || switch_channel_get_state(channel) == CS_HIBERNATE) {
+                        tech_pvt-&gt;q850_cause = SWITCH_CAUSE_MANDATORY_IE_MISSING;
</ins><span class="cx">                 }
</span><del>-                break;
</del><span class="cx">         case nua_callstate_terminated:
</span><del>-                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-&gt;q850_cause) {
-                        cause = tech_pvt-&gt;q850_cause;
-                    } else {
-                        cause = sofia_glue_sip_cause_to_freeswitch(status);
-                    }
-                                        switch_snprintf(st, sizeof(st), &quot;%d&quot;, status);
-                                        switch_channel_set_variable(channel, &quot;sip_term_status&quot;, st);
-                                        switch_snprintf(st, sizeof(st), &quot;%d&quot;, cause);
-                                        switch_channel_set_variable(channel, &quot;sip_term_cause&quot;, st);
-                                        switch_channel_hangup(channel, cause);
</del><ins>+                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-&gt;q850_cause) {
+                                cause = tech_pvt-&gt;q850_cause;
+                        } else {
+                                cause = sofia_glue_sip_cause_to_freeswitch(status);
+                        }
+                        if (status) {
+                                switch_snprintf(st, sizeof(st), &quot;%d&quot;, status);
+                                switch_channel_set_variable(channel, &quot;sip_term_status&quot;, st);
+                                switch_snprintf(st, sizeof(st), &quot;sip:%d&quot;, 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, &quot;sip_hangup_phrase&quot;, phrase);
</ins><span class="cx">                                 }
</span><span class="cx">                         }
</span><del>-                        
</del><ins>+                        switch_snprintf(st, sizeof(st), &quot;%d&quot;, cause);
+                        switch_channel_set_variable(channel, &quot;sip_term_cause&quot;, st);
+                        switch_channel_hangup(channel, cause);
+                }
+                
+
+                if (ss_state == nua_callstate_terminated) {
</ins><span class="cx">                         if (tech_pvt-&gt;sofia_private) {
</span><del>-                                sofia_private = tech_pvt-&gt;sofia_private;
</del><span class="cx">                                 tech_pvt-&gt;sofia_private = NULL;
</span><del>-                                free(sofia_private);
</del><span class="cx">                         }
</span><ins>+                        
+                        tech_pvt-&gt;nh = NULL;
+        
+                        if (nh) {
+                                nua_handle_bind(nh, NULL);
+                                nua_handle_destroy(nh);
+                        }
+                }
+                
+                break;
+        }
</ins><span class="cx"> 
</span><del>-                        tech_pvt-&gt;nh = NULL;                
</del><ins>+  done:
+        return;
+}
</ins><span class="cx"> 
</span><ins>+typedef struct {
+        char *exten;
+        char *event;
+        char *reply_uuid;
+        char *bridge_to_uuid;
+        switch_memory_pool_t *pool;
+} nightmare_xfer_helper_t;
</ins><span class="cx"> 
</span><del>-                } else if (sofia_private) {
-                        free(sofia_private);
</del><ins>+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-&gt;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-&gt;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, &amp;tsession, &amp;cause, nhelper-&gt;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, &quot;Cannot Create Outgoing Channel! [%s]\n&quot;, nhelper-&gt;exten);
+                                        nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;messsage/sipfrag&quot;),
+                                                           NUTAG_SUBSTATE(nua_substate_terminated),
+                                                           SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;), SIPTAG_EVENT_STR(nhelper-&gt;event), TAG_END());
+                                        status = SWITCH_STATUS_FALSE;
+                                } else {
+                                        tuuid_str = switch_core_session_get_uuid(tsession);
+                                        switch_ivr_uuid_bridge(nhelper-&gt;bridge_to_uuid, tuuid_str);
+                                        switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER&quot;);
+                                        sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
+                                        nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
+                                                           NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;), SIPTAG_EVENT_STR(nhelper-&gt;event), TAG_END());
+                                        switch_core_session_rwunlock(tsession);
+                                }
+                        }
+                        switch_core_session_rwunlock(session);
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (nh) {
-                        nua_handle_bind(nh, NULL);
-                        nua_handle_destroy(nh);
-                }
-                break;
</del><ins>+                switch_core_session_rwunlock(a_session);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-  done:
-        return;
</del><ins>+        pool = nhelper-&gt;pool;
+        switch_core_destroy_memory_pool(&amp;pool);
+
+        return NULL;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void launch_nightmare_xfer(nightmare_xfer_helper_t *nhelper)
+{
+        switch_thread_t *thread;
+        switch_threadattr_t *thd_attr = NULL;
+
+        switch_threadattr_create(&amp;thd_attr, nhelper-&gt;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(&amp;thread, thd_attr, nightmare_xfer_thread_run, nhelper, nhelper-&gt;pool);
+}
+
</ins><span class="cx"> /*---------------------------------------*/
</span><ins>+
</ins><span class="cx"> 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[])
</span><span class="cx"> {
</span><span class="cx">         /* Incoming refer */
</span><span class="lines">@@ -2080,6 +3954,8 @@
</span><span class="cx">         su_home_t *home = NULL;
</span><span class="cx">         char *full_ref_by = NULL;
</span><span class="cx">         char *full_ref_to = NULL;
</span><ins>+        nightmare_xfer_helper_t *nightmare_xfer_helper;
+        switch_memory_pool_t *npool;
</ins><span class="cx"> 
</span><span class="cx">         if (!(profile-&gt;mflags &amp; MFLAG_REFER)) {
</span><span class="cx">                 nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
</span><span class="lines">@@ -2091,45 +3967,51 @@
</span><span class="cx">                 goto done;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_channel_test_flag(channel_a, CF_PROXY_MODE)) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Transfer on bypass media not allowed.\n&quot;);
-                nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
-                goto done;
-        }
-
</del><span class="cx">         from = sip-&gt;sip_from;
</span><span class="cx">         to = sip-&gt;sip_to;
</span><del>-        
</del><ins>+
</ins><span class="cx">         home = su_home_new(sizeof(*home));
</span><span class="cx">         switch_assert(home != NULL);
</span><span class="cx"> 
</span><del>-        if (sip-&gt;sip_referred_by) {                
</del><ins>+        if (sip-&gt;sip_referred_by) {
</ins><span class="cx">                 full_ref_by = sip_header_as_string(home, (void *) sip-&gt;sip_referred_by);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if ((refer_to = sip-&gt;sip_refer_to)) {
</span><ins>+                char *rep;
</ins><span class="cx">                 full_ref_to = sip_header_as_string(home, (void *) sip-&gt;sip_refer_to);
</span><span class="cx"> 
</span><del>-                if (profile-&gt;pflags &amp; PFLAG_FULL_ID) {
-                        exten = switch_mprintf(&quot;%s@%s&quot;, (char *) refer_to-&gt;r_url-&gt;url_user, (char *) refer_to-&gt;r_url-&gt;url_host);
</del><ins>+                if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
+                        exten = switch_core_session_sprintf(session, &quot;%s@%s&quot;, (char *) refer_to-&gt;r_url-&gt;url_user, (char *) refer_to-&gt;r_url-&gt;url_host);
</ins><span class="cx">                 } else {
</span><span class="cx">                         exten = (char *) refer_to-&gt;r_url-&gt;url_user;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Process REFER to [%s@%s]\n&quot;, exten, (char *) refer_to-&gt;r_url-&gt;url_host);
</span><span class="cx"> 
</span><del>-                if (refer_to-&gt;r_url-&gt;url_headers) {
</del><ins>+                if (refer_to-&gt;r_url-&gt;url_headers &amp;&amp; (rep = (char *)switch_stristr(&quot;Replaces=&quot;, refer_to-&gt;r_url-&gt;url_headers))) {
</ins><span class="cx">                         sip_replaces_t *replaces;
</span><span class="cx">                         nua_handle_t *bnh;
</span><del>-                        char *rep;
</del><span class="cx"> 
</span><del>-                        if ((rep = strchr(refer_to-&gt;r_url-&gt;url_headers, '='))) {
</del><ins>+                        if (switch_channel_test_flag(channel_a, CF_PROXY_MODE)) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot Attended Transfer BYPASS MEDIA CALLS!\n&quot;);
+                                switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER_ERROR&quot;);
+                                nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
+                                                   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
+                                goto done;
+                        }
+                        
+                        if (rep) {
</ins><span class="cx">                                 const char *br_a = NULL, *br_b = NULL;
</span><span class="cx">                                 char *buf;
</span><ins>+                                char *p;
</ins><span class="cx"> 
</span><del>-                                rep++;
</del><ins>+                                rep = switch_core_session_strdup(session, rep + 9);
</ins><span class="cx"> 
</span><ins>+                                if ((p = strchr(rep, ';'))) {
+                                        *p = '\0';
+                                }
+                                
</ins><span class="cx">                                 if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
</span><span class="cx">                                         rep = url_unescape(buf, (const char *) rep);
</span><span class="cx">                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Replaces: [%s]\n&quot;, rep);
</span><span class="lines">@@ -2144,6 +4026,7 @@
</span><span class="cx">                                         private_object_t *b_tech_pvt = NULL;
</span><span class="cx">                                         switch_core_session_t *b_session = NULL;
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">                                         switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep);
</span><span class="cx">                                         if ((b_private = nua_handle_magic(bnh))) {
</span><span class="cx">                                                 if (!(b_session = switch_core_session_locate(b_private-&gt;uuid))) {
</span><span class="lines">@@ -2154,42 +4037,47 @@
</span><span class="cx"> 
</span><span class="cx">                                                 br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
</span><span class="cx">                                                 br_b = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
</span><ins>+
+                                                if (br_a &amp;&amp; br_b) {
+                                                        switch_core_session_t *new_b_session = NULL, *a_session = NULL, *tmp = NULL;
</ins><span class="cx">                                                 
</span><del>-                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Attended Transfer [%s][%s]\n&quot;, switch_str_nil(br_a), switch_str_nil(br_b));
</del><ins>+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Attended Transfer [%s][%s]\n&quot;, 
+                                                                                          switch_str_nil(br_a),
+                                                                                          switch_str_nil(br_b));
</ins><span class="cx"> 
</span><del>-                                                if (br_a &amp;&amp; br_b) {
-                                                        switch_core_session_t *new_b_session = NULL, *a_session = NULL;
-                                                                
</del><ins>+                                                        if ((profile-&gt;media_options &amp; MEDIA_OPT_BYPASS_AFTER_ATT_XFER) &amp;&amp; (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, &quot;true&quot;);
+                                                                switch_core_session_rwunlock(tmp);
+                                                        }
+                                                        
</ins><span class="cx">                                                         switch_ivr_uuid_bridge(br_b, br_a);
</span><span class="cx">                                                         switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER&quot;);
</span><span class="cx">                                                         nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
</span><span class="cx">                                                                            NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
</span><span class="cx"> 
</span><del>-                                                        switch_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
-                                                        switch_ivr_park_session(b_session);
</del><ins>+                                                        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), &quot;park_timeout&quot;, &quot;2&quot;);
+                                                        switch_channel_set_state(switch_core_session_get_channel(b_session), CS_PARK);
+
</ins><span class="cx">                                                         new_b_session = switch_core_session_locate(br_b);
</span><span class="cx">                                                         a_session = switch_core_session_locate(br_a);
</span><span class="cx">                                                         sofia_info_send_sipfrag(a_session, new_b_session);
</span><ins>+
</ins><span class="cx">                                                         if (new_b_session) {
</span><span class="cx">                                                                 switch_core_session_rwunlock(new_b_session);
</span><span class="cx">                                                         }
</span><ins>+
</ins><span class="cx">                                                         if (a_session) {
</span><span class="cx">                                                                 switch_core_session_rwunlock(a_session);
</span><span class="cx">                                                         }
</span><del>-                                                        //switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
</del><span class="cx">                                                 } else {
</span><span class="cx">                                                         if (!br_a &amp;&amp; !br_b) {
</span><del>-                                                                switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-                                                                switch_set_flag_locked(b_tech_pvt, TFLAG_XFER);
-                                                                b_tech_pvt-&gt;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-&gt;nh,
-                                                                                        NUTAG_NEWSUB(1),
-                                                                                        SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                                                                        NUTAG_SUBSTATE(nua_substate_terminated),
-                                                                                        SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-                                                                                        SIPTAG_EVENT_STR(etmp),
-                                                                                        TAG_END());
</del><ins>+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Cannot transfer channels that are not in a bridge.\n&quot;);
+                                                                nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
+                                                                                   NUTAG_SUBSTATE(nua_substate_terminated),
+                                                                                   SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
</ins><span class="cx">                                                         } else {
</span><span class="cx">                                                                 switch_core_session_t *t_session;
</span><span class="cx">                                                                 switch_channel_t *hup_channel;
</span><span class="lines">@@ -2202,8 +4090,8 @@
</span><span class="cx">                                                                         private_object_t *h_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session);
</span><span class="cx">                                                                         t_session = switch_core_session_locate(br_b);
</span><span class="cx">                                                                         hup_channel = channel_a;
</span><del>-                                                                        switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
-                                                                        switch_clear_flag_locked(h_tech_pvt, TFLAG_SIP_HOLD);
</del><ins>+                                                                        sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+                                                                        sofia_clear_flag_locked(h_tech_pvt, TFLAG_SIP_HOLD);
</ins><span class="cx">                                                                         switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
</span><span class="cx">                                                                 }
</span><span class="cx"> 
</span><span class="lines">@@ -2218,15 +4106,13 @@
</span><span class="cx">                                                                         if (!switch_strlen_zero(full_ref_to)) {
</span><span class="cx">                                                                                 switch_channel_set_variable(t_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
</span><span class="cx">                                                                         }
</span><del>-                                                                        
</del><ins>+
</ins><span class="cx">                                                                         switch_ivr_session_transfer(t_session, ext, NULL, NULL);
</span><span class="cx">                                                                         nua_notify(tech_pvt-&gt;nh,
</span><del>-                                                                                                NUTAG_NEWSUB(1),
-                                                                                                SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                                                                                NUTAG_SUBSTATE(nua_substate_terminated),
-                                                                                                SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-                                                                                                SIPTAG_EVENT_STR(etmp),
-                                                                                                TAG_END());
</del><ins>+                                                                                           NUTAG_NEWSUB(1),
+                                                                                           SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
+                                                                                           NUTAG_SUBSTATE(nua_substate_terminated),
+                                                                                           SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
</ins><span class="cx">                                                                         switch_core_session_rwunlock(t_session);
</span><span class="cx">                                                                         switch_channel_hangup(hup_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
</span><span class="cx">                                                                 } else {
</span><span class="lines">@@ -2248,12 +4134,9 @@
</span><span class="cx">                                                 switch_channel_t *channel = switch_core_session_get_channel(session);
</span><span class="cx"> 
</span><span class="cx">                                                 if ((a_session = switch_core_session_locate(br_a))) {
</span><del>-                                                        switch_core_session_t *tsession;
-                                                        switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
-                                                        uint32_t timeout = 60;
-                                                        char *tuuid_str;
</del><span class="cx">                                                         const char *port = NULL;
</span><del>-                                                        switch_status_t status;
</del><ins>+                                                        char *param_string = &quot;&quot;;
+                                                        int count = 0, bytes = 0;
</ins><span class="cx"> 
</span><span class="cx">                                                         if (refer_to &amp;&amp; refer_to-&gt;r_url &amp;&amp; refer_to-&gt;r_url-&gt;url_port) {
</span><span class="cx">                                                                 port = refer_to-&gt;r_url-&gt;url_port;
</span><span class="lines">@@ -2262,42 +4145,56 @@
</span><span class="cx">                                                         if (switch_strlen_zero(port)) {
</span><span class="cx">                                                                 port = &quot;5060&quot;;
</span><span class="cx">                                                         }
</span><ins>+                                                        
</ins><span class="cx">                                                         channel = switch_core_session_get_channel(a_session);
</span><span class="cx">                                                         
</span><del>-                                                        exten = switch_mprintf(&quot;sofia/%s/%s@%s:%s&quot;,
-                                                                                                   profile-&gt;name,
-                                                                                                   refer_to-&gt;r_url-&gt;url_user,
-                                                                                                   refer_to-&gt;r_url-&gt;url_host,
-                                                                                                   port);
-                                                        
</del><ins>+                                                        if (refer_to-&gt;r_params) {
+                                                                for (count = 0; refer_to-&gt;r_params[count] ; count++) {
+                                                                        bytes += strlen(refer_to-&gt;r_params[count]) + 1;
+                                                                }
+
+                                                                if (bytes) {
+                                                                        bytes += 2;
+
+                                                                        param_string = switch_core_session_alloc(session, bytes);
+                                                                        *param_string = ';';
+                                                                        for (count = 0; refer_to-&gt;r_params[count] ; count++) {
+                                                                                switch_snprintf(param_string + strlen(param_string), bytes - strlen(param_string), &quot;%s;&quot;, refer_to-&gt;r_params[count]);
+                                                                        }
+                                                                
+                                                                        if (end_of(param_string) == ';') {
+                                                                                end_of(param_string) = '\0';
+                                                                        }
+                                                                }
+                                                        }
+
+                                                        exten = switch_core_session_sprintf(session, &quot;sofia/%s/sip:%s@%s&quot;, 
+                                                                                                                                profile-&gt;name, refer_to-&gt;r_url-&gt;url_user, 
+                                                                                                                                refer_to-&gt;r_url-&gt;url_host);
+
+                                                        switch_core_new_memory_pool(&amp;npool);
+                                                        nightmare_xfer_helper = switch_core_alloc(npool, sizeof(*nightmare_xfer_helper));
+                                                        nightmare_xfer_helper-&gt;exten = switch_core_strdup(npool, exten);
+                                                        nightmare_xfer_helper-&gt;event = switch_core_strdup(npool, etmp);
+                                                        nightmare_xfer_helper-&gt;reply_uuid = switch_core_strdup(npool, switch_core_session_get_uuid(session));
+                                                        nightmare_xfer_helper-&gt;bridge_to_uuid = switch_core_strdup(npool, br_a);
+                                                        nightmare_xfer_helper-&gt;pool = npool;
+
</ins><span class="cx">                                                         switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
</span><ins>+
</ins><span class="cx">                                                         if (!switch_strlen_zero(full_ref_by)) {
</span><span class="cx">                                                                 switch_channel_set_variable(channel, SOFIA_SIP_HEADER_PREFIX &quot;Referred-By&quot;, full_ref_by);
</span><span class="cx">                                                         }
</span><ins>+
</ins><span class="cx">                                                         if (!switch_strlen_zero(full_ref_to)) {
</span><span class="cx">                                                                 switch_channel_set_variable(channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
</span><span class="cx">                                                         }
</span><del>-                                                        status = switch_ivr_originate(a_session,
-                                                                                                                  &amp;tsession, &amp;cause, exten, timeout, &amp;noop_state_handler, NULL, NULL, NULL, SOF_NONE);
</del><span class="cx"> 
</span><del>-                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot Create Outgoing Channel! [%s]\n&quot;, exten);
-                                                        nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                                                           NUTAG_SUBSTATE(nua_substate_terminated),
-                                                                           SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
</del><ins>+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Good Luck, you'll need it......\n&quot;);
+                                                        launch_nightmare_xfer(nightmare_xfer_helper);
</ins><span class="cx">                                                         
</span><span class="cx">                                                         switch_core_session_rwunlock(a_session);
</span><span class="cx"> 
</span><del>-                                                        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, &quot;ATTENDED_TRANSFER&quot;);
-                                                        switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                                                        nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
-                                                                           NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
-                                                        switch_core_session_rwunlock(tsession);
</del><span class="cx">                                                 } else {
</span><span class="cx">                                                         goto error;
</span><span class="cx">                                                 }
</span><span class="lines">@@ -2328,7 +4225,7 @@
</span><span class="cx"> 
</span><span class="cx">                 if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
</span><span class="cx">                         switch_core_session_t *b_session;
</span><del>-                        
</del><ins>+
</ins><span class="cx">                         if ((b_session = switch_core_session_locate(br))) {
</span><span class="cx">                                 switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
</span><span class="cx">                                 switch_channel_set_variable(channel, &quot;transfer_fallback_extension&quot;, from-&gt;a_user);
</span><span class="lines">@@ -2338,23 +4235,20 @@
</span><span class="cx">                                 if (!switch_strlen_zero(full_ref_to)) {
</span><span class="cx">                                         switch_channel_set_variable(b_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
</span><span class="cx">                                 }
</span><ins>+
</ins><span class="cx">                                 switch_ivr_session_transfer(b_session, exten, NULL, NULL);
</span><span class="cx">                                 switch_core_session_rwunlock(b_session);
</span><span class="cx">                         }
</span><span class="cx"> 
</span><span class="cx">                         switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;BLIND_TRANSFER&quot;);
</span><span class="cx">                         nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
</span><del>-                           NUTAG_SUBSTATE(nua_substate_terminated),
-                           SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;),
-                           SIPTAG_EVENT_STR(etmp),
-                           TAG_END());
-                         
</del><ins>+                                           NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 200 OK&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
+
</ins><span class="cx">                 } else {
</span><span class="cx">                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot Blind Transfer 1 Legged calls\n&quot;);
</span><span class="cx">                         switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;ATTENDED_TRANSFER_ERROR&quot;);
</span><span class="cx">                         nua_notify(tech_pvt-&gt;nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;),
</span><del>-                                           NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;), SIPTAG_EVENT_STR(etmp),
-                                           TAG_END());
</del><ins>+                                           NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR(&quot;SIP/2.0 403 Forbidden&quot;), SIPTAG_EVENT_STR(etmp), TAG_END());
</ins><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -2364,9 +4258,6 @@
</span><span class="cx">                 home = NULL;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (exten &amp;&amp; strchr(exten, '@')) {
-                switch_safe_free(exten);
-        }
</del><span class="cx">         if (etmp) {
</span><span class="cx">                 switch_safe_free(etmp);
</span><span class="cx">         }
</span><span class="lines">@@ -2378,8 +4269,9 @@
</span><span class="cx">         const char *signal_ptr;
</span><span class="cx">         const char *rec_header;
</span><span class="cx">         const char *clientcode_header;
</span><del>-        switch_dtmf_t dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
-        
</del><ins>+        switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0) };
+        switch_event_t *event;
+
</ins><span class="cx">         if (session) {
</span><span class="cx">                 /* Get the channel */
</span><span class="cx">                 switch_channel_t *channel = switch_core_session_get_channel(session);
</span><span class="lines">@@ -2387,47 +4279,75 @@
</span><span class="cx">                 /* Barf if we didn't get our private */
</span><span class="cx">                 assert(switch_core_session_get_private(session));
</span><span class="cx"> 
</span><del>-                if (sip &amp;&amp; sip-&gt;sip_content_type &amp;&amp; sip-&gt;sip_content_type-&gt;c_type &amp;&amp; sip-&gt;sip_content_type-&gt;c_subtype &amp;&amp; 
</del><ins>+                if (sip &amp;&amp; sip-&gt;sip_content_type &amp;&amp; sip-&gt;sip_content_type-&gt;c_type &amp;&amp; sip-&gt;sip_content_type-&gt;c_subtype &amp;&amp;
</ins><span class="cx">                         sip-&gt;sip_payload &amp;&amp; sip-&gt;sip_payload-&gt;pl_data) {
</span><span class="cx">                         if (!strncasecmp(sip-&gt;sip_content_type-&gt;c_type, &quot;application&quot;, 11) &amp;&amp; !strcasecmp(sip-&gt;sip_content_type-&gt;c_subtype, &quot;dtmf-relay&quot;)) {
</span><span class="cx">                                 /* Try and find signal information in the payload */
</span><span class="cx">                                 if ((signal_ptr = switch_stristr(&quot;Signal=&quot;, sip-&gt;sip_payload-&gt;pl_data))) {
</span><ins>+                                        int tmp;
</ins><span class="cx">                                         /* move signal_ptr where we need it (right past Signal=) */
</span><span class="cx">                                         signal_ptr = signal_ptr + 7;
</span><del>-                                        dtmf.digit = *signal_ptr;
</del><ins>+
+                                        /* handle broken devices with spaces after the = (cough) VegaStream (cough) */
+                                        while (*signal_ptr &amp;&amp; *signal_ptr == ' ') signal_ptr++;
+
+                                        if (*signal_ptr &amp;&amp; (*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);
+                                        }
</ins><span class="cx">                                 } else {
</span><span class="cx">                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Bad signal\n&quot;);
</span><del>-                                        goto fail;
</del><ins>+                                        goto end;
</ins><span class="cx">                                 }
</span><span class="cx"> 
</span><span class="cx">                                 if ((signal_ptr = switch_stristr(&quot;Duration=&quot;, sip-&gt;sip_payload-&gt;pl_data))) {
</span><span class="cx">                                         int tmp;
</span><span class="cx">                                         signal_ptr += 9;
</span><ins>+
+                                        /* handle broken devices with spaces after the = (cough) VegaStream (cough) */
+                                        while (*signal_ptr &amp;&amp; *signal_ptr == ' ') signal_ptr++;
+                                        
</ins><span class="cx">                                         if ((tmp = atoi(signal_ptr)) &lt;= 0) {
</span><del>-                                                tmp = SWITCH_DEFAULT_DTMF_DURATION;
-                                        } 
</del><ins>+                                                tmp = switch_core_default_dtmf_duration(0);
+                                        }
</ins><span class="cx">                                         dtmf.duration = tmp * 8;
</span><span class="cx">                                 }
</span><span class="cx">                         } else if (!strncasecmp(sip-&gt;sip_content_type-&gt;c_type, &quot;application&quot;, 11) &amp;&amp; !strcasecmp(sip-&gt;sip_content_type-&gt;c_subtype, &quot;dtmf&quot;)) {
</span><del>-                                dtmf.digit = *sip-&gt;sip_payload-&gt;pl_data;
</del><ins>+                                int tmp = atoi(sip-&gt;sip_payload-&gt;pl_data);
+                                dtmf.digit = switch_rfc2833_to_char(tmp);
</ins><span class="cx">                         } else {
</span><del>-                                goto fail;
</del><ins>+                                goto end;
</ins><span class="cx">                         }
</span><del>-                
</del><ins>+
</ins><span class="cx">                         if (dtmf.digit) {
</span><span class="cx">                                 /* queue it up */
</span><span class="cx">                                 switch_channel_queue_dtmf(channel, &amp;dtmf);
</span><span class="cx"> 
</span><span class="cx">                                 /* print debug info */
</span><span class="cx">                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;INFO DTMF(%c)\n&quot;, dtmf.digit);
</span><ins>+                                
+                                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)) &amp;&amp; (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, &amp;idtmf) == SWITCH_STATUS_SUCCESS) {
+                                                                switch_core_session_send_dtmf(session_b, &amp;idtmf);
+                                                        }
+                                                }
</ins><span class="cx"> 
</span><ins>+                                                switch_core_session_rwunlock(session_b);
+                                        }
+                                }
+
</ins><span class="cx">                                 /* Send 200 OK response */
</span><span class="cx">                                 nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
</span><del>-        
-                                return;
-                        } else {
-                                goto fail;
</del><span class="cx">                         }
</span><ins>+                        goto end;
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 if ((clientcode_header = sofia_glue_get_unknown_header(sip, &quot;x-clientcode&quot;))) {
</span><span class="lines">@@ -2435,10 +4355,8 @@
</span><span class="cx">                                 switch_channel_set_variable(channel, &quot;call_clientcode&quot;, clientcode_header);
</span><span class="cx">                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Setting CMC to %s\n&quot;, clientcode_header);
</span><span class="cx">                                 nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
</span><del>-                        } else {
-                                goto fail;
</del><span class="cx">                         }
</span><del>-                        return;
</del><ins>+                        goto end;
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 if ((rec_header = sofia_glue_get_unknown_header(sip, &quot;record&quot;))) {
</span><span class="lines">@@ -2470,16 +4388,74 @@
</span><span class="cx">                                         }
</span><span class="cx">                                 }
</span><span class="cx">                         }
</span><del>-                        return;
</del><span class="cx">                 }
</span><span class="cx">         }
</span><ins>+
+ end:
+
+
+        if (sip &amp;&amp; switch_event_create(&amp;event, SWITCH_EVENT_RECV_INFO) == SWITCH_STATUS_SUCCESS) {
+                sip_alert_info_t *alert_info = sip_alert_info(sip);
+
+                if (sip &amp;&amp; sip-&gt;sip_content_type) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;SIP-Content-Type&quot;, sip-&gt;sip_content_type-&gt;c_type);
+                }
+
+                if (sip-&gt;sip_from &amp;&amp; sip-&gt;sip_from-&gt;a_url) {
+                        if (sip-&gt;sip_from-&gt;a_url-&gt;url_user) {
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;SIP-From-User&quot;, sip-&gt;sip_from-&gt;a_url-&gt;url_user);
+                        }
+
+                        if (sip-&gt;sip_from-&gt;a_url-&gt;url_host) {
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;SIP-From-Host&quot;, sip-&gt;sip_from-&gt;a_url-&gt;url_host);
+                        }
+                }
+
+                if (sip-&gt;sip_to &amp;&amp; sip-&gt;sip_to-&gt;a_url) {
+                        if (sip-&gt;sip_to-&gt;a_url-&gt;url_user) {
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;SIP-To-User&quot;, sip-&gt;sip_to-&gt;a_url-&gt;url_user);
+                        }
+
+                        if (sip-&gt;sip_to-&gt;a_url-&gt;url_host) {
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;SIP-To-Host&quot;, sip-&gt;sip_to-&gt;a_url-&gt;url_host);
+                        }
+                }
+
+
+                if (sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url) {
+                        if (sip-&gt;sip_contact-&gt;m_url-&gt;url_user) {
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;SIP-Contact-User&quot;, sip-&gt;sip_contact-&gt;m_url-&gt;url_user);
+                        }
+
+                        if (sip-&gt;sip_contact-&gt;m_url-&gt;url_host) {
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;SIP-Contact-Host&quot;, sip-&gt;sip_contact-&gt;m_url-&gt;url_host);
+                        }
+                }
+
+
+                if (sip-&gt;sip_call_info) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Call-Info&quot;, sip_header_as_string(nua_handle_home(nh), (void *) sip-&gt;sip_call_info));
+                }
+
+                if (alert_info) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Alert-Info&quot;, sip_header_as_string(nua_handle_home(nh), (void *) alert_info));
+                }
+
+
+                if (sip-&gt;sip_payload &amp;&amp; sip-&gt;sip_payload-&gt;pl_data) {
+                        switch_event_add_body(event, &quot;%s&quot;, sip-&gt;sip_payload-&gt;pl_data);
+                }
+
+                switch_event_fire(&amp;event);
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;dispatched freeswitch event for INFO\n&quot;);
+        }
+
+        nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>- fail:
-        nua_respond(nh, 488, &quot;Unsupported Request&quot;, NUTAG_WITH_THIS(nua), TAG_END());
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> #define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix &quot;_user&quot;, #varprefix &quot;_host&quot;, #varprefix &quot;_port&quot;, #varprefix &quot;_uri&quot;, #varprefix &quot;_params&quot;)
</span><span class="cx"> const char *_url_set_chanvars(switch_core_session_t *session, url_t *url, const char *user_var,
</span><span class="cx">                                                           const char *host_var, const char *port_var, const char *uri_var, const char *params_var)
</span><span class="lines">@@ -2539,7 +4515,9 @@
</span><span class="cx">         sip_remote_party_id_t *rpid = NULL;
</span><span class="cx">         sip_p_asserted_identity_t *passerted = NULL;
</span><span class="cx">         sip_p_preferred_identity_t *ppreferred = NULL;
</span><ins>+        sip_privacy_t *privacy = NULL;
</ins><span class="cx">         sip_alert_info_t *alert_info = NULL;
</span><ins>+        sip_call_info_t *call_info = NULL;
</ins><span class="cx">         private_object_t *tech_pvt = NULL;
</span><span class="cx">         switch_channel_t *channel = NULL;
</span><span class="cx">         const char *channel_name = NULL;
</span><span class="lines">@@ -2554,76 +4532,195 @@
</span><span class="cx">         uint32_t sess_count = switch_core_session_count();
</span><span class="cx">         uint32_t sess_max = switch_core_session_limit(0);
</span><span class="cx">         int is_auth = 0, calling_myself = 0;
</span><del>-        su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua));
-        
</del><ins>+        int network_port = 0;
+        char *is_nat = NULL;
+        char acl_token[512] = &quot;&quot;;
+        sofia_transport_t transport;
</ins><span class="cx"> 
</span><del>-        if (sess_count &gt;= sess_max || !(profile-&gt;pflags &amp; PFLAG_RUNNING)) {
</del><ins>+        profile-&gt;ib_calls++;
+
+        if (sess_count &gt;= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING)) {
</ins><span class="cx">                 nua_respond(nh, 503, &quot;Maximum Calls In Progress&quot;, SIPTAG_RETRY_AFTER_STR(&quot;300&quot;), TAG_END());
</span><del>-                return;
</del><ins>+                goto fail;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!sip || !sip-&gt;sip_request || !sip-&gt;sip_request-&gt;rq_method_name) {
</span><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Received an invalid packet!\n&quot;);
</span><span class="cx">                 nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
</span><del>-                return;
</del><ins>+                goto fail;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (!(sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;NO CONTACT!\n&quot;);
+                nua_respond(nh, 400, &quot;Missing Contact Header&quot;, TAG_END());
+                goto fail;
+        }
+
+        sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &amp;network_port);
+
+        if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
+                if (sip &amp;&amp; sip-&gt;sip_via) {
+                        const char *port = sip-&gt;sip_via-&gt;v_port;
+                        const char *host = sip-&gt;sip_via-&gt;v_host;
+
+                        if (host &amp;&amp; sip-&gt;sip_via-&gt;v_received) {
+                                is_nat = &quot;via received&quot;;
+                        } else if (host &amp;&amp; strcmp(network_ip, host)) {
+                                is_nat = &quot;via host&quot;;
+                        } else if (port &amp;&amp; atoi(port) != network_port) {
+                                is_nat = &quot;via port&quot;;
+                        }
+                }
+        }
+
+        if (!is_nat &amp;&amp; profile-&gt;nat_acl_count) {
+                uint32_t x = 0;
+                int ok = 1;
+                char *last_acl = NULL;
+                const char *contact_host = NULL;
+
+                if (sip &amp;&amp; sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url) {
+                        contact_host = sip-&gt;sip_contact-&gt;m_url-&gt;url_host;
+                }
+
+                if (!switch_strlen_zero(contact_host)) {
+                        for (x = 0; x &lt; profile-&gt;nat_acl_count; x++) {
+                                last_acl = profile-&gt;nat_acl[x];
+                                if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
+                                        break;
+                                }
+                        }
+
+                        if (ok) {
+                                is_nat = last_acl;
+                        }
+                }
+        }
</ins><span class="cx">         
</span><del>-        get_addr(network_ip, sizeof(network_ip), &amp;((struct sockaddr_in *) my_addrinfo-&gt;ai_addr)-&gt;sin_addr);
-
</del><span class="cx">         if (profile-&gt;acl_count) {
</span><span class="cx">                 uint32_t x = 0;
</span><del>-                for (x = 0 ; x &lt; profile-&gt;acl_count; x++) {
-                        if (!switch_check_network_list_ip(network_ip, profile-&gt;acl[x])) {
-                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;IP %s Rejected by acl %s\n&quot;, network_ip,  profile-&gt;acl[x]);
</del><ins>+                int ok = 1;
+                char *last_acl = NULL;
+                const char *token = NULL;
+
+                for (x = 0; x &lt; profile-&gt;acl_count; x++) {
+                        last_acl = profile-&gt;acl[x];
+                        if (!(ok = switch_check_network_list_ip_token(network_ip, last_acl, &amp;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, &quot;IP %s Approved by acl \&quot;%s[%s]\&quot;. Access Granted.\n&quot;,
+                                                                  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, &quot;IP %s Rejected by acl \&quot;%s\&quot;\n&quot;, network_ip, switch_str_nil(last_acl));
</ins><span class="cx">                                 nua_respond(nh, SIP_403_FORBIDDEN, TAG_END());
</span><del>-                                return;
</del><ins>+                                goto fail;
+                        } else {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;IP %s Rejected by acl \&quot;%s\&quot;. Falling back to Digest auth.\n&quot;,
+                                                                  network_ip, switch_str_nil(last_acl));
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-
-        if ((profile-&gt;pflags &amp; PFLAG_AUTH_CALLS) || (!(profile-&gt;pflags &amp; PFLAG_BLIND_AUTH) &amp;&amp; (sip-&gt;sip_proxy_authorization || sip-&gt;sip_authorization))) {
-                if (strcmp(network_ip, profile-&gt;sipip)) {
-                        if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &amp;v_event)) {
</del><ins>+        if (!is_auth &amp;&amp;
+                (sofia_test_pflag(profile, PFLAG_AUTH_CALLS) || (!sofia_test_pflag(profile, PFLAG_BLIND_AUTH) &amp;&amp; (sip-&gt;sip_proxy_authorization || sip-&gt;sip_authorization)))) {
+                if (!strcmp(network_ip, profile-&gt;sipip) &amp;&amp; network_port == profile-&gt;sip_port) {
+                        calling_myself++;
+                } else {
+                        if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &amp;v_event, NULL)) {
</ins><span class="cx">                                 if (v_event) {
</span><span class="cx">                                         switch_event_destroy(&amp;v_event);
</span><span class="cx">                                 }
</span><ins>+                                
+                                if (sip-&gt;sip_authorization || sip-&gt;sip_proxy_authorization) {
+                                        goto fail;
+                                }
+
</ins><span class="cx">                                 return;
</span><span class="cx">                         }
</span><del>-                } else {
-                        calling_myself++;
</del><span class="cx">                 }
</span><span class="cx">                 is_auth++;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        
-        if (!(sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url)) {
-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;NO CONTACT!\n&quot;);
-                nua_respond(nh, 400, &quot;Missing Contact Header&quot;, TAG_END());
-                return;
</del><ins>+        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-&gt;sip_call_id-&gt;i_id);
+                } else {
+                        session = switch_core_session_request(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL);
+                }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        
-        if (!sofia_endpoint_interface || !(session = switch_core_session_request(sofia_endpoint_interface, NULL))) {
</del><ins>+        if (!session) {
</ins><span class="cx">                 nua_respond(nh, 503, &quot;Maximum Calls In Progress&quot;, SIPTAG_RETRY_AFTER_STR(&quot;300&quot;), TAG_END());
</span><del>-                return;
</del><ins>+                goto fail;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) {
</span><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Hey where is my memory pool?\n&quot;);
</span><span class="cx">                 nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
</span><span class="cx">                 switch_core_session_destroy(&amp;session);
</span><del>-                return;
</del><ins>+                goto fail;
</ins><span class="cx">         }
</span><ins>+
+
</ins><span class="cx">         switch_mutex_init(&amp;tech_pvt-&gt;flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
</span><ins>+        switch_mutex_init(&amp;tech_pvt-&gt;sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
</ins><span class="cx"> 
</span><ins>+        tech_pvt-&gt;remote_ip = switch_core_session_strdup(session, network_ip);
+        tech_pvt-&gt;remote_port = network_port;
+
+        channel = tech_pvt-&gt;channel = switch_core_session_get_channel(session);
+
+        if (*acl_token) {
+                switch_channel_set_variable(channel, &quot;acl_token&quot;, 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, &quot;Authenticating user %s\n&quot;, acl_token);
+                        } else {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Error Authenticating user %s\n&quot;, acl_token);
+                        }
+                }
+        }
+
+        if (sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url) {
+                char tmp[35] = &quot;&quot;;
+                const char *ipv6 = strchr(tech_pvt-&gt;remote_ip, ':');
+
+                transport = sofia_glue_url2transport(sip-&gt;sip_contact-&gt;m_url);
+
+                tech_pvt-&gt;record_route =
+                        switch_core_session_sprintf(session,
+                        &quot;sip:%s@%s%s%s:%d;transport=%s&quot;,
+                        sip-&gt;sip_contact-&gt;m_url-&gt;url_user,
+                        ipv6 ? &quot;[&quot; : &quot;&quot;,
+                        tech_pvt-&gt;remote_ip,
+                        ipv6 ? &quot;]&quot; : &quot;&quot;,
+                        tech_pvt-&gt;remote_port,
+                        sofia_glue_transport2str(transport));
+
+                switch_channel_set_variable(channel, &quot;sip_received_ip&quot;, tech_pvt-&gt;remote_ip);
+                snprintf(tmp, sizeof(tmp), &quot;%d&quot;, tech_pvt-&gt;remote_port);
+                switch_channel_set_variable(channel, &quot;sip_received_port&quot;, tmp);
+        }
+
+        if (sip-&gt;sip_via) {
+                switch_channel_set_variable(channel, &quot;sip_via_protocol&quot;, sofia_glue_transport2str(sofia_glue_via2transport(sip-&gt;sip_via)));
+        }
+
</ins><span class="cx">         if (*key != '\0') {
</span><span class="cx">                 tech_pvt-&gt;key = switch_core_session_strdup(session, key);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        channel = tech_pvt-&gt;channel = switch_core_session_get_channel(session);
-        
</del><ins>+
</ins><span class="cx">         if (is_auth) {
</span><span class="cx">                 switch_channel_set_variable(channel, &quot;sip_authorized&quot;, &quot;true&quot;);
</span><span class="cx">         }
</span><span class="lines">@@ -2634,8 +4731,8 @@
</span><span class="cx"> 
</span><span class="cx">         if (v_event) {
</span><span class="cx">                 switch_event_header_t *hp;
</span><del>-                
-                for(hp = v_event-&gt;headers; hp; hp = hp-&gt;next) {
</del><ins>+
+                for (hp = v_event-&gt;headers; hp; hp = hp-&gt;next) {
</ins><span class="cx">                         switch_channel_set_variable(channel, hp-&gt;name, hp-&gt;value);
</span><span class="cx">                 }
</span><span class="cx">                 switch_event_destroy(&amp;v_event);
</span><span class="lines">@@ -2672,29 +4769,46 @@
</span><span class="cx"> 
</span><span class="cx">         if ((rpid = sip_remote_party_id(sip))) {
</span><span class="cx">                 if (rpid-&gt;rpid_url &amp;&amp; rpid-&gt;rpid_url-&gt;url_user) {
</span><ins>+                        char *full_rpid_header = sip_header_as_string(nh-&gt;nh_home, (void *) rpid); 
</ins><span class="cx">                         from_user = rpid-&gt;rpid_url-&gt;url_user;
</span><ins>+                        if (!switch_strlen_zero(full_rpid_header)) {
+                                switch_channel_set_variable(channel, &quot;sip_Remote-Party-ID&quot;, full_rpid_header);
+                        }
+
</ins><span class="cx">                 }
</span><span class="cx">                 if (!switch_strlen_zero(rpid-&gt;rpid_display)) {
</span><span class="cx">                         displayname = rpid-&gt;rpid_display;
</span><span class="cx">                 }
</span><ins>+                switch_channel_set_variable(channel, &quot;sip_cid_type&quot;, &quot;rpid&quot;);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if ((passerted = sip_p_asserted_identity(sip))) {
</span><span class="cx">                 if (passerted-&gt;paid_url &amp;&amp; passerted-&gt;paid_url-&gt;url_user) {
</span><ins>+                        char *full_paid_header = sip_header_as_string(nh-&gt;nh_home, (void *) passerted);
</ins><span class="cx">                         from_user = passerted-&gt;paid_url-&gt;url_user;
</span><ins>+                        if (!switch_strlen_zero(full_paid_header)) {
+                                switch_channel_set_variable(channel, &quot;sip_P-Asserted-Identity&quot;, from_user);
+                        }
</ins><span class="cx">                 }
</span><span class="cx">                 if (!switch_strlen_zero(passerted-&gt;paid_display)) {
</span><span class="cx">                         displayname = passerted-&gt;paid_display;
</span><span class="cx">                 }
</span><ins>+                switch_channel_set_variable(channel, &quot;sip_cid_type&quot;, &quot;pid&quot;);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if ((ppreferred = sip_p_preferred_identity(sip))) {
</span><span class="cx">                 if (ppreferred-&gt;ppid_url &amp;&amp; ppreferred-&gt;ppid_url-&gt;url_user) {
</span><ins>+                        char *full_ppid_header = sip_header_as_string(nh-&gt;nh_home, (void *) ppreferred);
</ins><span class="cx">                         from_user = ppreferred-&gt;ppid_url-&gt;url_user;
</span><ins>+                        if (!switch_strlen_zero(full_ppid_header)) {
+                                switch_channel_set_variable(channel, &quot;sip_P-Preferred-Identity&quot;, full_ppid_header);
+                        }
+                        
</ins><span class="cx">                 }
</span><span class="cx">                 if (!switch_strlen_zero(ppreferred-&gt;ppid_display)) {
</span><span class="cx">                         displayname = ppreferred-&gt;ppid_display;
</span><span class="cx">                 }
</span><ins>+                switch_channel_set_variable(channel, &quot;sip_cid_type&quot;, &quot;pid&quot;);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (from_user) {
</span><span class="lines">@@ -2703,18 +4817,29 @@
</span><span class="cx"> 
</span><span class="cx">         if (sip-&gt;sip_request-&gt;rq_url) {
</span><span class="cx">                 const char *req_uri = url_set_chanvars(session, sip-&gt;sip_request-&gt;rq_url, sip_req);
</span><del>-                if (profile-&gt;pflags &amp; PFLAG_FULL_ID) {
</del><ins>+                if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
</ins><span class="cx">                         destination_number = req_uri;
</span><span class="cx">                 } else {
</span><span class="cx">                         destination_number = sip-&gt;sip_request-&gt;rq_url-&gt;url_user;
</span><span class="cx">                 }
</span><ins>+                if (sip-&gt;sip_request-&gt;rq_url-&gt;url_params &amp;&amp; (sofia_glue_find_parameter(sip-&gt;sip_request-&gt;rq_url-&gt;url_params, &quot;intercom=true&quot;))) {
+                        switch_channel_set_variable(channel, &quot;sip_auto_answer_detected&quot;, &quot;true&quot;);
+                }
+        }
+
+        if (!destination_number &amp;&amp; sip-&gt;sip_to &amp;&amp; sip-&gt;sip_to-&gt;a_url) {
+                destination_number = sip-&gt;sip_to-&gt;a_url-&gt;url_user;
+        }
+        
+        if (destination_number) {
</ins><span class="cx">                 check_decode(destination_number, session);
</span><ins>+        } else {
+                destination_number = &quot;service&quot;;
</ins><span class="cx">         }
</span><del>-
</del><ins>+        
</ins><span class="cx">         if (sip-&gt;sip_to &amp;&amp; sip-&gt;sip_to-&gt;a_url) {
</span><span class="cx">                 const char *host, *user;
</span><span class="cx">                 int port;
</span><del>-                sofia_transport_t transport;
</del><span class="cx">                 url_t *transport_url;
</span><span class="cx"> 
</span><span class="cx">                 if (sip-&gt;sip_record_route &amp;&amp; sip-&gt;sip_record_route-&gt;r_url) {
</span><span class="lines">@@ -2728,10 +4853,12 @@
</span><span class="cx"> 
</span><span class="cx">                 url_set_chanvars(session, sip-&gt;sip_to-&gt;a_url, sip_to);
</span><span class="cx">                 if (switch_channel_get_variable(channel, &quot;sip_to_uri&quot;)) {
</span><del>-
</del><ins>+                        const char *ipv6;
+                        const char *tmp, *at, *url = NULL;
+                        
</ins><span class="cx">                         host = switch_channel_get_variable(channel, &quot;sip_to_host&quot;);
</span><span class="cx">                         user = switch_channel_get_variable(channel, &quot;sip_to_user&quot;);
</span><del>-                
</del><ins>+
</ins><span class="cx">                         switch_channel_set_variable(channel, &quot;sip_to_comment&quot;, sip-&gt;sip_to-&gt;a_comment);
</span><span class="cx"> 
</span><span class="cx">                         if (sip-&gt;sip_to-&gt;a_params) {
</span><span class="lines">@@ -2744,42 +4871,70 @@
</span><span class="cx">                                 port = sofia_glue_transport_has_tls(transport) ? profile-&gt;tls_sip_port : profile-&gt;sip_port;
</span><span class="cx">                         }
</span><span class="cx"> 
</span><del>-                        tech_pvt-&gt;to_uri = switch_core_session_sprintf(session, &quot;sip:%s@%s:%d;transport=%s&quot;,
-                                                 user, host, port, sofia_glue_transport2str(transport));
</del><ins>+                        ipv6 = strchr(host, ':');
+                        tech_pvt-&gt;to_uri =
+                                switch_core_session_sprintf(session,
+                                        &quot;sip:%s@%s%s%s:%d;transport=%s&quot;,
+                                        user, ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                        host, ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                        port,
+                                        sofia_glue_transport2str(transport));
</ins><span class="cx"> 
</span><del>-                        if (profile-&gt;ndlb &amp; PFLAG_NDLB_TO_IN_200_CONTACT) {
-                                if (strchr(tech_pvt-&gt;to_uri, '&gt;')) {
-                                        tech_pvt-&gt;reply_contact = tech_pvt-&gt;to_uri;
-                                } else {
-                                        tech_pvt-&gt;reply_contact = switch_core_session_sprintf(session, &quot;&lt;%s&gt;&quot;, tech_pvt-&gt;to_uri);
-                                }
</del><ins>+                        if (sofia_glue_check_nat(profile, tech_pvt-&gt;remote_ip)) {
+                                url = (sofia_glue_transport_has_tls(transport)) ? profile-&gt;tls_public_url : profile-&gt;public_url;
+                        } else { 
+                                url = (sofia_glue_transport_has_tls(transport)) ? profile-&gt;tls_url : profile-&gt;url;
+                        }                        
+                        
+                        tmp = sofia_overcome_sip_uri_weakness(session, url, transport, SWITCH_TRUE, NULL);
+        
+                        if ((at = strchr(tmp, '@'))) {
+                                url = switch_core_session_sprintf(session, &quot;sip:%s%s&quot;, user, at);
+                        }
+
+                        if (url) {
+                                const char *brackets = NULL;
+                                const char *proto = NULL;
+                                
+                                brackets = strchr(url, '&gt;');
+                                proto = switch_stristr(&quot;transport=&quot;, url);
+                                tech_pvt-&gt;reply_contact = switch_core_session_sprintf(session, &quot;%s%s%s%s%s&quot;,
+                                                                                                                                          brackets ? &quot;&quot; : &quot;&lt;&quot;, url,
+                                                                                                                                          proto ? &quot;&quot; : &quot;;transport=&quot;,
+                                                                                                                                          proto ? &quot;&quot; : sofia_glue_transport2str(transport),
+                                                                                                                                          brackets ? &quot;&quot; : &quot;&gt;&quot;);
</ins><span class="cx">                         } else {
</span><del>-                                const char *url;
-
-                                if ((url = (sofia_glue_transport_has_tls(transport)) ? profile-&gt;tls_url : profile-&gt;url)) {
-                                        if (strchr(url, '&gt;')) {
-                                                tech_pvt-&gt;reply_contact = switch_core_session_sprintf(session, &quot;%s;transport=%s&quot;, url, sofia_glue_transport2str(transport));
-                                        } else {
-                                                tech_pvt-&gt;reply_contact = switch_core_session_sprintf(session, &quot;&lt;%s;transport=%s&gt;&quot;, url, sofia_glue_transport2str(transport));
-                                        }
-                                } else {
-                                        switch_channel_hangup(tech_pvt-&gt;channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-                                }
</del><ins>+                                switch_channel_hangup(tech_pvt-&gt;channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</ins><span class="cx">                         }
</span><ins>+                        
</ins><span class="cx">                 } else {
</span><del>-                        const char *url;
-
-                        if ((url = (sofia_glue_transport_has_tls(transport)) ? profile-&gt;tls_url : profile-&gt;url)) {
-                                if (strchr(url, '&gt;')) {
-                                        tech_pvt-&gt;reply_contact = switch_core_session_sprintf(session, &quot;%s;transport=%s&quot;, url, sofia_glue_transport2str(transport));
-                                } else {
-                                        tech_pvt-&gt;reply_contact = switch_core_session_sprintf(session, &quot;&lt;%s;transport=%s&gt;&quot;, url, sofia_glue_transport2str(transport));
-                                }
</del><ins>+                        const char *url = NULL;
+                        if (sofia_glue_check_nat(profile, tech_pvt-&gt;remote_ip)) {
+                        url = (sofia_glue_transport_has_tls(transport)) ? profile-&gt;tls_public_url : profile-&gt;public_url;
+                        } else { 
+                                url = (sofia_glue_transport_has_tls(transport)) ? profile-&gt;tls_url : profile-&gt;url;
+                        }                        
+                        
+                        if (url) {
+                                const char *brackets = NULL;
+                                const char *proto = NULL;
+                                
+                                brackets = strchr(url, '&gt;');
+                                proto = switch_stristr(&quot;transport=&quot;, url);
+                                tech_pvt-&gt;reply_contact = switch_core_session_sprintf(session, &quot;%s%s%s%s%s&quot;,
+                                                                                                                                          brackets ? &quot;&quot; : &quot;&lt;&quot;, url,
+                                                                                                                                          proto ? &quot;&quot; : &quot;;transport=&quot;,
+                                                                                                                                          proto ? &quot;&quot; : sofia_glue_transport2str(transport),
+                                                                                                                                          brackets ? &quot;&quot; : &quot;&gt;&quot;);
</ins><span class="cx">                         } else {
</span><span class="cx">                                 switch_channel_hangup(tech_pvt-&gt;channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><ins>+        
+        if (sofia_glue_check_nat(profile, tech_pvt-&gt;remote_ip)) {
+                tech_pvt-&gt;user_via = sofia_glue_create_external_via(session, profile, tech_pvt-&gt;transport);
+        }
</ins><span class="cx"> 
</span><span class="cx">         if (sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url) {
</span><span class="cx">                 const char *contact_uri = url_set_chanvars(session, sip-&gt;sip_contact-&gt;m_url, sip_contact);
</span><span class="lines">@@ -2815,11 +4970,11 @@
</span><span class="cx"> 
</span><span class="cx">         switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;INBOUND CALL&quot;);
</span><span class="cx"> 
</span><del>-        if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
</ins><span class="cx">                 switch_channel_set_flag(channel, CF_PROXY_MODE);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (switch_test_flag(tech_pvt, TFLAG_PROXY_MEDIA)) {
</del><ins>+        if (sofia_test_flag(tech_pvt, TFLAG_PROXY_MEDIA)) {
</ins><span class="cx">                 switch_channel_set_flag(channel, CF_PROXY_MEDIA);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -2831,8 +4986,8 @@
</span><span class="cx">         if (sip-&gt;sip_subject &amp;&amp; sip-&gt;sip_subject-&gt;g_string) {
</span><span class="cx">                 switch_channel_set_variable(channel, &quot;sip_subject&quot;, sip-&gt;sip_subject-&gt;g_string);
</span><span class="cx">         }
</span><del>-        
-        if (sip-&gt;sip_user_agent &amp;&amp; !switch_strlen_zero(sip-&gt;sip_user_agent-&gt;g_string)){
</del><ins>+
+        if (sip-&gt;sip_user_agent &amp;&amp; !switch_strlen_zero(sip-&gt;sip_user_agent-&gt;g_string)) {
</ins><span class="cx">                 switch_channel_set_variable(channel, &quot;sip_user_agent&quot;, sip-&gt;sip_user_agent-&gt;g_string);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -2854,20 +5009,6 @@
</span><span class="cx">                 switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (sip-&gt;sip_request-&gt;rq_url) {
-                sofia_gateway_t *gateway;
-                char *from_key;
-                char *user = (char *) sip-&gt;sip_request-&gt;rq_url-&gt;url_user;
-                check_decode(user, session);
-                from_key = switch_core_session_sprintf(session, &quot;sip:%s@%s&quot;, user, sip-&gt;sip_request-&gt;rq_url-&gt;url_host);
-
-                if ((gateway = sofia_reg_find_gateway(from_key))) {
-                        context = gateway-&gt;register_context;
-                        switch_channel_set_variable(channel, &quot;sip_gateway&quot;, gateway-&gt;name);
-                        sofia_reg_release_gateway(gateway);
-                }
-        }
-
</del><span class="cx">         if (!context) {
</span><span class="cx">                 context = switch_channel_get_variable(channel, &quot;user_context&quot;);
</span><span class="cx">         }
</span><span class="lines">@@ -2890,7 +5031,16 @@
</span><span class="cx">                 su_free(profile-&gt;home, tmp);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (sofia_test_pflag(profile, PFLAG_PRESENCE)) {
</del><ins>+        if ((call_info = sip_call_info(sip))) {
+                char *tmp = sip_header_as_string(profile-&gt;home, (void *) call_info);
+                if (call_info-&gt;ci_params &amp;&amp; (msg_params_find(call_info-&gt;ci_params , &quot;answer-after=0&quot;))) {
+                        switch_channel_set_variable(channel, &quot;sip_auto_answer_detected&quot;, &quot;true&quot;);
+                }
+                switch_channel_set_variable(channel, &quot;sip_call_info&quot;, tmp);
+                su_free(profile-&gt;home, tmp);
+        }
+
+        if (profile-&gt;pres_type) {
</ins><span class="cx">                 const char *user = switch_str_nil(sip-&gt;sip_from-&gt;a_url-&gt;url_user);
</span><span class="cx">                 const char *host = switch_str_nil(sip-&gt;sip_from-&gt;a_url-&gt;url_host);
</span><span class="cx"> 
</span><span class="lines">@@ -2900,14 +5050,111 @@
</span><span class="cx">                 free(tmp);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+
+        if (strstr(destination_number, &quot;gw+&quot;)) {
+                const char *gw_name = destination_number + 3;
+                sofia_gateway_t *gateway;
+                if (gw_name &amp;&amp; (gateway = sofia_reg_find_gateway(gw_name))) {
+                        context = switch_core_session_strdup(session, gateway-&gt;register_context);
+                        switch_channel_set_variable(channel, &quot;sip_gateway&quot;, gateway-&gt;name);
+
+                        if (gateway-&gt;extension) {
+                                destination_number = switch_core_session_strdup(session, gateway-&gt;extension);
+                        }
+
+                        gateway-&gt;ib_calls++;
+
+                        if (gateway-&gt;ib_vars) {
+                                switch_event_header_t *hp;
+                                for(hp = gateway-&gt;ib_vars-&gt;headers; hp; hp = hp-&gt;next) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s setting variable [%s]=[%s]\n&quot;,
+                                                                          switch_channel_get_name(channel), hp-&gt;name, hp-&gt;value);
+                                        switch_channel_set_variable(channel, hp-&gt;name, hp-&gt;value);
+                                }
+                        }
+
+                        sofia_reg_release_gateway(gateway);
+                }
+        }
+
+        if (sip-&gt;sip_replaces) {
+                nua_handle_t *bnh;
+                if ((bnh = nua_handle_by_replaces(nua, sip-&gt;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-&gt;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 &amp;&amp; data &amp;&amp; !strcasecmp(app, &quot;conference&quot;)) {
+                                                destination_number = switch_core_session_sprintf(b_session, &quot;answer,conference:%s&quot;, data);
+                                                dialplan = &quot;inline&quot;;
+                                        } 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 &amp;&amp; 
+                                                                        (!b_tech_pvt || !sofia_test_flag(b_tech_pvt, TFLAG_SIP_HOLD)) &amp;&amp; 
+                                                                        (!c_tech_pvt || !sofia_test_flag(c_tech_pvt, TFLAG_SIP_HOLD))) {
+                                                                        char *ext = switch_core_session_sprintf(b_session, &quot;conference:%s@sla+flags{mintwo}&quot;, uuid);
+                                                                
+                                                                        switch_channel_set_flag(c_channel, CF_REDIRECT);
+                                                                        switch_ivr_session_transfer(b_session, ext, &quot;inline&quot;, NULL);
+                                                                        switch_ivr_session_transfer(c_session, ext, &quot;inline&quot;, 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, &quot;answer,conference:%s@sla+flags{mintwo}&quot;, uuid);
+                                                        } else {
+                                                                destination_number = switch_core_session_sprintf(b_session, &quot;answer,intercept:%s&quot;, uuid);
+                                                        }
+
+                                                        dialplan = &quot;inline&quot;;
+                                                }
+                                        }
+                                        switch_core_session_rwunlock(b_session);
+                                }
+                        }
+                        nua_handle_unref(bnh);
+                }
+        }
+
</ins><span class="cx">         check_decode(displayname, session);
</span><span class="cx">         tech_pvt-&gt;caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
</span><span class="cx">                                                                                                                  from_user,
</span><span class="cx">                                                                                                                  dialplan,
</span><del>-                                                                                                                 displayname,
-                                                                                                                 from_user,
-                                                                                                                 network_ip,
-                                                                                                                 NULL, NULL, NULL, MODNAME, context, destination_number);
</del><ins>+                                                                                                                 displayname, from_user, network_ip, NULL, NULL, NULL, MODNAME, context, destination_number);
</ins><span class="cx"> 
</span><span class="cx">         if (tech_pvt-&gt;caller_profile) {
</span><span class="cx"> 
</span><span class="lines">@@ -2925,13 +5172,23 @@
</span><span class="cx">                                         switch_clear_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NAME);
</span><span class="cx">                                         switch_clear_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NUMBER);
</span><span class="cx">                                 }
</span><del>-                        } 
-                        
</del><ins>+                        }
+
</ins><span class="cx">                         if (rpid-&gt;rpid_screen &amp;&amp; !strcasecmp(rpid-&gt;rpid_screen, &quot;no&quot;)) {
</span><span class="cx">                                 switch_clear_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_SCREEN);
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx"> 
</span><ins>+                if ((privacy = sip_privacy(sip))) {
+                        char *full_priv_header = sip_header_as_string(nh-&gt;nh_home, (void *) privacy); 
+                        if (!switch_strlen_zero(full_priv_header)) {
+                                switch_channel_set_variable(channel, &quot;sip_Privacy&quot;, full_priv_header);
+                        }
+                        if (msg_params_find(privacy-&gt;priv_values, &quot;id&quot;)) {
+                                switch_set_flag(tech_pvt-&gt;caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+                        }
+                }
+
</ins><span class="cx">                 /* Loop thru unknown Headers Here so we can do something with them */
</span><span class="cx">                 for (un = sip-&gt;sip_unknown; un; un = un-&gt;un_next) {
</span><span class="cx">                         if (!strncasecmp(un-&gt;un_name, &quot;Diversion&quot;, 9)) {
</span><span class="lines">@@ -2944,27 +5201,43 @@
</span><span class="cx">                                                 free(tmp_name);
</span><span class="cx">                                         }
</span><span class="cx">                                 }
</span><ins>+                        } else if (!strncasecmp(un-&gt;un_name, &quot;History-Info&quot;, 12)) {
+                                switch_channel_set_variable(channel, &quot;sip_history_info&quot;, un-&gt;un_value);
</ins><span class="cx">                         } else if (!strncasecmp(un-&gt;un_name, &quot;X-&quot;, 2) || !strncasecmp(un-&gt;un_name, &quot;P-&quot;, 2)) {
</span><span class="cx">                                 if (!switch_strlen_zero(un-&gt;un_value)) {
</span><del>-                                        char *new_name;
-                                        if ((new_name = switch_mprintf(&quot;%s%s&quot;, SOFIA_SIP_HEADER_PREFIX, un-&gt;un_name))) {
</del><ins>+                                        char new_name[512] = &quot;&quot;;
+                                        int reps  = 0;
+                                        for(;;) {
+                                                char postfix[25] = &quot;&quot;;
+                                                if (reps &gt; 0) {
+                                                        switch_snprintf(postfix, sizeof(postfix), &quot;-%d&quot;, reps);
+                                                }
+                                                reps++;
+                                                switch_snprintf(new_name, sizeof(new_name), &quot;%s%s%s&quot;, SOFIA_SIP_HEADER_PREFIX, un-&gt;un_name, postfix);
+
+                                                if (switch_channel_get_variable(channel, new_name)) {
+                                                        continue;
+                                                }
+
</ins><span class="cx">                                                 switch_channel_set_variable(channel, new_name, un-&gt;un_value);
</span><del>-                                                free(new_name);
</del><ins>+                                                break;
</ins><span class="cx">                                         }
</span><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><del>-
</del><ins>+                
</ins><span class="cx">                 switch_channel_set_caller_profile(channel, tech_pvt-&gt;caller_profile);
</span><span class="cx">         }
</span><del>-
</del><ins>+        
</ins><span class="cx">         if (!(sofia_private = malloc(sizeof(*sofia_private)))) {
</span><span class="cx">                 abort();
</span><span class="cx">         }
</span><ins>+
</ins><span class="cx">         memset(sofia_private, 0, sizeof(*sofia_private));
</span><ins>+        sofia_private-&gt;is_call++;
</ins><span class="cx">         tech_pvt-&gt;sofia_private = sofia_private;
</span><span class="cx">         
</span><del>-        if ((profile-&gt;pflags &amp; PFLAG_PRESENCE)) {
</del><ins>+        if ((profile-&gt;pres_type)) {
</ins><span class="cx">                 sofia_presence_set_chat_hash(tech_pvt, sip);
</span><span class="cx">         }
</span><span class="cx">         switch_copy_string(tech_pvt-&gt;sofia_private-&gt;uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt-&gt;sofia_private-&gt;uuid));
</span><span class="lines">@@ -3010,28 +5283,25 @@
</span><span class="cx">                         contact_host = switch_str_nil(contact-&gt;url_host);
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-
-                if (profile-&gt;pflags &amp; PFLAG_PRESENCE) {
-
-                        sql = switch_mprintf(
-                                                                 &quot;insert into sip_dialogs values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')&quot;,
</del><ins>+                if (profile-&gt;pres_type) {
+                        sql = switch_mprintf(&quot;insert into sip_dialogs &quot;
+                                                                 &quot;(call_id,uuid,sip_to_user,sip_to_host,sip_from_user,sip_from_host,contact_user,&quot;
+                                                                 &quot;contact_host,state,direction,user_agent,profile_name,hostname) &quot;
+                                                                 &quot;values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')&quot;,
</ins><span class="cx">                                                                  call_id,
</span><span class="cx">                                                                  tech_pvt-&gt;sofia_private-&gt;uuid,
</span><del>-                                                                 to_user,
-                                                                 to_host,
-                                                                 dialog_from_user,
-                                                                 dialog_from_host,
-                                                                 contact_user,
-                                                                 contact_host,
-                                                                 &quot;confirmed&quot;,
-                                                                 &quot;inbound&quot;,
-                                                                 user_agent
-                                                                 );
-                        
</del><ins>+                                                                 to_user, to_host, dialog_from_user, dialog_from_host, 
+                                                                 contact_user, contact_host, &quot;confirmed&quot;, &quot;inbound&quot;, user_agent,
+                                                                 profile-&gt;name, mod_sofia_globals.hostname);
</ins><span class="cx">                         switch_assert(sql);
</span><span class="cx">                         sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
</span><span class="cx">                 }
</span><del>-                
</del><ins>+
+                if (is_nat) {
+                        sofia_set_flag(tech_pvt, TFLAG_NAT);
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Setting NAT mode based on %s\n&quot;, is_nat);
+                        switch_channel_set_variable(channel, &quot;sip_nat_detected&quot;, &quot;true&quot;);
+                }
</ins><span class="cx">                 return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3042,30 +5312,33 @@
</span><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;LUKE'S VOICE: Artoo, see what you can do with it. Hang on back there....\n&quot;
</span><span class="cx">                                                   &quot;Green laserfire moves past the beeping little robot as his head turns.  &quot;
</span><span class="cx">                                                   &quot;After a few beeps and a twist of his mechanical arm,\n&quot;
</span><del>-                                                  &quot;Artoo reduces the max sessions to %d thus, saving the switch from certian doom.\n&quot;, 
-                                                  sess_count - 10);
-
</del><ins>+                                                  &quot;Artoo reduces the max sessions to %d thus, saving the switch from certain doom.\n&quot;, sess_count - 10);
</ins><span class="cx">                 switch_mutex_unlock(profile-&gt;flag_mutex);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (tech_pvt-&gt;hash_key) {
</span><ins>+                switch_mutex_lock(tech_pvt-&gt;profile-&gt;flag_mutex);
</ins><span class="cx">                 switch_core_hash_delete(tech_pvt-&gt;profile-&gt;chat_hash, tech_pvt-&gt;hash_key);
</span><ins>+                switch_mutex_unlock(tech_pvt-&gt;profile-&gt;flag_mutex);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         nua_handle_bind(nh, NULL);
</span><del>-        free(tech_pvt-&gt;sofia_private);
</del><ins>+        sofia_private_free(sofia_private);
</ins><span class="cx">         switch_core_session_destroy(&amp;session);
</span><span class="cx">         nua_respond(nh, 503, &quot;Maximum Calls In Progress&quot;, SIPTAG_RETRY_AFTER_STR(&quot;300&quot;), TAG_END());
</span><ins>+        return;
+
+ fail:
+        profile-&gt;ib_failed_calls++;
+        return;
+
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void sofia_handle_sip_i_options(int status,
</span><del>-                                                  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[])
</del><ins>+                                                                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[])
</ins><span class="cx"> {
</span><del>-        nua_respond(nh, SIP_200_OK,
-                                NUTAG_WITH_THIS(nua),
-                                TAG_END());
-        nua_handle_destroy(nh);
</del><ins>+        nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void sofia_info_send_sipfrag(switch_core_session_t *aleg, switch_core_session_t *bleg)
</span><span class="lines">@@ -3073,19 +5346,33 @@
</span><span class="cx">         private_object_t *b_tech_pvt = NULL, *a_tech_pvt = NULL;
</span><span class="cx">         char message[256] = &quot;&quot;;
</span><span class="cx"> 
</span><del>-        if (aleg &amp;&amp; bleg) {
</del><ins>+        if (aleg &amp;&amp; bleg &amp;&amp; switch_core_session_compare(aleg, bleg)) {
+                switch_channel_t *channel = switch_core_session_get_channel(bleg);
+                const char *ua = switch_channel_get_variable(channel, &quot;sip_user_agent&quot;);
+                
</ins><span class="cx">                 a_tech_pvt = (private_object_t *) switch_core_session_get_private(aleg);
</span><span class="cx">                 b_tech_pvt = (private_object_t *) switch_core_session_get_private(bleg);
</span><del>-                
</del><ins>+
</ins><span class="cx">                 if (b_tech_pvt &amp;&amp; a_tech_pvt &amp;&amp; a_tech_pvt-&gt;caller_profile) {
</span><span class="cx">                         switch_caller_profile_t *acp = a_tech_pvt-&gt;caller_profile;
</span><del>-
-                        if (switch_strlen_zero(acp-&gt;caller_id_name)) {
-                                snprintf(message, sizeof(message), &quot;From:\r\nTo: %s\r\n&quot;, acp-&gt;caller_id_number);
-                        } else {
-                                snprintf(message, sizeof(message), &quot;From:\r\nTo: \&quot;%s\&quot; %s\r\n&quot;, acp-&gt;caller_id_name, acp-&gt;caller_id_number);
</del><ins>+                        
+                        if (ua &amp;&amp; switch_stristr(&quot;snom&quot;, ua)) {
+                                if (switch_strlen_zero(acp-&gt;caller_id_name)) {
+                                        snprintf(message, sizeof(message), &quot;From:\r\nTo: %s\r\n&quot;, acp-&gt;caller_id_number);
+                                } else {
+                                        snprintf(message, sizeof(message), &quot;From:\r\nTo: \&quot;%s\&quot; %s\r\n&quot;, acp-&gt;caller_id_name, acp-&gt;caller_id_number);
+                                }
+                                nua_info(b_tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;), SIPTAG_PAYLOAD_STR(message), TAG_END());
+                        } else if (ua &amp;&amp; switch_stristr(&quot;polycom&quot;, ua)) {
+                                if (switch_strlen_zero(acp-&gt;caller_id_name)) {
+                                        snprintf(message, sizeof(message), &quot;P-Asserted-Identity: \&quot;%s\&quot; &lt;%s&gt;&quot;, acp-&gt;caller_id_number, acp-&gt;caller_id_number);
+                                } else {
+                                        snprintf(message, sizeof(message), &quot;P-Asserted-Identity: \&quot;%s\&quot; &lt;%s&gt;&quot;, acp-&gt;caller_id_name, acp-&gt;caller_id_number);
+                                }
+                                nua_update(b_tech_pvt-&gt;nh,
+                                                   TAG_IF(!switch_strlen_zero_buf(message), SIPTAG_HEADER_STR(message)),
+                                                   TAG_END());
</ins><span class="cx">                         }
</span><del>-                        nua_info(b_tech_pvt-&gt;nh, SIPTAG_CONTENT_TYPE_STR(&quot;message/sipfrag&quot;), SIPTAG_PAYLOAD_STR(message), TAG_END());
</del><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> }
</span><span class="lines">@@ -3119,49 +5406,49 @@
</span><span class="cx">         char var1[] = &quot;sip_&quot;;
</span><span class="cx">         char *cp, *sh, *sh_end, *sh_save;
</span><span class="cx"> 
</span><del>-        /* Build the static part of the sip_header_name variable from        */
-        /* the header_type. If the header type is &quot;referred_by&quot; then        */
-        /* sip_header_name = &quot;sip_referred_by_&quot;.                        */
</del><ins>+        /* Build the static part of the sip_header_name variable from   */
+        /* the header_type. If the header type is &quot;referred_by&quot; then    */
+        /* sip_header_name = &quot;sip_referred_by_&quot;.                        */
</ins><span class="cx">         sh = sip_header_name;
</span><span class="cx">         sh_end = sh + sizeof(sip_header_name) - 1;
</span><del>-        for (cp=var1; *cp; cp++, sh++) {
</del><ins>+        for (cp = var1; *cp; cp++, sh++) {
</ins><span class="cx">                 *sh = *cp;
</span><span class="cx">         }
</span><span class="cx">         *sh = '\0';
</span><span class="cx"> 
</span><del>-        /* Copy the header_type to the sip_header_name. Before copying         */
</del><ins>+        /* Copy the header_type to the sip_header_name. Before copying  */
</ins><span class="cx">         /* each character, check that we aren't going to overflow the   */
</span><del>-        /* 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 &amp;&amp; (sh &lt; (sh_end-1))); cp++, sh++) {
</del><ins>+        /* 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 &amp;&amp; (sh &lt; (sh_end - 1))); cp++, sh++) {
</ins><span class="cx">                 *sh = *cp;
</span><span class="cx">         }
</span><span class="cx">         *sh++ = '_';
</span><span class="cx">         *sh = '\0';
</span><span class="cx"> 
</span><del>-        /* sh now points to the NULL at the end of the partially built        */
</del><ins>+        /* sh now points to the NULL at the end of the partially built  */
</ins><span class="cx">         /* sip_header_name variable.  This is also the start of the     */
</span><span class="cx">         /* variable part of the sip_header_name built from the lvalue   */
</span><del>-        /* of the parms data.                                           */
</del><ins>+        /* of the params data.                                          */
</ins><span class="cx">         sh_save = sh;
</span><span class="cx"> 
</span><span class="cx">         while (params &amp;&amp; params[0]) {
</span><span class="cx"> 
</span><del>-                /* 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 != '=') &amp;&amp; *cp &amp;&amp; (sh &lt; sh_end)); cp++, sh++) {
</del><ins>+                /* 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 != '=') &amp;&amp; *cp &amp;&amp; (sh &lt; sh_end)); cp++, sh++) {
</ins><span class="cx">                         *sh = *cp;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                /* cp now points to either the end of the parms data or the        */
-                /* equal (=) sign spearating the lvalue and rvalue.                */
</del><ins>+                /* cp now points to either the end of the params data or the */
+                /* equal (=) sign separating the lvalue and rvalue.          */
</ins><span class="cx">                 if (*cp == '=')
</span><del>-                        cp++;        
</del><ins>+                        cp++;
</ins><span class="cx">                 *sh = '\0';
</span><span class="cx">                 switch_channel_set_variable(channel, sip_header_name, cp);
</span><span class="cx"> 
</span><del>-                /* Bump pointer to next param in the list.  Also reset the        */
</del><ins>+                /* Bump pointer to next param in the list.  Also reset the      */
</ins><span class="cx">                 /* sip_header_name pointer to the beginning of the dynamic area */
</span><span class="cx">                 params++;
</span><span class="cx">                 sh = sh_save;
</span><span class="lines">@@ -3176,5 +5463,5 @@
</span><span class="cx">  * c-basic-offset:4
</span><span class="cx">  * End:
</span><span class="cx">  * For VIM:
</span><del>- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
</del><ins>+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
</ins><span class="cx">  */
</span><span class="cx">Property changes on: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:eol-style
</span><span class="cx">   + native
</span></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_gluecfromrev14389freeswitchtrunksrcmodendpointsmod_sofiasofia_gluec"></a>
<div class="copfile"><h4>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)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,4225 @@
</span><ins>+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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 &lt;anthm@freeswitch.org&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ * Ken Rice, Asteria Solutions Group, Inc &lt;ken@asteriasgi.com&gt;
+ * Paul D. Tinsley &lt;pdt at jackhammer.org&gt;
+ * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
+ * Eliot Gable &lt;egable AT.AT broadvox.com&gt;
+ *
+ *
+ * sofia_glue.c -- SOFIA SIP Endpoint (code to tie sofia to freeswitch)
+ *
+ */
+#include &quot;mod_sofia.h&quot;
+#include &lt;switch_stun.h&gt;
+
+
+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-&gt;ip;
+        uint32_t port = t38_options-&gt;port;
+        const char *family = &quot;IP4&quot;;
+        const char *username = tech_pvt-&gt;profile-&gt;username;
+
+        if (!ip) {
+                if (!(ip = tech_pvt-&gt;adv_sdp_audio_ip)) {
+                        ip = tech_pvt-&gt;proxy_sdp_audio_ip;
+                }
+        }
+
+        if (!port) {
+                if (!(port = tech_pvt-&gt;adv_sdp_audio_port)) {
+                        port = tech_pvt-&gt;proxy_sdp_audio_port;
+                }
+        }
+
+        if (!tech_pvt-&gt;owner_id) {
+                tech_pvt-&gt;owner_id = (uint32_t) switch_epoch_time_now(NULL) - port;
+        }
+
+        if (!tech_pvt-&gt;session_id) {
+                tech_pvt-&gt;session_id = tech_pvt-&gt;owner_id;
+        }
+
+        tech_pvt-&gt;session_id++;
+
+        family = strchr(ip, ':') ? &quot;IP6&quot; : &quot;IP4&quot;;
+        switch_snprintf(buf, sizeof(buf),
+                                        &quot;v=0\n&quot;
+                                        &quot;o=%s %010u %010u IN %s %s\n&quot;
+                                        &quot;s=%s\n&quot;
+                                        &quot;c=IN %s %s\n&quot; 
+                                        &quot;t=0 0\n&quot;
+                                        &quot;m=image %d udptl t38\n&quot;
+                                        &quot;a=T38MaxBitRate:%d\n&quot;
+                                        &quot;%s&quot;
+                                        &quot;%s&quot;
+                                        &quot;%s&quot;
+                                        &quot;a=T38FaxRateManagement:%s\n&quot;
+                                        &quot;a=T38FaxMaxBuffer:%d\n&quot;
+                                        &quot;a=T38FaxMaxDatagram:%d\n&quot;
+                                        &quot;a=T38FaxUdpEC:%s\n&quot;
+                                        &quot;a=T38VendorInfo:%s\n&quot;,
+                                        
+                                        username,
+                                        tech_pvt-&gt;owner_id, 
+                                        tech_pvt-&gt;session_id,
+                                        family,
+                                        ip,
+                                        username,
+                                        family,
+                                        ip,
+                                        port,
+                                        
+                                        t38_options-&gt;T38MaxBitRate,
+                                        t38_options-&gt;T38FaxFillBitRemoval ? &quot;a=T38FaxFillBitRemoval\n&quot; : &quot;&quot;,
+                                        t38_options-&gt;T38FaxTranscodingMMR ? &quot;a=T38FaxTranscodingMMR\n&quot; : &quot;&quot;,
+                                        t38_options-&gt;T38FaxTranscodingJBIG ? &quot;a=T38FaxTranscodingJBIG\n&quot; : &quot;&quot;,
+                                        t38_options-&gt;T38FaxRateManagement,
+                                        t38_options-&gt;T38FaxMaxBuffer,
+                                        t38_options-&gt;T38FaxMaxDatagram,
+                                        t38_options-&gt;T38FaxUdpEC,
+                                        t38_options-&gt;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-&gt;channel, &quot;sip_video_fmtp&quot;);
+        const char *ov_fmtp = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_force_video_fmtp&quot;);
+        char srbuf[128] = &quot;&quot;;
+        const char *var_val;
+        const char *username = tech_pvt-&gt;profile-&gt;username;
+
+        if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG) ||
+                ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;supress_cng&quot;)) &amp;&amp; switch_true(val)) ||
+                ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;suppress_cng&quot;)) &amp;&amp; switch_true(val))) {
+                use_cng = 0;
+                tech_pvt-&gt;cng_pt = 0;
+        }
+
+        if (!force &amp;&amp; !ip &amp;&amp; !sr
+                &amp;&amp; (switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA))) {
+                return;
+        }
+
+        if (!ip) {
+                if (!(ip = tech_pvt-&gt;adv_sdp_audio_ip)) {
+                        ip = tech_pvt-&gt;proxy_sdp_audio_ip;
+                }
+        }
+        if (!port) {
+                if (!(port = tech_pvt-&gt;adv_sdp_audio_port)) {
+                        port = tech_pvt-&gt;proxy_sdp_audio_port;
+                }
+        }
+
+        if (!sr) {
+                sr = &quot;sendrecv&quot;;
+        }
+
+        if (!tech_pvt-&gt;owner_id) {
+                tech_pvt-&gt;owner_id = (uint32_t) switch_epoch_time_now(NULL) - port;
+        }
+
+        if (!tech_pvt-&gt;session_id) {
+                tech_pvt-&gt;session_id = tech_pvt-&gt;owner_id;
+        }
+
+        tech_pvt-&gt;session_id++;
+
+        if ((tech_pvt-&gt;profile-&gt;ndlb &amp; PFLAG_NDLB_SENDRECV_IN_SESSION) || 
+                ((var_val=switch_channel_get_variable(tech_pvt-&gt;channel, &quot;ndlb_sendrecv_in_session&quot;)) &amp;&amp; switch_true(var_val))) {
+                switch_snprintf(srbuf, sizeof(srbuf), &quot;a=%s\n&quot;, sr);
+                sr = NULL;
+        }
+        
+        family = strchr(ip, ':') ? &quot;IP6&quot; : &quot;IP4&quot;;
+        switch_snprintf(buf, sizeof(buf),
+                                        &quot;v=0\n&quot;
+                                        &quot;o=%s %010u %010u IN %s %s\n&quot;
+                                        &quot;s=%s\n&quot;
+                                        &quot;c=IN %s %s\n&quot; &quot;t=0 0\n&quot;
+                                        &quot;%sm=audio %d RTP/%sAVP&quot;,
+                                        username,
+                                        tech_pvt-&gt;owner_id, tech_pvt-&gt;session_id, family, ip, username, family, ip, 
+                                        srbuf,
+                                        port,
+                                        (!switch_strlen_zero(tech_pvt-&gt;local_crypto_key) 
+                                        &amp;&amp; sofia_test_flag(tech_pvt,TFLAG_SECURE)) ? &quot;S&quot; : &quot;&quot;);
+
+        if (tech_pvt-&gt;rm_encoding) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, tech_pvt-&gt;pt);
+        } else if (tech_pvt-&gt;num_codecs) {
+                int i;
+                int already_did[128] = { 0 };
+                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
+
+                        if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+                                continue;
+                        }
+
+                        if (imp-&gt;ianacode &lt; 128) {
+                                if (already_did[imp-&gt;ianacode]) {
+                                        continue;
+                                }
+
+                                already_did[imp-&gt;ianacode] = 1;
+                        }
+
+                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, imp-&gt;ianacode);
+                        if (!ptime) {
+                                ptime = imp-&gt;microseconds_per_packet / 1000;
+                        }
+                }
+        }
+
+        if (tech_pvt-&gt;dtmf_type == DTMF_2833 &amp;&amp; tech_pvt-&gt;te &gt; 95) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, tech_pvt-&gt;te);
+        }
+
+        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG) &amp;&amp; tech_pvt-&gt;cng_pt &amp;&amp; use_cng) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, tech_pvt-&gt;cng_pt);
+        }
+
+        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;\n&quot;);
+
+
+        if (tech_pvt-&gt;rm_encoding) {
+                rate = tech_pvt-&gt;rm_rate;
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d %s/%d\n&quot;, tech_pvt-&gt;agreed_pt, tech_pvt-&gt;rm_encoding, rate);
+                if (tech_pvt-&gt;fmtp_out) {
+                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=fmtp:%d %s\n&quot;, tech_pvt-&gt;agreed_pt, tech_pvt-&gt;fmtp_out);
+                }
+                if (tech_pvt-&gt;read_codec.implementation &amp;&amp; !ptime) {
+                        ptime = tech_pvt-&gt;read_codec.implementation-&gt;microseconds_per_packet / 1000;
+                }
+
+        } else if (tech_pvt-&gt;num_codecs) {
+                int i;
+                int already_did[128] = { 0 };
+                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
+
+                        if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+                                continue;
+                        }
+
+                        if (imp-&gt;ianacode &lt; 128) {
+                                if (already_did[imp-&gt;ianacode]) {
+                                        continue;
+                                }
+
+                                already_did[imp-&gt;ianacode] = 1;
+                        }
+
+                        rate = imp-&gt;samples_per_second;
+
+                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d %s/%d\n&quot;, imp-&gt;ianacode, imp-&gt;iananame, rate);
+                        if (imp-&gt;fmtp) {
+                                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=fmtp:%d %s\n&quot;, imp-&gt;ianacode, imp-&gt;fmtp);
+                        }
+                }
+        }
+
+        if (tech_pvt-&gt;dtmf_type == DTMF_2833 &amp;&amp; tech_pvt-&gt;te &gt; 95) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n&quot;, tech_pvt-&gt;te, tech_pvt-&gt;te);
+        }
+        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG) &amp;&amp; tech_pvt-&gt;cng_pt &amp;&amp; use_cng) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d CN/8000\n&quot;, tech_pvt-&gt;cng_pt);
+                if (!tech_pvt-&gt;rm_encoding) {
+                        tech_pvt-&gt;cng_pt = 0;
+                }
+        } else {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=silenceSupp:off - - - -\n&quot;);
+        }
+
+        if (ptime) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=ptime:%d\n&quot;, ptime);
+        }
+
+        if (sr) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=%s\n&quot;, sr);
+        } 
+
+        if (!switch_strlen_zero(tech_pvt-&gt;local_crypto_key) &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=crypto:%s\n&quot;, tech_pvt-&gt;local_crypto_key);
+                //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=encryption:optional\n&quot;);
+#if 0
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;m=audio %d RTP/AVP&quot;, port);
+
+                if (tech_pvt-&gt;rm_encoding) {
+                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, tech_pvt-&gt;pt);
+                } else if (tech_pvt-&gt;num_codecs) {
+                        int i;
+                        int already_did[128] = { 0 };
+                        for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                                const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
+
+                                if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+                                        continue;
+                                }
+
+                                if (imp-&gt;ianacode &lt; 128) {
+                                        if (already_did[imp-&gt;ianacode]) {
+                                                continue;
+                                        }
+
+                                        already_did[imp-&gt;ianacode] = 1;
+                                }
+
+                                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, imp-&gt;ianacode);
+                        }
+                }
+
+                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;\na=crypto:%s\n&quot;, tech_pvt-&gt;local_crypto_key);
+#endif
+        }
+
+        if (sofia_test_flag(tech_pvt, TFLAG_VIDEO)) {
+                if (!switch_channel_test_flag(tech_pvt-&gt;channel, CF_ANSWERED) &amp;&amp; !switch_channel_test_flag(tech_pvt-&gt;channel, CF_EARLY_MEDIA) &amp;&amp;
+                        !tech_pvt-&gt;local_sdp_video_port) {
+                        sofia_glue_tech_choose_video_port(tech_pvt, 0);
+                }
+
+                if ((v_port = tech_pvt-&gt;adv_sdp_video_port)) {
+                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;m=video %d RTP/AVP&quot;, v_port);
+                        
+                        /*****************************/
+                        if (tech_pvt-&gt;video_rm_encoding) {
+                                sofia_glue_tech_set_video_codec(tech_pvt, 0);
+                                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, tech_pvt-&gt;video_agreed_pt);
+                        } else if (tech_pvt-&gt;num_codecs) {
+                                int i;
+                                int already_did[128] = { 0 };
+                                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
+
+                                        if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+                                                continue;
+                                        }
+
+                                        if (imp-&gt;ianacode &lt; 128) {
+                                                if (already_did[imp-&gt;ianacode]) {
+                                                        continue;
+                                                }
+                                                already_did[imp-&gt;ianacode] = 1;
+                                        }
+
+                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot; %d&quot;, imp-&gt;ianacode);
+                                        if (!ptime) {
+                                                ptime = imp-&gt;microseconds_per_packet / 1000;
+                                        }
+                                }
+                        }
+
+                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;\n&quot;);
+
+                        if (tech_pvt-&gt;video_rm_encoding) {
+                                const char *of;
+                                rate = tech_pvt-&gt;video_rm_rate;
+                                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d %s/%ld\n&quot;, tech_pvt-&gt;video_pt, tech_pvt-&gt;video_rm_encoding,
+                                                                tech_pvt-&gt;video_rm_rate);
+
+                                pass_fmtp = NULL;
+
+                                if (switch_channel_get_variable(tech_pvt-&gt;channel, SWITCH_SIGNAL_BOND_VARIABLE)) {
+                                        if ((of = switch_channel_get_variable_partner(tech_pvt-&gt;channel, &quot;sip_video_fmtp&quot;))) {
+                                                pass_fmtp = of;
+                                        }
+                                }
+
+                                if (ov_fmtp) {
+                                        pass_fmtp = ov_fmtp;
+                                }
+
+                                if (pass_fmtp) {
+                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=fmtp:%d %s\n&quot;, tech_pvt-&gt;video_pt, pass_fmtp);
+                                }
+
+                        } else if (tech_pvt-&gt;num_codecs) {
+                                int i;
+                                int already_did[128] = { 0 };
+
+                                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
+
+                                        if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+                                                continue;
+                                        }
+
+                                        if (imp-&gt;ianacode &lt; 128) {
+                                                if (already_did[imp-&gt;ianacode]) {
+                                                        continue;
+                                                }
+                                                already_did[imp-&gt;ianacode] = 1;
+                                        }
+
+                                        if (!rate) {
+                                                rate = imp-&gt;samples_per_second;
+                                        }
+
+                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=rtpmap:%d %s/%d\n&quot;, imp-&gt;ianacode, imp-&gt;iananame,
+                                                                        imp-&gt;samples_per_second);
+                                        if (imp-&gt;fmtp) {
+                                                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=fmtp:%d %s\n&quot;, imp-&gt;ianacode, imp-&gt;fmtp);
+                                        } else {
+                                                if (pass_fmtp) {
+                                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;a=fmtp:%d %s\n&quot;, imp-&gt;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-&gt;channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA)) {
+                return;
+        }
+
+        if (tech_pvt-&gt;num_codecs) {
+                return;
+        }
+
+        switch_assert(tech_pvt-&gt;session != NULL);
+
+        if ((abs = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;absolute_codec_string&quot;))) {
+                codec_string = abs;
+        } else {
+                if (!(codec_string = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;codec_string&quot;))) {
+                        if (tech_pvt-&gt;profile-&gt;codec_string) {
+                                codec_string = tech_pvt-&gt;profile-&gt;codec_string;
+                        }
+                }
+
+                if ((ocodec = switch_channel_get_variable(tech_pvt-&gt;channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
+                        if (!codec_string || sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_DISABLE_TRANSCODING)) {
+                                codec_string = ocodec;
+                        } else {
+                                if (!(codec_string = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;%s,%s&quot;, ocodec, codec_string))) {
+                                        codec_string = ocodec;
+                                }
+                        }
+                }
+        }
+
+        if (codec_string) {
+                char *tmp_codec_string;
+                if ((tmp_codec_string = switch_core_session_strdup(tech_pvt-&gt;session, codec_string))) {
+                        tech_pvt-&gt;codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt-&gt;codec_order, SWITCH_MAX_CODECS);
+                        tech_pvt-&gt;num_codecs =
+                                switch_loadable_module_get_codecs_sorted(tech_pvt-&gt;codecs, SWITCH_MAX_CODECS, tech_pvt-&gt;codec_order, tech_pvt-&gt;codec_order_last);
+                }
+        } else {
+                tech_pvt-&gt;num_codecs = switch_loadable_module_get_codecs(tech_pvt-&gt;codecs, sizeof(tech_pvt-&gt;codecs) / sizeof(tech_pvt-&gt;codecs[0]));
+        }
+
+
+}
+
+void sofia_glue_check_video_codecs(private_object_t *tech_pvt)
+{
+        if (tech_pvt-&gt;num_codecs &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_VIDEO)) {
+                int i;
+                tech_pvt-&gt;video_count = 0;
+                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                        if (tech_pvt-&gt;codecs[i]-&gt;codec_type == SWITCH_CODEC_TYPE_VIDEO) {
+                                tech_pvt-&gt;video_count++;
+                        }
+                }
+                if (tech_pvt-&gt;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-&gt;flag_mutex);
+        switch_mutex_lock(profile-&gt;flag_mutex);
+
+        /* copy flags from profile to the sofia private */
+        for(x = 0; x &lt; TFLAG_MAX; x++ ) {
+                tech_pvt-&gt;flags[x] = profile-&gt;flags[x];
+        }
+
+        tech_pvt-&gt;profile = profile;
+        profile-&gt;inuse++;
+        switch_mutex_unlock(profile-&gt;flag_mutex);
+        switch_mutex_unlock(tech_pvt-&gt;flag_mutex);
+
+        if (tech_pvt-&gt;bte) {
+                tech_pvt-&gt;te = tech_pvt-&gt;bte;
+        } else if (!tech_pvt-&gt;te) {
+                tech_pvt-&gt;te = profile-&gt;te;
+        }
+
+        tech_pvt-&gt;dtmf_type = profile-&gt;dtmf_type;
+
+        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG)) {
+                if (tech_pvt-&gt;bcng_pt) {
+                        tech_pvt-&gt;cng_pt = tech_pvt-&gt;bcng_pt;
+                } else if (!tech_pvt-&gt;cng_pt) {
+                        tech_pvt-&gt;cng_pt = profile-&gt;cng_pt;
+                }
+        }
+
+        tech_pvt-&gt;session = session;
+        tech_pvt-&gt;channel = switch_core_session_get_channel(session);
+        switch_core_session_set_private(session, tech_pvt);
+
+        switch_snprintf(name, sizeof(name), &quot;sofia/%s/%s&quot;, profile-&gt;name, channame);
+        if ((p = strchr(name, ';'))) {
+                *p = '\0';
+        }
+        switch_channel_set_name(tech_pvt-&gt;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 = &quot;&quot;;
+        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, &quot;host:&quot;, 5)) {
+                status = (*ip = switch_stun_host_lookup(sourceip + 5, pool)) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+        } else if (!strncasecmp(sourceip, &quot;stun:&quot;, 5)) {
+                char *p;
+
+                if (!sofia_test_pflag(profile, PFLAG_STUN_ENABLED)) {
+                        *ip = switch_core_strdup(pool, profile-&gt;rtpip);
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Trying to use STUN but its disabled!\n&quot;);
+                        return SWITCH_STATUS_SUCCESS;
+                }
+                
+                stun_ip = strdup(sourceip + 5);
+
+                if ((p = strchr(stun_ip, ':'))) {
+                        int iport;
+                        *p++ = '\0';
+                        iport = atoi(p);
+                        if (iport &gt; 0 &amp;&amp; iport &lt; 0xFFFF) {
+                                stun_port = (switch_port_t) iport;
+                        }
+                }
+
+                if (switch_strlen_zero(stun_ip)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;STUN Failed! NO STUN SERVER\n&quot;);
+                        goto out;
+                }
+
+                for (x = 0; x &lt; 5; x++) {
+                        if (sofia_test_pflag(profile, PFLAG_FUNNY_STUN) || 
+                                (tech_pvt &amp;&amp; (var = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;funny_stun&quot;)) &amp;&amp; switch_true(var))) {
+                                error = &quot;funny&quot;;
+                                funny++;
+                        }
+                        if ((status = switch_stun_lookup(ip, port, stun_ip, stun_port, &amp;error, pool)) != SWITCH_STATUS_SUCCESS) {
+                                switch_yield(100000);
+                        } else {
+                                break;
+                        }
+                }
+                if (status != SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;STUN Failed! %s:%d [%s]\n&quot;, stun_ip, stun_port, error);
+                        goto out;
+                }
+                if (!*ip) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;STUN Failed! No IP returned\n&quot;);
+                        goto out;
+                }
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;STUN Success [%s]:[%d]\n&quot;, *ip, *port);
+                status = SWITCH_STATUS_SUCCESS;
+                if (tech_pvt) {
+                        if (myport == *port &amp;&amp; !strcmp(*ip, tech_pvt-&gt;profile-&gt;rtpip)) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;STUN Not Required ip and port match. [%s]:[%d]\n&quot;, *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, &quot;STUN completely disabled.\n&quot;);
+                                }
+                        } else {
+                                tech_pvt-&gt;stun_ip = switch_core_session_strdup(tech_pvt-&gt;session, stun_ip);
+                                tech_pvt-&gt;stun_port = stun_port;
+                                tech_pvt-&gt;stun_flags |= STUN_FLAG_SET;
+                                if (funny) {
+                                        tech_pvt-&gt;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-&gt;sip_unknown; un; un = un-&gt;un_next) {
+                if (!strcasecmp(un-&gt;un_name, name)) {
+                        if (!switch_strlen_zero(un-&gt;un_value)) {
+                                return un-&gt;un_value;
+                        }
+                }
+        }
+        return NULL;
+}
+
+switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int force)
+{
+        char *ip = tech_pvt-&gt;profile-&gt;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-&gt;channel, CF_PROXY_MODE) ||
+                        switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA) || tech_pvt-&gt;adv_sdp_audio_port) {
+                        return SWITCH_STATUS_SUCCESS;
+                }
+        }
+
+        if (tech_pvt-&gt;local_sdp_audio_port) {
+                switch_rtp_release_port(tech_pvt-&gt;profile-&gt;rtpip, tech_pvt-&gt;local_sdp_audio_port);
+        }
+
+
+        tech_pvt-&gt;local_sdp_audio_ip = ip;
+
+        if (!(tech_pvt-&gt;local_sdp_audio_port = switch_rtp_request_port(tech_pvt-&gt;profile-&gt;rtpip))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;No RTP ports available!\n&quot;);
+                return SWITCH_STATUS_FALSE;
+        }
+        sdp_port = tech_pvt-&gt;local_sdp_audio_port;
+
+        if (!(use_ip = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_adv_audio_ip&quot;)) &amp;&amp; !sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_AUTO_NAT)) {
+                if (tech_pvt-&gt;profile-&gt;extrtpip) {
+                        use_ip = tech_pvt-&gt;profile-&gt;extrtpip;
+                }
+        }
+
+        if (use_ip) {
+                tech_pvt-&gt;extrtpip = switch_core_session_strdup(tech_pvt-&gt;session, use_ip);
+                if (sofia_glue_ext_address_lookup(tech_pvt-&gt;profile, tech_pvt, &amp;ip, &amp;sdp_port, 
+                                                                                  tech_pvt-&gt;extrtpip, switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
+                        return SWITCH_STATUS_FALSE;
+                }
+        }
+
+        if (!use_ip &amp;&amp; tech_pvt-&gt;profile-&gt;extrtpip &amp;&amp; sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) {
+                tech_pvt-&gt;adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt-&gt;session, ip ? ip : tech_pvt-&gt;profile-&gt;extrtpip);
+                switch_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP, &amp;external_port, SWITCH_FALSE);
+        } else {
+                tech_pvt-&gt;adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt-&gt;session, ip);
+        }
+        
+        tech_pvt-&gt;adv_sdp_audio_port = external_port != 0 ? external_port : sdp_port;
+
+        switch_snprintf(tmp, sizeof(tmp), &quot;%d&quot;, sdp_port);
+        switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt-&gt;adv_sdp_audio_ip);
+        switch_channel_set_variable(tech_pvt-&gt;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-&gt;profile-&gt;rtpip;
+        switch_port_t sdp_port;
+        char tmp[50];
+        switch_port_t external_port = 0;
+
+        if (!force) {
+                if (switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MODE) || switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA)
+                        || tech_pvt-&gt;local_sdp_video_port) {
+                        return SWITCH_STATUS_SUCCESS;
+                }
+        }
+
+        if (tech_pvt-&gt;local_sdp_video_port) {
+                switch_rtp_release_port(tech_pvt-&gt;profile-&gt;rtpip, tech_pvt-&gt;local_sdp_video_port);
+        }
+
+        if (!(tech_pvt-&gt;local_sdp_video_port = switch_rtp_request_port(tech_pvt-&gt;profile-&gt;rtpip))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;No RTP ports available!\n&quot;);
+                return SWITCH_STATUS_FALSE;
+        }
+        sdp_port = tech_pvt-&gt;local_sdp_video_port;
+
+
+        if (tech_pvt-&gt;profile-&gt;extrtpip) {
+                if (sofia_glue_ext_address_lookup(tech_pvt-&gt;profile, tech_pvt, &amp;ip, &amp;sdp_port, tech_pvt-&gt;profile-&gt;extrtpip,
+                                                                                  switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
+                        return SWITCH_STATUS_FALSE;
+                }
+        }
+
+        if (sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) {
+                switch_nat_add_mapping((switch_port_t)sdp_port, SWITCH_NAT_UDP, &amp;external_port, SWITCH_FALSE);
+        }
+        
+        tech_pvt-&gt;adv_sdp_video_port = external_port != 0 ? external_port : sdp_port;
+
+        switch_snprintf(tmp, sizeof(tmp), &quot;%d&quot;, sdp_port);
+        switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt-&gt;adv_sdp_audio_ip);
+        switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+sofia_transport_t sofia_glue_str2transport(const char *str)
+{
+        if (!strncasecmp(str, &quot;udp&quot;, 3)) {
+                return SOFIA_TRANSPORT_UDP;
+        } else if (!strncasecmp(str, &quot;tcp&quot;, 3)) {
+                return SOFIA_TRANSPORT_TCP;
+        } else if (!strncasecmp(str, &quot;sctp&quot;, 4)) {
+                return SOFIA_TRANSPORT_SCTP;
+        } else if (!strncasecmp(str, &quot;tls&quot;, 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-&gt;url_scheme &amp;&amp; !strcasecmp(url-&gt;url_scheme, &quot;sips&quot;)) {
+                tls++;
+        }
+
+        if ((ptr = sofia_glue_find_parameter(url-&gt;url_params, &quot;transport=&quot;))) {
+                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-&gt;v_protocol)
+                return SOFIA_TRANSPORT_UNKNOWN;
+
+        if ((ptr = strrchr(via-&gt;v_protocol, '/'))) {
+                ptr++;
+
+                if (!strncasecmp(ptr, &quot;udp&quot;, 3)) {
+                        return SOFIA_TRANSPORT_UDP;
+                } else if (!strncasecmp(ptr, &quot;tcp&quot;, 3)) {
+                        return SOFIA_TRANSPORT_TCP;
+                } else if (!strncasecmp(ptr, &quot;tls&quot;, 3)) {
+                        return SOFIA_TRANSPORT_TCP_TLS;
+                } else if (!strncasecmp(ptr, &quot;sctp&quot;, 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 &quot;tcp&quot;;
+
+        case SOFIA_TRANSPORT_TCP_TLS:
+                return &quot;tls&quot;;
+
+        case SOFIA_TRANSPORT_SCTP:
+                return &quot;sctp&quot;;
+
+        default:
+                return &quot;udp&quot;;
+        }
+}
+
+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-&gt;extsipip,
+                                                                 (sofia_glue_transport_has_tls(transport))
+                                                                 ? profile-&gt;tls_sip_port : profile-&gt;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 &amp;&amp; port != 5060) {
+                if (session) {
+                        return switch_core_session_sprintf(session, &quot;SIP/2.0/%s %s:%d;rport&quot;, sofia_glue_transport2str(transport), ip, port);                
+                } else {
+                        return switch_mprintf(&quot;SIP/2.0/%s %s:%d;rport&quot;, sofia_glue_transport2str(transport), ip, port);                
+                }
+        } else {
+                if (session) {
+                        return switch_core_session_sprintf(session, &quot;SIP/2.0/%s %s;rport&quot;, sofia_glue_transport2str(transport), ip);
+                } else {
+                        return switch_mprintf(&quot;SIP/2.0/%s %s;rport&quot;, sofia_glue_transport2str(transport), ip);
+                }
+        }
+}
+
+char *sofia_glue_strip_uri(const char *str)
+{
+        char *p;
+        char *r;
+
+        if ((p = strchr(str, '&lt;'))) {
+                p++;
+                r = strdup(p);
+                if ((p = strchr(r, '&gt;'))) {
+                        *p = '\0';
+                }
+        } else {
+                r = strdup(str);
+        }
+
+        return r;
+}
+
+int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip)
+{
+        return (network_ip &amp;&amp; 
+                        profile-&gt;local_network &amp;&amp; 
+                        sofia_test_pflag(profile, PFLAG_AUTO_NAT) &amp;&amp; 
+                        !switch_check_network_list_ip(network_ip, profile-&gt;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-&gt;ai_addr, addrinfo-&gt;ai_addrlen);
+        }
+
+        if (port) {
+                *port = get_port(addrinfo-&gt;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(&quot;;fs_&quot;, stripped))) {
+                *p = '\0'; 
+        }
+
+        if (transport &amp;&amp; transport != SOFIA_TRANSPORT_UDP) {
+
+                if (switch_stristr(&quot;port=&quot;, stripped)) {
+                        new_uri = switch_core_session_sprintf(session, &quot;%s%s%s&quot;, uri_only ? &quot;&quot; : &quot;&lt;&quot;, stripped, uri_only ? &quot;&quot; : &quot;&gt;&quot;);
+                } else {
+
+                        if (strchr(stripped, ';')) {
+                                if (params) {
+                                        new_uri = switch_core_session_sprintf(session, &quot;%s%s;transport=%s;%s%s&quot;,
+                                                                                                                  uri_only ? &quot;&quot; : &quot;&lt;&quot;, stripped, sofia_glue_transport2str(transport), params, uri_only ? &quot;&quot; : &quot;&gt;&quot;);
+                                } else {
+                                        new_uri = switch_core_session_sprintf(session, &quot;%s%s;transport=%s%s&quot;,
+                                                                                                                  uri_only ? &quot;&quot; : &quot;&lt;&quot;, stripped, sofia_glue_transport2str(transport), uri_only ? &quot;&quot; : &quot;&gt;&quot;);
+                                }
+                        } else {
+                                if (params) {
+                                        new_uri = switch_core_session_sprintf(session, &quot;%s%s;transport=%s;%s%s&quot;,
+                                                                                                                  uri_only ? &quot;&quot; : &quot;&lt;&quot;, stripped, sofia_glue_transport2str(transport), params, uri_only ? &quot;&quot; : &quot;&gt;&quot;);
+                                } else {
+                                        new_uri = switch_core_session_sprintf(session, &quot;%s%s;transport=%s%s&quot;,
+                                                                                                                  uri_only ? &quot;&quot; : &quot;&lt;&quot;, stripped, sofia_glue_transport2str(transport), uri_only ? &quot;&quot; : &quot;&gt;&quot;);
+                                }
+                        }
+                }
+        } else {
+                if (params) {
+                        new_uri = switch_core_session_sprintf(session, &quot;%s%s;%s%s&quot;, uri_only ? &quot;&quot; : &quot;&lt;&quot;, stripped, params, uri_only ? &quot;&quot; : &quot;&gt;&quot;);
+                } else {
+                        if (uri_only) {
+                                new_uri = stripped;
+                        } else {
+                                new_uri = switch_core_session_sprintf(session, &quot;&lt;%s&gt;&quot;, 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] = &quot;&quot;;
+        char rp[RA_PTR_LEN] = &quot;&quot;;
+        char rvp[RA_PTR_LEN] = &quot;&quot;;
+        char *p, *ip_ptr = NULL, *port_ptr = NULL, *vid_port_ptr = NULL, *pe;
+        int x;
+        const char *val;
+        
+        if (switch_strlen_zero(tech_pvt-&gt;remote_sdp_str)) {
+                return SWITCH_STATUS_FALSE;
+        }
+
+        if ((p = (char *) switch_stristr(&quot;c=IN IP4 &quot;, tech_pvt-&gt;remote_sdp_str)) ||
+                (p = (char *) switch_stristr(&quot;c=IN IP6 &quot;, tech_pvt-&gt;remote_sdp_str))) {
+                ip_ptr = p + 9;
+        }
+
+        if ((p = (char *) switch_stristr(&quot;m=audio &quot;, tech_pvt-&gt;remote_sdp_str))) {
+                port_ptr = p + 8;
+        }
+
+        if ((p = (char *) switch_stristr(&quot;m=image &quot;, tech_pvt-&gt;remote_sdp_str))) {
+                port_ptr = p + 8;
+        }
+
+        if ((p = (char *) switch_stristr(&quot;m=video &quot;, tech_pvt-&gt;remote_sdp_str))) {
+                vid_port_ptr = p + 8;
+        }
+
+        if (!(ip_ptr &amp;&amp; port_ptr)) {
+                return SWITCH_STATUS_FALSE;
+        }
+
+        p = ip_ptr;
+        pe = p + strlen(p);
+        x = 0;
+        while (x &lt; sizeof(rip) - 1 &amp;&amp; p &amp;&amp; *p &amp;&amp; ((*p &gt;= '0' &amp;&amp; *p &lt;= '9') || *p == '.' || *p == ':' || (*p &gt;= 'a' &amp;&amp; *p &lt;= 'f') || (*p &gt;= 'A' &amp;&amp; *p &lt;= 'F'))) {
+                rip[x++] = *p;
+                p++;
+                if (p &gt;= pe) {
+                        return SWITCH_STATUS_FALSE;
+                }
+        }
+
+        p = port_ptr;
+        x = 0;
+        while (x &lt; sizeof(rp) - 1 &amp;&amp; p &amp;&amp; *p &amp;&amp; (*p &gt;= '0' &amp;&amp; *p &lt;= '9')) {
+                rp[x++] = *p;
+                p++;
+                if (p &gt;= pe) {
+                        return SWITCH_STATUS_FALSE;
+                }
+        }
+
+        p = vid_port_ptr;
+        x = 0;
+        while (x &lt; sizeof(rvp) - 1 &amp;&amp; p &amp;&amp; *p &amp;&amp; (*p &gt;= '0' &amp;&amp; *p &lt;= '9')) {
+                rvp[x++] = *p;
+                p++;
+                if (p &gt;= pe) {
+                        return SWITCH_STATUS_FALSE;
+                }
+        }
+
+        if (!(*rip &amp;&amp; *rp)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;invalid SDP\n&quot;);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        tech_pvt-&gt;remote_sdp_audio_ip = switch_core_session_strdup(tech_pvt-&gt;session, rip);
+        tech_pvt-&gt;remote_sdp_audio_port = (switch_port_t) atoi(rp);
+        
+        if (*rvp) {
+                tech_pvt-&gt;remote_sdp_video_ip = switch_core_session_strdup(tech_pvt-&gt;session, rip);
+                tech_pvt-&gt;remote_sdp_video_port = (switch_port_t) atoi(rvp);
+        }
+
+        if (tech_pvt-&gt;remote_sdp_video_ip &amp;&amp; tech_pvt-&gt;remote_sdp_video_port) {
+                if (!strcmp(tech_pvt-&gt;remote_sdp_video_ip, rip) &amp;&amp; atoi(rvp) == tech_pvt-&gt;remote_sdp_video_port) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Remote video address:port [%s:%d] has not changed.\n&quot;,
+                                                          tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port);
+                } else {
+                        sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO);
+                        switch_channel_set_flag(tech_pvt-&gt;channel, CF_VIDEO);
+                        if (switch_rtp_ready(tech_pvt-&gt;video_rtp_session)) {
+                                if (switch_rtp_set_remote_address(tech_pvt-&gt;video_rtp_session, tech_pvt-&gt;remote_sdp_video_ip, 
+                                                                                                  tech_pvt-&gt;remote_sdp_video_port, SWITCH_TRUE, &amp;err) !=
+                                        SWITCH_STATUS_SUCCESS) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;VIDEO RTP REPORTS ERROR: [%s]\n&quot;, err);
+                                } else {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;VIDEO RTP CHANGING DEST TO: [%s:%d]\n&quot;,
+                                                                          tech_pvt-&gt;remote_sdp_video_ip, tech_pvt-&gt;remote_sdp_video_port);
+                                        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_DISABLE_RTP_AUTOADJ) &amp;&amp; !switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MODE) &amp;&amp;
+                                                !((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;disable_rtp_auto_adjust&quot;)) &amp;&amp; switch_true(val))) {
+                                                /* Reactivate the NAT buster flag. */
+                                                switch_rtp_set_flag(tech_pvt-&gt;video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+                                        }
+                                }
+                        }
+                }
+        }
+
+        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                char *remote_host = switch_rtp_get_remote_host(tech_pvt-&gt;rtp_session);
+                switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt-&gt;rtp_session);
+                
+                if (remote_host &amp;&amp; remote_port &amp;&amp; !strcmp(remote_host, tech_pvt-&gt;remote_sdp_audio_ip) &amp;&amp; remote_port == tech_pvt-&gt;remote_sdp_audio_port) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Remote address:port [%s:%d] has not changed.\n&quot;,
+                                                          tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port);
+                        return SWITCH_STATUS_SUCCESS;
+                }
+                
+                if (switch_rtp_set_remote_address(tech_pvt-&gt;rtp_session, tech_pvt-&gt;remote_sdp_audio_ip, 
+                                                                                  tech_pvt-&gt;remote_sdp_audio_port, SWITCH_TRUE, &amp;err) != SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;AUDIO RTP REPORTS ERROR: [%s]\n&quot;, err);
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;AUDIO RTP CHANGING DEST TO: [%s:%d]\n&quot;,
+                                                          tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port);
+                        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_DISABLE_RTP_AUTOADJ) &amp;&amp;
+                                !((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;disable_rtp_auto_adjust&quot;)) &amp;&amp; switch_true(val))) {
+                                /* Reactivate the NAT buster flag. */
+                                switch_rtp_set_flag(tech_pvt-&gt;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] = &quot;&quot;;
+        char vport_buf[25] = &quot;&quot;;
+        char *new_sdp;
+        int bad = 0;
+
+        if (switch_strlen_zero(tech_pvt-&gt;local_sdp_str)) {
+                return;
+        }
+
+        len = strlen(tech_pvt-&gt;local_sdp_str) * 2;
+        
+        if (switch_stristr(&quot;sendonly&quot;, tech_pvt-&gt;local_sdp_str) || switch_stristr(&quot;0.0.0.0&quot;, tech_pvt-&gt;local_sdp_str)) {
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Skip patch on hold SDP\n&quot;);
+            return;
+        }
+        
+        if (switch_strlen_zero(tech_pvt-&gt;adv_sdp_audio_ip) || !tech_pvt-&gt;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, &quot;%s I/O Error\n&quot;, switch_channel_get_name(tech_pvt-&gt;channel));
+                        return;
+                }
+                tech_pvt-&gt;iananame = switch_core_session_strdup(tech_pvt-&gt;session, &quot;PROXY&quot;);
+                tech_pvt-&gt;rm_rate = 8000;
+                tech_pvt-&gt;codec_ms = 20;
+        }
+        
+        new_sdp = switch_core_session_alloc(tech_pvt-&gt;session, len);
+        switch_snprintf(port_buf, sizeof(port_buf), &quot;%u&quot;, tech_pvt-&gt;adv_sdp_audio_port);
+        
+
+        p = tech_pvt-&gt;local_sdp_str;
+        q = new_sdp;
+        pe = p + strlen(p);
+        qe = q + len - 1;
+
+        while(p &amp;&amp; *p) {
+                if (p &gt;= pe) {
+                        bad = 1;
+                        goto end;
+                }
+                
+                if (q &gt;= qe) {
+                        bad = 2;
+                        goto end;
+                }
+
+            if (tech_pvt-&gt;adv_sdp_audio_ip &amp;&amp; !strncmp(&quot;c=IN IP&quot;, p, 7)) {
+                        strncpy(q, p, 9);
+                        p += 9;
+                        q += 9;
+                        strncpy(q, tech_pvt-&gt;adv_sdp_audio_ip, strlen(tech_pvt-&gt;adv_sdp_audio_ip));
+                        q += strlen(tech_pvt-&gt;adv_sdp_audio_ip);
+
+                        while(p &amp;&amp; *p &amp;&amp; ((*p &gt;= '0' &amp;&amp; *p &lt;= '9') || *p == '.' || *p == ':' || (*p &gt;= 'A' &amp;&amp; *p &lt;= 'F') || (*p &gt;= 'a' &amp;&amp; *p &lt;= 'f'))) {
+                                if (p &gt;= pe) {
+                                        bad = 3;
+                                        goto end;
+                                }
+                                p++;
+                        }
+
+                    has_ip++;
+
+                } else if (!strncmp(&quot;m=audio &quot;, p, 8) || (!strncmp(&quot;m=image &quot;, p, 8))) {
+                        strncpy(q, p, 8);
+                        p += 8;
+
+                        if (p &gt;= pe) {
+                                bad = 4;
+                                goto end;
+                        }
+
+
+                        q += 8;
+                        
+                        if (q &gt;= qe) {
+                                bad = 5;
+                                goto end;
+                        }
+
+
+                        strncpy(q, port_buf, strlen(port_buf));
+                        q += strlen(port_buf);
+
+                        if (q &gt;= qe) {
+                                bad = 6;
+                                goto end;
+                        }
+
+                        while (p &amp;&amp; *p &amp;&amp; (*p &gt;= '0' &amp;&amp; *p &lt;= '9')) {
+                                if (p &gt;= pe) {
+                                        bad = 7;
+                                        goto end;
+                                }
+                                p++;
+                        }
+
+                        has_audio++;                
+
+            } else if (!strncmp(&quot;m=video &quot;, p, 8)) {
+                        if (!has_video) {
+                                sofia_glue_tech_choose_video_port(tech_pvt, 1);
+                                tech_pvt-&gt;video_rm_encoding = &quot;PROXY-VID&quot;;
+                                tech_pvt-&gt;video_rm_rate = 90000;
+                                tech_pvt-&gt;video_codec_ms = 0;
+                                switch_snprintf(vport_buf, sizeof(vport_buf), &quot;%u&quot;, tech_pvt-&gt;adv_sdp_video_port);
+                        }
+
+                        strncpy(q, p, 8);
+                        p += 8;
+
+                        if (p &gt;= pe) {
+                                bad = 8;
+                                goto end;
+                        }
+
+                        q += 8;
+
+                        if (q &gt;= qe) {
+                                bad = 9;
+                                goto end;
+                        }
+
+                        strncpy(q, vport_buf, strlen(vport_buf));
+                        q += strlen(vport_buf);
+
+                        if (q &gt;= qe) {
+                                bad = 10;
+                                goto end;
+                        }
+
+                        while (p &amp;&amp; *p &amp;&amp; (*p &gt;= '0' &amp;&amp; *p &lt;= '9')) {
+
+                                if (p &gt;= pe) {
+                                        bad = 11;
+                                        goto end;
+                                }
+
+                                p++;
+                        }
+                        
+                        has_video++;
+            }
+            
+            while (p &amp;&amp; *p &amp;&amp; *p != '\n') {
+
+                        if (p &gt;= pe) {
+                                bad = 12;
+                                goto end;
+                        }
+
+                        if (q &gt;= qe) {
+                                bad = 13;
+                                goto end;
+                        }
+
+                        *q++ = *p++;
+            }
+                
+                if (p &gt;= pe) {
+            bad = 14;
+            goto end;
+        }
+                
+                if (q &gt;= qe) {
+                        bad = 15;
+                        goto end;
+                }
+
+            *q++ = *p++;
+
+        }
+
+ end:
+
+        if (bad) {
+                return;
+        }
+
+
+        if (switch_channel_down(tech_pvt-&gt;channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s too late.\n&quot;, switch_channel_get_name(tech_pvt-&gt;channel));
+                return;
+        }
+
+
+        if (!has_ip &amp;&amp; !has_audio) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s SDP has no audio in it.\n%s\n&quot;,
+                                                  switch_channel_get_name(tech_pvt-&gt;channel), tech_pvt-&gt;local_sdp_str);
+                return;
+        }
+        
+
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s Patched SDP\n---\n%s\n+++\n%s\n&quot;,
+                                          switch_channel_get_name(tech_pvt-&gt;channel), tech_pvt-&gt;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-&gt;sofia_mutex);
+        tech_pvt-&gt;local_sdp_str = dup ? switch_core_session_strdup(tech_pvt-&gt;session, sdp_str) : (char *)sdp_str;
+        switch_mutex_unlock(tech_pvt-&gt;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 = &quot;&quot;;
+        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-&gt;profile-&gt;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-&gt;caller_id_name;
+        cid_num = caller_profile-&gt;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-&gt;from_str) {
+                const char* sipip;
+                const char* format;
+                const char *alt = NULL;
+
+                if (sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) {
+                        sipip = tech_pvt-&gt;profile-&gt;extsipip;
+                } else {
+                        sipip = tech_pvt-&gt;profile-&gt;extsipip ? tech_pvt-&gt;profile-&gt;extsipip : tech_pvt-&gt;profile-&gt;sipip;
+                }
+
+                format = strchr(sipip, ':') ? &quot;\&quot;%s\&quot; &lt;sip:%s%s[%s]&gt;&quot; : &quot;\&quot;%s\&quot; &lt;sip:%s%s%s&gt;&quot;;
+
+                if ((alt = switch_channel_get_variable(channel, &quot;sip_invite_domain&quot;))) {
+                        sipip = alt;
+                }
+                        
+                tech_pvt-&gt;from_str = 
+                        switch_core_session_sprintf(tech_pvt-&gt;session,
+                                                                                format,
+                                                                                cid_name,
+                                                                                cid_num,
+                                                                                !switch_strlen_zero(cid_num) ? &quot;@&quot; : &quot;&quot;,
+                                                                                sipip);
+        }
+
+        if ((alertbuf = switch_channel_get_variable(channel, &quot;alert_info&quot;))) {
+                alert_info = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;Alert-Info: %s&quot;, 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-&gt;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 = &quot;cluecon.com&quot;, *p;
+                const char *priv = &quot;off&quot;;
+                const char *screen = &quot;no&quot;;
+                const char *invite_params = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_invite_params&quot;);
+                const char *invite_to_params = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_invite_to_params&quot;);
+                const char *invite_to_uri = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_invite_to_uri&quot;);
+                const char *invite_contact_params = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_invite_contact_params&quot;);
+                const char *invite_from_params = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_invite_from_params&quot;);
+                const char *from_var = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_from_uri&quot;);
+                const char *from_display = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;sip_from_display&quot;);
+                
+                if (switch_strlen_zero(tech_pvt-&gt;dest)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;URL Error!\n&quot;);
+                        return SWITCH_STATUS_FALSE;
+                }
+
+                if ((d_url = sofia_glue_get_url_from_contact(tech_pvt-&gt;dest, 1))) {
+                        url = d_url;
+                } else {
+                        url = tech_pvt-&gt;dest;
+                }
+
+                url_str = url;
+
+                if (from_var) {
+                        if (strncasecmp(from_var, &quot;sip:&quot;, 4) || strncasecmp(from_var, &quot;sips:&quot;, 5)) {
+                                use_from_str = switch_core_session_strdup(tech_pvt-&gt;session, from_var);
+                        } else {
+                                use_from_str = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;sip:%s&quot;, from_var);
+                        }
+                } else if (!switch_strlen_zero(tech_pvt-&gt;gateway_from_str)) {
+                        use_from_str = tech_pvt-&gt;gateway_from_str;
+                } else {
+                        use_from_str = tech_pvt-&gt;from_str;
+                }
+
+                if (!switch_strlen_zero(tech_pvt-&gt;gateway_from_str)) {
+                        rpid_domain = switch_core_session_strdup(session, tech_pvt-&gt;gateway_from_str);
+                } else if (!switch_strlen_zero(tech_pvt-&gt;from_str)) {
+                        rpid_domain = switch_core_session_strdup(session, tech_pvt-&gt;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 = &quot;cluecon.com&quot;;
+                }
+
+                /*
+                 * 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-&gt;transport == SOFIA_TRANSPORT_UNKNOWN &amp;&amp; switch_strlen_zero(tech_pvt-&gt;gateway_name)) {
+                        if ((p = (char *) switch_stristr(&quot;port=&quot;, url))) {
+                                p += 5;
+                                tech_pvt-&gt;transport = sofia_glue_str2transport(p);
+                        } else {
+                                if ((t_var = switch_channel_get_variable(channel, &quot;sip_transport&quot;))) {
+                                        tech_pvt-&gt;transport = sofia_glue_str2transport(t_var);
+                                }
+                        }
+
+                        if (tech_pvt-&gt;transport == SOFIA_TRANSPORT_UNKNOWN) {
+                                tech_pvt-&gt;transport = SOFIA_TRANSPORT_UDP;
+                        }
+                }
+
+                if (sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) {
+                        tech_pvt-&gt;user_via = sofia_glue_create_external_via(session, tech_pvt-&gt;profile, tech_pvt-&gt;transport);
+                }
+
+                if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_TLS) &amp;&amp; sofia_glue_transport_has_tls(tech_pvt-&gt;transport)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;TLS not supported by profile\n&quot;);
+                        return SWITCH_STATUS_FALSE;
+                }
+
+                if (switch_strlen_zero(tech_pvt-&gt;invite_contact)) {
+                        const char * contact;
+                        if ((contact = switch_channel_get_variable(channel, &quot;sip_contact_user&quot;))) {
+                                char *ip_addr;
+                                char *ipv6;
+                                
+                                if (sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) { 
+                                        ip_addr = (switch_check_network_list_ip(tech_pvt-&gt;remote_ip, tech_pvt-&gt;profile-&gt;local_network)) 
+                                                ? tech_pvt-&gt;profile-&gt;sipip : tech_pvt-&gt;profile-&gt;extsipip;
+                                } else {
+                                        ip_addr = tech_pvt-&gt;profile-&gt;extsipip ? tech_pvt-&gt;profile-&gt;extsipip : tech_pvt-&gt;profile-&gt;sipip;
+                                }
+                                
+                                ipv6 = strchr(ip_addr, ':');
+
+                                if (sofia_glue_transport_has_tls(tech_pvt-&gt;transport)) {
+                                        tech_pvt-&gt;invite_contact = switch_core_session_sprintf(session, &quot;sip:%s@%s%s%s:%d&quot;, contact, 
+                                                                                                                                                   ipv6 ? &quot;[&quot; : &quot;&quot;, ip_addr, ipv6 ? &quot;]&quot; : &quot;&quot;, 
+                                                                                                                                                   tech_pvt-&gt;profile-&gt;tls_sip_port);
+                                } else {
+                                        tech_pvt-&gt;invite_contact = switch_core_session_sprintf(session, &quot;sip:%s@%s%s%s:%d&quot;, contact, 
+                                                                                                                                                   ipv6 ? &quot;[&quot; : &quot;&quot;, ip_addr, ipv6 ? &quot;]&quot; : &quot;&quot;, tech_pvt-&gt;profile-&gt;sip_port);
+                                }
+                        } else {
+                                if (sofia_glue_transport_has_tls(tech_pvt-&gt;transport)) {
+                                        tech_pvt-&gt;invite_contact = tech_pvt-&gt;profile-&gt;tls_url;
+                                } else {
+                                        if (sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) { 
+                                                tech_pvt-&gt;invite_contact = tech_pvt-&gt;profile-&gt;public_url;
+                                        } else {
+                                                tech_pvt-&gt;invite_contact = tech_pvt-&gt;profile-&gt;url;
+                                        }
+                                }
+                        }
+                }
+
+                url_str = sofia_overcome_sip_uri_weakness(session, url, tech_pvt-&gt;transport, SWITCH_TRUE, invite_params);
+                invite_contact = sofia_overcome_sip_uri_weakness(session, tech_pvt-&gt;invite_contact, tech_pvt-&gt;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-&gt;dest_to, 0, SWITCH_FALSE, invite_to_params ? invite_to_params : invite_params);
+
+
+                /*
+                   Does the &quot;genius&quot; who wanted SIP to be &quot;text-based&quot; so it was &quot;easier to read&quot; even use it now,
+                   or did he just suggest it to make our lives miserable?
+                 */
+                use_from_str = from_str;
+                if (!from_display &amp;&amp; !strcasecmp(tech_pvt-&gt;caller_profile-&gt;caller_id_name, &quot;_undef_&quot;)) {
+                        from_str = switch_core_session_sprintf(session, &quot;&lt;%s&gt;&quot;, use_from_str);
+                } else {
+                        from_str = switch_core_session_sprintf(session, &quot;\&quot;%s\&quot; &lt;%s&gt;&quot;, from_display ? from_display : 
+                                                                                                   tech_pvt-&gt;caller_profile-&gt;caller_id_name, use_from_str);
+                }
+                
+                if (!(call_id = switch_channel_get_variable(channel, &quot;sip_outgoing_call_id&quot;))) {
+                        if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_UUID_AS_CALLID)) {
+                                call_id = switch_core_session_get_uuid(session);
+                        }
+                }
+                
+                tech_pvt-&gt;nh = nua_handle(tech_pvt-&gt;profile-&gt;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-&gt;dest &amp;&amp; (strstr(tech_pvt-&gt;dest, &quot;;fs_nat&quot;) || strstr(tech_pvt-&gt;dest, &quot;;received&quot;) 
+                                                           || ((val = switch_channel_get_variable(channel, &quot;sip_sticky_contact&quot;)) &amp;&amp; switch_true(val)))) {
+                        sofia_set_flag(tech_pvt, TFLAG_NAT);
+                        tech_pvt-&gt;record_route = switch_core_session_strdup(tech_pvt-&gt;session, url_str);
+                        route_uri = tech_pvt-&gt;record_route;
+                        session_timeout = SOFIA_NAT_SESSION_TIMEOUT;
+                        switch_channel_set_variable(channel, &quot;sip_nat_detected&quot;, &quot;true&quot;);
+                }
+                
+                if ((val = switch_channel_get_variable(channel, &quot;sip_cid_type&quot;))) {
+                        cid_type = sofia_cid_name2type(val);
+                }
+                switch (cid_type) {
+                case CID_TYPE_PID:
+                        if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
+                                tech_pvt-&gt;asserted_id = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;\&quot;%s\&quot;&lt;sip:%s@%s&gt;&quot;,
+                                                                                                                                        tech_pvt-&gt;caller_profile-&gt;caller_id_name,
+                                                                                                                                        tech_pvt-&gt;caller_profile-&gt;caller_id_number, 
+                                                                                                                                        rpid_domain);
+                        } else {
+                                tech_pvt-&gt;preferred_id = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;\&quot;%s\&quot;&lt;sip:%s@%s&gt;&quot;,
+                                                                                                                                         tech_pvt-&gt;caller_profile-&gt;caller_id_name,
+                                                                                                                                         tech_pvt-&gt;caller_profile-&gt;caller_id_number, 
+                                                                                                                                         rpid_domain);
+                        }
+                        
+                        if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+                                tech_pvt-&gt;privacy = &quot;id&quot;;
+                        } else {
+                                tech_pvt-&gt;privacy = &quot;none&quot;;
+                        }
+
+                        break;
+                case CID_TYPE_RPID:
+                        {
+                                if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) {
+                                        priv = &quot;name&quot;;
+                                        if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+                                                priv = &quot;full&quot;;
+                                        }
+                                } else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+                                        priv = &quot;full&quot;;
+                                }
+                                
+                                if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
+                                        screen = &quot;yes&quot;;
+                                }
+                                
+                                tech_pvt-&gt;rpid = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;\&quot;%s\&quot;&lt;sip:%s@%s&gt;;party=calling;screen=%s;privacy=%s&quot;,
+                                                                                                                         tech_pvt-&gt;caller_profile-&gt;caller_id_name,
+                                                                                                                         tech_pvt-&gt;caller_profile-&gt;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-&gt;is_call++;
+
+                tech_pvt-&gt;sofia_private = sofia_private;
+                switch_copy_string(tech_pvt-&gt;sofia_private-&gt;uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt-&gt;sofia_private-&gt;uuid));
+                nua_handle_bind(tech_pvt-&gt;nh, tech_pvt-&gt;sofia_private);
+        }
+
+        if (tech_pvt-&gt;e_dest) {
+                char *user = NULL, *host = NULL;
+                char hash_key[256] = &quot;&quot;;
+
+                e_dest = strdup(tech_pvt-&gt;e_dest);
+                switch_assert(e_dest != NULL);
+                user = e_dest;
+
+                if ((host = strchr(user, '@'))) {
+                        *host++ = '\0';
+                }
+                switch_snprintf(hash_key, sizeof(hash_key), &quot;%s%s%s&quot;, user, host, cid_num);
+
+                tech_pvt-&gt;chat_from = tech_pvt-&gt;from_str;
+                tech_pvt-&gt;chat_to = tech_pvt-&gt;dest;
+                if (tech_pvt-&gt;profile-&gt;pres_type) {
+                        tech_pvt-&gt;hash_key = switch_core_session_strdup(tech_pvt-&gt;session, hash_key);
+                        switch_mutex_lock(tech_pvt-&gt;profile-&gt;flag_mutex);
+                        switch_core_hash_insert(tech_pvt-&gt;profile-&gt;chat_hash, tech_pvt-&gt;hash_key, tech_pvt);
+                        switch_mutex_unlock(tech_pvt-&gt;profile-&gt;flag_mutex);
+                }
+                free(e_dest);
+        }
+
+        holdstr = sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? &quot;*&quot; : &quot;&quot;;
+
+        if (!switch_channel_get_variable(channel, &quot;sofia_profile_name&quot;)) {
+                switch_channel_set_variable(channel, &quot;sofia_profile_name&quot;, tech_pvt-&gt;profile-&gt;name);
+        }
+
+        SWITCH_STANDARD_STREAM(stream);
+        if ((hi = switch_channel_variable_first(channel))) {
+                for (; hi; hi = hi-&gt;next) {
+                        const char *name = (char *) hi-&gt;name;
+                        char *value = (char *) hi-&gt;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(&amp;stream, &quot;%s: %s\r\n&quot;, hname, value);
+                        }
+                }
+                switch_channel_variable_last(channel);
+        }
+
+        if (stream.data) {
+                extra_headers = stream.data;
+        }
+
+        session_timeout = tech_pvt-&gt;profile-&gt;session_timeout;
+        if ((val = switch_channel_get_variable(channel, SOFIA_SESSION_TIMEOUT))) {
+                int v_session_timeout = atoi(val);
+                if (v_session_timeout &gt;= 0) {
+                        session_timeout = v_session_timeout;
+                }
+        }
+
+        if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+                if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                        sofia_glue_tech_proxy_remote_addr(tech_pvt);
+                }
+                sofia_glue_tech_patch_sdp(tech_pvt);
+        }
+
+        if (!switch_strlen_zero(tech_pvt-&gt;dest)) {
+                dst = sofia_glue_get_destination(tech_pvt-&gt;dest);
+
+                if (dst-&gt;route_uri) {
+                        route_uri = sofia_overcome_sip_uri_weakness(tech_pvt-&gt;session, dst-&gt;route_uri, tech_pvt-&gt;transport, SWITCH_TRUE, NULL);
+                }
+        
+                if (dst-&gt;route) {
+                        route = dst-&gt;route;
+                }
+        }
+
+        if ((val = switch_channel_get_variable(channel, &quot;sip_route_uri&quot;))) {
+                route_uri = switch_core_session_strdup(session, val);
+                route = NULL;
+        }
+        
+        if (route_uri) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%s Setting proxy route to %s\n&quot;, route_uri, switch_channel_get_name(channel));
+                tech_pvt-&gt;route_uri = switch_core_session_strdup(tech_pvt-&gt;session, route_uri);
+        }
+
+        nua_invite(tech_pvt-&gt;nh,
+                           NUTAG_AUTOANSWER(0),
+                           NUTAG_SESSION_TIMER(session_timeout),
+                           TAG_IF(tech_pvt-&gt;redirected, NUTAG_URL(tech_pvt-&gt;redirected)),
+                           TAG_IF(!switch_strlen_zero(tech_pvt-&gt;user_via), SIPTAG_VIA_STR(tech_pvt-&gt;user_via)),
+                           TAG_IF(!switch_strlen_zero(tech_pvt-&gt;rpid), SIPTAG_REMOTE_PARTY_ID_STR(tech_pvt-&gt;rpid)),
+                           TAG_IF(!switch_strlen_zero(tech_pvt-&gt;preferred_id), SIPTAG_P_PREFERRED_IDENTITY_STR(tech_pvt-&gt;preferred_id)),
+                           TAG_IF(!switch_strlen_zero(tech_pvt-&gt;asserted_id), SIPTAG_P_ASSERTED_IDENTITY_STR(tech_pvt-&gt;asserted_id)),
+                           TAG_IF(!switch_strlen_zero(tech_pvt-&gt;privacy), SIPTAG_PRIVACY_STR(tech_pvt-&gt;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-&gt;adv_sdp_audio_ip),
+                           SOATAG_USER_SDP_STR(tech_pvt-&gt;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-&gt;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-&gt;sofia_mutex);
+        caller_profile = switch_channel_get_caller_profile(channel);
+
+        if (sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) { 
+                sipip = tech_pvt-&gt;profile-&gt;extsipip;
+                contact_url = tech_pvt-&gt;profile-&gt;public_url;
+        } else {
+                sipip = tech_pvt-&gt;profile-&gt;extsipip ? tech_pvt-&gt;profile-&gt;extsipip : tech_pvt-&gt;profile-&gt;sipip;
+                contact_url = tech_pvt-&gt;profile-&gt;url;
+        }
+
+        format = strchr(sipip, ':') ? &quot;\&quot;%s\&quot; &lt;sip:%s@[%s]&gt;&quot; : &quot;\&quot;%s\&quot; &lt;sip:%s@%s&gt;&quot;;
+
+        if ((tech_pvt-&gt;from_str = switch_core_session_sprintf(session, format,
+                                                                                                                        caller_profile-&gt;caller_id_name,
+                                                                                                                        caller_profile-&gt;caller_id_number, sipip))) {
+
+                const char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
+
+                tech_pvt-&gt;nh2 = nua_handle(tech_pvt-&gt;profile-&gt;nua, NULL,
+                                                                   SIPTAG_TO_STR(tech_pvt-&gt;dest),
+                                                                   SIPTAG_FROM_STR(tech_pvt-&gt;from_str),
+                                                                   SIPTAG_CONTACT_STR(contact_url),
+                                                                   TAG_END());
+
+                nua_handle_bind(tech_pvt-&gt;nh2, tech_pvt-&gt;sofia_private);
+
+                nua_invite(tech_pvt-&gt;nh2,
+                                   SIPTAG_CONTACT_STR(contact_url),
+                                   TAG_IF(!switch_strlen_zero(tech_pvt-&gt;user_via), SIPTAG_VIA_STR(tech_pvt-&gt;user_via)),
+                                   SOATAG_ADDRESS(tech_pvt-&gt;adv_sdp_audio_ip),
+                                   SOATAG_USER_SDP_STR(tech_pvt-&gt;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, &quot;Memory Error!\n&quot;);
+        }
+        switch_mutex_unlock(tech_pvt-&gt;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-&gt;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-&gt;sdp_media; m; m = m-&gt;m_next) {
+                                        if (m-&gt;m_type != sdp_media_audio || !m-&gt;m_port) {
+                                                continue;
+                                        }
+
+                                        connection = sdp-&gt;sdp_connection;
+                                        if (m-&gt;m_connections) {
+                                                connection = m-&gt;m_connections;
+                                        }
+
+                                        if (connection) {
+                                                tech_pvt-&gt;proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt-&gt;session, connection-&gt;c_address);
+                                        }
+                                        tech_pvt-&gt;proxy_sdp_audio_port = (switch_port_t) m-&gt;m_port;
+                                        if (tech_pvt-&gt;proxy_sdp_audio_ip &amp;&amp; tech_pvt-&gt;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), &quot;rtp_%s_%s&quot;, switch_str_nil(prefix), _s) ; \
+        switch_snprintf(var_val, sizeof(var_val), &quot;%&quot; SWITCH_SIZE_T_FMT, _i); \
+        switch_channel_set_variable(tech_pvt-&gt;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] = &quot;&quot;, var_val[35] = &quot;&quot;;
+
+        if (stats) {
+
+                add_stat(stats-&gt;inbound.raw_bytes, &quot;in_raw_bytes&quot;);
+                add_stat(stats-&gt;inbound.media_bytes, &quot;in_media_bytes&quot;);
+                add_stat(stats-&gt;inbound.packet_count, &quot;in_packet_count&quot;);
+                add_stat(stats-&gt;inbound.media_packet_count, &quot;in_media_packet_count&quot;);
+                add_stat(stats-&gt;inbound.skip_packet_count, &quot;in_skip_packet_count&quot;);
+                add_stat(stats-&gt;inbound.jb_packet_count, &quot;in_jb_packet_count&quot;);
+                add_stat(stats-&gt;inbound.dtmf_packet_count, &quot;in_dtmf_packet_count&quot;);
+                add_stat(stats-&gt;inbound.cng_packet_count, &quot;in_cng_packet_count&quot;);
+                add_stat(stats-&gt;inbound.cng_packet_count, &quot;in_flush_packet_count&quot;);
+
+                add_stat(stats-&gt;outbound.raw_bytes, &quot;out_raw_bytes&quot;);
+                add_stat(stats-&gt;outbound.media_bytes, &quot;out_media_bytes&quot;);
+                add_stat(stats-&gt;outbound.packet_count, &quot;out_packet_count&quot;);
+                add_stat(stats-&gt;outbound.media_packet_count, &quot;out_media_packet_count&quot;);
+                add_stat(stats-&gt;outbound.skip_packet_count, &quot;out_skip_packet_count&quot;);
+                add_stat(stats-&gt;outbound.dtmf_packet_count, &quot;out_dtmf_packet_count&quot;);
+                add_stat(stats-&gt;outbound.cng_packet_count, &quot;out_cng_packet_count&quot;);
+                
+        }
+}
+
+void sofia_glue_set_rtp_stats(private_object_t *tech_pvt)
+{
+        if (tech_pvt-&gt;rtp_session) {
+        set_stats(tech_pvt-&gt;rtp_session, tech_pvt, &quot;audio&quot;);
+        }
+
+        if (tech_pvt-&gt;video_rtp_session) {
+        set_stats(tech_pvt-&gt;video_rtp_session, tech_pvt, &quot;video&quot;);
+        }
+}
+
+void sofia_glue_deactivate_rtp(private_object_t *tech_pvt)
+{
+        int loops = 0;
+        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                while (loops &lt; 10 &amp;&amp; (sofia_test_flag(tech_pvt, TFLAG_READING) || sofia_test_flag(tech_pvt, TFLAG_WRITING))) {
+                        switch_yield(10000);
+                        loops++;
+                }
+        }
+
+        if (tech_pvt-&gt;rtp_session) {
+                switch_rtp_destroy(&amp;tech_pvt-&gt;rtp_session);
+        } else if (tech_pvt-&gt;local_sdp_audio_port) {
+                switch_rtp_release_port(tech_pvt-&gt;profile-&gt;rtpip, tech_pvt-&gt;local_sdp_audio_port);
+        }
+
+        if (tech_pvt-&gt;local_sdp_audio_port &gt; 0 &amp;&amp; sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) { 
+                switch_nat_del_mapping((switch_port_t)tech_pvt-&gt;local_sdp_audio_port, SWITCH_NAT_UDP);
+        }
+        
+        if (tech_pvt-&gt;video_rtp_session) {
+                switch_rtp_destroy(&amp;tech_pvt-&gt;video_rtp_session);
+        } else if (tech_pvt-&gt;local_sdp_video_port) {
+                switch_rtp_release_port(tech_pvt-&gt;profile-&gt;rtpip, tech_pvt-&gt;local_sdp_video_port);
+        }
+
+                
+        if (tech_pvt-&gt;local_sdp_video_port &gt; 0 &amp;&amp; sofia_glue_check_nat(tech_pvt-&gt;profile, tech_pvt-&gt;remote_ip)) { 
+                switch_nat_del_mapping((switch_port_t)tech_pvt-&gt;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-&gt;video_read_codec.implementation &amp;&amp; switch_core_codec_ready(&amp;tech_pvt-&gt;video_read_codec)) {
+                if (!force) {
+                        return SWITCH_STATUS_SUCCESS;
+                }
+                if (strcasecmp(tech_pvt-&gt;video_read_codec.implementation-&gt;iananame, tech_pvt-&gt;video_rm_encoding) ||
+                        tech_pvt-&gt;video_read_codec.implementation-&gt;samples_per_second != tech_pvt-&gt;video_rm_rate) {
+
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Changing Codec from %s to %s\n&quot;,
+                                                          tech_pvt-&gt;video_read_codec.implementation-&gt;iananame, tech_pvt-&gt;video_rm_encoding);
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;video_read_codec);
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;video_write_codec);
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Already using %s\n&quot;, tech_pvt-&gt;video_read_codec.implementation-&gt;iananame);
+                        return SWITCH_STATUS_SUCCESS;
+                }
+        }
+
+        if (!tech_pvt-&gt;video_rm_encoding) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec with no name?\n&quot;);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        if (switch_core_codec_init(&amp;tech_pvt-&gt;video_read_codec,
+                                                           tech_pvt-&gt;video_rm_encoding,
+                                                           tech_pvt-&gt;video_rm_fmtp,
+                                                           tech_pvt-&gt;video_rm_rate,
+                                                           0,
+                                                           1,
+                                                           SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+                                                           NULL, switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec?\n&quot;);
+                return SWITCH_STATUS_FALSE;
+        } else {
+                if (switch_core_codec_init(&amp;tech_pvt-&gt;video_write_codec,
+                                                                   tech_pvt-&gt;video_rm_encoding,
+                                                                   tech_pvt-&gt;video_rm_fmtp,
+                                                                   tech_pvt-&gt;video_rm_rate,
+                                                                   0,
+                                                                   1,
+                                                                   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+                                                                   NULL, switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec?\n&quot;);
+                        return SWITCH_STATUS_FALSE;
+                } else {
+                        int ms;
+                        tech_pvt-&gt;video_read_frame.rate = tech_pvt-&gt;video_rm_rate;
+                        ms = tech_pvt-&gt;video_write_codec.implementation-&gt;microseconds_per_packet / 1000;
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set VIDEO Codec %s %s/%ld %d ms\n&quot;,
+                                                          switch_channel_get_name(tech_pvt-&gt;channel), tech_pvt-&gt;video_rm_encoding, tech_pvt-&gt;video_rm_rate, tech_pvt-&gt;video_codec_ms);
+                        tech_pvt-&gt;video_read_frame.codec = &amp;tech_pvt-&gt;video_read_codec;
+
+                        tech_pvt-&gt;video_fmtp_out = switch_core_session_strdup(tech_pvt-&gt;session, tech_pvt-&gt;video_write_codec.fmtp_out);
+
+                        tech_pvt-&gt;video_write_codec.agreed_pt = tech_pvt-&gt;video_agreed_pt;
+                        tech_pvt-&gt;video_read_codec.agreed_pt = tech_pvt-&gt;video_agreed_pt;
+                        switch_core_session_set_video_read_codec(tech_pvt-&gt;session, &amp;tech_pvt-&gt;video_read_codec);
+                        switch_core_session_set_video_write_codec(tech_pvt-&gt;session, &amp;tech_pvt-&gt;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-&gt;iananame) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;No audio codec available\n&quot;);
+                switch_goto_status(SWITCH_STATUS_FALSE, end);
+        }
+
+        if (tech_pvt-&gt;read_codec.implementation &amp;&amp; switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                if (!force) {
+                        switch_goto_status(SWITCH_STATUS_SUCCESS, end);
+                }
+                if (strcasecmp(tech_pvt-&gt;read_codec.implementation-&gt;iananame, tech_pvt-&gt;iananame) ||
+                        tech_pvt-&gt;read_codec.implementation-&gt;samples_per_second != tech_pvt-&gt;rm_rate) {
+
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Changing Codec from %s to %s\n&quot;,
+                                                          tech_pvt-&gt;read_codec.implementation-&gt;iananame, tech_pvt-&gt;rm_encoding);
+                        switch_core_session_lock_codec_write(tech_pvt-&gt;session);
+                        switch_core_session_lock_codec_read(tech_pvt-&gt;session);
+                        resetting = 1;
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;read_codec);
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;write_codec);
+                        switch_core_session_reset(tech_pvt-&gt;session, SWITCH_TRUE, SWITCH_TRUE);
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Already using %s\n&quot;, tech_pvt-&gt;read_codec.implementation-&gt;iananame);
+                        switch_goto_status(SWITCH_STATUS_SUCCESS, end);
+                }
+        }
+        
+        if (switch_core_codec_init(&amp;tech_pvt-&gt;read_codec,
+                                                           tech_pvt-&gt;iananame,
+                                                           tech_pvt-&gt;rm_fmtp,
+                                                           tech_pvt-&gt;rm_rate,
+                                                           tech_pvt-&gt;codec_ms,
+                                                           1,
+                                                           SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt-&gt;profile-&gt;codec_flags,
+                                                           NULL, switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec?\n&quot;);
+                switch_goto_status(SWITCH_STATUS_FALSE, end);
+        }
+
+        if (switch_core_codec_init(&amp;tech_pvt-&gt;write_codec,
+                                                           tech_pvt-&gt;iananame,
+                                                           tech_pvt-&gt;rm_fmtp,
+                                                           tech_pvt-&gt;rm_rate,
+                                                           tech_pvt-&gt;codec_ms,
+                                                           1,
+                                                           SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt-&gt;profile-&gt;codec_flags,
+                                                           NULL, switch_core_session_get_pool(tech_pvt-&gt;session)) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec?\n&quot;);
+                switch_goto_status(SWITCH_STATUS_FALSE, end);
+        }
+
+        switch_assert(tech_pvt-&gt;read_codec.implementation);
+        switch_assert(tech_pvt-&gt;write_codec.implementation);
+
+        tech_pvt-&gt;read_impl = *tech_pvt-&gt;read_codec.implementation;
+        tech_pvt-&gt;write_impl = *tech_pvt-&gt;write_codec.implementation;
+
+
+        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                switch_assert(tech_pvt-&gt;read_codec.implementation);
+                switch_rtp_set_default_samples_per_interval(tech_pvt-&gt;rtp_session, tech_pvt-&gt;read_impl.samples_per_packet);
+        }
+
+        tech_pvt-&gt;read_frame.rate = tech_pvt-&gt;rm_rate;
+        ms = tech_pvt-&gt;write_codec.implementation-&gt;microseconds_per_packet / 1000;
+
+        if (!switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can't load codec?\n&quot;);
+                switch_goto_status(SWITCH_STATUS_FALSE, end);
+        }
+
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set Codec %s %s/%ld %d ms %d samples\n&quot;,
+                                          switch_channel_get_name(tech_pvt-&gt;channel), tech_pvt-&gt;iananame, tech_pvt-&gt;rm_rate, tech_pvt-&gt;codec_ms,
+                                          tech_pvt-&gt;read_impl.samples_per_packet);
+        tech_pvt-&gt;read_frame.codec = &amp;tech_pvt-&gt;read_codec;
+
+        tech_pvt-&gt;write_codec.agreed_pt = tech_pvt-&gt;agreed_pt;
+        tech_pvt-&gt;read_codec.agreed_pt = tech_pvt-&gt;agreed_pt;
+
+        if (force != 2) {
+                switch_core_session_set_read_codec(tech_pvt-&gt;session, &amp;tech_pvt-&gt;read_codec);
+                switch_core_session_set_write_codec(tech_pvt-&gt;session, &amp;tech_pvt-&gt;write_codec);
+        }
+
+        tech_pvt-&gt;fmtp_out = switch_core_session_strdup(tech_pvt-&gt;session, tech_pvt-&gt;write_codec.fmtp_out);
+
+        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                switch_rtp_set_default_payload(tech_pvt-&gt;rtp_session, tech_pvt-&gt;pt);
+        }
+
+ end:
+        if (resetting) {
+                switch_core_session_unlock_codec_write(tech_pvt-&gt;session);
+                switch_core_session_unlock_codec_read(tech_pvt-&gt;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] = &quot;&quot;;
+        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-&gt;local_raw_key;
+        } else {
+                key = tech_pvt-&gt;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 &amp;&amp; *p &amp;&amp; *p == '=') {
+                *p-- = '\0';
+        }
+
+        tech_pvt-&gt;local_crypto_key = switch_core_session_sprintf(tech_pvt-&gt;session, &quot;%d %s inline:%s&quot;, index, type_str, b64_key);
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set Local Key [%s]\n&quot;, tech_pvt-&gt;local_crypto_key);
+
+        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_DISABLE_SRTP_AUTH) &amp;&amp;
+                !((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;NDLB_support_asterisk_missing_srtp_auth&quot;)) &amp;&amp; switch_true(val))) {
+                tech_pvt-&gt;crypto_type = type;
+        } else {
+                tech_pvt-&gt;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-&gt;rtp_session)) {
+                goto bad;
+        }
+
+        index = atoi(key_str);
+
+        p = strchr(key_str, ' ');
+
+        if (p &amp;&amp; *p &amp;&amp; *(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, &quot;Parse Error near [%s]\n&quot;, p);
+                        goto bad;
+                }
+
+                p = strchr(p, ' ');
+                if (p &amp;&amp; *p &amp;&amp; *(p + 1)) {
+                        p++;
+                        if (strncasecmp(p, &quot;inline:&quot;, 7)) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Parse Error near [%s]\n&quot;, p);
+                                goto bad;
+                        }
+
+                        p += 7;
+                        switch_b64_decode(p, (char *) key, sizeof(key));
+
+                        if (direction == SWITCH_RTP_CRYPTO_SEND) {
+                                tech_pvt-&gt;crypto_send_type = type;
+                                memcpy(tech_pvt-&gt;local_raw_key, key, SWITCH_RTP_KEY_LEN);
+                        } else {
+                                tech_pvt-&gt;crypto_recv_type = type;
+                                memcpy(tech_pvt-&gt;remote_raw_key, key, SWITCH_RTP_KEY_LEN);
+                        }
+                        return SWITCH_STATUS_SUCCESS;
+                }
+
+        }
+
+  bad:
+
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error!\n&quot;);
+        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-&gt;profile-&gt;rtp_timeout_sec;
+        uint32_t rtp_hold_timeout_sec = tech_pvt-&gt;profile-&gt;rtp_hold_timeout_sec;
+        char *timer_name = NULL;
+        const char *var;
+
+        switch_assert(tech_pvt != NULL);
+
+        if (switch_channel_down(tech_pvt-&gt;channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_mutex_lock(tech_pvt-&gt;sofia_mutex);
+
+        if (switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                switch_rtp_reset_media_timer(tech_pvt-&gt;rtp_session);
+        }
+
+        if ((var = switch_channel_get_variable(tech_pvt-&gt;channel, SOFIA_SECURE_MEDIA_VARIABLE)) &amp;&amp; switch_true(var)) {
+                sofia_set_flag_locked(tech_pvt, TFLAG_SECURE);
+        }
+
+        if (switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MODE)) {
+                status = SWITCH_STATUS_SUCCESS;
+                goto end;
+        }
+
+        if (switch_rtp_ready(tech_pvt-&gt;rtp_session) &amp;&amp; !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-&gt;read_impl.bits_per_second;
+        ms = tech_pvt-&gt;read_impl.microseconds_per_packet;
+
+        if (myflags) {
+                flags = myflags;
+        } else if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_DISABLE_RTP_AUTOADJ) &amp;&amp;
+                                !((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;disable_rtp_auto_adjust&quot;)) &amp;&amp; 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-&gt;channel, &quot;dtmf_type&quot;))) {
+                if (!strcasecmp(val, &quot;rfc2833&quot;)) {
+                        tech_pvt-&gt;dtmf_type = DTMF_2833;
+                } else if (!strcasecmp(val, &quot;info&quot;)) {
+                        tech_pvt-&gt;dtmf_type = DTMF_INFO;
+                } else {
+                        tech_pvt-&gt;dtmf_type = tech_pvt-&gt;profile-&gt;dtmf_type;
+                }
+        }
+
+        if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_PASS_RFC2833)
+                || ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;pass_rfc2833&quot;)) &amp;&amp; switch_true(val))) {
+                sofia_set_flag(tech_pvt, TFLAG_PASS_RFC2833);
+        }
+
+
+        if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_AUTOFLUSH)
+                || ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_autoflush&quot;)) &amp;&amp; switch_true(val))) {
+                flags |= SWITCH_RTP_FLAG_AUTOFLUSH;
+        }
+
+        if (!(sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_REWRITE_TIMESTAMPS) ||
+                  ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_rewrite_timestamps&quot;)) &amp;&amp; !switch_true(val)))) {
+                flags |= SWITCH_RTP_FLAG_RAW_WRITE;
+        }
+
+        if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG)) {
+                tech_pvt-&gt;cng_pt = 0;
+        } else if (tech_pvt-&gt;cng_pt) {
+                flags |= SWITCH_RTP_FLAG_AUTO_CNG;
+        }
+
+        if (tech_pvt-&gt;rtp_session &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+                //const char *ip = switch_channel_get_variable(tech_pvt-&gt;channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
+                //const char *port = switch_channel_get_variable(tech_pvt-&gt;channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
+                char *remote_host = switch_rtp_get_remote_host(tech_pvt-&gt;rtp_session);
+                switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt-&gt;rtp_session);
+                
+                if (remote_host &amp;&amp; remote_port &amp;&amp; !strcmp(remote_host, tech_pvt-&gt;remote_sdp_audio_ip) &amp;&amp; remote_port == tech_pvt-&gt;remote_sdp_audio_port) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Audio params are unchanged for %s.\n&quot;, switch_channel_get_name(tech_pvt-&gt;channel));
+                        goto video;
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Audio params changed for %s from %s:%d to %s:%d\n&quot;, 
+                                                          switch_channel_get_name(tech_pvt-&gt;channel),
+                                                          remote_host, remote_port, tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port);
+                }
+        }
+
+        if (!switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;AUDIO RTP [%s] %s port %d -&gt; %s port %d codec: %u ms: %d\n&quot;,
+                                                  switch_channel_get_name(tech_pvt-&gt;channel),
+                                                  tech_pvt-&gt;local_sdp_audio_ip,
+                                                  tech_pvt-&gt;local_sdp_audio_port,
+                                                  tech_pvt-&gt;remote_sdp_audio_ip,
+                                                  tech_pvt-&gt;remote_sdp_audio_port, tech_pvt-&gt;agreed_pt, tech_pvt-&gt;read_impl.microseconds_per_packet / 1000);
+        }
+
+        switch_snprintf(tmp, sizeof(tmp), &quot;%d&quot;, tech_pvt-&gt;local_sdp_audio_port);
+        switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt-&gt;adv_sdp_audio_ip);
+        switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+
+        if (tech_pvt-&gt;rtp_session &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
+                sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+                
+                if (switch_rtp_set_remote_address(tech_pvt-&gt;rtp_session, tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port, SWITCH_TRUE, &amp;err) !=
+                        SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;AUDIO RTP REPORTS ERROR: [%s]\n&quot;, err);
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;AUDIO RTP CHANGING DEST TO: [%s:%d]\n&quot;,
+                                                          tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port);
+                        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_DISABLE_RTP_AUTOADJ) &amp;&amp;
+                                !((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;disable_rtp_auto_adjust&quot;)) &amp;&amp; switch_true(val))) {
+                                /* Reactivate the NAT buster flag. */
+                                switch_rtp_set_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+                        }
+                }
+                goto video;
+        }
+
+        if (switch_channel_test_flag(tech_pvt-&gt;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-&gt;profile, PFLAG_DISABLE_RTP_AUTOADJ) &amp;&amp;
+                        !((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;disable_rtp_auto_adjust&quot;)) &amp;&amp; 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,
+                                                  &quot;PROXY AUDIO RTP [%s] %s:%d-&gt;%s:%d codec: %u ms: %d\n&quot;,
+                                                  switch_channel_get_name(tech_pvt-&gt;channel),
+                                                  tech_pvt-&gt;local_sdp_audio_ip,
+                                                  tech_pvt-&gt;local_sdp_audio_port,
+                                                  tech_pvt-&gt;remote_sdp_audio_ip,
+                                                  tech_pvt-&gt;remote_sdp_audio_port, tech_pvt-&gt;agreed_pt, tech_pvt-&gt;read_impl.microseconds_per_packet / 1000);
+
+        } else {
+                timer_name = tech_pvt-&gt;profile-&gt;timer_name;
+
+                if ((var = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_timer_name&quot;))) {
+                        timer_name = (char *) var;
+                }
+        }
+
+        if (switch_channel_up(tech_pvt-&gt;channel) &amp;&amp; !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
+                tech_pvt-&gt;rtp_session = switch_rtp_new(tech_pvt-&gt;local_sdp_audio_ip,
+                                                                                           tech_pvt-&gt;local_sdp_audio_port,
+                                                                                           tech_pvt-&gt;remote_sdp_audio_ip,
+                                                                                           tech_pvt-&gt;remote_sdp_audio_port,
+                                                                                           tech_pvt-&gt;agreed_pt,
+                                                                                           tech_pvt-&gt;read_impl.samples_per_packet,
+                                                                                           tech_pvt-&gt;codec_ms * 1000,
+                                                                                           (switch_rtp_flag_t) flags, timer_name, &amp;err,
+                                                                                           switch_core_session_get_pool(tech_pvt-&gt;session));
+        }
+
+        if (switch_rtp_ready(tech_pvt-&gt;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-&gt;channel, CF_FS_RTP);
+                
+                if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_enable_vad_in&quot;)) &amp;&amp; switch_true(val)) {
+                        vad_in = 1;
+                }
+                if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_enable_vad_out&quot;)) &amp;&amp; switch_true(val)) {
+                        vad_out = 1;
+                }
+
+                if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_disable_vad_in&quot;)) &amp;&amp; switch_true(val)) {
+                        vad_in = 0;
+                }
+                if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_disable_vad_out&quot;)) &amp;&amp; switch_true(val)) {
+                        vad_out = 0;
+                }
+
+                if ((tech_pvt-&gt;stun_flags &amp; STUN_FLAG_SET) &amp;&amp; (val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_stun_ping&quot;))) {
+                        int ival = atoi(val);
+                        
+                        if (ival &lt;= 0) {
+                                if (switch_true(val)) {
+                                        ival = 6;
+                                }
+                        }
+
+                        stun_ping = (ival * tech_pvt-&gt;read_impl.samples_per_second) / tech_pvt-&gt;read_impl.samples_per_packet;
+                }
+
+                tech_pvt-&gt;ssrc = switch_rtp_get_ssrc(tech_pvt-&gt;rtp_session);
+                sofia_set_flag(tech_pvt, TFLAG_RTP);
+                sofia_set_flag(tech_pvt, TFLAG_IO);
+                
+                switch_rtp_intentional_bugs(tech_pvt-&gt;rtp_session, tech_pvt-&gt;rtp_bugs);
+                
+                if ((vad_in &amp;&amp; inb) || (vad_out &amp;&amp; !inb)) {
+                        switch_rtp_enable_vad(tech_pvt-&gt;rtp_session, tech_pvt-&gt;session, &amp;tech_pvt-&gt;read_codec, SWITCH_VAD_FLAG_TALKING);
+                        sofia_set_flag(tech_pvt, TFLAG_VAD);
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;AUDIO RTP Engage VAD for %s ( %s %s )\n&quot;,
+                                                          switch_channel_get_name(switch_core_session_get_channel(tech_pvt-&gt;session)), vad_in ? &quot;in&quot; : &quot;&quot;, vad_out ? &quot;out&quot; : &quot;&quot;);
+                }
+
+                if (stun_ping) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Setting stun ping to %s:%d\n&quot;, tech_pvt-&gt;stun_ip, stun_ping);
+                        switch_rtp_activate_stun_ping(tech_pvt-&gt;rtp_session, tech_pvt-&gt;stun_ip, tech_pvt-&gt;stun_port, 
+                                                                                  stun_ping, (tech_pvt-&gt;stun_flags &amp; STUN_FLAG_FUNNY) ? 1 : 0);
+                }
+
+                if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;jitterbuffer_msec&quot;))) {
+                        int len = atoi(val);
+
+                        if (len &lt; 100 || len &gt; 1000) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Jitterbuffer spec [%d] must be between 100 and 1000\n&quot;, len);
+                        } else {
+                                int qlen;
+
+                                qlen = len / (tech_pvt-&gt;read_impl.microseconds_per_packet / 1000);
+
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Setting Jitterbuffer to %dms (%d frames)\n&quot;, len, qlen);
+                                switch_rtp_activate_jitter_buffer(tech_pvt-&gt;rtp_session, qlen);
+                        }
+                }
+
+                if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_timeout_sec&quot;))) {
+                        int v = atoi(val);
+                        if (v &gt;= 0) {
+                                rtp_timeout_sec = v;
+                        }
+                }
+
+                if ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;rtp_hold_timeout_sec&quot;))) {
+                        int v = atoi(val);
+                        if (v &gt;= 0) {
+                                rtp_hold_timeout_sec = v;
+                        }
+                }
+
+                if (rtp_timeout_sec) {
+                        tech_pvt-&gt;max_missed_packets = (tech_pvt-&gt;read_impl.samples_per_second * rtp_timeout_sec) /
+                                tech_pvt-&gt;read_impl.samples_per_packet;
+
+                        switch_rtp_set_max_missed_packets(tech_pvt-&gt;rtp_session, tech_pvt-&gt;max_missed_packets);
+                        if (!rtp_hold_timeout_sec) {
+                                rtp_hold_timeout_sec = rtp_timeout_sec * 10;
+                        }
+                }
+
+                if (rtp_hold_timeout_sec) {
+                        tech_pvt-&gt;max_missed_hold_packets = (tech_pvt-&gt;read_impl.samples_per_second * rtp_hold_timeout_sec) /
+                                tech_pvt-&gt;read_impl.samples_per_packet;
+                }
+
+                if (tech_pvt-&gt;te) {
+                        switch_rtp_set_telephony_event(tech_pvt-&gt;rtp_session, tech_pvt-&gt;te);
+                }
+
+                if (sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG) ||
+                        ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;supress_cng&quot;)) &amp;&amp; switch_true(val)) ||
+                        ((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;suppress_cng&quot;)) &amp;&amp; switch_true(val))) {
+                        tech_pvt-&gt;cng_pt = 0;
+                }
+
+                if (tech_pvt-&gt;cng_pt &amp;&amp; !sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set comfort noise payload to %u\n&quot;, tech_pvt-&gt;cng_pt);
+                        switch_rtp_set_cng_pt(tech_pvt-&gt;rtp_session, tech_pvt-&gt;cng_pt);
+                }
+
+                if (tech_pvt-&gt;remote_crypto_key &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+                        sofia_glue_add_crypto(tech_pvt, tech_pvt-&gt;remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
+                        switch_rtp_add_crypto_key(tech_pvt-&gt;rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, tech_pvt-&gt;crypto_type, tech_pvt-&gt;local_raw_key,
+                                                                          SWITCH_RTP_KEY_LEN);
+                        switch_rtp_add_crypto_key(tech_pvt-&gt;rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt-&gt;crypto_tag, tech_pvt-&gt;crypto_type, tech_pvt-&gt;remote_raw_key,
+                                                                          SWITCH_RTP_KEY_LEN);
+                        switch_channel_set_variable(tech_pvt-&gt;channel, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE, &quot;true&quot;);
+                }
+
+          video:
+
+                sofia_glue_check_video_codecs(tech_pvt);
+
+                if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) &amp;&amp; tech_pvt-&gt;video_rm_encoding &amp;&amp; tech_pvt-&gt;remote_sdp_video_port) {
+                        if (!tech_pvt-&gt;local_sdp_video_port) {
+                                sofia_glue_tech_choose_video_port(tech_pvt, 1);
+                        }
+
+                        if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_DISABLE_RTP_AUTOADJ) &amp;&amp; !switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MODE) &amp;&amp;
+                                !((val = switch_channel_get_variable(tech_pvt-&gt;channel, &quot;disable_rtp_auto_adjust&quot;)) &amp;&amp; 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-&gt;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-&gt;video_rtp_session = switch_rtp_new(tech_pvt-&gt;local_sdp_audio_ip,
+                                                                                                                 tech_pvt-&gt;local_sdp_video_port,
+                                                                                                                 tech_pvt-&gt;remote_sdp_video_ip,
+                                                                                                                 tech_pvt-&gt;remote_sdp_video_port,
+                                                                                                                 tech_pvt-&gt;video_agreed_pt,
+                                                                                                                 1, 10000, (switch_rtp_flag_t) flags, NULL, &amp;err, switch_core_session_get_pool(tech_pvt-&gt;session));
+
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;%sVIDEO RTP [%s] %s:%d-&gt;%s:%d codec: %u ms: %d [%s]\n&quot;,
+                                                          switch_channel_test_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA) ? &quot;PROXY &quot; : &quot;&quot;,
+                                                          switch_channel_get_name(tech_pvt-&gt;channel),
+                                                          tech_pvt-&gt;local_sdp_audio_ip,
+                                                          tech_pvt-&gt;local_sdp_video_port,
+                                                          tech_pvt-&gt;remote_sdp_video_ip,
+                                                          tech_pvt-&gt;remote_sdp_video_port, tech_pvt-&gt;video_agreed_pt,
+                                                          0, switch_rtp_ready(tech_pvt-&gt;video_rtp_session) ? &quot;SUCCESS&quot; : err);
+
+                        if (switch_rtp_ready(tech_pvt-&gt;video_rtp_session)) {
+                                switch_channel_set_flag(tech_pvt-&gt;channel, CF_VIDEO);
+                        } else {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;VIDEO RTP REPORTS ERROR: [%s]\n&quot;, switch_str_nil(err));
+                                switch_channel_hangup(tech_pvt-&gt;channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                goto end;
+                        }
+                }
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;AUDIO RTP REPORTS ERROR: [%s]\n&quot;, switch_str_nil(err));
+                switch_channel_hangup(tech_pvt-&gt;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-&gt;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-&gt;sdp_attributes; attr; attr = attr-&gt;a_next) {
+                if (switch_strlen_zero(attr-&gt;a_name)) {
+                        continue;
+                }
+
+                if (!strcasecmp(attr-&gt;a_name, &quot;ptime&quot;)) {
+                        dptime = atoi(attr-&gt;a_value);
+                        break;
+                }
+        }
+
+        for (m = sdp-&gt;sdp_media; m; m = m-&gt;m_next) {
+                ptime = dptime;
+                if ( m-&gt;m_type == sdp_media_image &amp;&amp; m-&gt;m_port) {
+                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;,t38&quot;);
+                } else if (m-&gt;m_type == sdp_media_audio &amp;&amp; m-&gt;m_port) {
+                        for (attr = m-&gt;m_attributes; attr; attr = attr-&gt;a_next) {
+                                if (switch_strlen_zero(attr-&gt;a_name)) {
+                                        continue;
+                                }
+                                if (!strcasecmp(attr-&gt;a_name, &quot;ptime&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        ptime = atoi(attr-&gt;a_value);
+                                        break;
+                                }
+                        }
+                        connection = sdp-&gt;sdp_connection;
+                        if (m-&gt;m_connections) {
+                                connection = m-&gt;m_connections;
+                        }
+
+                        if (!connection) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot find a c= line in the sdp at media or session level!\n&quot;);
+                                break;
+                        }
+
+                        for (i = 0; i &lt; num_codecs; i++) {
+                                const switch_codec_implementation_t *imp = codecs[i];
+                                if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_AUDIO || imp-&gt;ianacode &gt; 127 || already_did[imp-&gt;ianacode]) {
+                                        continue;
+                                }
+                                for (map = m-&gt;m_rtpmaps; map; map = map-&gt;rm_next) {
+                                        if ( map-&gt;rm_pt &gt; 127 ||  already_did[map-&gt;rm_pt]) {
+                                                continue;
+                                        }
+
+                                        if (map-&gt;rm_pt &lt; 96) {
+                                                match = (map-&gt;rm_pt == imp-&gt;ianacode) ? 1 : 0;
+                                        } else {
+                                                if (map-&gt;rm_encoding) {
+                                                        match = strcasecmp(map-&gt;rm_encoding, imp-&gt;iananame) ? 0 : 1;
+                                                } else {
+                                                        match = 0;
+                                                }
+                                        }
+
+                                        if (match) {
+                                                if (ptime &gt; 0) {
+                                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;,%s@%uh@%di&quot;, imp-&gt;iananame, (unsigned int) map-&gt;rm_rate, ptime);
+                                                } else {
+                                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;,%s@%uh&quot;, imp-&gt;iananame, (unsigned int) map-&gt;rm_rate);
+                                                }
+                                                already_did[imp-&gt;ianacode] = 1;
+                                                break;
+                                        }
+                                }
+                        }
+                } else if (m-&gt;m_type == sdp_media_video &amp;&amp; m-&gt;m_port) {
+                        connection = sdp-&gt;sdp_connection;
+                        if (m-&gt;m_connections) {
+                                connection = m-&gt;m_connections;
+                        }
+
+                        if (!connection) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot find a c= line in the sdp at media or session level!\n&quot;);
+                                break;
+                        }
+                        for (i = 0; i &lt; num_codecs; i++) {
+                                const switch_codec_implementation_t *imp = codecs[i];
+                                if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_VIDEO || imp-&gt;ianacode &gt; 127 || already_did[imp-&gt;ianacode]) {
+                                        continue;
+                                }
+                                for (map = m-&gt;m_rtpmaps; map; map = map-&gt;rm_next) {
+                                        if ( map-&gt;rm_pt &gt; 127 || already_did[map-&gt;rm_pt]) {
+                                                continue;
+                                        }
+
+                                        if (map-&gt;rm_pt &lt; 96) {
+                                                match = (map-&gt;rm_pt == imp-&gt;ianacode) ? 1 : 0;
+                                        } else {
+                                                if(map-&gt;rm_encoding) {
+                                                        match = strcasecmp(map-&gt;rm_encoding, imp-&gt;iananame) ? 0 : 1;
+                                                } else {
+                                                        match = 0;
+                                                }
+                                        }
+
+                                        if (match) {
+                                                if(ptime &gt; 0) {
+                                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;,%s@%uh@%di&quot;, imp-&gt;iananame, (unsigned int) map-&gt;rm_rate, ptime);
+                                                } else {
+                                                        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), &quot;,%s@%uh&quot;, imp-&gt;iananame, (unsigned int) map-&gt;rm_rate);
+                                                }
+                                                already_did[imp-&gt;ianacode] = 1;
+                                                break;
+                                        }
+                                }
+                        }
+                }
+        }
+        if (buf[0] == ',') {
+                switch_channel_set_variable(channel, &quot;ep_codec_string&quot;, 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-&gt;num_codecs) {
+                        if ((sdp = sdp_session(parser))) {
+                                match = sofia_glue_negotiate_sdp(tech_pvt-&gt;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-&gt;channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, &quot;EARLY MEDIA&quot;);
+                sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+                switch_channel_mark_pre_answered(tech_pvt-&gt;channel);
+                return SWITCH_STATUS_SUCCESS;
+        }
+
+
+        return SWITCH_STATUS_FALSE;
+}
+
+void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
+{
+        if (sendonly &amp;&amp; switch_channel_test_flag(tech_pvt-&gt;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-&gt;channel, &quot;unknown&quot;, &quot;hold&quot;, NULL);
+
+                        if (tech_pvt-&gt;max_missed_hold_packets) {
+                                switch_rtp_set_max_missed_packets(tech_pvt-&gt;rtp_session, tech_pvt-&gt;max_missed_hold_packets);
+                        }
+
+                        if (!(stream = switch_channel_get_variable(tech_pvt-&gt;channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+                                stream = tech_pvt-&gt;profile-&gt;hold_music;
+                        }
+
+                        if (stream &amp;&amp; strcasecmp(stream, &quot;silence&quot;)) {
+                                if (!strcasecmp(stream, &quot;indicate_hold&quot;)) {
+                                        switch_channel_set_flag(tech_pvt-&gt;channel, CF_SUSPEND);
+                                        switch_channel_set_flag(tech_pvt-&gt;channel, CF_HOLD);
+                                        switch_ivr_hold_uuid(switch_channel_get_variable(tech_pvt-&gt;channel, SWITCH_SIGNAL_BOND_VARIABLE), NULL, 0);
+                                } else {
+                                        switch_ivr_broadcast(switch_channel_get_variable(tech_pvt-&gt;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-&gt;max_missed_packets) {
+                                switch_rtp_reset_media_timer(tech_pvt-&gt;rtp_session);
+                                switch_rtp_set_max_missed_packets(tech_pvt-&gt;rtp_session, tech_pvt-&gt;max_missed_packets);
+                        }
+
+                        if ((uuid = switch_channel_get_variable(tech_pvt-&gt;channel, SWITCH_SIGNAL_BOND_VARIABLE)) &amp;&amp; (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-&gt;channel, CF_HOLD)) {
+                                        switch_ivr_unhold(b_session);
+                                        switch_channel_clear_flag(tech_pvt-&gt;channel, CF_SUSPEND);
+                                        switch_channel_clear_flag(tech_pvt-&gt;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-&gt;channel, &quot;unknown&quot;, &quot;unhold&quot;, 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-&gt;profile, PFLAG_GREEDY);
+        scrooge = !!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SCROOGE);
+        
+        if (!greedy || !scrooge) {
+                if ((val = switch_channel_get_variable(channel, &quot;sip_codec_negotiation&quot;))) {
+                        if (!strcasecmp(val, &quot;greedy&quot;)) {
+                                greedy = 1;
+                        } else if (!strcasecmp(val, &quot;scrooge&quot;)) {
+                                scrooge = 1;
+                                greedy = 1;
+                        }
+                }
+        }
+
+        if ((tech_pvt-&gt;origin = switch_core_session_strdup(session, (char *) sdp-&gt;sdp_origin-&gt;o_username))) {
+
+                if (tech_pvt-&gt;profile-&gt;auto_rtp_bugs &amp; RTP_BUG_CISCO_SKIP_MARK_BIT_2833) {
+
+                        if (strstr(tech_pvt-&gt;origin, &quot;CiscoSystemsSIP-GW-UserAgent&quot;)) {
+                                tech_pvt-&gt;rtp_bugs |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833;
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Activate Buggy RFC2833 Mode!\n&quot;);
+                        }
+                }
+                
+                if (tech_pvt-&gt;profile-&gt;auto_rtp_bugs &amp; RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833) {
+                        if (strstr(tech_pvt-&gt;origin, &quot;Sonus_UAC&quot;)) {
+                                tech_pvt-&gt;rtp_bugs |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+                                                                  &quot;Hello,\nI see you have a Sonus!\n&quot;
+                                                                  &quot;FYI, Sonus cannot follow the RFC on the proper way to send DTMF.\n&quot;
+                                                                  &quot;Sadly, my creator had to spend several hours figuring this out so I thought you'd like to know that!\n&quot;
+                                                                  &quot;Don't worry, DTMF will work but you may want to ask them to fix it......\n&quot;
+                                                                  );
+                        }
+                }
+        }
+
+        if ((m = sdp-&gt;sdp_media) &amp;&amp; (m-&gt;m_mode == sdp_sendonly || m-&gt;m_mode == sdp_inactive)) {
+                sendonly = 2;                        /* global sendonly always wins */
+        }
+
+        for (attr = sdp-&gt;sdp_attributes; attr; attr = attr-&gt;a_next) {
+                if (switch_strlen_zero(attr-&gt;a_name)) {
+                        continue;
+                }
+
+                if (!strcasecmp(attr-&gt;a_name, &quot;sendonly&quot;) || !strcasecmp(attr-&gt;a_name, &quot;inactive&quot;)) {
+                        sendonly = 1;
+                } else if (sendonly &lt; 2 &amp;&amp; !strcasecmp(attr-&gt;a_name, &quot;sendrecv&quot;)) {
+                        sendonly = 0;
+                } else if (!strcasecmp(attr-&gt;a_name, &quot;ptime&quot;)) {
+                        dptime = atoi(attr-&gt;a_value);
+                } else if (!strcasecmp(attr-&gt;a_name, &quot;maxptime&quot;)) {
+                        dmaxptime = atoi(attr-&gt;a_value);
+                }
+        }
+
+        if (!tech_pvt-&gt;hold_laps) {
+                tech_pvt-&gt;hold_laps++;
+                sofia_glue_toggle_hold(tech_pvt, sendonly);
+        }
+
+        for (m = sdp-&gt;sdp_media; m; m = m-&gt;m_next) {
+                sdp_connection_t *connection;
+
+                ptime = dptime;
+                maxptime = dmaxptime;
+
+                if (m-&gt;m_proto == sdp_proto_srtp) {
+                        got_savp++;
+                } else if (m-&gt;m_proto == sdp_proto_rtp) {
+                        got_avp++;
+                } else if (m-&gt;m_proto == sdp_proto_udptl) {
+                        got_udptl++;
+                }
+
+                if (got_udptl &amp;&amp; m-&gt;m_type == sdp_media_image &amp;&amp; m-&gt;m_port) {
+                        switch_t38_options_t *t38_options = switch_core_session_alloc(tech_pvt-&gt;session, sizeof(switch_t38_options_t));
+                        
+                        for (attr = m-&gt;m_attributes; attr; attr = attr-&gt;a_next) {
+                                if (!strcasecmp(attr-&gt;a_name, &quot;T38MaxBitRate&quot;) &amp;&amp; attr-&gt;a_value) { 
+                                        t38_options-&gt;T38MaxBitRate = (uint32_t) atoi(attr-&gt;a_value);
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38FaxFillBitRemoval&quot;)) {
+                                        t38_options-&gt;T38FaxFillBitRemoval = SWITCH_TRUE;
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38FaxTranscodingMMR&quot;)) {
+                                        t38_options-&gt;T38FaxTranscodingMMR = SWITCH_TRUE;
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38FaxTranscodingJBIG&quot;)) {
+                                        t38_options-&gt;T38FaxTranscodingJBIG = SWITCH_TRUE;
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38FaxRateManagement&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        t38_options-&gt;T38FaxRateManagement = switch_core_session_strdup(tech_pvt-&gt;session, attr-&gt;a_value);
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38FaxMaxBuffer&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        t38_options-&gt;T38FaxMaxBuffer = (uint32_t) atoi(attr-&gt;a_value);
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38FaxMaxDatagram&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        t38_options-&gt;T38FaxMaxDatagram = (uint32_t) atoi(attr-&gt;a_value);
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38FaxUdpEC&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        t38_options-&gt;T38FaxUdpEC = switch_core_session_strdup(tech_pvt-&gt;session, attr-&gt;a_value);
+                                } else  if (!strcasecmp(attr-&gt;a_name, &quot;T38VendorInfo&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        t38_options-&gt;T38VendorInfo = switch_core_session_strdup(tech_pvt-&gt;session, attr-&gt;a_value);
+                                }
+                        }
+
+                        switch_channel_set_variable(tech_pvt-&gt;channel, &quot;has_t38&quot;, &quot;true&quot;);
+                        switch_channel_set_private(tech_pvt-&gt;channel, &quot;t38_options&quot;, t38_options);
+
+                        //switch_channel_set_flag(tech_pvt-&gt;channel, CF_PROXY_MEDIA);
+                        //switch_rtp_set_flag(tech_pvt-&gt;rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA);
+
+                } else if (m-&gt;m_type == sdp_media_audio &amp;&amp; m-&gt;m_port &amp;&amp; !got_audio) {
+                        sdp_rtpmap_t *map;
+
+                        for (attr = m-&gt;m_attributes; attr; attr = attr-&gt;a_next) {
+                                if (!strcasecmp(attr-&gt;a_name, &quot;ptime&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        ptime = atoi(attr-&gt;a_value);
+                                } else if (!strcasecmp(attr-&gt;a_name, &quot;maxptime&quot;) &amp;&amp; attr-&gt;a_value) {
+                                        maxptime = atoi(attr-&gt;a_value);
+                                } else if (!got_crypto &amp;&amp; !strcasecmp(attr-&gt;a_name, &quot;crypto&quot;) &amp;&amp; !switch_strlen_zero(attr-&gt;a_value)) {
+                                        int crypto_tag;
+
+                                        if (m-&gt;m_proto != sdp_proto_srtp) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;a=crypto in RTP/AVP, refer to rfc3711\n&quot;);
+                                                match = 0;
+                                                goto done;
+                                        }
+
+                                        crypto = attr-&gt;a_value;
+                                        crypto_tag = atoi(crypto);
+
+                                        if (tech_pvt-&gt;remote_crypto_key &amp;&amp; switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                                                if (crypto_tag &amp;&amp; crypto_tag == tech_pvt-&gt;crypto_tag) {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Existing key is still valid.\n&quot;);
+                                                } else {
+                                                        const char *a = switch_stristr(&quot;AES&quot;, tech_pvt-&gt;remote_crypto_key);
+                                                        const char *b = switch_stristr(&quot;AES&quot;, crypto);
+
+                                                        /* Change our key every time we can */
+                                                        if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
+                                                                switch_channel_set_variable(tech_pvt-&gt;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-&gt;rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt-&gt;crypto_type,
+                                                                                                                  tech_pvt-&gt;local_raw_key, SWITCH_RTP_KEY_LEN);
+                                                        } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
+                                                                switch_channel_set_variable(tech_pvt-&gt;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-&gt;rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt-&gt;crypto_type,
+                                                                                                                  tech_pvt-&gt;local_raw_key, SWITCH_RTP_KEY_LEN);
+                                                        } else {
+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Crypto Setup Failed!.\n&quot;);
+                                                        }
+                                                                                                                
+                                                        if (a &amp;&amp; b &amp;&amp; !strncasecmp(a, b, 23)) {
+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Change Remote key to [%s]\n&quot;, crypto);
+                                                                tech_pvt-&gt;remote_crypto_key = switch_core_session_strdup(tech_pvt-&gt;session, crypto);
+                                                                tech_pvt-&gt;crypto_tag = crypto_tag;
+                                                                
+                                                                if (switch_rtp_ready(tech_pvt-&gt;rtp_session) &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_SECURE)) {
+                                                                        sofia_glue_add_crypto(tech_pvt, tech_pvt-&gt;remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
+                                                                        switch_rtp_add_crypto_key(tech_pvt-&gt;rtp_session, SWITCH_RTP_CRYPTO_RECV, tech_pvt-&gt;crypto_tag,
+                                                                                                                          tech_pvt-&gt;crypto_type, tech_pvt-&gt;remote_raw_key, SWITCH_RTP_KEY_LEN);
+                                                                }
+                                                                got_crypto++;
+                                                        } else {
+                                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Ignoring unacceptable key\n&quot;);
+                                                        }
+                                                }
+                                        } else if (!switch_rtp_ready(tech_pvt-&gt;rtp_session)) {
+                                                tech_pvt-&gt;remote_crypto_key = switch_core_session_strdup(tech_pvt-&gt;session, crypto);
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set Remote Key [%s]\n&quot;, tech_pvt-&gt;remote_crypto_key);
+                                                tech_pvt-&gt;crypto_tag = crypto_tag;
+                                                got_crypto++;
+
+                                                if (switch_strlen_zero(tech_pvt-&gt;local_crypto_key)) {
+                                                        if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
+                                                                switch_channel_set_variable(tech_pvt-&gt;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-&gt;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, &quot;Crypto Setup Failed!.\n&quot;);
+                                                        }
+                                                }
+                                        }
+                                }
+                        }
+
+                        if (got_crypto &amp;&amp; !got_avp) {
+                                switch_channel_set_variable(tech_pvt-&gt;channel, SOFIA_CRYPTO_MANDATORY_VARIABLE, &quot;true&quot;);
+                                switch_channel_set_variable(tech_pvt-&gt;channel, SOFIA_SECURE_MEDIA_VARIABLE, &quot;true&quot;);
+                        }
+
+                        connection = sdp-&gt;sdp_connection;
+                        if (m-&gt;m_connections) {
+                                connection = m-&gt;m_connections;
+                        }
+
+                        if (!connection) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot find a c= line in the sdp at media or session level!\n&quot;);
+                                match = 0;
+                                break;
+                        }
+
+                  greed:
+                        x = 0;
+
+                        if (tech_pvt-&gt;rm_encoding) {
+                                for (map = m-&gt;m_rtpmaps; map; map = map-&gt;rm_next) {
+                                        if (map-&gt;rm_pt &lt; 96) {
+                                                match = (map-&gt;rm_pt == tech_pvt-&gt;pt) ? 1 : 0;
+                                        } else {
+                                                match = strcasecmp(switch_str_nil(map-&gt;rm_encoding), tech_pvt-&gt;iananame) ? 0 : 1;
+                                        }
+
+                                        if (match &amp;&amp; connection-&gt;c_address &amp;&amp; tech_pvt-&gt;remote_sdp_audio_ip &amp;&amp; 
+                                                !strcmp(connection-&gt;c_address, tech_pvt-&gt;remote_sdp_audio_ip) &amp;&amp; m-&gt;m_port == tech_pvt-&gt;remote_sdp_audio_port) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Our existing sdp is still good [%s %s:%d], let's keep it.\n&quot;,
+                                                                                  tech_pvt-&gt;rm_encoding, tech_pvt-&gt;remote_sdp_audio_ip, tech_pvt-&gt;remote_sdp_audio_port);
+                                                got_audio = 1;
+                                                break;
+                                        }
+                                }
+                        }
+
+
+
+                        for (map = m-&gt;m_rtpmaps; map; map = map-&gt;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++ &lt; skip) {
+                                        continue;
+                                }
+
+                                if (!(rm_encoding = map-&gt;rm_encoding)) {
+                                        rm_encoding = &quot;&quot;;
+                                }
+
+                                if (!te &amp;&amp; !strcasecmp(rm_encoding, &quot;telephone-event&quot;)) {
+                                        te = tech_pvt-&gt;te = (switch_payload_t) map-&gt;rm_pt;
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set 2833 dtmf payload to %u\n&quot;, te);
+                                        if (tech_pvt-&gt;rtp_session) {
+                                                switch_rtp_set_telephony_event(tech_pvt-&gt;rtp_session, tech_pvt-&gt;te);
+                                        }
+                                }
+
+                                if (!sofia_test_pflag(tech_pvt-&gt;profile, PFLAG_SUPPRESS_CNG) &amp;&amp; !cng_pt &amp;&amp; !strcasecmp(rm_encoding, &quot;CN&quot;)) {
+                                        cng_pt = (switch_payload_t) map-&gt;rm_pt;
+                                        if (tech_pvt-&gt;rtp_session) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Set comfort noise payload to %u\n&quot;, cng_pt);
+                                                switch_rtp_set_cng_pt(tech_pvt-&gt;rtp_session, tech_pvt-&gt;cng_pt);
+                                        }
+                                }
+
+                                if (match) {
+                                        if (te &amp;&amp; cng_pt) {
+                                                break;
+                                        }
+                                        continue;
+                                }
+
+                                if (greedy) {
+                                        first = mine;
+                                        last = first + 1;
+                                } else {
+                                        first = 0;
+                                        last = tech_pvt-&gt;num_codecs;
+                                }
+                                
+                                if (maxptime &amp;&amp; (!ptime || ptime &gt; maxptime)) {
+                                        ptime = maxptime;
+                                }
+
+                                for (i = first; i &lt; last &amp;&amp; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
+                                        uint32_t codec_rate = imp-&gt;samples_per_second;
+                                        if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+                                                continue;
+                                        }
+
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Audio Codec Compare [%s:%d:%u:%d]/[%s:%d:%u:%d]\n&quot;,
+                                                                          rm_encoding, map-&gt;rm_pt, (int) map-&gt;rm_rate, ptime,
+                                                                          imp-&gt;iananame, imp-&gt;ianacode, codec_rate, imp-&gt;microseconds_per_packet / 1000);
+                                        if (map-&gt;rm_pt &lt; 96) {
+                                                match = (map-&gt;rm_pt == imp-&gt;ianacode) ? 1 : 0;
+                                        } else {
+                                                match = strcasecmp(rm_encoding, imp-&gt;iananame) ? 0 : 1;
+                                        }
+
+                                        if (match) {
+                                                if (scrooge) {
+                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
+                                                                                          &quot;Bah HUMBUG! Sticking with %s@%uh@%ui\n&quot;, 
+                                                                                          imp-&gt;iananame, imp-&gt;samples_per_second, imp-&gt;microseconds_per_packet / 1000);
+                                                } else {
+                                                        if ((ptime &amp;&amp; ptime * 1000 != imp-&gt;microseconds_per_packet) || 
+                                                                map-&gt;rm_rate != codec_rate) {
+                                                                near_rate = map-&gt;rm_rate;
+                                                                near_match = imp;
+                                                                match = 0;
+                                                                continue;
+                                                        }
+                                                }
+                                                mimp = imp;
+                                                break;
+                                        } else {
+                                                match = 0;
+                                        }
+                                }
+
+                                if (!match &amp;&amp; near_match) {
+                                        const switch_codec_implementation_t *search[1];
+                                        char *prefs[1];
+                                        char tmp[80];
+                                        int num;
+                                        
+                                        switch_snprintf(tmp, sizeof(tmp), &quot;%s@%uh@%ui&quot;, near_match-&gt;iananame, near_rate ? near_rate : near_match-&gt;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-&gt;microseconds_per_packet / 1000 &lt;= maxptime) {
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Substituting codec %s@%ui@%uh\n&quot;,
+                                                                                  mimp-&gt;iananame, mimp-&gt;microseconds_per_packet / 1000, mimp-&gt;samples_per_second);
+                                                match = 1;
+                                        } else {
+                                                mimp = NULL;
+                                                match = 0;
+                                        }
+                                        
+                                }
+
+                                if (!match &amp;&amp; greedy) {
+                                        skip++;
+                                        continue;
+                                }
+
+                                if (mimp) {
+                                        char tmp[50];
+                                        tech_pvt-&gt;rm_encoding = switch_core_session_strdup(session, (char *) map-&gt;rm_encoding);
+                                        tech_pvt-&gt;iananame = switch_core_session_strdup(session, (char *) mimp-&gt;iananame);
+                                        tech_pvt-&gt;pt = (switch_payload_t) map-&gt;rm_pt;
+                                        tech_pvt-&gt;rm_rate = map-&gt;rm_rate;
+                                        if (!strcasecmp((char *) mimp-&gt;iananame, &quot;ilbc&quot;) &amp;&amp; switch_strlen_zero((char*)map-&gt;rm_fmtp)) {
+                                                /* default to 30 when no mode is defined for ilbc ONLY */
+                                                tech_pvt-&gt;codec_ms = 30;
+                                        } else {
+                                                tech_pvt-&gt;codec_ms = mimp-&gt;microseconds_per_packet / 1000;
+                                        }
+                                        tech_pvt-&gt;remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection-&gt;c_address);
+                                        tech_pvt-&gt;rm_fmtp = switch_core_session_strdup(session, (char *) map-&gt;rm_fmtp);
+                                        tech_pvt-&gt;remote_sdp_audio_port = (switch_port_t) m-&gt;m_port;
+                                        tech_pvt-&gt;agreed_pt = (switch_payload_t) map-&gt;rm_pt;
+                                        switch_snprintf(tmp, sizeof(tmp), &quot;%d&quot;, tech_pvt-&gt;remote_sdp_audio_port);
+                                        switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt-&gt;remote_sdp_audio_ip);
+                                        switch_channel_set_variable(tech_pvt-&gt;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 &amp;&amp; greedy &amp;&amp; mine &lt; tech_pvt-&gt;num_codecs) {
+                                mine++;
+                                skip = 0;
+                                goto greed;
+                        }
+
+                } else if (m-&gt;m_type == sdp_media_video &amp;&amp; m-&gt;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-&gt;channel, &quot;video_possible&quot;, &quot;true&quot;);
+
+                        connection = sdp-&gt;sdp_connection;
+                        if (m-&gt;m_connections) {
+                                connection = m-&gt;m_connections;
+                        }
+
+                        if (!connection) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot find a c= line in the sdp at media or session level!\n&quot;);
+                                match = 0;
+                                break;
+                        }
+
+                        for (map = m-&gt;m_rtpmaps; map; map = map-&gt;rm_next) {
+
+                                for (attr = m-&gt;m_attributes; attr; attr = attr-&gt;a_next) {
+                                        if (!strcasecmp(attr-&gt;a_name, &quot;framerate&quot;) &amp;&amp; attr-&gt;a_value) {
+                                                framerate = atoi(attr-&gt;a_value);
+                                        }
+                                }
+                                if (!(rm_encoding = map-&gt;rm_encoding)) {
+                                        rm_encoding = &quot;&quot;;
+                                }
+
+                                for (i = 0; i &lt; tech_pvt-&gt;num_codecs; i++) {
+                                        const switch_codec_implementation_t *imp = tech_pvt-&gt;codecs[i];
+
+                                        if (imp-&gt;codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+                                                continue;
+                                        }
+
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Video Codec Compare [%s:%d]/[%s:%d]\n&quot;,
+                                                                          rm_encoding, map-&gt;rm_pt, imp-&gt;iananame, imp-&gt;ianacode);
+                                        if (map-&gt;rm_pt &lt; 96) {
+                                                vmatch = (map-&gt;rm_pt == imp-&gt;ianacode) ? 1 : 0;
+                                        } else {
+                                                vmatch = strcasecmp(rm_encoding, imp-&gt;iananame) ? 0 : 1;
+                                        }
+
+
+                                        if (vmatch &amp;&amp; (map-&gt;rm_rate == imp-&gt;samples_per_second)) {
+                                                mimp = imp;
+                                                break;
+                                        } else {
+                                                vmatch = 0;
+                                        }
+                                }
+
+
+                                if (mimp) {
+                                        if ((tech_pvt-&gt;video_rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
+                                                char tmp[50];
+                                                tech_pvt-&gt;video_pt = (switch_payload_t) map-&gt;rm_pt;
+                                                tech_pvt-&gt;video_rm_rate = map-&gt;rm_rate;
+                                                tech_pvt-&gt;video_codec_ms = mimp-&gt;microseconds_per_packet / 1000;
+                                                tech_pvt-&gt;remote_sdp_video_ip = switch_core_session_strdup(session, (char *) connection-&gt;c_address);
+                                                tech_pvt-&gt;video_rm_fmtp = switch_core_session_strdup(session, (char *) map-&gt;rm_fmtp);
+                                                tech_pvt-&gt;remote_sdp_video_port = (switch_port_t) m-&gt;m_port;
+                                                tech_pvt-&gt;video_agreed_pt = (switch_payload_t) map-&gt;rm_pt;
+                                                switch_snprintf(tmp, sizeof(tmp), &quot;%d&quot;, tech_pvt-&gt;remote_sdp_video_port);
+                                                switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, tech_pvt-&gt;remote_sdp_audio_ip);
+                                                switch_channel_set_variable(tech_pvt-&gt;channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
+                                                switch_channel_set_variable(tech_pvt-&gt;channel, &quot;sip_video_fmtp&quot;, tech_pvt-&gt;video_rm_fmtp);
+                                                switch_snprintf(tmp, sizeof(tmp), &quot;%d&quot;, tech_pvt-&gt;video_agreed_pt);
+                                                switch_channel_set_variable(tech_pvt-&gt;channel, &quot;sip_video_pt&quot;, tmp);
+                                                sofia_glue_check_video_codecs(tech_pvt);
+                                                break;
+                                        } else {
+                                                vmatch = 0;
+                                        }
+                                }
+                        }
+                }
+        }
+        
+ done:
+        tech_pvt-&gt;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-&gt;channel, SWITCH_SIGNAL_BOND_VARIABLE))
+                &amp;&amp; (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) &amp;&amp; (switch_channel_test_flag(other_channel, CF_OUTBOUND) &amp;&amp;
+                                                                                                                                switch_channel_test_flag(tech_pvt-&gt;channel, CF_OUTBOUND) &amp;&amp;
+                                                                                                                                switch_channel_test_flag(tech_pvt-&gt;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, '&lt;')) &amp;&amp; (e = strchr(url, '&gt;'))) {
+                url++;
+                if (to_dup) {
+                        url = strdup(url);
+                        e = strchr(url, '&gt;');
+                }
+
+                *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, &quot;Profile %s is not running\n&quot;, profile-&gt;name);
+#endif
+                        profile = NULL;
+                        goto done;
+                }
+                if (switch_thread_rwlock_tryrdlock(profile-&gt;rwlock) != SWITCH_STATUS_SUCCESS) {
+#ifdef SOFIA_DEBUG_RWLOCKS
+                        switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, &quot;Profile %s is locked\n&quot;, profile-&gt;name);
+#endif
+                        profile = NULL;
+                }
+        } else {
+#ifdef SOFIA_DEBUG_RWLOCKS
+                switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, &quot;Profile %s is not in the hash\n&quot;, key);
+#endif
+        }
+#ifdef SOFIA_DEBUG_RWLOCKS
+        if (profile) {
+                switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, &quot;XXXXXXXXXXXXXX LOCK %s\n&quot;, profile-&gt;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, &quot;XXXXXXXXXXXXXX UNLOCK %s\n&quot;, profile-&gt;name);
+#endif
+                switch_thread_rwlock_unlock(profile-&gt;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-&gt;deleted) {
+                if (gp-&gt;state != REG_STATE_NOREG) {
+                        gp-&gt;retry = 0;
+                        gp-&gt;state = REG_STATE_UNREGISTER;
+                }
+
+                gp-&gt;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, &amp;err))) {
+                switch_xml_free(xml_root);
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Reload XML [%s]\n&quot;, 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, &amp;var, NULL, &amp;val);
+            if ((pptr = (sofia_profile_t *) val)) {
+                                int rsec = 10;
+                                int diff = (int) (switch_epoch_time_now(NULL) - pptr-&gt;started);
+                                int remain = rsec - diff;
+                                if (sofia_test_pflag(pptr, PFLAG_RESPAWN) || !sofia_test_pflag(pptr, PFLAG_RUNNING)) {
+                                        continue;
+                                }
+
+                                if (diff &lt; rsec) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+                                                                          &quot;Profile %s must be up for at least %d seconds to stop/restart.\nPlease wait %d second%s\n&quot;,
+                                                                          pptr-&gt;name, rsec, remain, remain == 1 ? &quot;&quot; : &quot;s&quot;);
+                                        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, &amp;var, NULL, &amp;val);
+                        if ((pptr = (sofia_profile_t *) val) &amp;&amp; pptr == profile) {
+                                aliases[i++] = strdup((char *) var);
+                                if (i == 512) {
+                                        abort();
+                                }
+                        }
+                }
+
+                for (j = 0; j &lt; i &amp;&amp; j &lt; 512; j++) {
+                        switch_core_hash_delete(mod_sofia_globals.profile_hash, aliases[j]);
+                        free(aliases[j]);
+                }
+
+                for (gp = profile-&gt;gateways; gp; gp = gp-&gt;next) {
+                        switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp-&gt;name);
+                        switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp-&gt;register_from);
+                        switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp-&gt;register_contact);
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;deleted gateway %s\n&quot;, gp-&gt;name);
+                        profile-&gt;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[] =
+                &quot;CREATE TABLE sip_registrations (\n&quot;
+                &quot;   call_id         VARCHAR(255),\n&quot;
+                &quot;   sip_user        VARCHAR(255),\n&quot;
+                &quot;   sip_host        VARCHAR(255),\n&quot;
+                &quot;   presence_hosts  VARCHAR(255),\n&quot;
+                &quot;   contact         VARCHAR(1024),\n&quot;
+                &quot;   status          VARCHAR(255),\n&quot;
+                &quot;   rpid            VARCHAR(255),\n&quot; 
+                &quot;   expires         INTEGER,\n&quot; 
+                &quot;   user_agent      VARCHAR(255),\n&quot; 
+                &quot;   server_user     VARCHAR(255),\n&quot;
+                &quot;   server_host     VARCHAR(255),\n&quot; 
+                &quot;   profile_name    VARCHAR(255),\n&quot; 
+                &quot;   hostname        VARCHAR(255),\n&quot; 
+                &quot;   network_ip      VARCHAR(255),\n&quot; 
+                &quot;   network_port    VARCHAR(6),\n&quot; 
+                &quot;   sip_username    VARCHAR(255),\n&quot; 
+                &quot;   sip_realm       VARCHAR(255)\n&quot; 
+                &quot;);\n&quot;;
+
+
+        char pres_sql[] =
+                &quot;CREATE TABLE sip_presence (\n&quot;
+                &quot;   sip_user        VARCHAR(255),\n&quot;
+                &quot;   sip_host        VARCHAR(255),\n&quot;
+                &quot;   status          VARCHAR(255),\n&quot;
+                &quot;   rpid            VARCHAR(255),\n&quot; 
+                &quot;   expires         INTEGER,\n&quot; 
+                &quot;   user_agent      VARCHAR(255),\n&quot; 
+                &quot;   profile_name    VARCHAR(255),\n&quot; 
+                &quot;   hostname        VARCHAR(255),\n&quot; 
+                &quot;   network_ip      VARCHAR(255),\n&quot; 
+                &quot;   network_port    VARCHAR(6)\n&quot; 
+                &quot;);\n&quot;;
+
+        char dialog_sql[] =
+                &quot;CREATE TABLE sip_dialogs (\n&quot;
+                &quot;   call_id         VARCHAR(255),\n&quot;
+                &quot;   uuid            VARCHAR(255),\n&quot;
+                &quot;   sip_to_user     VARCHAR(255),\n&quot;
+                &quot;   sip_to_host     VARCHAR(255),\n&quot;
+                &quot;   sip_from_user   VARCHAR(255),\n&quot;
+                &quot;   sip_from_host   VARCHAR(255),\n&quot;
+                &quot;   contact_user    VARCHAR(255),\n&quot;
+                &quot;   contact_host    VARCHAR(255),\n&quot;
+                &quot;   state           VARCHAR(255),\n&quot; 
+                &quot;   direction       VARCHAR(255),\n&quot; 
+                &quot;   user_agent      VARCHAR(255),\n&quot; 
+                &quot;   profile_name    VARCHAR(255),\n&quot;
+        &quot;   hostname        VARCHAR(255)\n&quot;
+                &quot;);\n&quot;;
+
+        char sub_sql[] =
+                &quot;CREATE TABLE sip_subscriptions (\n&quot;
+                &quot;   proto           VARCHAR(255),\n&quot;
+                &quot;   sip_user        VARCHAR(255),\n&quot;
+                &quot;   sip_host        VARCHAR(255),\n&quot;
+                &quot;   sub_to_user     VARCHAR(255),\n&quot;
+                &quot;   sub_to_host     VARCHAR(255),\n&quot;
+                &quot;   presence_hosts  VARCHAR(255),\n&quot;
+                &quot;   event           VARCHAR(255),\n&quot;
+                &quot;   contact         VARCHAR(1024),\n&quot;
+                &quot;   call_id         VARCHAR(255),\n&quot;
+                &quot;   full_from       VARCHAR(255),\n&quot;
+                &quot;   full_via        VARCHAR(255),\n&quot;
+                &quot;   expires         INTEGER,\n&quot; 
+                &quot;   user_agent      VARCHAR(255),\n&quot; 
+                &quot;   accept          VARCHAR(255),\n&quot;
+                &quot;   profile_name    VARCHAR(255),\n&quot;
+                &quot;   hostname        VARCHAR(255),\n&quot;
+                &quot;   network_port    VARCHAR(6),\n&quot;
+                &quot;   network_ip      VARCHAR(255)\n&quot;
+                &quot;);\n&quot;;
+
+        char auth_sql[] = 
+                &quot;CREATE TABLE sip_authentication (\n&quot; 
+                &quot;   nonce           VARCHAR(255),\n&quot; 
+                &quot;   expires         INTEGER,&quot; 
+                &quot;   profile_name    VARCHAR(255),\n&quot;
+                &quot;   hostname        VARCHAR(255)\n&quot;
+                &quot;);\n&quot;;
+
+        /* should we move this glue to sofia_sla or keep it here where all db init happens? XXX MTK */
+        char shared_appearance_sql[] = 
+                &quot;CREATE TABLE sip_shared_appearance_subscriptions (\n&quot;
+                &quot;   subscriber        VARCHAR(255),\n&quot;
+                &quot;   call_id           VARCHAR(255),\n&quot;
+                &quot;   aor               VARCHAR(255),\n&quot;
+                &quot;   profile_name      VARCHAR(255),\n&quot;
+                &quot;   hostname          VARCHAR(255),\n&quot;
+                &quot;   contact_str       VARCHAR(255),\n&quot;
+                &quot;   network_ip        VARCHAR(255)\n&quot; 
+                &quot;);\n&quot;;
+
+        char shared_appearance_dialogs_sql[] = 
+                &quot;CREATE TABLE sip_shared_appearance_dialogs (\n&quot;
+                &quot;   profile_name      VARCHAR(255),\n&quot;
+                &quot;   hostname          VARCHAR(255),\n&quot;
+                &quot;   contact_str       VARCHAR(255),\n&quot;
+                &quot;   call_id           VARCHAR(255),\n&quot;
+                &quot;   network_ip        VARCHAR(255),\n&quot;
+                &quot;   expires           INTEGER\n&quot;
+                &quot;);\n&quot;;
+
+        if (switch_odbc_available() &amp;&amp; profile-&gt;odbc_dsn) {
+                int x;
+                char *indexes[] = {
+                        &quot;create index sr_call_id on sip_registrations (call_id)&quot;,
+                        &quot;create index sr_sip_user on sip_registrations (sip_user)&quot;,
+                        &quot;create index sr_sip_host on sip_registrations (sip_host)&quot;,
+                        &quot;create index sr_profile_name on sip_registrations (profile_name)&quot;,
+                        &quot;create index sr_presence_hosts on sip_registrations (presence_hosts)&quot;,
+                        &quot;create index sr_contact on sip_registrations (contact)&quot;,
+                        &quot;create index sr_expires on sip_registrations (expires)&quot;,
+                        &quot;create index sr_hostname on sip_registrations (hostname)&quot;,
+                        &quot;create index sr_status on sip_registrations (status)&quot;,
+                        &quot;create index sr_network_ip on sip_registrations (network_ip)&quot;,
+                        &quot;create index sr_network_port on sip_registrations (network_port)&quot;,
+                        &quot;create index sr_sip_username on sip_registrations (sip_username)&quot;,
+                        &quot;create index sr_sip_realm on sip_registrations (sip_realm)&quot;,
+                        &quot;create index ss_call_id on sip_subscriptions (call_id)&quot;,
+                        &quot;create index ss_hostname on sip_subscriptions (hostname)&quot;,
+                        &quot;create index ss_hostname on sip_subscriptions (network_ip)&quot;,
+                        &quot;create index ss_sip_user on sip_subscriptions (sip_user)&quot;,
+                        &quot;create index ss_sip_host on sip_subscriptions (sip_host)&quot;,
+                        &quot;create index ss_presence_hosts on sip_subscriptions (presence_hosts)&quot;,
+                        &quot;create index ss_event on sip_subscriptions (event)&quot;,
+                        &quot;create index ss_proto on sip_subscriptions (proto)&quot;,
+                        &quot;create index ss_sub_to_user on sip_subscriptions (sub_to_user)&quot;,
+                        &quot;create index ss_sub_to_host on sip_subscriptions (sub_to_host)&quot;,
+                        &quot;create index sd_uuid on sip_dialogs (uuid)&quot;,
+                        &quot;create index sd_hostname on sip_dialogs (hostname)&quot;,
+                        &quot;create index sp_hostname on sip_presence (hostname)&quot;,
+                        &quot;create index sa_nonce on sip_authentication (nonce)&quot;,
+                        &quot;create index sa_hostname on sip_authentication (hostname)&quot;,
+                        &quot;create index ssa_hostname on sip_shared_appearance_subscriptions (hostname)&quot;,
+                        &quot;create index ssa_hostname on sip_shared_appearance_subscriptions (network_ip)&quot;,
+                        &quot;create index ssa_subscriber on sip_shared_appearance_subscriptions (subscriber)&quot;,
+                        &quot;create index ssa_profile_name on sip_shared_appearance_subscriptions (profile_name)&quot;,
+                        &quot;create index ssa_aor on sip_shared_appearance_subscriptions (aor)&quot;,
+                        &quot;create index ssd_profile_name on sip_shared_appearance_dialogs (profile_name)&quot;,
+                        &quot;create index ssd_hostname on sip_shared_appearance_dialogs (hostname)&quot;,
+                        &quot;create index ssd_contact_str on sip_shared_appearance_dialogs (contact_str)&quot;,
+                        &quot;create index ssd_call_id on sip_shared_appearance_dialogs (call_id)&quot;,
+                        &quot;create index ssd_expires on sip_shared_appearance_dialogs (expires)&quot;,
+                        NULL        
+                };
+
+                if (!(profile-&gt;master_odbc = switch_odbc_handle_new(profile-&gt;odbc_dsn, profile-&gt;odbc_user, profile-&gt;odbc_pass))) {
+                        return 0;
+                }
+                if (switch_odbc_handle_connect(profile-&gt;master_odbc) != SWITCH_ODBC_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Connecting ODBC DSN: %s\n&quot;, profile-&gt;odbc_dsn);
+                        return 0;
+                }
+
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Connected ODBC DSN: %s\n&quot;, profile-&gt;odbc_dsn);
+                
+                test_sql = switch_mprintf(&quot;delete from sip_registrations where (contact like '%%TCP%%' &quot;
+                                                                  &quot;or status like '%%TCP%%' or status like '%%TLS%%') and hostname='%q' &quot;
+                                                                  &quot;and network_ip!='-1' and network_port!='-1' and sip_username != '-1'&quot;, 
+                                                                  mod_sofia_globals.hostname);
+
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, &quot;DROP TABLE sip_registrations&quot;, NULL);
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, reg_sql, NULL);
+                }
+                free(test_sql);
+
+
+                test_sql = switch_mprintf(&quot;delete from sip_subscriptions where hostname='%q' and network_ip!='-1' and network_port!='-1'&quot;, mod_sofia_globals.hostname);
+
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, &quot;DROP TABLE sip_subscriptions&quot;, NULL);
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, sub_sql, NULL);
+                }
+
+                free(test_sql);
+                test_sql = switch_mprintf(&quot;delete from sip_dialogs where hostname='%q'&quot;, mod_sofia_globals.hostname);
+
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, &quot;DROP TABLE sip_dialogs&quot;, NULL);
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, dialog_sql, NULL);
+                }
+
+                test_sql = switch_mprintf(&quot;delete from sip_presence where hostname='%q'&quot;, mod_sofia_globals.hostname);
+
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, &quot;DROP TABLE sip_presence&quot;, NULL);
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, pres_sql, NULL);
+                }
+
+                free(test_sql);
+                test_sql = switch_mprintf(&quot;delete from sip_authentication where hostname='%q'&quot;, mod_sofia_globals.hostname);
+
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, &quot;DROP TABLE sip_authentication&quot;, NULL);
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, auth_sql, NULL);
+                }
+                free(test_sql);
+
+                test_sql = switch_mprintf(&quot;delete from sip_shared_appearance_subscriptions where contact_str='' or hostname='%q' and network_ip!='-1'&quot;,
+                                                                  mod_sofia_globals.hostname);
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, &quot;DROP TABLE sip_shared_appearance_subscriptions&quot;, NULL);
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, shared_appearance_sql, NULL);
+                }
+                free(test_sql);
+
+
+                test_sql = switch_mprintf(&quot;delete from sip_shared_appearance_dialogs where contact_str='' or hostname='%q' and network_ip!='-1'&quot;,
+                                                                  mod_sofia_globals.hostname);
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, &quot;DROP TABLE sip_shared_appearance_dialogs&quot;, NULL);
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, shared_appearance_dialogs_sql, NULL);
+                }
+                free(test_sql);
+
+
+                for (x = 0; indexes[x]; x++) {
+                        switch_odbc_handle_exec(profile-&gt;master_odbc, indexes[x], NULL);
+                }
+
+
+        } else if (profile-&gt;odbc_dsn) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;ODBC IS NOT AVAILABLE!\n&quot;);
+        } else {
+                if (!(profile-&gt;master_db = switch_core_db_open_file(profile-&gt;dbname))) {
+                        return 0;
+                }
+
+                test_sql = switch_mprintf(&quot;delete from sip_registrations where (contact like '%%TCP%%' &quot;
+                                                                  &quot;or status like '%%TCP%%' or status like '%%TLS%%') and hostname='%q' &quot;
+                                                                  &quot;and network_ip!='-1' and network_port!='-1' and sip_username != '-1'&quot;,
+                                                                  mod_sofia_globals.hostname);
+                
+                switch_core_db_test_reactive(profile-&gt;master_db, test_sql, &quot;DROP TABLE sip_registrations&quot;, reg_sql);
+                free(test_sql);
+
+                test_sql = switch_mprintf(&quot;delete from sip_subscriptions where hostname='%q' and network_ip!='-1'&quot;, mod_sofia_globals.hostname);
+                switch_core_db_test_reactive(profile-&gt;master_db, test_sql, &quot;DROP TABLE sip_subscriptions&quot;, sub_sql);
+                free(test_sql);
+
+                test_sql = switch_mprintf(&quot;delete from sip_dialogs where hostname='%q'&quot;, mod_sofia_globals.hostname);
+                switch_core_db_test_reactive(profile-&gt;master_db, test_sql, &quot;DROP TABLE sip_dialogs&quot;, dialog_sql);
+                free(test_sql);
+
+                test_sql = switch_mprintf(&quot;delete from sip_presence where hostname='%q'&quot;, mod_sofia_globals.hostname);
+                switch_core_db_test_reactive(profile-&gt;master_db, test_sql, &quot;DROP TABLE sip_presence&quot;, pres_sql);
+                free(test_sql);
+
+                test_sql = switch_mprintf(&quot;delete from sip_authentication where hostname='%q'&quot;, mod_sofia_globals.hostname);
+                switch_core_db_test_reactive(profile-&gt;master_db, test_sql, &quot;DROP TABLE sip_authentication&quot;, auth_sql);
+                free(test_sql);
+
+                
+                test_sql = switch_mprintf(&quot;delete from sip_shared_appearance_subscriptions where contact_str = '' or hostname='%q' and network_ip!='-1'&quot;,
+                                                                  mod_sofia_globals.hostname);
+                switch_core_db_test_reactive(profile-&gt;master_db, test_sql, &quot;DROP TABLE sip_shared_appearance_subscriptions&quot;, shared_appearance_sql);
+                free(test_sql);
+
+                test_sql = switch_mprintf(&quot;delete from sip_shared_appearance_dialogs where contact_str = '' or hostname='%q'&quot;, mod_sofia_globals.hostname);
+                switch_core_db_test_reactive(profile-&gt;master_db, test_sql, &quot;DROP TABLE sip_shared_appearance_dialogs&quot;, shared_appearance_dialogs_sql);
+                free(test_sql);
+                
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssa_hostname on sip_shared_appearance_subscriptions (hostname)&quot;, 
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssa_subscriber on sip_shared_appearance_subscriptions (subscriber)&quot;, 
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssa_profile_name on sip_shared_appearance_subscriptions (profile_name)&quot;, 
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssa_aor on sip_shared_appearance_subscriptions (aor)&quot;, NULL, NULL, NULL);
+                
+
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssd_profile_name on sip_shared_appearance_dialogs (profile_name)&quot;, 
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssd_hostname on sip_shared_appearance_dialogs (hostname)&quot;, 
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssd_hostname on sip_shared_appearance_dialogs (network_ip)&quot;, 
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssd_contact_str on sip_shared_appearance_dialogs (contact_str)&quot;,  
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssd_call_id on sip_shared_appearance_dialogs (call_id)&quot;,  
+                                                        NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ssd_expires on sip_shared_appearance_dialogs (expires)&quot;, 
+                                                        NULL, NULL, NULL);
+                
+
+
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_call_id on sip_registrations (call_id)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_sip_user on sip_registrations (sip_user)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_sip_host on sip_registrations (sip_host)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_profile_name on sip_registrations (profile_name)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_presence_hosts on sip_registrations (presence_hosts)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_contact on sip_registrations (contact)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_expires on sip_registrations (expires)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_hostname on sip_registrations (hostname)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_status on sip_registrations (status)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_network_ip on sip_registrations (network_ip)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_network_port on sip_registrations (network_port)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_sip_username on sip_registrations (sip_username)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sr_sip_realm on sip_registrations (sip_realm)&quot;, NULL, NULL, NULL);
+
+
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_call_id on sip_subscriptions (call_id)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_hostname on sip_subscriptions (hostname)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_hostname on sip_subscriptions (network_ip)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_sip_user on sip_subscriptions (sip_user)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_sip_host on sip_subscriptions (sip_host)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_presence_hosts on sip_subscriptions (presence_hosts)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_event on sip_subscriptions (event)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_proto on sip_subscriptions (proto)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_sub_to_user on sip_subscriptions (sub_to_user)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists ss_sub_to_host on sip_subscriptions (sub_to_host)&quot;, NULL, NULL, NULL);
+
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sd_uuid on sip_dialogs (uuid)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sd_hostname on sip_dialogs (hostname)&quot;, NULL, NULL, NULL);
+
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sp_hostname on sip_presence (hostname)&quot;, NULL, NULL, NULL);
+
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sa_nonce on sip_authentication (nonce)&quot;, NULL, NULL, NULL);
+                switch_core_db_exec(profile-&gt;master_db, &quot;create index if not exists sa_hostname on sip_authentication (hostname)&quot;, NULL, NULL, NULL);
+        }
+
+        if (switch_odbc_available() &amp;&amp; profile-&gt;odbc_dsn) {
+                return profile-&gt;master_odbc ? 1 : 0;
+        }
+
+        return profile-&gt;master_db ? 1 : 0;
+}
+
+void sofia_glue_sql_close(sofia_profile_t *profile)
+{
+        if (switch_odbc_available() &amp;&amp; profile-&gt;master_odbc) {
+                switch_odbc_handle_destroy(&amp;profile-&gt;master_odbc);
+        } else {
+                switch_core_db_close(profile-&gt;master_db);
+                profile-&gt;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 &amp;&amp; *sqlp);
+        sql = *sqlp;
+
+        if (profile-&gt;sql_queue) {
+                if (sql_already_dynamic) {
+                        d_sql = sql;
+                } else {
+                        d_sql = strdup(sql);
+                }
+
+                switch_assert(d_sql);
+                if ((status = switch_queue_trypush(profile-&gt;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-&gt;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() &amp;&amp; profile-&gt;odbc_dsn) {
+                switch_odbc_statement_handle_t stmt;
+                if (switch_odbc_handle_exec(profile-&gt;master_odbc, sql, &amp;stmt) != SWITCH_ODBC_SUCCESS) {
+                        char *err_str;
+                        err_str = switch_odbc_handle_get_error(profile-&gt;master_odbc, stmt);
+                        if (!switch_strlen_zero(err_str)) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;ERR: [%s]\n[%s]\n&quot;, sql, err_str);
+                        }
+                        switch_safe_free(err_str);
+                }
+                switch_odbc_statement_handle_free(&amp;stmt);
+        } else if (profile-&gt;odbc_dsn) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;ODBC IS NOT AVAILABLE!\n&quot;);
+        } else {
+                if (master) {
+                        db = profile-&gt;master_db;
+                } else {
+                        if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;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() &amp;&amp; profile-&gt;odbc_dsn) {
+                switch_odbc_handle_callback_exec(profile-&gt;master_odbc, sql, callback, pdata);
+        } else if (profile-&gt;odbc_dsn) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;ODBC IS NOT AVAILABLE!\n&quot;);
+        } else {
+
+                if (master) {
+                        db = profile-&gt;master_db;
+                } else {
+                        if (!(db = switch_core_db_open_file(profile-&gt;dbname))) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
+                                goto end;
+                        }
+                }
+
+                switch_core_db_exec(db, sql, callback, pdata, &amp;errmsg);
+
+                if (errmsg) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;SQL ERR: [%s] %s\n&quot;, sql, errmsg);
+                        free(errmsg);
+                }
+
+                if (!master &amp;&amp; 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-&gt;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() &amp;&amp; profile-&gt;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-&gt;dbname))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
+                goto end;
+        }
+
+        if (switch_core_db_prepare(db, sql, -1, &amp;stmt, 0)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Statement Error [%s]!\n&quot;, sql);
+                goto fail;
+        } else {
+                int running = 1;
+                int colcount;
+
+                while (running &lt; 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)) &gt; 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 &amp;&amp; (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, &quot;rpid&quot;)) {
+                return CID_TYPE_RPID;
+        }
+
+        if (!strcasecmp(name, &quot;pid&quot;)) {
+                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-&gt;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 &lt; and &gt; */
+        if (!(contact = sofia_glue_get_url_from_contact(data, 1))) {
+                goto mem_fail;
+        }
+
+        if((eoc = strstr(contact, &quot;;fs_path=&quot;))) {
+                *eoc = '\0';
+
+                if(!(route = strdup(eoc + 9))) {
+                        goto mem_fail;
+                }
+
+                for (p = route; p &amp;&amp; *p ; p++) {
+                        if (*p == '&gt;' || *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 &gt; route_uri) &amp;&amp; *p == ' ');
+                }
+        } 
+        
+        if (!(to = strdup(data))) {
+                goto mem_fail;
+        }
+
+        if((eoc = strstr(to, &quot;;fs_path=&quot;))) {
+                *eoc++ = '&gt;';        
+                *eoc = '\0';        
+        }
+        
+        if ((p = strstr(contact, &quot;;fs_&quot;))) {
+                *p = '\0';
+        }
+        
+        dst-&gt;contact = contact;
+        dst-&gt;to = to;
+        dst-&gt;route = route;
+        dst-&gt;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-&gt;contact);
+                switch_safe_free(dst-&gt;route);
+                switch_safe_free(dst-&gt;route_uri);
+                switch_safe_free(dst-&gt;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:
+ */
</ins></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_presencecfromrev14389freeswitchtrunksrcmodendpointsmod_sofiasofia_presencec"></a>
<div class="copfile"><h4>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)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,2195 @@
</span><ins>+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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 &lt;anthm@freeswitch.org&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ * Ken Rice, Asteria Solutions Group, Inc &lt;ken@asteriasgi.com&gt;
+ * Paul D. Tinsley &lt;pdt at jackhammer.org&gt;
+ * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
+ *
+ *
+ * sofia_presence.c -- SOFIA SIP Endpoint (presence code)
+ *
+ */
+#include &quot;mod_sofia.h&quot;
+
+#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 = &quot;text/html&quot;;
+        sofia_destination_t *dst = NULL;
+
+        if (!to) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing To: header.\n&quot;);
+                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,
+                                                  &quot;Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n&quot;, proto, from, to,
+                                                  body ? body : &quot;[no body]&quot;, prof ? prof : &quot;NULL&quot;);
+                goto end;
+        }
+
+        if (switch_strlen_zero(host)) {
+                host = profile-&gt;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, &quot;Cannot find user. [%s][%s]\n&quot;, 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, &quot;Memory Error!\n&quot;);
+                        goto end;
+                }
+
+                if ((p = strchr(fp, '@'))) {
+                        *p++ = '\0';
+                }
+
+                if (switch_strlen_zero(p)) {
+                        p = profile-&gt;domain_name;
+                        if (switch_strlen_zero(p)) {
+                                p = host;
+                        }
+                }
+
+                ffrom = switch_mprintf(&quot;\&quot;%s\&quot; &lt;sip:%s+%s@%s&gt;&quot;, 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, &quot;Memory Error!\n&quot;);
+                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-&gt;nua, NULL, TAG_IF(dst-&gt;route_uri, NUTAG_PROXY(dst-&gt;route_uri)), TAG_IF(dst-&gt;route, SIPTAG_ROUTE_STR(dst-&gt;route)),
+                                                SIPTAG_FROM_STR(from), NUTAG_URL(contact),
+                                                SIPTAG_TO_STR(dst-&gt;to), SIPTAG_CONTACT_STR(profile-&gt;url),
+                                                TAG_END());
+        nua_handle_bind(msg_nh, &amp;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-&gt;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(
+                                                          &quot;select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,&quot;
+                                                          &quot;full_via,expires,user_agent,accept,profile_name,network_ip&quot;
+                                                          &quot;,-1,'unavailable','unavailable' from sip_subscriptions where event='presence' and hostname='%q'&quot;, 
+                                                          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, &amp;val);
+                        profile = (sofia_profile_t *) val;
+                        if (profile-&gt;pres_type != PRES_TYPE_FULL) {
+                                continue;
+                        }
+                        helper.profile = profile;
+                        helper.event = NULL;
+                        if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, sofia_presence_sub_callback, &amp;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-&gt;ireg_mutex,
+                                                                                &quot;select sip_user,sip_host,'Registered','unknown','' from sip_registrations&quot;,
+                                                                                sofia_presence_resub_callback, profile) != SWITCH_TRUE) {
+                return;
+        }
+
+        if (sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex,
+                                                                                &quot;select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions &quot;
+                                                                                &quot;where proto='ext' or proto='user' or proto='conf'&quot;, sofia_presence_resub_callback, profile) != SWITCH_TRUE) {
+                return;
+        }
+}
+
+char *sofia_presence_translate_rpid(char *in, char *ext)
+{
+        char *r = in;
+
+        if (in &amp;&amp; (switch_stristr(&quot;null&quot;, in))) {
+                in = NULL;
+        }
+
+        if (!in) {
+                in = ext;
+        }
+
+        if (!in) {
+                return NULL;
+        }
+
+        if (!strcasecmp(in, &quot;dnd&quot;) || !strcasecmp(in, &quot;idle&quot;)) {
+                r = &quot;busy&quot;;
+        }
+
+        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, &quot;mwi-message-account&quot;))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing required Header 'MWI-Message-Account'\n&quot;);
+                return;
+        }
+
+        if (!(yn = switch_event_get_header(event, &quot;mwi-messages-waiting&quot;))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Missing required Header 'MWI-Messages-Waiting'\n&quot;);
+                return;
+        }
+
+        call_id = switch_event_get_header(event, &quot;call-id&quot;);
+        sub_call_id = switch_event_get_header(event, &quot;sub-call-id&quot;);
+
+        if (!call_id &amp;&amp; !sub_call_id) {
+                for_everyone = 1;
+        }
+
+
+        dup_account = strdup(account);
+        switch_assert(dup_account != NULL);
+        sofia_glue_get_user_host(dup_account, &amp;user, &amp;host);
+
+
+        if ((pname = switch_event_get_header(event, &quot;sofia-profile&quot;))) {
+                if (!(profile = sofia_glue_find_profile(pname))) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;No profile %s\n&quot;, pname);
+                }
+        }
+
+        if (!profile) {
+                if (!host || !(profile = sofia_glue_find_profile(host))) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Cannot find profile %s\n&quot;, switch_str_nil(host));
+                        switch_safe_free(dup_account);
+                        return;
+                }
+        }
+
+        if (profile-&gt;domain_name &amp;&amp; strcasecmp(profile-&gt;domain_name, host)) {
+                host = profile-&gt;domain_name;
+        }
+
+        h.profile = profile;
+        h.total = 0;
+
+        SWITCH_STANDARD_STREAM(stream);
+
+        for (hp = event-&gt;headers; hp; hp = hp-&gt;next) {
+                if (!strncasecmp(hp-&gt;name, &quot;mwi-&quot;, 4)) {
+                        char *tmp = NULL;
+                        char *value = hp-&gt;value;
+                        if (!strcasecmp(hp-&gt;name, &quot;mwi-message-account&quot;) &amp;&amp; strncasecmp(hp-&gt;value, &quot;sip:&quot;, 4)) {
+                                tmp = switch_mprintf(&quot;sip:%s&quot;, hp-&gt;value);
+                                value = tmp;
+                        }
+                        stream.write_function(&amp;stream, &quot;%s: %s\r\n&quot;, hp-&gt;name + 4, value);
+                        switch_safe_free(tmp);
+                }
+        }
+
+        stream.write_function(&amp;stream, &quot;\r\n&quot;);
+        
+        sql = NULL;
+
+        if (for_everyone) {
+                sql = switch_mprintf(&quot;select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,&quot;
+                                                         &quot;full_via,expires,user_agent,accept,profile_name,network_ip&quot;
+                                                         &quot;,'%q','%q' from sip_subscriptions where event='message-summary' &quot;
+                                                         &quot;and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')&quot;,
+                                                         stream.data, host, user, host, host);
+        } else if (sub_call_id) {
+                sql = switch_mprintf(&quot;select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,&quot;
+                                                         &quot;full_via,expires,user_agent,accept,profile_name,network_ip&quot;
+                                                         &quot;,'%q','%q' from sip_subscriptions where event='message-summary' &quot;
+                                                         &quot;and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%' and call_id='%q')&quot;,
+                                                         stream.data, host, user, host, host, sub_call_id);
+        }
+
+
+        if (sql) {
+                sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, sofia_presence_mwi_callback, &amp;h);
+                free(sql);
+                sql = NULL;
+                
+        }
+
+        if (for_everyone) {
+                sql = switch_mprintf(&quot;select sip_user,sip_host,contact,profile_name,network_ip,'%q' &quot;
+                                                         &quot;from sip_registrations where sip_user='%q' and sip_host='%q'&quot;, 
+                                                         stream.data, user, host);
+        } else if (call_id) {
+                sql = switch_mprintf(&quot;select sip_user,sip_host,contact,profile_name,network_ip,'%q' &quot;
+                                                         &quot;from sip_registrations where sip_user='%q' and sip_host='%q' and call_id='%q'&quot;, 
+                                                         stream.data, user, host, call_id);
+        }
+
+        if (sql) {
+                switch_assert(sql != NULL);
+                sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, sofia_presence_mwi_callback2, &amp;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, &quot;from&quot;);
+        char *proto = switch_event_get_header(event, &quot;proto&quot;);
+        char *rpid = switch_event_get_header(event, &quot;rpid&quot;);
+        char *status = switch_event_get_header(event, &quot;status&quot;);
+        char *event_type = switch_event_get_header(event, &quot;event_type&quot;);
+        char *alt_event_type = switch_event_get_header(event, &quot;alt_event_type&quot;);
+        char *sql = NULL;
+        char *euser = NULL, *user = NULL, *host = NULL;
+
+        if (!mod_sofia_globals.running) {
+                return;
+        }
+
+        if (rpid &amp;&amp; !strcasecmp(rpid, &quot;n/a&quot;)) {
+                rpid = NULL;
+        }
+
+        if (status &amp;&amp; !strcasecmp(status, &quot;n/a&quot;)) {
+                status = NULL;
+        }
+        
+        if (status &amp;&amp; switch_stristr(&quot;CS_HANGUP&quot;, status)) {
+                status = &quot;Call Ended&quot;;
+        }
+
+        if (rpid) {
+                rpid = sofia_presence_translate_rpid(rpid, status);
+        }
+        
+        if (event-&gt;event_id == SWITCH_EVENT_ROSTER) {
+                struct presence_helper helper = { 0 };
+
+                if (!mod_sofia_globals.profile_hash)
+                        return;
+
+                if (from) {
+                        sql = switch_mprintf(
+                                                                 &quot;select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,&quot;
+                                                                 &quot;sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,&quot;
+                                                                 &quot;sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,&quot;
+                                                                 &quot;sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,&quot;
+                                                                 &quot;sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip&quot;
+                                                                 &quot;,1,'%q','%q',sip_presence.status,sip_presence.rpid &quot;
+                                                                 &quot;from sip_subscriptions left join sip_presence on &quot;
+                                                                 &quot;(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and &quot;
+                                                                 &quot;sip_subscriptions.profile_name=sip_presence.profile_name) &quot;
+                                                                 &quot;where sip_subscriptions.event='presence' and sip_subscriptions.full_from like '%%%q%%'&quot;, 
+                                                                 switch_str_nil(status), switch_str_nil(rpid), from);
+                } else {
+                        sql = switch_mprintf(
+                                                                 &quot;select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,&quot;
+                                                                 &quot;sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,&quot;
+                                                                 &quot;sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,&quot;
+                                                                 &quot;sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,&quot;
+                                                                 &quot;sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip&quot;
+                                                                 &quot;,1,'%q','%q',sip_presence.status,sip_presence.rpid &quot;
+                                                                 &quot;from sip_subscriptions left join sip_presence on &quot;
+                                                                 &quot;(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and &quot;
+                                                                 &quot;sip_subscriptions.profile_name=sip_presence.profile_name) &quot;
+                                                                 &quot;where sip_subscriptions.event='presence'&quot;, 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, &amp;var, NULL, &amp;val);
+                        profile = (sofia_profile_t *) val;
+
+                        if (strcmp((char *)var, profile-&gt;name)) {
+                                if (mod_sofia_globals.debug_presence &gt; 0) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;%s is an alias, skipping\n&quot;, (char *) var);
+                                }
+                                continue;
+                        }
+                        if (profile-&gt;pres_type != PRES_TYPE_FULL) {
+                                if (mod_sofia_globals.debug_presence &gt; 0) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;%s is passive, skipping\n&quot;, (char *) var);
+                                }
+                                continue;
+                        }
+                        helper.profile = profile;
+                        helper.event = NULL;
+                        sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, sofia_presence_sub_callback, &amp;helper);
+                }
+                switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+                free(sql);
+                return;
+        }
+
+        if (switch_strlen_zero(event_type)) {
+                event_type = &quot;presence&quot;;
+        }
+
+        if (switch_strlen_zero(alt_event_type)) {
+                alt_event_type = &quot;presence&quot;;
+        }
+
+        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-&gt;event_id) {
+        case SWITCH_EVENT_PRESENCE_PROBE:
+                if (proto) {
+                        char *to = switch_event_get_header(event, &quot;to&quot;);
+                        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 &amp;&amp; probe_host &amp;&amp; (profile = sofia_glue_find_profile(probe_host))) {
+                                sql = switch_mprintf(&quot;select sip_registrations.sip_user, '%q', sip_registrations.status, &quot;
+                                                                         &quot;sip_registrations.rpid,'', sip_dialogs.uuid, sip_dialogs.state, sip_dialogs.direction, &quot;
+                                                                         &quot;sip_dialogs.sip_to_user, sip_dialogs.sip_to_host, sip_presence.status,sip_presence.rpid &quot;
+                                                                         &quot;from sip_registrations left join sip_dialogs on &quot;
+                                                                         &quot;(sip_dialogs.sip_from_user = sip_registrations.sip_user &quot;
+                                                                         &quot;and sip_dialogs.sip_from_host = sip_registrations.sip_host) &quot;
+                                                                         &quot;left join sip_presence on &quot;
+                                                                         &quot;(sip_registrations.sip_user=sip_presence.sip_user and sip_registrations.sip_host=sip_presence.sip_host and &quot;
+                                                                         &quot;sip_registrations.profile_name=sip_presence.profile_name) &quot;
+                                                                         &quot;where sip_registrations.sip_user='%q' and &quot;
+                                                                         &quot;(sip_registrations.sip_host='%q' or sip_registrations.presence_hosts like '%%%q%%')&quot;, 
+                                                                         probe_host, probe_euser, probe_host, probe_host);
+                                switch_assert(sql);
+
+                                
+                                if (mod_sofia_globals.debug_presence &gt; 0) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;%s START_PRESENCE_PROBE_SQL\n&quot;, profile-&gt;name);
+                                }
+
+                                if (mod_sofia_globals.debug_presence &gt; 1) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;%s DUMP PRESENCE_PROBE_SQL:\n%s\n&quot;, profile-&gt;name, sql);
+                                }
+
+                                sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, sofia_presence_resub_callback, profile);
+                                if (mod_sofia_globals.debug_presence &gt; 0) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;%s END_PRESENCE_PROBE_SQL\n\n&quot;, profile-&gt;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, &amp;var, NULL, &amp;val);
+                profile = (sofia_profile_t *) val;
+
+                if (strcmp((char *)var, profile-&gt;name)) {
+                        if (mod_sofia_globals.debug_presence &gt; 0) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;%s is an alias, skipping\n&quot;, (char *) var);
+                        }
+                        continue;
+                }
+
+                if (profile-&gt;pres_type != PRES_TYPE_FULL) {
+                        if (mod_sofia_globals.debug_presence &gt; 0) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;%s is passive, skipping\n&quot;, (char *) var);
+                        }
+                        continue;
+                }
+                
+
+                if ((sql = switch_mprintf(
+                                                         
+                                                         &quot;select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,&quot;
+                                                         &quot;sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,&quot;
+                                                         &quot;sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,&quot;
+                                                         &quot;sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,&quot;
+                                                         &quot;sip_subscriptions.accept,sip_subscriptions.profile_name&quot;
+                                                         &quot;,'%q','%q','%q',sip_presence.status,sip_presence.rpid &quot;
+                                                         &quot;from sip_subscriptions &quot;
+                                                         &quot;left join sip_presence on &quot;
+                                                         &quot;(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and &quot;
+                                                         &quot;sip_subscriptions.profile_name=sip_presence.profile_name) &quot;
+                                                         &quot;where (event='%q' or event='%q') and sub_to_user='%q' &quot;
+                                                         &quot;and (sub_to_host='%q' or presence_hosts like '%%%q%%') &quot;
+                                                         &quot;and (sip_subscriptions.profile_name = '%q' or sip_subscriptions.presence_hosts != sip_subscriptions.sub_to_host)&quot;,
+                                                         switch_str_nil(status), switch_str_nil(rpid), host, event_type, alt_event_type, euser, host, host, profile-&gt;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 &gt; 0) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;%s START_PRESENCE_SQL (%s)\n&quot;, 
+                                                                  event-&gt;event_id == SWITCH_EVENT_PRESENCE_IN ? &quot;IN&quot; : &quot;OUT&quot;, profile-&gt;name);
+                        }
+
+                        if (mod_sofia_globals.debug_presence) {
+                                char *buf;
+                                switch_event_serialize(event, &amp;buf, SWITCH_FALSE);
+                                switch_assert(buf);
+                                if (mod_sofia_globals.debug_presence &gt; 1) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;DUMP PRESENCE SQL:\n%s\nEVENT DUMP:\n%s\n&quot;, sql, buf);
+                                } else {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;EVENT DUMP:\n%s\n&quot;, buf);
+                                }
+                                free(buf);
+                        }
+
+                        sofia_glue_execute_sql_callback(profile, SWITCH_FALSE,
+                                                                                        NULL, sql, sofia_presence_sub_callback, &amp;helper);
+
+                        if (mod_sofia_globals.debug_presence &gt; 0) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;%s END_PRESENCE_SQL (%s)\n&quot;, 
+                                                                  event-&gt;event_id == SWITCH_EVENT_PRESENCE_IN ? &quot;IN&quot; : &quot;OUT&quot;, profile-&gt;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) &amp;&amp; (!last || strcmp(last, this_sql))) {
+                                                sofia_glue_execute_sql(profile, &amp;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, &quot;Event Thread Started\n&quot;);
+
+        while (mod_sofia_globals.running == 1) {
+                int count = 0;
+                
+                if (switch_queue_trypop(mod_sofia_globals.presence_queue, &amp;pop) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_t *event = (switch_event_t *) pop;
+
+                        if (!pop) {
+                                break;
+                        }
+                        actual_sofia_presence_event_handler(event);
+                        switch_event_destroy(&amp;event);
+                        count++;
+                }
+
+                if (switch_queue_trypop(mod_sofia_globals.mwi_queue, &amp;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(&amp;event);
+                        count++;
+                }
+
+                if (!count) {
+                        switch_yield(100000);
+                }
+        }
+
+        while (switch_queue_trypop(mod_sofia_globals.presence_queue, &amp;pop) == SWITCH_STATUS_SUCCESS &amp;&amp; pop) {
+                switch_event_t *event = (switch_event_t *) pop;
+                switch_event_destroy(&amp;event);
+        }
+
+        while (switch_queue_trypop(mod_sofia_globals.mwi_queue, &amp;pop) == SWITCH_STATUS_SUCCESS &amp;&amp; pop) {
+                switch_event_t *event = (switch_event_t *) pop;
+                switch_event_destroy(&amp;event);
+        }
+
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, &quot;Event Thread Ended\n&quot;);
+
+        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(&amp;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(&amp;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(&amp;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(&amp;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, &quot;message-summary&quot;)) {
+                if (switch_event_create(&amp;event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;Message-Account&quot;, &quot;sip:%s@%s&quot;, user, host);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;VM-Sofia-Profile&quot;, profile-&gt;name);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;VM-sub-call-id&quot;, argv[7]);
+                        switch_event_fire(&amp;event);
+                }
+                return 0;
+        }
+
+        if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, user, host);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_subtype&quot;, &quot;probe&quot;);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto-specific-event-name&quot;, event_name);
+                switch_event_fire(&amp;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] = &quot;&quot;;
+
+        if (argc &gt; 5) {
+                uuid = switch_str_nil(argv[5]);
+                state = switch_str_nil(argv[6]);
+                direction = switch_str_nil(argv[7]);
+                if (argc &gt; 8) {
+                        switch_set_string(to_buf, argv[8]);
+                        switch_url_decode(to_buf);
+                        to_user = to_buf;
+                }
+                if (argc &gt; 10 &amp;&amp; !switch_strlen_zero(argv[9]) &amp;&amp; !switch_strlen_zero(argv[10])) {
+                        status = argv[9];
+                        rpid = argv[10];
+                }
+        }
+
+        if (switch_strlen_zero(proto)) {
+                proto = NULL;
+        }
+
+        if (mod_sofia_globals.debug_presence &gt; 0) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;%s PRESENCE_PROBE %s@%s\n&quot;, profile-&gt;name, user, host);
+        }
+
+        if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, proto ? proto : SOFIA_CHAT_PROTO);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, user, host);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, status);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;alt_event_type&quot;, &quot;dialog&quot;);
+                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;event_count&quot;, &quot;%d&quot;, 0);
+
+                if (!switch_strlen_zero(to_user)) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;to-user&quot;, to_user);
+                }
+                
+                if (switch_strlen_zero(state)) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;unique-id&quot;, SOFIA_CHAT_PROTO);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;channel-state&quot;, &quot;CS_HANGUP&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;answer-state&quot;, &quot;resubscribe&quot;);
+                } else {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;channel-state&quot;, &quot;CS_ROUTING&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;unique-id&quot;, uuid);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;answer-state&quot;, state);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;astate&quot;, state);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;presence-call-direction&quot;, direction);
+                }
+
+                switch_event_fire(&amp;event);
+        }
+
+        return 0;
+}
+
+static char *translate_rpid(char *in)
+{
+        char *r = in;
+
+        if (in &amp;&amp; (strstr(in, &quot;null&quot;) || strstr(in, &quot;NULL&quot;))) {
+                in = NULL;
+        }
+
+        if (!in || !strcasecmp(in, &quot;unknown&quot;)) {
+                r = &quot;online&quot;;
+                goto end;
+        }
+
+        if (!strcasecmp(in, &quot;busy&quot;)) {
+                r = in;
+                goto end;
+        }
+
+        if (!strcasecmp(in, &quot;unavailable&quot;)) {
+                r = &quot;away&quot;;
+                goto end;
+        }
+
+        if (!strcasecmp(in, &quot;idle&quot;)) {
+                r = &quot;busy&quot;;
+        }
+
+  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(&quot;polycom&quot;, user_agent)) {
+                *ct = &quot;application/xpidf+xml&quot;;
+                
+                /* of course!, lets make a big deal over dashes. Now the stupidity is complete. */
+
+                if (!strcmp(prpid, &quot;on-the-phone&quot;)) {
+                        prpid = &quot;onthephone&quot;;
+                }
+
+                ret = switch_mprintf(
+                                                          &quot;&lt;?xml version=\&quot;1.0\&quot;?&gt;\n&quot;
+                                                          &quot;&lt;!DOCTYPE presence PUBLIC \&quot;-//IETF//DTD RFCxxxx XPIDF 1.0//EN\&quot; \&quot;xpidf.dtd\&quot;&gt;\n&quot;
+                                                          &quot;&lt;presence&gt;\n&quot;
+                                                          &quot; &lt;status&gt;\n&quot;
+                                                          &quot;  &lt;note&gt;%s&lt;/note&gt;\n&quot;
+                                                          &quot; &lt;/status&gt;\n&quot;
+                                                          &quot; &lt;presentity uri=\&quot;%s;method=SUBSCRIBE\&quot; /&gt;\n&quot;
+                                                          &quot; &lt;atom id=\&quot;%s\&quot;&gt;\n&quot;
+                                                          &quot;  &lt;address uri=\&quot;%s;user=ip\&quot; priority=\&quot;0.800000\&quot;&gt;\n&quot;
+                                                          &quot;   &lt;status status=\&quot;%s\&quot; /&gt;\n&quot;
+                                                          &quot;   &lt;msnsubstatus substatus=\&quot;%s\&quot; /&gt;\n&quot;
+                                                          &quot;  &lt;/address&gt;\n&quot;
+                                                          &quot; &lt;/atom&gt;\n&quot;
+                                                          &quot;&lt;/presence&gt;\n&quot;, status, id, id, url, open, prpid
+                                                          );
+        } else {
+                *ct = &quot;application/pidf+xml&quot;;
+                ret = switch_mprintf(
+                                                          &quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;ISO-8859-1\&quot;?&gt; \n&quot;
+                                                          &quot;&lt;presence xmlns='urn:ietf:params:xml:ns:pidf' \n&quot;
+                                                          &quot;xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model' \n&quot;
+                                                          &quot;xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid' \n&quot;
+                                                          &quot;xmlns:c='urn:ietf:params:xml:ns:pidf:cipid' entity='%s'&gt;\n&quot;
+                                                          
+                                                          &quot; &lt;tuple id='t6a5ed77e'&gt;\n&quot;
+                                                          &quot;  &lt;status&gt;\r\n&quot;
+                                                          &quot;   &lt;basic&gt;%s&lt;/basic&gt;\n&quot;
+                                                          &quot;  &lt;/status&gt;\n&quot;
+                                                          &quot; &lt;/tuple&gt;\n&quot;
+                                                          &quot; &lt;dm:person id='p06360c4a'&gt;\n&quot;
+                                                          &quot;  &lt;rpid:activities&gt;\r\n&quot; 
+                                                          &quot;   &lt;rpid:%s/&gt;\n&quot;
+                                                          &quot;  &lt;/rpid:activities&gt;\n&quot;
+                                                          &quot;  &lt;dm:note&gt;%s&lt;/dm:note&gt;\n&quot;
+                                                          &quot; &lt;/dm:person&gt;\n&quot;
+                                                          &quot;&lt;/presence&gt;&quot;, 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 = &quot;no/idea&quot;;
+        time_t exptime = switch_epoch_time_now(NULL) + 3600;
+        int is_dialog = 0;
+        sofia_profile_t *ext_profile = NULL, *profile = helper-&gt;profile;
+        char sstr[128] = &quot;&quot;;
+        int kill_handle = 0;
+        char expires_str[10] = &quot;&quot;;
+
+        if (argc &gt; 18 &amp;&amp; !switch_strlen_zero(argv[17]) &amp;&amp; !switch_strlen_zero(argv[18])) {
+                status = argv[17];
+                rpid = argv[18];
+        }
+
+        in = helper-&gt;event &amp;&amp; helper-&gt;event-&gt;event_id == SWITCH_EVENT_PRESENCE_IN;
+
+
+        if (switch_strlen_zero(rpid)) {
+                rpid = &quot;unknown&quot;;
+        }
+
+        if (switch_strlen_zero(status)) {
+                if (!strcasecmp(rpid, &quot;busy&quot;)) {
+                        status = &quot;Busy&quot;;
+                } else if (!strcasecmp(rpid, &quot;unavailable&quot;)) {
+                        status = &quot;Idle&quot;;
+                } else if (!strcasecmp(rpid, &quot;away&quot;)) {
+                        status = &quot;Idle&quot;;
+                } else {
+                        status = &quot;Available&quot;;
+                }
+        }
+        
+        if (profile_name &amp;&amp; strcasecmp(profile_name, helper-&gt;profile-&gt;name)) {
+        if ((ext_profile = sofia_glue_find_profile(profile_name))) {
+            profile = ext_profile;
+        }
+    }
+        
+        if (!(nh = nua_handle_by_call_id(profile-&gt;nua, call_id))) {
+                goto end;
+        }
+        
+        if (expires) {
+                long tmp = atol(expires);
+                if (tmp &gt; 0) {
+                        exptime = tmp - switch_epoch_time_now(NULL) - SUB_OVERLAP;
+                } else {
+                        exptime = tmp;
+                }
+        }
+        
+        if (!rpid) {
+                rpid = &quot;unknown&quot;;
+        }
+
+        prpid = translate_rpid(rpid);
+
+        if (!strcasecmp(proto, SOFIA_CHAT_PROTO)) {
+                clean_id = switch_mprintf(&quot;sip:%s@%s&quot;, sub_to_user, sub_to_host);
+        } else {
+                clean_id = switch_mprintf(&quot;sip:%s+%s@%s&quot;, proto, sub_to_user, sub_to_host);
+        }
+
+        if (mod_sofia_globals.debug_presence &gt; 0) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, 
+                                                  &quot;SEND PRESENCE\nTo:      \t%s@%s\nFrom:    \t%s@%s\nCall-ID:  \t%s\nProfile:\t%s [%s]\n\n&quot;, 
+                                                  user, host, sub_to_user, sub_to_host, call_id, profile_name, helper-&gt;profile-&gt;name);
+        }
+
+        if (!strcasecmp(sub_to_host, host)) {
+                /* same host */
+                id = switch_mprintf(&quot;sip:%s+%s@%s&quot;, proto, sub_to_user, sub_to_host);
+        } else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) {
+                /*encapsulate */
+                id = switch_mprintf(&quot;sip:%s+%s+%s@%s&quot;, proto, sub_to_user, sub_to_host, host);
+        } else {
+                id = switch_mprintf(&quot;sip:%s@%s&quot;, sub_to_user, sub_to_host);
+        }
+
+        to = switch_mprintf(&quot;sip:%s@%s&quot;, user, host);
+
+        is_dialog = !strcmp(event, &quot;dialog&quot;);
+
+        if (helper-&gt;event) {
+                switch_stream_handle_t stream = { 0 };
+                const char *direction = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;presence-call-direction&quot;));
+                const char *uuid = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;unique-id&quot;));
+                const char *state = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;channel-state&quot;));
+                const char *event_status = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;status&quot;));
+                const char *astate = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;astate&quot;));
+                const char *answer_state = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;answer-state&quot;));
+                const char *dft_state;
+                const char *from_id = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;Other-Leg-Caller-ID-Number&quot;));
+                const char *to_user = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;variable_sip_to_user&quot;));
+                const char *from_user = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;variable_sip_from_user&quot;));
+                char *clean_to_user = NULL;
+                char *clean_from_user = NULL;
+                const char *p_to_user = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;to-user&quot;));
+#if 0
+                char *buf;
+                switch_event_serialize(helper-&gt;event, &amp;buf, SWITCH_FALSE);
+                switch_assert(buf);
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;CHANNEL_DATA:\n%s\n&quot;, buf);
+                free(buf);
+#endif
+
+                if (is_dialog) {
+                        SWITCH_STANDARD_STREAM(stream);
+                }
+
+                if (!strcasecmp(direction, &quot;outbound&quot;)) {
+                        direction = &quot;recipient&quot;;
+                        dft_state = &quot;early&quot;;
+                } else {
+                        direction = &quot;initiator&quot;;
+                        dft_state = &quot;confirmed&quot;;
+                }
+
+                if ((!strcasecmp(state, &quot;cs_execute&quot;) &amp;&amp; !strstr(event_status, &quot;hold&quot;)) || !strcasecmp(state, &quot;cs_reporting&quot;)) {
+                        goto end;
+                }
+
+                if (!strcasecmp(event_status, &quot;Registered&quot;)) {
+                        answer_state = &quot;resubscribe&quot;;
+                }
+
+                if (is_dialog) {
+                        stream.write_function(&amp;stream,
+                                                                  &quot;&lt;?xml version=\&quot;1.0\&quot;?&gt;\n&quot;
+                                                                  &quot;&lt;dialog-info xmlns=\&quot;urn:ietf:params:xml:ns:dialog-info\&quot; &quot;
+                                                                  &quot;version=\&quot;%s\&quot; state=\&quot;%s\&quot; entity=\&quot;%s\&quot;&gt;\n&quot;,
+                                                                  switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;event_count&quot;)),
+                                                                  !strcasecmp(answer_state, &quot;resubscribe&quot;) ? &quot;partial&quot; : &quot;full&quot;, clean_id);
+                }
+
+                if (strcasecmp(answer_state, &quot;resubscribe&quot;)) {
+
+                        if (!strcasecmp(state, &quot;cs_hangup&quot;)) {
+                                astate = &quot;terminated&quot;;
+                        } else if (switch_strlen_zero(astate)) {
+                                astate = switch_str_nil(switch_event_get_header(helper-&gt;event, &quot;answer-state&quot;));
+                                if (switch_strlen_zero(astate)) {
+                                        if (is_dialog) {
+                                                astate = dft_state;
+                                        } else {
+                                                astate = &quot;terminated&quot;;
+                                        }
+                                }
+                        }
+
+                        if (!strcasecmp(event_status, &quot;hold&quot;)) {
+                                astate = &quot;early&quot;;
+                        }
+
+                        if (!strcasecmp(astate, &quot;answered&quot;)) {
+                                astate = &quot;confirmed&quot;;
+                        }
+
+                        if (!strcasecmp(astate, &quot;ringing&quot;)) {
+                                if (!strcasecmp(direction, &quot;recipient&quot;)) {
+                                        astate = &quot;early&quot;;
+                                } else {
+                                        astate = &quot;confirmed&quot;;
+                                }
+                        }
+                        if (is_dialog) {
+                                stream.write_function(&amp;stream, &quot;&lt;dialog id=\&quot;%s\&quot; direction=\&quot;%s\&quot;&gt;\n&quot;, uuid, direction);
+                                stream.write_function(&amp;stream, &quot;&lt;state&gt;%s&lt;/state&gt;\n&quot;, astate);
+                        }
+                        if (!strcasecmp(astate, &quot;early&quot;) || !strcasecmp(astate, &quot;confirmed&quot;)) {
+
+                                clean_to_user = switch_mprintf(&quot;%s&quot;, sub_to_user ? sub_to_user : to_user);
+                                clean_from_user = switch_mprintf(&quot;%s&quot;, from_id ? from_id : from_user);
+
+                                if (is_dialog) {
+                                        if (!switch_strlen_zero(clean_to_user) &amp;&amp; !switch_strlen_zero(clean_from_user)) {
+                                                stream.write_function(&amp;stream, &quot;&lt;local&gt;\n&lt;identity display=\&quot;%s\&quot;&gt;sip:%s@%s&lt;/identity&gt;\n&quot;, clean_to_user, clean_to_user, host);
+                                                stream.write_function(&amp;stream, &quot;&lt;target uri=\&quot;sip:%s@%s\&quot;&gt;\n&quot;, clean_to_user, host);
+                                                stream.write_function(&amp;stream, &quot;&lt;param pname=\&quot;+sip.rendering\&quot; pvalue=\&quot;%s\&quot;/&gt;\n&quot;,
+                                                                                          !strcasecmp(event_status, &quot;hold&quot;) ? &quot;no&quot; : &quot;yes&quot;);
+                                                stream.write_function(&amp;stream, &quot;&lt;/target&gt;\n&lt;/local&gt;\n&quot;);
+                                                stream.write_function(&amp;stream, &quot;&lt;remote&gt;\n&lt;identity display=\&quot;%s\&quot;&gt;sip:%s@%s&lt;/identity&gt;\n&quot;, clean_from_user, clean_from_user,
+                                                                                          host);
+                                                stream.write_function(&amp;stream, &quot;&lt;target uri=\&quot;sip:**%s@%s\&quot;/&gt;\n&quot;, clean_to_user, host);
+                                                stream.write_function(&amp;stream, &quot;&lt;/remote&gt;\n&quot;);
+                                        } else if (!strcasecmp(proto, &quot;park&quot;)) {
+                                                stream.write_function(&amp;stream, &quot;&lt;local&gt;\n&lt;identity display=\&quot;parking\&quot;&gt;sip:parking@%s;fifo=%s&lt;/identity&gt;\n&quot;,
+                                                                                          host, !switch_strlen_zero(clean_to_user) ? clean_to_user : &quot;unknown&quot;);
+                                                stream.write_function(&amp;stream, &quot;&lt;target uri=\&quot;sip:parking@%s\&quot;&gt;\n&quot;, host);
+                                                stream.write_function(&amp;stream, &quot;&lt;param pname=\&quot;+sip.rendering\&quot; pvalue=\&quot;no\&quot;/&gt;\n&lt;/target&gt;\n&lt;/local&gt;\n&quot;);
+                                                stream.write_function(&amp;stream, &quot;&lt;remote&gt;\n&lt;identity display=\&quot;parking\&quot;&gt;sip:%s&lt;/identity&gt;\n&quot;, uuid);
+                                                stream.write_function(&amp;stream, &quot;&lt;target uri=\&quot;sip:park+%s\&quot;/&gt;\n&quot;, uuid);
+                                                stream.write_function(&amp;stream, &quot;&lt;/remote&gt;\n&quot;);
+                                        } else if (!strcasecmp(proto, &quot;conf&quot;)) {
+                                                stream.write_function(&amp;stream, &quot;&lt;local&gt;\n&lt;identity display=\&quot;conference\&quot;&gt;sip:conference@%s;conference=%s&lt;/identity&gt;\n&quot;,
+                                                                                          host, !switch_strlen_zero(clean_to_user) ? clean_to_user : &quot;unknown&quot;);
+                                                stream.write_function(&amp;stream, &quot;&lt;target uri=\&quot;sip:conference@%s\&quot;&gt;\n&quot;, host);
+                                                stream.write_function(&amp;stream, &quot;&lt;param pname=\&quot;+sip.rendering\&quot; pvalue=\&quot;yes\&quot;/&gt;\n&lt;/target&gt;\n&lt;/local&gt;\n&quot;);
+                                                stream.write_function(&amp;stream, &quot;&lt;remote&gt;\n&lt;identity display=\&quot;conference\&quot;&gt;sip:%s@%s&lt;/identity&gt;\n&quot;, uuid, host);
+                                                stream.write_function(&amp;stream, &quot;&lt;target uri=\&quot;sip:conf+%s@%s\&quot;/&gt;\n&quot;, uuid, host);
+                                                stream.write_function(&amp;stream, &quot;&lt;/remote&gt;\n&quot;);
+                                        }
+                                }
+
+                                switch_safe_free(clean_to_user);
+                                switch_safe_free(clean_from_user);
+                        }
+                        if (is_dialog) {
+                                stream.write_function(&amp;stream, &quot;&lt;/dialog&gt;\n&quot;);
+                        }
+                }
+
+                if (is_dialog) {
+                        stream.write_function(&amp;stream, &quot;&lt;/dialog-info&gt;\n&quot;);
+                        pl = stream.data;
+                        ct = &quot;application/dialog-info+xml&quot;;
+                }
+
+                if (!switch_strlen_zero(astate) &amp;&amp; !switch_strlen_zero(uuid) &amp;&amp; helper &amp;&amp; helper-&gt;stream.data &amp;&amp; strcmp(helper-&gt;last_uuid, uuid)) {
+                        helper-&gt;stream.write_function(&amp;helper-&gt;stream, &quot;update sip_dialogs set state='%s' where uuid='%s';&quot;, astate, uuid);
+
+                        switch_copy_string(helper-&gt;last_uuid, uuid, sizeof(helper-&gt;last_uuid));
+                }
+
+                if (!is_dialog) {
+                        char status_line[256] = &quot;&quot;;
+
+                        switch_set_string(status_line, status);
+
+                        if (in) {
+                                if (!strcmp(astate, &quot;early&quot;)) {
+                                        switch_snprintf(status_line, sizeof(status_line), &quot;Ring %s&quot;, switch_str_nil(from_id));
+                                        rpid = &quot;on-the-phone&quot;;
+                                } else if (!strcmp(astate, &quot;confirmed&quot;)) {
+                                        char *dest = switch_event_get_header(helper-&gt;event, &quot;Caller-Destination-Number&quot;);
+                                        if (switch_strlen_zero(from_id) &amp;&amp; !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), &quot;On The Phone %s&quot;, status);
+                                        } else {
+                                                switch_snprintf(status_line, sizeof(status_line), &quot;Talk %s&quot;, switch_str_nil(from_id));
+                                        }
+                                        rpid = &quot;on-the-phone&quot;;
+                                }
+
+                                open = &quot;open&quot;;
+                        } else {
+                                open = &quot;closed&quot;;
+                        }
+                        
+                        prpid = translate_rpid(rpid);
+                        pl = gen_pidf(user_agent, clean_id, profile-&gt;url, open, rpid, prpid, status_line, &amp;ct);
+                }
+                
+        } else {
+                if (in) {
+                        open = &quot;open&quot;;
+                } else {
+                        open = &quot;closed&quot;;
+                }
+                prpid = translate_rpid(rpid);
+                pl = gen_pidf(user_agent, clean_id, profile-&gt;url, open, rpid, prpid, status, &amp;ct);
+        }
+        
+        nua_handle_bind(nh, &amp;mod_sofia_globals.keep_private);
+        
+        if (helper-&gt;event &amp;&amp; helper-&gt;event-&gt;event_id == SWITCH_EVENT_PRESENCE_OUT) {
+                switch_set_string(sstr, &quot;terminated;reason=noresource&quot;);
+                switch_set_string(expires_str, &quot;0&quot;);
+        kill_handle = 1;
+        } else if (exptime &gt; 0) {
+                switch_snprintf(sstr, sizeof(sstr), &quot;active;expires=%u&quot;, (unsigned)exptime);
+        } else {
+                unsigned delta = (unsigned) (exptime * -1);
+                switch_snprintf(sstr, sizeof(sstr), &quot;active;expires=%u&quot;, delta);
+                switch_snprintf(expires_str, sizeof(expires_str), &quot;%u&quot;, delta);
+                if (nh &amp;&amp; nh-&gt;nh_ds &amp;&amp; nh-&gt;nh_ds-&gt;ds_usage) {
+                        nua_dialog_usage_set_refresh_range(nh-&gt;nh_ds-&gt;ds_usage, delta, delta);
+                }
+        }
+
+        if (mod_sofia_globals.debug_presence &gt; 0 &amp;&amp; pl) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;send payload:\n%s\n&quot;, 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 &amp;&amp; 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-&gt;profile;
+
+        if (profile_name &amp;&amp; strcasecmp(profile_name, h-&gt;profile-&gt;name)) {
+                if ((ext_profile = sofia_glue_find_profile(profile_name))) {
+                        profile = ext_profile;
+                }
+        }
+        
+        if (!(nh = nua_handle_by_call_id(h-&gt;profile-&gt;nua, call_id))) {
+                if (profile-&gt;debug) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Cannot find handle for %s\n&quot;, call_id);
+                }
+                goto end;
+        }
+
+        id = switch_mprintf(&quot;sip:%s@%s&quot;, sub_to_user, sub_to_host);
+        expire_sec = (int) (expire_sec - switch_epoch_time_now(NULL));
+        if (expire_sec &lt; 0) {
+                expire_sec = 3600;
+        }
+
+        nua_handle_bind(nh, &amp;mod_sofia_globals.keep_private);
+        nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR(&quot;active&quot;),
+                           SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR(&quot;application/simple-message-summary&quot;), SIPTAG_PAYLOAD_STR(body), TAG_END());
+
+        switch_safe_free(id);
+
+        h-&gt;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 = &quot;message-summary&quot;;
+        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-&gt;profile;
+        sofia_destination_t *dst = NULL;
+        char *contact_str, *contact, *user_via = NULL;
+
+        if (profile_name &amp;&amp; strcasecmp(profile_name, h-&gt;profile-&gt;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(&quot;sip:%s@%s&quot;, sub_to_user, profile-&gt;extsipip);
+                switch_assert(id);
+
+                if ((ptr = sofia_glue_find_parameter(o_contact, &quot;transport=&quot;))) {
+                        sofia_transport_t transport = sofia_glue_str2transport(ptr);
+                        transport_str = sofia_glue_transport2str(transport);
+
+                        switch (transport) {
+                        case SOFIA_TRANSPORT_TCP:
+                                contact_str = profile-&gt;tcp_public_contact;
+                                break;
+                        case SOFIA_TRANSPORT_TCP_TLS:
+                                contact_str = profile-&gt;tls_public_contact;
+                                break;
+                        default:
+                                contact_str = profile-&gt;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-&gt;public_url;
+                }
+                
+        } else {
+                contact_str = profile-&gt;url;
+                id = switch_mprintf(&quot;sip:%s@%s&quot;, sub_to_user, sub_to_host);
+        }
+
+        dst = sofia_glue_get_destination(o_contact);
+        switch_assert(dst);
+
+        nh = nua_handle(profile-&gt;nua, NULL, NUTAG_URL(contact),
+                                        SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id),
+                                        SIPTAG_CONTACT_STR(contact_str), TAG_END());
+        nua_handle_bind(nh, &amp;mod_sofia_globals.destroy_private);
+
+        nua_notify(nh,
+                           NUTAG_NEWSUB(1),
+                           TAG_IF(dst-&gt;route_uri, NUTAG_PROXY(dst-&gt;route_uri)), TAG_IF(dst-&gt;route, SIPTAG_ROUTE_STR(dst-&gt;route)),
+                           TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                           SIPTAG_EVENT_STR(event),
+                           SIPTAG_CONTENT_TYPE_STR(&quot;application/simple-message-summary&quot;),
+                           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] = &quot;&quot;;
+                sip_to_t const *to = sip-&gt;sip_to;
+                sip_from_t const *from = sip-&gt;sip_from;
+                sip_contact_t const *contact = sip-&gt;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 = &quot;sip&quot;;
+                char *d_user = NULL;
+                char *contact_str = &quot;&quot;;
+                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 = &quot;\&quot;user\&quot;&quot;;
+                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] = &quot;&quot;;
+                char *is_nat = NULL;
+                int is_auto_nat = 0;
+                const char *ipv6;
+
+                if (!(contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url)) {
+                        nua_respond(nh, 481, &quot;INVALID SUBSCRIPTION&quot;, TAG_END());
+                        return;
+                }
+
+                sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &amp;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-&gt;home, (void *) sip-&gt;sip_event);
+
+                port = (char *) contact-&gt;m_url-&gt;url_port;
+                contact_host = sip-&gt;sip_contact-&gt;m_url-&gt;url_host;
+                contact_user = sip-&gt;sip_contact-&gt;m_url-&gt;url_user;
+
+                display = contact-&gt;m_display;
+
+                if (switch_strlen_zero(display)) {
+                        if (from) {
+                                display = from-&gt;a_display;
+                                if (switch_strlen_zero(display)) {
+                                        display = &quot;\&quot;user\&quot;&quot;;
+                                }
+                        }
+                } else {
+                        display = &quot;\&quot;user\&quot;&quot;;
+                }
+
+                if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
+                        if (sip &amp;&amp; sip-&gt;sip_via) {
+                                const char *v_port = sip-&gt;sip_via-&gt;v_port;
+                                const char *v_host = sip-&gt;sip_via-&gt;v_host;
+
+                                if (v_host &amp;&amp; sip-&gt;sip_via-&gt;v_received) {
+                                        is_nat = &quot;via received&quot;;
+                                } else if (v_host &amp;&amp; strcmp(network_ip, v_host)) {
+                                        is_nat = &quot;via host&quot;;
+                                } else if (v_port &amp;&amp; atoi(v_port) != network_port) {
+                                        is_nat = &quot;via port&quot;;
+                                }
+                        }
+                }
+
+                if (!is_nat &amp;&amp; profile-&gt;nat_acl_count) {
+                        uint32_t x = 0;
+                        int ok = 1;
+                        char *last_acl = NULL;
+
+                        if (!switch_strlen_zero(contact_host)) {
+                                for (x = 0; x &lt; profile-&gt;nat_acl_count; x++) {
+                                        last_acl = profile-&gt;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), &quot;:%d&quot;, network_port);
+                        port = NULL;
+                }
+
+
+                if (port) {
+                        switch_snprintf(new_port, sizeof(new_port), &quot;:%s&quot;, port);
+                }
+
+                ipv6 = strchr(contact_host, ':');
+                if (contact-&gt;m_url-&gt;url_params) {
+                        contact_str = switch_mprintf(&quot;%s &lt;sip:%s@%s%s%s%s;%s&gt;%s&quot;,
+                                                                                display, contact-&gt;m_url-&gt;url_user,
+                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                contact_host,
+                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                new_port,
+                                                                                contact-&gt;m_url-&gt;url_params,
+                                                                                is_nat ? &quot;;fs_nat&quot; : &quot;&quot;);
+                } else {
+                        contact_str = switch_mprintf(&quot;%s &lt;sip:%s@%s%s%s%s&gt;%s&quot;,
+                                                                                display,
+                                                                                contact-&gt;m_url-&gt;url_user,
+                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                contact_host,
+                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                new_port,
+                                                                                is_nat ?  &quot;;fs_nat&quot; : &quot;&quot;);
+                }
+
+
+
+                /* 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-&gt;sip_request-&gt;rq_url-&gt;url_user &amp;&amp; !strncmp(sip-&gt;sip_request-&gt;rq_url-&gt;url_user, &quot;sla-agent&quot;, sizeof(&quot;sla-agent&quot;))) {
+                                /* only fire this on &lt;200 to try to avoid resubscribes. probably better ways to do this? */
+                                if (status &lt; 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(&quot;sip:%s@%s&quot;, to-&gt;a_url-&gt;url_user, to-&gt;a_url-&gt;url_host);
+                }
+
+                if (to) {
+                        to_user = to-&gt;a_url-&gt;url_user;
+                        to_host = to-&gt;a_url-&gt;url_host;
+                }
+
+                if (sip &amp;&amp; sip-&gt;sip_from) {
+                        from_user = sip-&gt;sip_from-&gt;a_url-&gt;url_user;
+                        from_host = sip-&gt;sip_from-&gt;a_url-&gt;url_host;
+                } else {
+                        from_user = &quot;n/a&quot;;
+                        from_host = &quot;n/a&quot;;
+                }
+
+                if (to_user &amp;&amp; (strstr(to_user, &quot;ext+&quot;) || strstr(to_user, &quot;user+&quot;))) {
+                        char protocol[80];
+                        char *p;
+
+                        switch_copy_string(protocol, to_user, sizeof(protocol));
+                        if ((p = strchr(protocol, '+'))) {
+                                *p = '\0';
+                        }
+
+                        if (switch_event_create(&amp;sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+                                switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, &quot;proto&quot;, protocol);
+                                switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;name);
+                                switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, to_user, to_host);
+                                switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, &quot;active&quot;);
+                                switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;Click To Call&quot;);
+                                switch_event_fire(&amp;sevent);
+                        }
+
+                } else {
+                        if (switch_event_create(&amp;sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+                                switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
+                                switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;name);
+                                switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, from_user, from_host);
+                                switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, &quot;to&quot;, &quot;%s@%s&quot;, to_user, to_host);
+                                switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, &quot;proto-specific-event-name&quot;, event);
+                                switch_event_fire(&amp;sevent);
+                        }
+                }
+
+                if (to_user &amp;&amp; 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 &amp;&amp; to_user &amp;&amp; to_host)) {
+                                nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
+                                goto end;
+                        }
+                }
+
+                call_id = sip-&gt;sip_call_id-&gt;i_id;
+                full_from = sip_header_as_string(profile-&gt;home, (void *) sip-&gt;sip_from);
+                full_via = sip_header_as_string(profile-&gt;home, (void *) sip-&gt;sip_via);
+                
+                exp_delta = profile-&gt;force_subscription_expires ? profile-&gt;force_subscription_expires : (sip-&gt;sip_expires ? sip-&gt;sip_expires-&gt;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), &quot;%ld&quot;, exp_delta);
+                
+                if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
+                        sql = switch_mprintf(&quot;delete from sip_subscriptions where call_id='%q'&quot;, call_id);
+                } else {
+                        sql = switch_mprintf(&quot;delete from sip_subscriptions where &quot;
+                                                                 &quot;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'&quot;,
+                                                                 proto, from_user, from_host, to_user, to_host, event, mod_sofia_globals.hostname);
+                }
+
+                switch_mutex_lock(profile-&gt;ireg_mutex);
+                switch_assert(sql != NULL);
+                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+
+                if (sub_state == nua_substate_terminated) {
+                        sstr = switch_mprintf(&quot;terminated&quot;);
+                } else {
+                        sip_accept_t *ap = sip-&gt;sip_accept;
+                        char accept[256] = &quot;&quot;;
+                        full_agent = sip_header_as_string(profile-&gt;home, (void *) sip-&gt;sip_user_agent);
+                        while (ap) {
+                                switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), &quot;%s%s &quot;, ap-&gt;ac_type, ap-&gt;ac_next ? &quot;,&quot; : &quot;&quot;);
+                                ap = ap-&gt;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(&quot;insert into sip_subscriptions &quot;
+                                                                 &quot;(proto,sip_user,sip_host,sub_to_user,sub_to_host,presence_hosts,event,contact,call_id,full_from,&quot;
+                                                                 &quot;full_via,expires,user_agent,accept,profile_name,hostname,network_ip) &quot;
+                                                                 &quot;values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%q')&quot;,
+                                                                 proto, from_user, from_host, to_user, to_host, profile-&gt;presence_hosts ? profile-&gt;presence_hosts : to_host, 
+                                                                 event, contact_str, call_id, full_from, full_via, 
+                                                                 exp_delta * -1, 
+                                                                 full_agent, accept, profile-&gt;name,mod_sofia_globals.hostname, network_ip);
+                                                                 
+                        
+                        if (mod_sofia_globals.debug_presence &gt; 0) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;%s SUBSCRIBE %s@%s %s@%s\n&quot;, profile-&gt;name, from_user, from_host, to_user, to_host);
+                        }
+
+                        switch_assert(sql != NULL);
+                        sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+
+                        sstr = switch_mprintf(&quot;active;expires=%ld&quot;, exp_delta);
+                }
+
+                switch_mutex_unlock(profile-&gt;ireg_mutex);
+
+                if (status &lt; 200) {
+                        char *sticky = NULL;
+                        char *contactstr = profile-&gt;url;
+                        
+                        if (is_nat) {
+                                char params[128] = &quot;&quot;;
+                                if (contact-&gt;m_url-&gt;url_params) {
+                                        switch_snprintf(params, sizeof(params), &quot;;%s&quot;, contact-&gt;m_url-&gt;url_params);
+                                }
+                                ipv6 = strchr(network_ip, ':');
+                                sticky = switch_mprintf(&quot;sip:%s@%s%s%s:%d%s&quot;,
+                                                                                contact_user,
+                                                                                ipv6 ? &quot;[&quot; : &quot;&quot;,
+                                                                                network_ip,
+                                                                                ipv6 ? &quot;]&quot; : &quot;&quot;,
+                                                                                network_port,
+                                                                                params);
+                        }
+
+                        if (is_auto_nat) {
+                                contactstr = profile-&gt;public_url;
+                        } else {
+                                contactstr = profile-&gt;url;
+                        }
+
+                        
+                        if (switch_stristr(&quot;port=tcp&quot;, contact-&gt;m_url-&gt;url_params)) {
+                                if (is_auto_nat) {
+                                        contactstr = profile-&gt;tcp_public_contact;
+                                } else {
+                                        contactstr = profile-&gt;tcp_contact;
+                                }
+                        } else if (switch_stristr(&quot;port=tls&quot;, contact-&gt;m_url-&gt;url_params)) {
+                                if (is_auto_nat) {
+                                        contactstr = profile-&gt;tls_contact;
+                                } else {
+                                        contactstr = profile-&gt;tls_public_contact;
+                                }
+                        }
+
+                        if (nh &amp;&amp; nh-&gt;nh_ds &amp;&amp; nh-&gt;nh_ds-&gt;ds_usage) {
+                                nua_dialog_usage_set_refresh_range(nh-&gt;nh_ds-&gt;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(&quot;application/notice&quot;),
+                                   SIPTAG_PAYLOAD_STR(&quot;Note: Come to ClueCon http://www.cluecon.com\n\n&quot;), TAG_END());
+#endif
+
+                switch_safe_free(sstr);
+
+                if ((sql = switch_mprintf(
+                                                                  &quot;select proto,sip_user,'%q',sub_to_user,sub_to_host,event,contact,call_id,full_from,&quot;
+                                                                  &quot;full_via,expires,user_agent,accept,profile_name,network_ip&quot;
+                                                                  &quot; from sip_subscriptions where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')&quot;, 
+                                                                  to_host, to_user, to_host, to_host))) {
+                        sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, sofia_presence_sub_reg_callback, profile);
+                        
+                        switch_safe_free(sql);
+                }
+          end:
+
+                if (event) {
+                        su_free(profile-&gt;home, event);
+                }
+
+                if (full_from) {
+                        su_free(profile-&gt;home, full_from);
+                }
+                if (full_via) {
+                        su_free(profile-&gt;home, full_via);
+                }
+                if (full_agent) {
+                        su_free(profile-&gt;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, &quot;INVALID SUBSCRIPTION&quot;, 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-&gt;subscriptions; gw_sub_ptr; gw_sub_ptr = gw_sub_ptr-&gt;next) {
+                if (!strcasecmp(gw_sub_ptr-&gt;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-&gt;o_type: message-summary (for example) */
+        if (!o) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Event information not given\n&quot;);
+                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-&gt;o_type, &quot;dialog&quot;) &amp;&amp; msg_params_find(o-&gt;o_params, &quot;sla&quot;)) {
+                        sofia_sla_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+                        return;
+                }
+        }
+
+        if (!sofia_private || !sofia_private-&gt;gateway) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Gateway information missing\n&quot;);
+                return;
+        }
+        
+        /* Find the subscription if one exists */
+        if (!(gw_sub_ptr = sofia_find_gateway_subscription(sofia_private-&gt;gateway, o-&gt;o_type))) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Could not find gateway subscription.  Gateway: %s.  Subscription Event: %s\n&quot;,
+                                sofia_private-&gt;gateway-&gt;name, o-&gt;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, &quot;got 200 OK response, updated state to SUB_STATE_SUBSCRIBE.\n&quot;);
+                gw_sub_ptr-&gt;state = SUB_STATE_SUBSCRIBE;
+                break;
+        case 100:
+                break;
+        default:
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;status (%d) != 200, updated state to SUB_STATE_FAILED.\n&quot;, status);
+                gw_sub_ptr-&gt;state = SUB_STATE_FAILED;
+                
+                if (sofia_private) {
+                        nua_handle_destroy(sofia_private-&gt;gateway-&gt;sub_nh);
+                        sofia_private-&gt;gateway-&gt;sub_nh = NULL;
+                        nua_handle_bind(sofia_private-&gt;gateway-&gt;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-&gt;sip_from;
+                char *from_user = NULL;
+                char *from_host = NULL;
+                char *rpid = &quot;unknown&quot;;
+                sip_payload_t *payload = sip-&gt;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-&gt;sip_request-&gt;rq_url-&gt;url_user &amp;&amp; !strncmp(sip-&gt;sip_request-&gt;rq_url-&gt;url_user, &quot;sla-agent&quot;, sizeof(&quot;sla-agent&quot;))) {
+                                sofia_sla_handle_sip_i_publish(nua, profile, nh, sip, tags);
+                                return;
+                        }
+                }
+
+                if (from) {
+                        from_user = (char *) from-&gt;a_url-&gt;url_user;
+                        from_host = (char *) from-&gt;a_url-&gt;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-&gt;pl_data, strlen(payload-&gt;pl_data)))) {
+                                char *status_txt = &quot;&quot;, *note_txt = &quot;&quot;;
+
+                                if (sip-&gt;sip_user_agent) {
+                                        full_agent = sip_header_as_string(profile-&gt;home, (void *) sip-&gt;sip_user_agent);
+                                }
+                                
+                                if ((tuple = switch_xml_child(xml, &quot;tuple&quot;)) &amp;&amp; (status = switch_xml_child(tuple, &quot;status&quot;))
+                                        &amp;&amp; (basic = switch_xml_child(status, &quot;basic&quot;))) {
+                                        status_txt = basic-&gt;txt;
+                                }
+
+                                if ((person = switch_xml_child(xml, &quot;dm:person&quot;)) &amp;&amp; (note = switch_xml_child(person, &quot;dm:note&quot;))) {
+                                        note_txt = note-&gt;txt;
+                                }
+
+                                if (person &amp;&amp; (act = switch_xml_child(person, &quot;rpid:activities&quot;)) &amp;&amp; act-&gt;child &amp;&amp; act-&gt;child-&gt;name) {
+                                        if ((rpid = strchr(act-&gt;child-&gt;name, ':'))) {
+                                                rpid++;
+                                        } else {
+                                                rpid = act-&gt;child-&gt;name;
+                                        }
+                                }
+
+                                if (!strcasecmp(status_txt, &quot;open&quot;)) {
+                                        if (switch_strlen_zero(note_txt)) {
+                                                note_txt = &quot;Available&quot;;
+                                        }
+                                        in = 1;
+                                } else if (!strcasecmp(status_txt, &quot;closed&quot;)) {
+                                        if (switch_strlen_zero(note_txt)) {
+                                                note_txt = &quot;Unavailable&quot;;
+                                        }
+                                }
+
+                                exp_delta = (sip-&gt;sip_expires ? sip-&gt;sip_expires-&gt;ex_delta : 3600);
+                                exp = (long) switch_epoch_time_now(NULL) + exp_delta;
+
+                                if ((sql =
+                                         switch_mprintf(&quot;delete from sip_presence where sip_user='%q' and sip_host='%q' &quot;
+                                                                        &quot; and profile_name='%q' and hostname='%q'&quot;,
+                                                                        from_user, from_host, profile-&gt;name, mod_sofia_globals.hostname
+                                                                        ))) {
+                                        sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+                                }
+                                         
+                                if ((sql =
+                                         switch_mprintf(&quot;insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent, profile_name, hostname) &quot;
+                                                                        &quot;values ('%q','%q','%q','%q',%ld,'%q','%q','%q')&quot;,
+                                                                        from_user, from_host, note_txt, rpid, exp, full_agent, profile-&gt;name, mod_sofia_globals.hostname))) {
+                                        sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+                                }
+                                
+                                event_type = sip_header_as_string(profile-&gt;home, (void *) sip-&gt;sip_event);
+
+                                if (in) {
+                                        if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;user-agent&quot;, full_agent);
+                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, from_user, from_host);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, note_txt);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, event_type);
+                                                switch_event_fire(&amp;event);
+                                        }
+                                } else {
+                                        if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;user-agent&quot;, full_agent);
+                                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, from_user, from_host);
+
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, event_type);
+                                                switch_event_fire(&amp;event);
+                                        }
+                                }
+
+                                if (event_type) {
+                                        su_free(profile-&gt;home, event_type);
+                                }
+
+                                if (full_agent) {
+                                        su_free(profile-&gt;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-&gt;sip_to-&gt;a_url;
+        url_t *from = sip-&gt;sip_from-&gt;a_url;
+        switch_snprintf(hash_key, len, &quot;%s%s%s&quot;, from-&gt;url_user, from-&gt;url_host, to-&gt;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-&gt;sip_from;
+                const char *from_user = NULL;
+                const char *from_host = NULL;
+                sip_to_t const *to = sip-&gt;sip_to;
+                const char *to_user = NULL;
+                const char *to_host = NULL;
+                sip_subject_t const *sip_subject = sip-&gt;sip_subject;
+                sip_payload_t *payload = sip-&gt;sip_payload;
+                const char *subject = &quot;n/a&quot;;
+                char *msg = NULL;
+
+                if (sip-&gt;sip_content_type &amp;&amp; sip-&gt;sip_content_type-&gt;c_subtype) {
+                        if (strstr(sip-&gt;sip_content_type-&gt;c_subtype, &quot;composing&quot;)) {
+                                return;
+                        }
+                }
+
+                if (from) {
+                        from_user = from-&gt;a_url-&gt;url_user;
+                        from_host = from-&gt;a_url-&gt;url_host;
+                }
+
+                if (to) {
+                        to_user = to-&gt;a_url-&gt;url_user;
+                        to_host = to-&gt;a_url-&gt;url_host;
+                }
+
+                if (!to_user) {
+                        return;
+                }
+
+                if (payload) {
+                        msg = payload-&gt;pl_data;
+                }
+
+                if (sip_subject) {
+                        subject = sip_subject-&gt;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-&gt;home, (void *) sip-&gt;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(&quot;%s@%s&quot;, to_user, to_host);
+                        }
+
+                        from_addr = switch_mprintf(&quot;%s@%s&quot;, 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-&gt;chat_hash, hash_key))) {
+                                channel = switch_core_session_get_channel(tech_pvt-&gt;session);
+                                if (switch_event_create(&amp;event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, from_addr);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;hint&quot;, full_from);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;to&quot;, to_addr);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;subject&quot;, &quot;SIMPLE MESSAGE&quot;);
+                                        if (msg) {
+                                                switch_event_add_body(event, &quot;%s&quot;, msg);
+                                        }
+                                        
+                                        if (switch_core_session_queue_event(tech_pvt-&gt;session, &amp;event) != SWITCH_STATUS_SUCCESS) {
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;delivery-failure&quot;, &quot;true&quot;);
+                                                switch_event_fire(&amp;event);
+                                        }
+                                }
+                        } else {
+                                switch_core_chat_send(proto, SOFIA_CHAT_PROTO, from_addr, to_addr, &quot;&quot;, msg, NULL, full_from);
+                        }
+                        switch_safe_free(to_addr);
+                        switch_safe_free(from_addr);
+                        if (full_from) {
+                                su_free(profile-&gt;home, full_from);
+                        }
+                }
+        }
+}
+
+void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip)
+{
+        char hash_key[256] = &quot;&quot;;
+        char buf[512];
+        su_home_t *home = NULL;
+
+        if (!tech_pvt || tech_pvt-&gt;hash_key || !sip || !sip-&gt;sip_from || !sip-&gt;sip_from-&gt;a_url || 
+                !sip-&gt;sip_from-&gt;a_url-&gt;url_user || !sip-&gt;sip_from-&gt;a_url-&gt;url_host) {
+                return;
+        }
+
+        if (sofia_reg_find_reg_url(tech_pvt-&gt;profile, sip-&gt;sip_from-&gt;a_url-&gt;url_user, sip-&gt;sip_from-&gt;a_url-&gt;url_host, buf, sizeof(buf))) {
+                home = su_home_new(sizeof(*home));
+                switch_assert(home != NULL);
+                tech_pvt-&gt;chat_from = sip_header_as_string(home, (const sip_header_t *) sip-&gt;sip_to);
+                tech_pvt-&gt;chat_to = switch_core_session_strdup(tech_pvt-&gt;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-&gt;profile-&gt;flag_mutex);
+        tech_pvt-&gt;hash_key = switch_core_session_strdup(tech_pvt-&gt;session, hash_key);
+        switch_core_hash_insert(tech_pvt-&gt;profile-&gt;chat_hash, tech_pvt-&gt;hash_key, tech_pvt);
+        switch_mutex_unlock(tech_pvt-&gt;profile-&gt;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:
+ */
</ins></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_regcfromrev14389freeswitchtrunksrcmodendpointsmod_sofiasofia_regc"></a>
<div class="copfile"><h4>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)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,2153 @@
</span><ins>+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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 &lt;anthm@freeswitch.org&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ * Ken Rice, &lt;krice at cometsig.com&gt;  (work sponsored by Comet Signaling LLC, CopperCom, Inc and Asteria Solutions Group, Inc)
+ * Paul D. Tinsley &lt;pdt at jackhammer.org&gt;
+ * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
+ * Marcel Barbulescu &lt;marcelbarbulescu@gmail.com&gt;
+ * David Knell &lt;&gt;
+ * Eliot Gable &lt;egable AT.AT broadvox.com&gt;
+ *
+ *
+ * sofia_ref.c -- SOFIA SIP Endpoint (registration code)
+ *
+ */
+#include &quot;mod_sofia.h&quot;
+
+static void sofia_reg_new_handle(sofia_gateway_t *gateway_ptr, int attach)
+{
+        int ss_state = nua_callstate_authenticating;
+
+        if (gateway_ptr-&gt;nh) {
+                nua_handle_bind(gateway_ptr-&gt;nh, NULL);
+                nua_handle_destroy(gateway_ptr-&gt;nh);
+                gateway_ptr-&gt;nh = NULL;
+                sofia_private_free(gateway_ptr-&gt;sofia_private);
+        }
+
+        gateway_ptr-&gt;nh = nua_handle(gateway_ptr-&gt;profile-&gt;nua, NULL,
+                                                                 SIPTAG_CALL_ID_STR(gateway_ptr-&gt;uuid_str),
+                                                                 SIPTAG_TO_STR(gateway_ptr-&gt;register_to),
+                                                                 NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr-&gt;register_from), TAG_END());
+        if (attach) {
+                if (!gateway_ptr-&gt;sofia_private) {
+                        gateway_ptr-&gt;sofia_private = malloc(sizeof(*gateway_ptr-&gt;sofia_private));
+                        switch_assert(gateway_ptr-&gt;sofia_private);
+                }
+                memset(gateway_ptr-&gt;sofia_private, 0, sizeof(*gateway_ptr-&gt;sofia_private));
+        
+                gateway_ptr-&gt;sofia_private-&gt;gateway = gateway_ptr;
+                nua_handle_bind(gateway_ptr-&gt;nh, gateway_ptr-&gt;sofia_private);
+        }
+}
+
+static void sofia_reg_kill_reg(sofia_gateway_t *gateway_ptr)
+{
+
+        if (gateway_ptr-&gt;state != REG_STATE_REGED) {
+                if (gateway_ptr-&gt;nh) {
+                        nua_handle_destroy(gateway_ptr-&gt;nh);
+                        gateway_ptr-&gt;nh = NULL;
+                }
+                return;
+        }
+        
+        /*
+        if (!gateway_ptr-&gt;nh) {
+                sofia_reg_new_handle(gateway_ptr, SWITCH_FALSE);
+        }
+        */
+
+        if (gateway_ptr-&gt;nh) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;UN-Registering %s\n&quot;, gateway_ptr-&gt;name);
+                nua_unregister(gateway_ptr-&gt;nh,
+                                           NUTAG_URL(gateway_ptr-&gt;register_url),
+                                           NUTAG_REGISTRAR(gateway_ptr-&gt;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(&amp;s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_GATEWAY_STATE) == SWITCH_STATUS_SUCCESS) {
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;Gateway&quot;, gateway-&gt;name);
+                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;State&quot;, sofia_state_string(gateway-&gt;state));
+                switch_event_fire(&amp;s_event);
+        }
+}
+
+void sofia_reg_unregister(sofia_profile_t *profile)
+{
+        sofia_gateway_t *gateway_ptr;
+        for (gateway_ptr = profile-&gt;gateways; gateway_ptr; gateway_ptr = gateway_ptr-&gt;next) {
+
+                if (gateway_ptr-&gt;sofia_private) {
+                        sofia_private_free(gateway_ptr-&gt;sofia_private);
+                }
+
+                if (gateway_ptr-&gt;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-&gt;gateways; gateway_ptr; gateway_ptr = gateway_ptr-&gt;next) {
+                sofia_gateway_subscription_t *gw_sub_ptr;
+
+                for (gw_sub_ptr = gateway_ptr-&gt;subscriptions; gw_sub_ptr; gw_sub_ptr = gw_sub_ptr-&gt;next) {
+                        int ss_state = nua_callstate_authenticating;
+                        sub_state_t ostate = gw_sub_ptr-&gt;state;
+                        char *user_via = NULL;
+                        
+                        if (!now) {
+                                gw_sub_ptr-&gt;state = ostate = SUB_STATE_UNSUBED;
+                                gw_sub_ptr-&gt;expires_str = &quot;0&quot;;
+                        }
+
+                        if (sofia_glue_check_nat(gateway_ptr-&gt;profile, gateway_ptr-&gt;register_proxy)) {
+                                user_via = sofia_glue_create_external_via(NULL, gateway_ptr-&gt;profile, gateway_ptr-&gt;register_transport);
+                        }
+
+                        switch (ostate) {
+                        case SUB_STATE_NOSUB:
+                                break;
+                        case SUB_STATE_SUBSCRIBE:
+                                gw_sub_ptr-&gt;expires = now + gw_sub_ptr-&gt;freq;
+                                gw_sub_ptr-&gt;state = SUB_STATE_SUBED;
+                                break;
+                        case SUB_STATE_UNSUBSCRIBE:
+                                gw_sub_ptr-&gt;state = SUB_STATE_NOSUB;
+
+                                /* not tested .. */
+                                nua_unsubscribe(gateway_ptr-&gt;nh,
+                                                                NUTAG_URL(gateway_ptr-&gt;register_url),
+                                                                TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                                                                SIPTAG_EVENT_STR(gw_sub_ptr-&gt;event),
+                                                                SIPTAG_ACCEPT_STR(gw_sub_ptr-&gt;content_type),
+                                                                SIPTAG_TO_STR(gateway_ptr-&gt;register_from),
+                                                                SIPTAG_FROM_STR(gateway_ptr-&gt;register_from),
+                                                                SIPTAG_CONTACT_STR(gateway_ptr-&gt;register_contact),
+                                                                TAG_NULL());
+                                
+                                break;
+                        case SUB_STATE_UNSUBED:
+                                gateway_ptr-&gt;sub_nh = nua_handle(gateway_ptr-&gt;profile-&gt;nua, NULL,
+                                                                                                 NUTAG_URL(gateway_ptr-&gt;register_proxy),
+                                                                                                 TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                                                                                                 SIPTAG_TO_STR(gateway_ptr-&gt;register_to),
+                                                                                                 NUTAG_CALLSTATE_REF(ss_state), 
+                                                                                                 SIPTAG_FROM_STR(gateway_ptr-&gt;register_from), TAG_END());
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;subscribing to [%s] on gateway [%s]\n&quot;, gw_sub_ptr-&gt;event, gateway_ptr-&gt;name);
+                                
+                                gateway_ptr-&gt;sofia_private = malloc(sizeof(*gateway_ptr-&gt;sofia_private));
+                                switch_assert(gateway_ptr-&gt;sofia_private);
+                                
+                                memset(gateway_ptr-&gt;sofia_private, 0, sizeof(*gateway_ptr-&gt;sofia_private));
+
+                                gateway_ptr-&gt;sofia_private-&gt;gateway = gateway_ptr;
+                                nua_handle_bind(gateway_ptr-&gt;nh, gateway_ptr-&gt;sofia_private);
+
+                                if (now) {
+                                        nua_subscribe(gateway_ptr-&gt;sub_nh,
+                                                                  NUTAG_URL(gateway_ptr-&gt;register_url),
+                                                                  TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                                                                  SIPTAG_EVENT_STR(gw_sub_ptr-&gt;event),
+                                                                  SIPTAG_ACCEPT_STR(gw_sub_ptr-&gt;content_type),  
+                                                                  SIPTAG_TO_STR(gateway_ptr-&gt;register_from),
+                                                                  SIPTAG_FROM_STR(gateway_ptr-&gt;register_from),
+                                                                  SIPTAG_CONTACT_STR(gateway_ptr-&gt;register_contact),
+                                                                  SIPTAG_EXPIRES_STR(gw_sub_ptr-&gt;expires_str),  // sofia stack bases its auto-refresh stuff on this
+                                                                  TAG_NULL());
+                                        gw_sub_ptr-&gt;retry = now + gw_sub_ptr-&gt;retry_seconds;
+                                } else {
+                                        nua_unsubscribe(gateway_ptr-&gt;sub_nh,
+                                                                        NUTAG_URL(gateway_ptr-&gt;register_url),
+                                                                        TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                                                                        SIPTAG_EVENT_STR(gw_sub_ptr-&gt;event),
+                                                                        SIPTAG_ACCEPT_STR(gw_sub_ptr-&gt;content_type),
+                                                                        SIPTAG_FROM_STR(gateway_ptr-&gt;register_from),
+                                                                        SIPTAG_TO_STR(gateway_ptr-&gt;register_from),
+                                                                        SIPTAG_CONTACT_STR(gateway_ptr-&gt;register_contact),
+                                                                        SIPTAG_EXPIRES_STR(gw_sub_ptr-&gt;expires_str),
+                                                                        TAG_NULL());
+                                }
+                                gw_sub_ptr-&gt;state = SUB_STATE_TRYING;
+                                break;
+                                
+                        case SUB_STATE_FAILED:
+                        case SUB_STATE_TRYING:
+                                if (gw_sub_ptr-&gt;retry &amp;&amp; now &gt;= gw_sub_ptr-&gt;retry) {
+                                        gw_sub_ptr-&gt;state = SUB_STATE_UNSUBED;
+                                        gw_sub_ptr-&gt;retry = 0;
+                                }
+                                break;
+                        default:
+                                if (now &gt;= gw_sub_ptr-&gt;expires) {
+                                        gw_sub_ptr-&gt;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-&gt;gateways; gateway_ptr; gateway_ptr = gateway_ptr-&gt;next) {
+                if (gateway_ptr-&gt;deleted &amp;&amp; gateway_ptr-&gt;state == REG_STATE_NOREG) {
+                        if (last) {
+                                last-&gt;next = gateway_ptr-&gt;next;
+                        } else {
+                                profile-&gt;gateways = gateway_ptr-&gt;next;
+                        }
+
+                        switch_core_hash_delete(mod_sofia_globals.gateway_hash, gateway_ptr-&gt;name);
+                        switch_core_hash_delete(mod_sofia_globals.gateway_hash, gateway_ptr-&gt;register_from);
+                        switch_core_hash_delete(mod_sofia_globals.gateway_hash, gateway_ptr-&gt;register_contact);
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Deleted gateway %s\n&quot;, gateway_ptr-&gt;name);
+                        if (gateway_ptr-&gt;ob_vars) {
+                                switch_event_destroy(&amp;gateway_ptr-&gt;ob_vars);
+                        }
+                        if (gateway_ptr-&gt;ib_vars) {
+                                switch_event_destroy(&amp;gateway_ptr-&gt;ib_vars);
+                        }
+                } else {
+                        last = gateway_ptr;
+                }
+        }
+
+        for (gateway_ptr = profile-&gt;gateways; gateway_ptr; gateway_ptr = gateway_ptr-&gt;next) {
+                reg_state_t ostate = gateway_ptr-&gt;state;
+                char *user_via = NULL;
+
+                if (!now) {
+                        gateway_ptr-&gt;state = ostate = REG_STATE_UNREGED;
+                        gateway_ptr-&gt;expires_str = &quot;0&quot;;
+                }
+
+                if (gateway_ptr-&gt;ping &amp;&amp; !gateway_ptr-&gt;pinging &amp;&amp; (now &gt;= gateway_ptr-&gt;ping &amp;&amp; (ostate == REG_STATE_NOREG || ostate == REG_STATE_REGED)) &amp;&amp;
+                        !gateway_ptr-&gt;deleted) {
+                        nua_handle_t *nh = nua_handle(profile-&gt;nua, NULL, NUTAG_URL(gateway_ptr-&gt;register_url), TAG_END());
+                        sofia_private_t *pvt;
+
+                        if (sofia_glue_check_nat(gateway_ptr-&gt;profile, gateway_ptr-&gt;register_proxy)) {
+                                user_via = sofia_glue_create_external_via(NULL, gateway_ptr-&gt;profile, gateway_ptr-&gt;register_transport);
+                        }
+
+                        pvt = malloc(sizeof(*pvt));
+                        switch_assert(pvt);
+                        memset(pvt, 0, sizeof(*pvt));
+                        pvt-&gt;destroy_nh = 1;
+                        pvt-&gt;destroy_me = 1;
+                        switch_copy_string(pvt-&gt;gateway_name, gateway_ptr-&gt;name, sizeof(pvt-&gt;gateway_name));
+                        nua_handle_bind(nh, pvt);
+
+                        gateway_ptr-&gt;pinging = 1;
+                        nua_options(nh, 
+                                                TAG_IF(gateway_ptr-&gt;register_sticky_proxy, NUTAG_PROXY(gateway_ptr-&gt;register_sticky_proxy)),
+                                                TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                                                SIPTAG_TO_STR(gateway_ptr-&gt;register_from),
+                                                SIPTAG_CONTACT_STR(gateway_ptr-&gt;register_contact),
+                                                SIPTAG_FROM_STR(gateway_ptr-&gt;register_from),
+                                                TAG_END());
+
+                        switch_safe_free(user_via);
+                        user_via = NULL;
+                }
+
+                switch (ostate) {
+                case REG_STATE_NOREG:
+                        if (!gateway_ptr-&gt;ping &amp;&amp; !gateway_ptr-&gt;pinging) {
+                                gateway_ptr-&gt;status = SOFIA_GATEWAY_UP;
+                        }
+                        break;
+                case REG_STATE_REGISTER:
+                        if (profile-&gt;debug) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Registered %s\n&quot;, gateway_ptr-&gt;name);
+                        }
+
+                        gateway_ptr-&gt;failures = 0;
+
+                        if (gateway_ptr-&gt;freq &gt; 60) {
+                                gateway_ptr-&gt;expires = now + (gateway_ptr-&gt;freq - 15);
+                        } else {
+                                gateway_ptr-&gt;expires = now + (gateway_ptr-&gt;freq - 2);
+                        }
+
+                        gateway_ptr-&gt;state = REG_STATE_REGED;
+                        gateway_ptr-&gt;status = SOFIA_GATEWAY_UP;
+                        break;
+
+                case REG_STATE_UNREGISTER:
+                        sofia_reg_kill_reg(gateway_ptr);
+                        gateway_ptr-&gt;state = REG_STATE_NOREG;
+                        break;
+                case REG_STATE_UNREGED:
+                        gateway_ptr-&gt;status = SOFIA_GATEWAY_DOWN;
+
+                        if (!gateway_ptr-&gt;nh) sofia_reg_new_handle(gateway_ptr, now ? 1 : 0);
+
+                        if (sofia_glue_check_nat(gateway_ptr-&gt;profile, gateway_ptr-&gt;register_proxy)) {
+                                user_via = sofia_glue_create_external_via(NULL, gateway_ptr-&gt;profile, gateway_ptr-&gt;register_transport);
+                        }
+
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Registering %s\n&quot;, gateway_ptr-&gt;name);
+                        
+                        if (now) {
+                                nua_register(gateway_ptr-&gt;nh,
+                                                         NUTAG_URL(gateway_ptr-&gt;register_url),
+                                                         TAG_IF(gateway_ptr-&gt;register_sticky_proxy, NUTAG_PROXY(gateway_ptr-&gt;register_sticky_proxy)),
+                                                         TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                                                         SIPTAG_TO_STR(gateway_ptr-&gt;register_from),
+                                                         SIPTAG_CONTACT_STR(gateway_ptr-&gt;register_contact),
+                                                         SIPTAG_FROM_STR(gateway_ptr-&gt;register_from),                                         
+                                                         SIPTAG_EXPIRES_STR(gateway_ptr-&gt;expires_str),
+                                                         NUTAG_REGISTRAR(gateway_ptr-&gt;register_proxy),
+                                                         NUTAG_OUTBOUND(&quot;no-options-keepalive&quot;), NUTAG_OUTBOUND(&quot;no-validate&quot;), NUTAG_KEEPALIVE(0), TAG_NULL());
+                                gateway_ptr-&gt;retry = now + gateway_ptr-&gt;retry_seconds;
+                        } else {
+                                nua_unregister(gateway_ptr-&gt;nh,
+                                                           NUTAG_URL(gateway_ptr-&gt;register_url),
+                                                           TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+                                                           SIPTAG_FROM_STR(gateway_ptr-&gt;register_from),
+                                                           SIPTAG_TO_STR(gateway_ptr-&gt;register_from),
+                                                           SIPTAG_EXPIRES_STR(gateway_ptr-&gt;expires_str),
+                                                           NUTAG_REGISTRAR(gateway_ptr-&gt;register_proxy),
+                                                           NUTAG_OUTBOUND(&quot;no-options-keepalive&quot;), NUTAG_OUTBOUND(&quot;no-validate&quot;), NUTAG_KEEPALIVE(0), TAG_NULL());
+                        }
+                        gateway_ptr-&gt;retry = now + gateway_ptr-&gt;retry_seconds;
+                        gateway_ptr-&gt;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, &quot;%s Failed Registration, setting retry to %d seconds.\n&quot;, 
+                                                                  gateway_ptr-&gt;name, gateway_ptr-&gt;retry_seconds * (gateway_ptr-&gt;failures + 1));
+                        gateway_ptr-&gt;retry =  now + (gateway_ptr-&gt;retry_seconds * (gateway_ptr-&gt;failures + 1));
+                        gateway_ptr-&gt;status = SOFIA_GATEWAY_DOWN;
+                        gateway_ptr-&gt;state = REG_STATE_FAIL_WAIT;
+                        break;
+                case REG_STATE_FAIL_WAIT:
+                        if (!gateway_ptr-&gt;retry || now &gt;= gateway_ptr-&gt;retry) {
+                                gateway_ptr-&gt;state = REG_STATE_UNREGED;
+                        }
+                        break;
+                case REG_STATE_TRYING:
+                        if (!gateway_ptr-&gt;retry || now &gt;= gateway_ptr-&gt;retry) {
+                                gateway_ptr-&gt;state = REG_STATE_FAILED;
+                        }
+                        break;
+                default:
+                        if (now &gt;= gateway_ptr-&gt;expires) {
+                                gateway_ptr-&gt;state = REG_STATE_UNREGED;
+                        }
+                        break;
+                }
+                if (ostate != gateway_ptr-&gt;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-&gt;val, argv[0], cbt-&gt;len);
+        cbt-&gt;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] = &quot;&quot;;
+        sofia_destination_t *dst = NULL;
+
+        switch_snprintf(to, sizeof(to), &quot;sip:%s@%s&quot;, argv[1], argv[2]);
+        dst = sofia_glue_get_destination(argv[3]);
+        switch_assert(dst);
+
+        nh = nua_handle(profile-&gt;nua, NULL, SIPTAG_FROM_STR(profile-&gt;url), SIPTAG_TO_STR(to), NUTAG_URL(dst-&gt;contact), SIPTAG_CONTACT_STR(profile-&gt;url), TAG_END());
+        nua_handle_bind(nh, &amp;mod_sofia_globals.destroy_private);
+        nua_options(nh, 
+                                TAG_IF(dst-&gt;route_uri, NUTAG_PROXY(dst-&gt;route_uri)),
+                                TAG_IF(dst-&gt;route, SIPTAG_ROUTE_STR(dst-&gt;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-&gt;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 = &quot;check-sync&quot;;
+        nua_handle_t *nh;
+        char *contact_url = NULL;
+        char *contact_str = NULL;
+        char *user_via = NULL;
+        char *id = NULL;
+
+        if (switch_stristr(&quot;snom&quot;, user_agent)) {
+                event = &quot;check-sync;reboot=true&quot;;
+        } else if (switch_stristr(&quot;linksys&quot;, user_agent)) {
+                event = &quot;reboot_now&quot;;
+        }
+
+        if ((contact_url = sofia_glue_get_url_from_contact((char *)contact, 1))) {
+                char *p;
+                id = switch_mprintf(&quot;sip:%s@%s&quot;, user, network_ip);
+
+                if ((p = strstr(contact_url, &quot;;fs_&quot;))) {
+                        *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, &quot;transport=&quot;))) {
+                                sofia_transport_t transport = sofia_glue_str2transport(ptr);
+                                transport_str = sofia_glue_transport2str(transport);
+                                
+                                switch (transport) {
+                                case SOFIA_TRANSPORT_TCP:
+                                        contact_str = profile-&gt;tcp_public_contact;
+                                        break;
+                                case SOFIA_TRANSPORT_TCP_TLS:
+                                        contact_str = profile-&gt;tls_public_contact;
+                                        break;
+                                default:
+                                        contact_str = profile-&gt;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-&gt;public_url;
+                        }
+                
+                } else {
+                        contact_str = profile-&gt;url;
+                }
+
+                nh = nua_handle(profile-&gt;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, &amp;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(&quot;application/simple-message-summary&quot;),
+                                   SIPTAG_PAYLOAD_STR(&quot;&quot;),
+                                   TAG_END());
+
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, &quot;Sending reboot command to %s\n&quot;, 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-&gt;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 &gt; 12 &amp;&amp; atoi(argv[12]) == 1) {
+                sofia_reg_send_reboot(profile, argv[1], argv[2], argv[3], argv[7], argv[11]);
+        }
+
+        if (argc &gt;= 3) {
+                if (switch_event_create_subclass(&amp;s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile-name&quot;, argv[10]);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;call-id&quot;, argv[0]);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;user&quot;, argv[1]);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;host&quot;, argv[2]);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;contact&quot;, argv[3]);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;expires&quot;, argv[6]);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;user-agent&quot;, argv[7]);
+                        switch_event_fire(&amp;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] = &quot;&quot;;
+        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 = &quot;none&quot;;
+        }
+
+        if (switch_strlen_zero(user)) {
+                switch_snprintf(sqlextra, sizeof(sqlextra), &quot; or (sip_host='%s')&quot;, host);
+        } else {
+                switch_snprintf(sqlextra, sizeof(sqlextra), &quot; or (sip_user='%s' and sip_host='%s')&quot;, user, host);
+        }
+
+        switch_snprintf(sql, sizeof(sql), &quot;select call_id,sip_user,sip_host,contact,status,rpid,expires&quot;
+                                        &quot;,user_agent,server_user,server_host,profile_name,network_ip&quot;
+                                        &quot;,%d from sip_registrations where call_id='%s' %s&quot;, 
+                                        reboot, call_id, sqlextra);
+        
+        switch_mutex_lock(profile-&gt;ireg_mutex);
+        sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_reg_del_callback, profile);
+        switch_mutex_unlock(profile-&gt;ireg_mutex);
+
+        switch_snprintf(sql, sizeof(sql), &quot;delete from sip_registrations where call_id='%s' or (sip_user='%s' and sip_host='%s')&quot;, 
+                                        call_id, user, host);
+        sofia_glue_execute_sql(profile, &amp;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() &amp;&amp; profile-&gt;odbc_dsn) {
+                if (!profile-&gt;master_odbc) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
+                        return;
+                }
+        } else {
+                if (!profile-&gt;master_db) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
+                        return;
+                }
+        }
+
+        switch_mutex_lock(profile-&gt;ireg_mutex);
+
+        if (now) {
+                switch_snprintf(sql, sizeof(sql), &quot;select call_id,sip_user,sip_host,contact,status,rpid,expires&quot;
+                                                &quot;,user_agent,server_user,server_host,profile_name,network_ip&quot;
+                                                &quot;,%d from sip_registrations where expires &gt; 0 and expires &lt;= %ld&quot;, reboot, (long) now);
+        } else {
+                switch_snprintf(sql, sizeof(sql), &quot;select call_id,sip_user,sip_host,contact,status,rpid,expires&quot;
+                                                &quot;,user_agent,server_user,server_host,profile_name,network_ip&quot;
+                                                &quot;,%d from sip_registrations where expires &gt; 0&quot;, reboot);
+        }
+
+        sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_reg_del_callback, profile);
+        if (now) {
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_registrations where expires &gt; 0 and expires &lt;= %ld and hostname='%s'&quot;, 
+                                                (long) now, mod_sofia_globals.hostname);
+        } else {
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_registrations where expires &gt; 0 and hostname='%s'&quot;, mod_sofia_globals.hostname);
+        }
+
+        sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+
+
+        if (now) {
+                switch_snprintf(sql, sizeof(sql), &quot;select call_id from sip_shared_appearance_dialogs where hostname='%s' &quot;
+                                                &quot;and profile_name='%s' and expires &lt;= %ld&quot;, 
+                                                mod_sofia_globals.hostname, profile-&gt;name, (long) now);
+        
+                sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_sla_dialog_del_callback, profile);
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_registrations where expires &gt; 0 and hostname='%s' and expires &lt;= %ld&quot;, 
+                                                mod_sofia_globals.hostname, (long) now);
+
+
+                sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+        }
+
+
+        if (now) {
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_presence where expires &gt; 0 and expires &lt;= %ld and hostname='%s'&quot;, 
+                                                (long) now, mod_sofia_globals.hostname);
+        } else {
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_presence where expires &gt; 0 and hostname='%s'&quot;, mod_sofia_globals.hostname);
+        }
+
+        sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+        if (now) {
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_authentication where expires &gt; 0 and expires &lt;= %ld and hostname='%s'&quot;, 
+                                                (long) now, mod_sofia_globals.hostname);
+        } else {
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_authentication where expires &gt; 0 and hostname='%s'&quot;, mod_sofia_globals.hostname);
+        }
+
+        sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+
+
+        if (now) {
+                switch_snprintf(sql, sizeof(sql), &quot;select call_id from sip_subscriptions where expires &gt; 0 and expires &lt;= %ld and hostname='%s'&quot;, 
+                                                (long) now, mod_sofia_globals.hostname);
+        } else {
+                switch_snprintf(sql, sizeof(sql), &quot;select call_id from sip_subscriptions where expires &gt; 0 and hostname='%s'&quot;, 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), &quot;delete from sip_subscriptions where expires &gt; 0 and expires &lt;= %ld and hostname='%s'&quot;, 
+                                                (long) now, mod_sofia_globals.hostname);
+        } else {
+                switch_snprintf(sql, sizeof(sql), &quot;delete from sip_subscriptions where expires &gt; 0 and hostname='%s'&quot;, mod_sofia_globals.hostname);
+        }
+
+        sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL);
+
+
+        if (now &amp;&amp; sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) {
+                switch_snprintf(sql, sizeof(sql), &quot;select call_id,sip_user,sip_host,contact,status,rpid,&quot;
+                                                &quot;expires,user_agent,server_user,server_host,profile_name&quot;
+                                                &quot; from sip_registrations where (status like '%%AUTO-NAT%%' &quot;
+                                                &quot;or status like '%%UDP-NAT%%') and hostname='%s'&quot;, mod_sofia_globals.hostname);
+
+                sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_reg_nat_callback, profile);
+        }
+
+        switch_mutex_unlock(profile-&gt;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] = &quot;&quot;;
+
+        if (!user) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Called with null user!\n&quot;);
+                return NULL;
+        }
+
+        cbt.val = val;
+        cbt.len = len;
+
+        if (host) {
+                switch_snprintf(sql, sizeof(sql), &quot;select contact from sip_registrations where sip_user='%s' and (sip_host='%s' or presence_hosts like '%%%s%%')&quot;
+                                                , user, host, host);
+        } else {
+                switch_snprintf(sql, sizeof(sql), &quot;select contact from sip_registrations where sip_user='%s'&quot;, user);
+        }
+
+
+        sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, sofia_reg_find_callback, &amp;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(&amp;uuid);
+        switch_uuid_format(uuid_str, &amp;uuid);
+
+        sql = switch_mprintf(&quot;insert into sip_authentication (nonce,expires,profile_name,hostname) &quot;
+                                                 &quot;values('%q', %ld, '%q', '%q')&quot;, uuid_str, switch_epoch_time_now(NULL) + profile-&gt;nonce_ttl, profile-&gt;name, mod_sofia_globals.hostname);
+        switch_assert(sql != NULL);
+        sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, profile-&gt;ireg_mutex);
+        switch_safe_free(sql);
+
+        auth_str = switch_mprintf(&quot;Digest realm=\&quot;%q\&quot;, nonce=\&quot;%q\&quot;,%s algorithm=MD5, qop=\&quot;auth\&quot;&quot;, realm, uuid_str, stale ? &quot; stale=\&quot;true\&quot;,&quot; : &quot;&quot;);
+
+        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-&gt;reg_db_domain;
+        char contact_str[1024] = &quot;&quot;;
+        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 = &quot;unknown&quot;;
+        const char *display = &quot;\&quot;user\&quot;&quot;;
+        char network_ip[80];
+        char network_port_c[6];
+        char url_ip[80];
+        char *register_gateway = NULL;
+        int network_port;
+        const char *reg_desc = &quot;Registered&quot;;
+        const char *call_id = NULL;
+        char *force_user;
+        char received_data[128] = &quot;&quot;;
+        char *path_val = NULL;
+        switch_event_t *auth_params = NULL;
+        int r = 0;
+
+        /* all callers must confirm that sip, sip-&gt;sip_request and sip-&gt;sip_contact are not NULL */
+        switch_assert(sip != NULL &amp;&amp; sip-&gt;sip_contact != NULL &amp;&amp; sip-&gt;sip_request != NULL);
+
+        sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &amp;network_port);
+
+        snprintf(network_port_c, sizeof(network_port_c), &quot;%d&quot;, network_port);
+
+        snprintf(url_ip, sizeof(url_ip), (msg_addrinfo(nua_current_request(nua)))-&gt;ai_addr-&gt;sa_family == AF_INET6 ? &quot;[%s]&quot; : &quot;%s&quot;, network_ip);
+
+        expires = sip-&gt;sip_expires;
+        authorization = sip-&gt;sip_authorization;
+        contact = sip-&gt;sip_contact;
+        to = sip-&gt;sip_to;
+
+        if (to) {
+                to_user = to-&gt;a_url-&gt;url_user;
+                to_host = to-&gt;a_url-&gt;url_host;
+        }
+
+        if (!to_user || !to_host) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Can not do authorization without a complete from header\n&quot;);
+                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-&gt;sip_from;
+
+        if (from) {
+                from_user = from-&gt;a_url-&gt;url_user;
+                from_host = from-&gt;a_url-&gt;url_host;
+        }
+
+        if (contact-&gt;m_url) {
+                const char *port = contact-&gt;m_url-&gt;url_port;
+                char new_port[25] = &quot;&quot;;
+                const char *contact_host = contact-&gt;m_url-&gt;url_host;
+                char *path_encoded = NULL;
+                int path_encoded_len = 0;
+                const char *proto = &quot;sip&quot;;
+                int is_tls = 0, is_tcp = 0;
+
+
+                if (switch_stristr(&quot;transport=tls&quot;, sip-&gt;sip_contact-&gt;m_url-&gt;url_params)) {
+                        is_tls += 1;
+                }
+                
+                if (sip-&gt;sip_contact-&gt;m_url-&gt;url_type == url_sips) {
+                        proto = &quot;sips&quot;;
+                        is_tls += 2;
+                }
+                
+                if (switch_stristr(&quot;transport=tcp&quot;, sip-&gt;sip_contact-&gt;m_url-&gt;url_params)) {
+                        is_tcp = 1;
+                }
+                
+                display = contact-&gt;m_display;
+                
+                if (is_nat) {
+                        if (is_tls) {
+                                reg_desc = &quot;Registered(TLS-NAT)&quot;;
+                        } else if (is_tcp) {
+                                reg_desc = &quot;Registered(TCP-NAT)&quot;;
+                        } else {
+                                reg_desc = &quot;Registered(UDP-NAT)&quot;;
+                        }
+                        //contact_host = url_ip;
+                        //switch_snprintf(new_port, sizeof(new_port), &quot;:%d&quot;, network_port);
+                        //port = NULL;
+                } else {
+                        if (is_tls) {
+                                reg_desc = &quot;Registered(TLS)&quot;;
+                        } else if (is_tcp) {
+                                reg_desc = &quot;Registered(TCP)&quot;;
+                        } else {
+                                reg_desc = &quot;Registered(UDP)&quot;;
+                        }
+                }
+
+                if (switch_strlen_zero(display)) {
+                        if (to) {
+                                display = to-&gt;a_display;
+                                if (switch_strlen_zero(display)) {
+                                        display = &quot;\&quot;user\&quot;&quot;;
+                                }
+                        }
+                }
+
+                if (sip-&gt;sip_path) {
+                        path_val = sip_header_as_string(nua_handle_home(nh), (void *) sip-&gt;sip_path);
+                        path_encoded_len = (strlen(path_val) * 3) + 1;
+                        switch_zmalloc(path_encoded, path_encoded_len);
+                        switch_copy_string(path_encoded, &quot;;fs_path=&quot;, 10);
+                        switch_url_encode(path_val, path_encoded + 9, path_encoded_len - 9);
+                } else if (is_nat) {
+                        char my_contact_str[1024];
+                        if (sip-&gt;sip_contact-&gt;m_url-&gt;url_params) {
+                                switch_snprintf(my_contact_str, sizeof(my_contact_str), &quot;sip:%s@%s:%d;%s&quot;, 
+                                                                contact-&gt;m_url-&gt;url_user, url_ip, network_port, sip-&gt;sip_contact-&gt;m_url-&gt;url_params);
+                        } else {
+                                switch_snprintf(my_contact_str, sizeof(my_contact_str), &quot;sip:%s@%s:%d&quot;, contact-&gt;m_url-&gt;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, &quot;;fs_path=&quot;, 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), &quot;:%s&quot;, port);
+                }
+
+                if (is_nat &amp;&amp; sofia_test_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT)) {
+                        switch_snprintf(received_data, sizeof(received_data), &quot;;received=%s:%d&quot;, url_ip, network_port);
+                }
+
+                if (contact-&gt;m_url-&gt;url_params) {
+                        switch_snprintf(contact_str, sizeof(contact_str), &quot;%s &lt;%s:%s@%s%s;%s%s%s%s&gt;&quot;,
+                                                        display, proto, contact-&gt;m_url-&gt;url_user, contact_host, new_port, 
+                                                        contact-&gt;m_url-&gt;url_params, received_data, is_nat ? &quot;;fs_nat=yes&quot; : &quot;&quot;, path_encoded ? path_encoded : &quot;&quot;);
+                } else {
+                        switch_snprintf(contact_str, sizeof(contact_str), &quot;%s &lt;%s:%s@%s%s%s%s%s&gt;&quot;, display, proto, contact-&gt;m_url-&gt;url_user, contact_host, new_port,
+                                                        received_data, is_nat ? &quot;;fs_nat=yes&quot; : &quot;&quot;, path_encoded ? path_encoded : &quot;&quot;);
+                }
+
+                switch_safe_free(path_encoded);
+        }
+
+        if (expires) {
+                exptime = expires-&gt;ex_delta;
+        } else if (contact-&gt;m_expires) {
+                exptime = atol(contact-&gt;m_expires);
+        }
+
+        if (regtype == REG_REGISTER) {
+                authorization = sip-&gt;sip_authorization;
+        } else if (regtype == REG_INVITE) {
+                authorization = sip-&gt;sip_proxy_authorization;
+        }
+
+        if (regtype == REG_AUTO_REGISTER || (regtype == REG_REGISTER &amp;&amp; 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-&gt;sip_request-&gt;rq_method_name,
+                                                                                         key, keylen, network_ip, v_event, exptime, regtype, to_user, &amp;auth_params)) == AUTH_STALE) {
+                        stale = 1;
+                }
+
+                if (exptime &amp;&amp; v_event &amp;&amp; *v_event) {
+                        char *exp_var;
+                        char *allow_multireg = NULL;
+
+                        allow_multireg = switch_event_get_header(*v_event, &quot;sip-allow-multiple-registrations&quot;);
+                        if ( allow_multireg &amp;&amp; switch_false(allow_multireg) ) {
+                                avoid_multi_reg = 1;
+                        }
+
+                        register_gateway = switch_event_get_header(*v_event, &quot;sip-register-gateway&quot;);
+
+                        /* 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, &quot;sip-force-user&quot;))) {
+                                to_user = force_user;
+                        }
+
+                        if ((v_contact_str = switch_event_get_header(*v_event, &quot;sip-force-contact&quot;))) {
+                                if (!strcasecmp(v_contact_str, &quot;NDLB-connectile-dysfunction-2.0&quot;)) {
+                                        char *path_encoded;
+                                        size_t path_encoded_len;
+                                        char my_contact_str[1024];
+
+                                        switch_snprintf(my_contact_str, sizeof(my_contact_str), &quot;sip:%s@%s:%d&quot;, contact-&gt;m_url-&gt;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, &quot;;fs_nat=yes;fs_path=&quot;, 21);
+                                        switch_url_encode(my_contact_str, path_encoded + 20, path_encoded_len - 20);
+                                        reg_desc = &quot;Registered(AUTO-NAT-2.0)&quot;;
+                                        exptime = 30;
+                                        switch_snprintf(contact_str + strlen(contact_str), sizeof(contact_str) - strlen(contact_str), &quot;%s&quot;, path_encoded);
+                                        free(path_encoded);
+                                } else {
+                                        if (*received_data &amp;&amp; sofia_test_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT)) {
+                                                switch_snprintf(received_data, sizeof(received_data), &quot;;received=%s:%d&quot;, url_ip, network_port);
+                                        }
+
+        
+                                        if (!strcasecmp(v_contact_str, &quot;nat-connectile-dysfunction&quot;) ||
+                                                !strcasecmp(v_contact_str, &quot;NDLB-connectile-dysfunction&quot;) || !strcasecmp(v_contact_str, &quot;NDLB-tls-connectile-dysfunction&quot;)) {
+                                                if (contact-&gt;m_url-&gt;url_params) {
+                                                        switch_snprintf(contact_str, sizeof(contact_str), &quot;%s &lt;sip:%s@%s:%d;%s%s;fs_nat=yes&gt;&quot;,
+                                                                                        display, contact-&gt;m_url-&gt;url_user, url_ip, network_port, contact-&gt;m_url-&gt;url_params, received_data);
+                                                } else {
+                                                        switch_snprintf(contact_str, sizeof(contact_str), &quot;%s &lt;sip:%s@%s:%d%s;fs_nat=yes&gt;&quot;, display, contact-&gt;m_url-&gt;url_user, url_ip,
+                                                                                        network_port, received_data);
+                                                }
+                                                if (strstr(v_contact_str, &quot;tls&quot;)) {
+                                                        reg_desc = &quot;Registered(TLSHACK)&quot;;
+                                                } else {
+                                                        reg_desc = &quot;Registered(AUTO-NAT)&quot;;
+                                                        exptime = 30;
+                                                }
+                                                nat_hack = 1;
+                                        } else {
+                                                char *p;
+                                                switch_copy_string(contact_str, v_contact_str, sizeof(contact_str));
+                                                for (p = contact_str; p &amp;&amp; *p; p++) {
+                                                        if (*p == '\'' || *p == '[' || *p == ']') {
+                                                                *p = '&quot;';
+                                                        }
+                                                }
+                                        }
+                                }
+                        }
+
+                        if ((exp_var = switch_event_get_header(*v_event, &quot;sip-force-expires&quot;))) {
+                                int tmp = atoi(exp_var);
+                                if (tmp &gt; 0) {
+                                        exptime = tmp;
+                                }
+                        }
+                }
+
+                if (auth_res != AUTH_OK &amp;&amp; !stale) {
+                        if (profile-&gt;debug) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Send %s for [%s@%s]\n&quot;, forbidden ? &quot;forbidden&quot; : &quot;challenge&quot;, 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-&gt;challenge_realm;
+
+                if (switch_strlen_zero(realm) || !strcasecmp(realm, &quot;auto_to&quot;)) {
+                        realm = to_host;
+                } else if (!strcasecmp(realm, &quot;auto_from&quot;)) {
+                        realm = from_host;
+                }
+
+                if (regtype == REG_REGISTER) {
+                        sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale);
+                        if (profile-&gt;debug) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Requesting Registration from: [%s@%s]\n&quot;, 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-&gt;sip_call_id-&gt;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 &amp;&amp; avoid_multi_reg ) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
+                                        &quot;Disabling multiple registrations on a per-user basis for %s@%s\n&quot;, 
+                                        switch_str_nil(to_user), switch_str_nil(to_host) );
+                multi_reg = 0;
+        }
+
+        if (exptime) {
+                const char *agent = &quot;dunno&quot;;
+                char guess_ip4[256];
+                const char *username = &quot;unknown&quot;;
+                const char *realm = reg_host;
+
+                if (auth_params) {
+                        username = switch_event_get_header(auth_params, &quot;sip_auth_username&quot;);
+                        realm = switch_event_get_header(auth_params, &quot;sip_auth_realm&quot;);
+                }
+
+                if (sip-&gt;sip_user_agent) {
+                        agent = sip-&gt;sip_user_agent-&gt;g_string;
+                }
+
+                if (multi_reg) {
+                        if (multi_reg_contact) {
+                                sql = switch_mprintf(&quot;delete from sip_registrations where sip_user='%q' and sip_host='%q' and contact='%q'&quot;, to_user, reg_host, contact_str);
+                        } else {
+                                sql = switch_mprintf(&quot;delete from sip_registrations where call_id='%q'&quot;, call_id);
+                        }
+                } else {
+                        sql = switch_mprintf(&quot;delete from sip_registrations where sip_user='%q' and sip_host='%q'&quot;, 
+                                                                 to_user, reg_host);
+                }
+                switch_mutex_lock(profile-&gt;ireg_mutex);
+                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+                
+                switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET);
+                sql = switch_mprintf(&quot;insert into sip_registrations &quot;
+                                                         &quot;(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires,&quot;
+                                                         &quot;user_agent,server_user,server_host,profile_name,hostname,network_ip,network_port,sip_username,sip_realm) &quot;
+                                                         &quot;values ('%q','%q', '%q','%q','%q','%q', '%q', %ld, '%q', '%q', '%q', '%q', '%q', '%q', '%q','%q','%q')&quot;, 
+                                                         call_id, to_user, reg_host, profile-&gt;presence_hosts ? profile-&gt;presence_hosts : reg_host, 
+                                                         contact_str, reg_desc, rpid, (long) switch_epoch_time_now(NULL) + (long) exptime * 2, 
+                                                         agent, from_user, guess_ip4, profile-&gt;name, mod_sofia_globals.hostname, network_ip, network_port_c, username, realm);
+                                                         
+                if (sql) {
+                        sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+                }
+
+
+                switch_mutex_unlock(profile-&gt;ireg_mutex);
+
+                if (switch_event_create_subclass(&amp;s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile-name&quot;, profile-&gt;name);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;from-user&quot;, to_user);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;from-host&quot;, reg_host);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;presence-hosts&quot;, profile-&gt;presence_hosts ? profile-&gt;presence_hosts : reg_host);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;contact&quot;, contact_str);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;call-id&quot;, call_id);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;statusd&quot;, reg_desc);
+                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;expires&quot;, &quot;%ld&quot;, (long) exptime);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;to-user&quot;, from_user);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;to-host&quot;, from_host);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;network-ip&quot;, network_ip);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;network-port&quot;, network_port_c);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;username&quot;, username);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;realm&quot;, realm);
+                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;user-agent&quot;, agent);
+                        switch_event_fire(&amp;s_event);
+                }
+
+
+
+                if (profile-&gt;debug) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+                                                          &quot;Register:\nFrom:    [%s@%s]\nContact: [%s]\nExpires: [%ld]\n&quot;, to_user, reg_host, contact_str, (long) exptime);
+                }
+
+                
+#if 0
+                if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;user-agent&quot;,
+                                                                                   (sip &amp;&amp; sip-&gt;sip_user_agent) ? sip-&gt;sip_user_agent-&gt;g_string : &quot;unknown&quot;);
+                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, to_user, reg_host);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;Registered&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
+                        switch_event_fire(&amp;event);
+                }
+#else
+                if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, &quot;sip&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, to_user, reg_host);
+                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;to&quot;, &quot;%s@%s&quot;, to_user, reg_host);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;Registered&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_subtype&quot;, &quot;probe&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
+                        switch_event_fire(&amp;event);
+                }
+#endif
+
+
+        } else {
+
+                if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, SOFIA_CHAT_PROTO);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;user-agent&quot;,
+                                                                                   (sip &amp;&amp; sip-&gt;sip_user_agent) ? sip-&gt;sip_user_agent-&gt;g_string : &quot;unknown&quot;);
+                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s@%s&quot;, to_user, reg_host);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;Unregistered&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
+                        switch_event_fire(&amp;event);
+                }
+#if 0
+                if (switch_event_create(&amp;event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, &quot;sip&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, profile-&gt;url);
+                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, &quot;%s+%s@%s&quot;, SOFIA_CHAT_PROTO, to_user, reg_host);
+
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;status&quot;, &quot;unavailable&quot;);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_type&quot;, &quot;presence&quot;);
+                        switch_event_fire(&amp;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(&quot;delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'&quot;, to_user, reg_host, contact_str);
+                        } else {
+                                sql = switch_mprintf(&quot;delete from sip_subscriptions where call_id='%q'&quot;, call_id);
+                        }
+
+                        sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+
+                        if (multi_reg_contact) {
+                                sql = switch_mprintf(&quot;delete from sip_registrations where sip_user='%q' and sip_host='%q' and contact='%q'&quot;, to_user, reg_host, contact_str);
+                        } else {
+                                sql = switch_mprintf(&quot;delete from sip_registrations where call_id='%q'&quot;, call_id);
+                        }
+
+                        sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+
+                        switch_safe_free(icontact);
+                } else {
+                        if ((sql = switch_mprintf(&quot;delete from sip_subscriptions where sip_user='%q' and sip_host='%q'&quot;, to_user, reg_host))) {
+                                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+                        }
+
+                        if ((sql = switch_mprintf(&quot;delete from sip_registrations where sip_user='%q' and sip_host='%q'&quot;, to_user, reg_host))) {
+                                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+                        }
+                }
+        }
+
+
+        if (regtype == REG_REGISTER) {
+                char exp_param[128] = &quot;&quot;;
+                char date[80] = &quot;&quot;;
+
+                s_event = NULL;
+
+                if (exptime) {
+                        switch_snprintf(exp_param, sizeof(exp_param), &quot;expires=%ld&quot;, exptime);
+                        sip_contact_add_param(nua_handle_home(nh), sip-&gt;sip_contact, exp_param);
+
+                        if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER)) {
+                                if (switch_event_create(&amp;s_event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
+                                        switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;Message-Account&quot;, &quot;sip:%s@%s&quot;, to_user, reg_host);
+                                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;VM-Sofia-Profile&quot;, profile-&gt;name);
+                                        switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;VM-Call-ID&quot;, call_id);
+                                }
+                        }
+                } else {
+                        if (switch_event_create_subclass(&amp;s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) {
+                                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;profile-name&quot;, profile-&gt;name);
+                                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;from-user&quot;, to_user);
+                                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;from-host&quot;, reg_host);
+                                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;contact&quot;, contact_str);
+                                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;call-id&quot;, call_id);
+                                switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, &quot;rpid&quot;, rpid);
+                                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, &quot;expires&quot;, &quot;%ld&quot;, (long) exptime);
+                        }
+                }
+                
+                switch_rfc822_date(date, switch_micro_time_now());
+                nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip-&gt;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(&amp;s_event);
+                }
+
+                if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
+                        char *full_contact = sip_header_as_string(nua_handle_home(nh), (void *) sip-&gt;sip_contact);
+                        if (full_contact &amp;&amp; switch_stristr(&quot;SUBSCRIBE&quot;, 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(&amp;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] = &quot;&quot;;
+        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), &amp;network_port);
+
+        if (!(sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;NO CONTACT!\n&quot;);
+                nua_respond(nh, 400, &quot;Missing Contact Header&quot;, TAG_END());
+                goto end;
+        }
+
+        if (!(profile-&gt;mflags &amp; 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 &amp;&amp; sip-&gt;sip_via) {
+                        const char *port = sip-&gt;sip_via-&gt;v_port;
+                        const char *host = sip-&gt;sip_via-&gt;v_host;
+                                        
+                        if (host &amp;&amp; sip-&gt;sip_via-&gt;v_received) {
+                                is_nat = &quot;via received&quot;;
+                        } else if (host &amp;&amp; strcmp(network_ip, host)) {
+                                is_nat = &quot;via host&quot;;
+                        } else if (port &amp;&amp; atoi(port) != network_port) {
+                                is_nat = &quot;via port&quot;;
+                        }
+                }
+        }
+
+        if (!is_nat &amp;&amp; profile-&gt;nat_acl_count) {
+                uint32_t x = 0;
+                int ok = 1;
+                char *last_acl = NULL;
+                const char *contact_host = NULL;
+
+                if (sip &amp;&amp; sip-&gt;sip_contact &amp;&amp; sip-&gt;sip_contact-&gt;m_url) {
+                        contact_host = sip-&gt;sip_contact-&gt;m_url-&gt;url_host;
+                }
+
+                if (!switch_strlen_zero(contact_host)) {
+                        for (x = 0; x &lt; profile-&gt;nat_acl_count; x++) {
+                                last_acl = profile-&gt;nat_acl[x];
+                                if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
+                                        break;
+                                }
+                        }
+                                
+                        if (ok) {
+                                is_nat = last_acl;
+                        }
+                }
+        }
+                        
+        if (profile-&gt;reg_acl_count) {
+                uint32_t x = 0;
+                int ok = 1;
+                char *last_acl = NULL;
+
+                for (x = 0; x &lt; profile-&gt;reg_acl_count; x++) {
+                        last_acl = profile-&gt;reg_acl[x];
+                        if (!(ok = switch_check_network_list_ip(network_ip, last_acl))) {
+                                break;
+                        }
+                }
+
+                if (ok &amp;&amp; !sofia_test_pflag(profile, PFLAG_BLIND_REG)) {
+                        type = REG_AUTO_REGISTER;
+                } else if (!ok) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;IP %s Rejected by acl \&quot;%s\&quot;\n&quot;, network_ip, profile-&gt;reg_acl[x]);
+                        nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
+                        goto end;
+                }
+        }
+
+        if (!sip || !sip-&gt;sip_request || !sip-&gt;sip_request-&gt;rq_method_name) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Received an invalid packet!\n&quot;);
+                nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+                goto end;
+        }
+
+        sofia_reg_handle_register(nua, profile, nh, sip, type, key, sizeof(key), &amp;v_event, is_nat);
+        
+        if (v_event) {
+                switch_event_fire(&amp;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 &amp;&amp; sofia_private-&gt;gateway) {
+                reg_state_t ostate = sofia_private-&gt;gateway-&gt;state;
+                switch (status) {
+                case 200:
+                        if (sip &amp;&amp; sip-&gt;sip_contact) {
+                                sip_contact_t *contact = sip-&gt;sip_contact;
+                                const char *new_expires;
+                                uint32_t expi;
+                                if (contact-&gt;m_next) {
+                                        const char *sipip = profile-&gt;extsipip ?  profile-&gt;extsipip : profile-&gt;sipip;
+                                        for ( ; contact &amp;&amp; strcasecmp(contact-&gt;m_url-&gt;url_host, sipip); contact = contact-&gt;m_next);
+                                }
+
+                                if (!contact) {
+                                        contact = sip-&gt;sip_contact;
+                                }
+
+                                if (contact-&gt;m_expires) {
+                                        new_expires = contact-&gt;m_expires;
+                                        expi = (uint32_t) atoi(new_expires);
+        
+                                        if (expi &gt; 0 &amp;&amp; expi != sofia_private-&gt;gateway-&gt;freq) {
+                                                sofia_private-&gt;gateway-&gt;freq = expi;
+                                                sofia_private-&gt;gateway-&gt;expires_str = switch_core_sprintf(sofia_private-&gt;gateway-&gt;pool, &quot;%d&quot;, expi);
+
+                                                if (expi &gt; 60) {
+                                                        sofia_private-&gt;gateway-&gt;expires = switch_epoch_time_now(NULL) + (expi - 15);
+                                                } else {
+                                                        sofia_private-&gt;gateway-&gt;expires = switch_epoch_time_now(NULL) + (expi - 2);
+                                                }
+
+
+                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+                                                                                  &quot;Changing expire time to %d by request of proxy %s\n&quot;, expi, sofia_private-&gt;gateway-&gt;register_proxy);
+                                        }
+                                }
+                        }
+                        sofia_private-&gt;gateway-&gt;state = REG_STATE_REGISTER;
+                        break;
+                case 100:
+                        break;
+                default:
+                        sofia_private-&gt;gateway-&gt;state = REG_STATE_FAILED;
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;%s Registration Failed with status %s [%d]. failure #%d\n&quot;, 
+                                                          sofia_private-&gt;gateway-&gt;name, switch_str_nil(phrase), status, ++sofia_private-&gt;gateway-&gt;failures);
+                        break;
+                }
+                if (ostate != sofia_private-&gt;gateway-&gt;state) {
+                        sofia_reg_fire_custom_gateway_state_event(sofia_private-&gt;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] = &quot;&quot;;
+        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 &amp;&amp; (channel = switch_core_session_get_channel(session))) {
+                sip_auth_username = switch_channel_get_variable(channel, &quot;sip_auth_username&quot;);
+                sip_auth_password = switch_channel_get_variable(channel, &quot;sip_auth_password&quot;);
+        }
+
+        if (sofia_private &amp;&amp; *sofia_private-&gt;auth_gateway_name) {
+                gw_name = sofia_private-&gt;auth_gateway_name;
+        }
+
+        if (session) {
+                private_object_t *tech_pvt;
+
+                if ((tech_pvt = switch_core_session_get_private(session)) &amp;&amp; sofia_test_flag(tech_pvt, TFLAG_REFER)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Received reply from REFER\n&quot;);
+                        goto end;
+                }
+
+                gw_name = switch_channel_get_variable(switch_core_session_get_channel(session), &quot;sip_use_gateway&quot;);
+        }
+
+
+        if (sip-&gt;sip_www_authenticate) {
+                authenticate = sip-&gt;sip_www_authenticate;
+        } else if (sip-&gt;sip_proxy_authenticate) {
+                authenticate = sip-&gt;sip_proxy_authenticate;
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Missing Authenticate Header!\n&quot;);
+                goto end;
+        }
+        scheme = (char const *) authenticate-&gt;au_scheme;
+        if (authenticate-&gt;au_params) {
+                for (indexnum = 0; (cur = (char *) authenticate-&gt;au_params[indexnum]); indexnum++) {
+                        if ((realm = strstr(cur, &quot;realm=&quot;))) {
+                                realm += 6;
+                                break;
+                        }
+                }
+        }
+
+        if (!gateway) {
+                if (gw_name) {
+                        var_gateway = sofia_reg_find_gateway((char *)gw_name);
+                }
+
+
+                if (!var_gateway &amp;&amp; realm) {
+                        char rb[512] = &quot;&quot;;
+                        char *p = (char *) realm;
+                        while((*p == '&quot;')) {
+                                p++;
+                        }
+                        switch_set_string(rb, p);
+                        if ((p = strchr(rb, '&quot;'))) {
+                                *p = '\0';
+                        }
+                        var_gateway = sofia_reg_find_gateway(rb);
+                }
+
+                if (!var_gateway &amp;&amp; sip &amp;&amp; sip-&gt;sip_to) {
+                        var_gateway = sofia_reg_find_gateway(sip-&gt;sip_to-&gt;a_url-&gt;url_host);
+                }
+                
+                if (var_gateway) {
+                        gateway = var_gateway;
+                }
+        }
+
+        
+
+
+        if (!(scheme &amp;&amp; realm)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;No scheme and realm!\n&quot;);
+                goto end;
+        }
+
+        if (sip_auth_username &amp;&amp; sip_auth_password) {
+                switch_snprintf(authentication, sizeof(authentication), &quot;%s:%s:%s:%s&quot;, scheme, realm, sip_auth_username, sip_auth_password);
+        } else if (gateway) {
+                switch_snprintf(authentication, sizeof(authentication), &quot;%s:%s:%s:%s&quot;, scheme, realm, gateway-&gt;auth_username, gateway-&gt;register_password);
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;No Matching gateway found\n&quot;);
+                goto cancel;                
+        }
+
+        if (profile-&gt;debug) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Authenticating '%s' with '%s'.\n&quot;,
+                        (sip_auth_username &amp;&amp; sip_auth_password) ? sip_auth_username : gateway-&gt;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-&gt;expires_str : &quot;3600&quot;), 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] = &quot;&quot;;
+        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-&gt;au_params) {
+                for (indexnum = 0; (cur = authorization-&gt;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 == '&quot;') {
+                                                *val++ = '\0';
+                                        }
+                                        if ((p = strchr(val, '&quot;'))) {
+                                                *p = '\0';
+                                        }
+
+                                        if (!strcasecmp(var, &quot;username&quot;)) {
+                                                username = strdup(val);
+                                        } else if (!strcasecmp(var, &quot;realm&quot;)) {
+                                                realm = strdup(val);
+                                        } else if (!strcasecmp(var, &quot;nonce&quot;)) {
+                                                nonce = strdup(val);
+                                        } else if (!strcasecmp(var, &quot;uri&quot;)) {
+                                                uri = strdup(val);
+                                        } else if (!strcasecmp(var, &quot;qop&quot;)) {
+                                                qop = strdup(val);
+                                        } else if (!strcasecmp(var, &quot;cnonce&quot;)) {
+                                                cnonce = strdup(val);
+                                        } else if (!strcasecmp(var, &quot;response&quot;)) {
+                                                response = strdup(val);
+                                        } else if (!strcasecmp(var, &quot;nc&quot;)) {
+                                                nc = strdup(val);
+                                        }
+                                }
+
+                                free(work);
+                        }
+                }
+        }
+
+        if (!(username &amp;&amp; realm &amp;&amp; nonce &amp;&amp; uri &amp;&amp; response)) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Invalid Authorization header!\n&quot;);
+                ret = AUTH_STALE;
+                goto end;
+        }
+
+        /* Optional check that auth name == SIP username */
+        if ((regtype == REG_REGISTER) &amp;&amp; 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, &quot;SIP username %s does not match auth username\n&quot;, switch_str_nil(to_user));
+                        goto end;
+                }
+        }
+
+        if (switch_strlen_zero(np)) {
+                first = 1;
+                sql = switch_mprintf(&quot;select nonce from sip_authentication where nonce='%q'&quot;, nonce);
+                switch_assert(sql != NULL);
+                if (!sofia_glue_execute_sql2str(profile, profile-&gt;ireg_mutex, sql, np, nplen)) {
+                        free(sql);
+                        ret = AUTH_STALE;
+                        goto end;
+                }
+                free(sql);
+        }
+
+        switch_event_create(&amp;params, SWITCH_EVENT_REQUEST_PARAMS);
+        switch_assert(params);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;action&quot;, &quot;sip_auth&quot;);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_profile&quot;, profile-&gt;name);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_user_agent&quot;,
+                                                                   (sip &amp;&amp; sip-&gt;sip_user_agent) ? sip-&gt;sip_user_agent-&gt;g_string : &quot;unknown&quot;);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_username&quot;, username);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_realm&quot;, realm);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_nonce&quot;, nonce);
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_uri&quot;, uri);
+
+        if (sip-&gt;sip_contact) {
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_contact_user&quot;, sip-&gt;sip_contact-&gt;m_url-&gt;url_user);
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_contact_host&quot;, sip-&gt;sip_contact-&gt;m_url-&gt;url_host);
+        }
+
+        if (sip-&gt;sip_to) {
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_to_user&quot;, sip-&gt;sip_to-&gt;a_url-&gt;url_user);
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_to_host&quot;, sip-&gt;sip_to-&gt;a_url-&gt;url_host);
+                if (sip-&gt;sip_to-&gt;a_url-&gt;url_port) {
+                        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_to_port&quot;, sip-&gt;sip_to-&gt;a_url-&gt;url_port);
+                }
+        }
+
+        if (sip-&gt;sip_from) {
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_from_user&quot;, sip-&gt;sip_from-&gt;a_url-&gt;url_user);
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_from_host&quot;, sip-&gt;sip_from-&gt;a_url-&gt;url_host);
+                if (sip-&gt;sip_from-&gt;a_url-&gt;url_port) {
+                        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_from_port&quot;, sip-&gt;sip_from-&gt;a_url-&gt;url_port);
+                }
+        }
+
+        if (sip-&gt;sip_request) {
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_request_user&quot;, sip-&gt;sip_request-&gt;rq_url-&gt;url_user);
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_request_host&quot;, sip-&gt;sip_request-&gt;rq_url-&gt;url_host);
+                if (sip-&gt;sip_request-&gt;rq_url-&gt;url_port) {
+                        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_request_port&quot;, sip-&gt;sip_request-&gt;rq_url-&gt;url_port);
+                }
+        }
+
+        if (qop) {
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_qop&quot;, qop);
+        }
+        if (cnonce) {
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_cnonce&quot;, cnonce);
+        }
+        if (nc) {
+                switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_nc&quot;, nc);
+        }
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_response&quot;, response);
+
+        switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;sip_auth_method&quot;, (sip &amp;&amp; sip-&gt;sip_request) ? sip-&gt;sip_request-&gt;rq_method_name : NULL);
+
+        if (auth_params) {
+                switch_event_dup(auth_params, params);
+        }
+
+
+        if (!switch_strlen_zero(profile-&gt;reg_domain)) {
+                domain_name = profile-&gt;reg_domain;
+        } else {
+                domain_name = realm;
+        }
+
+        if (switch_xml_locate_user(&quot;id&quot;, switch_strlen_zero(username) ? &quot;nobody&quot; : username, 
+                                                           domain_name, ip, &amp;xml, &amp;domain, &amp;user, &amp;group, params) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Can't find user [%s@%s]\n&quot;
+                                                  &quot;You must define a domain called '%s' in your directory and add a user with the id=\&quot;%s\&quot; attribute\n&quot;
+                                                  &quot;and you must configure your device to use the proper domain in it's authentication credentials.\n&quot;
+                                                  , username, domain_name, domain_name, username);
+
+                ret = AUTH_FORBIDDEN;
+                goto end;
+        } else {
+                const char *type = switch_xml_attr(user, &quot;type&quot;);
+                if (type &amp;&amp; !strcasecmp(type, &quot;pointer&quot;)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Cant register a pointer.\n&quot;);
+                        ret = AUTH_FORBIDDEN;
+                        goto end;
+                }
+        }
+        
+        if (!(number_alias = (char *) switch_xml_attr(user, &quot;number-alias&quot;))) {
+                number_alias = switch_strlen_zero(username) ? &quot;nobody&quot; : username;
+        }
+
+        dparams = switch_xml_child(domain, &quot;params&quot;);
+        uparams = switch_xml_child(user, &quot;params&quot;);
+        if (group) {
+                gparams = switch_xml_child(group, &quot;params&quot;);
+        }
+
+        if (!(dparams || uparams)) {
+                ret = AUTH_OK;
+                goto skip_auth;
+        }
+
+        if (dparams) {
+                for (param = switch_xml_child(dparams, &quot;param&quot;); param; param = param-&gt;next) {
+                        const char *var = switch_xml_attr_soft(param, &quot;name&quot;);
+                        const char *val = switch_xml_attr_soft(param, &quot;value&quot;);
+
+                        if (!strcasecmp(var, &quot;sip-forbid-register&quot;) &amp;&amp; switch_true(val)) {
+                                ret = AUTH_FORBIDDEN;
+                                goto end;
+                        }
+
+                        if (!strcasecmp(var, &quot;password&quot;)) {
+                                passwd = val;
+                        }
+
+                        if (!strcasecmp(var, &quot;auth-acl&quot;)) {
+                                auth_acl = val;
+                        }
+
+                        if (!strcasecmp(var, &quot;a1-hash&quot;)) {
+                                a1_hash = val;
+                        }
+                }
+        }
+
+        if (gparams) {
+                for (param = switch_xml_child(gparams, &quot;param&quot;); param; param = param-&gt;next) {
+                        const char *var = switch_xml_attr_soft(param, &quot;name&quot;);
+                        const char *val = switch_xml_attr_soft(param, &quot;value&quot;);
+
+                        if (!strcasecmp(var, &quot;sip-forbid-register&quot;) &amp;&amp; switch_true(val)) {
+                                ret = AUTH_FORBIDDEN;
+                                goto end;
+                        }
+
+                        if (!strcasecmp(var, &quot;password&quot;)) {
+                                passwd = val;
+                        }
+
+                        if (!strcasecmp(var, &quot;auth-acl&quot;)) {
+                                auth_acl = val;
+                        }
+
+                        if (!strcasecmp(var, &quot;a1-hash&quot;)) {
+                                a1_hash = val;
+                        }
+                }
+        }
+
+        if (uparams) {
+                for (param = switch_xml_child(uparams, &quot;param&quot;); param; param = param-&gt;next) {
+                        const char *var = switch_xml_attr_soft(param, &quot;name&quot;);
+                        const char *val = switch_xml_attr_soft(param, &quot;value&quot;);
+
+                        if (!strcasecmp(var, &quot;sip-forbid-register&quot;) &amp;&amp; switch_true(val)) {
+                                ret = AUTH_FORBIDDEN;
+                                goto end;
+                        }
+
+                        if (!strcasecmp(var, &quot;password&quot;)) {
+                                passwd = val;
+                        }
+
+                        if (!strcasecmp(var, &quot;auth-acl&quot;)) {
+                                auth_acl = val;
+                        }
+
+                        if (!strcasecmp(var, &quot;a1-hash&quot;)) {
+                                a1_hash = val;
+                        }
+                }
+        }
+
+        if (auth_acl) {
+                if (!switch_check_network_list_ip(ip, auth_acl)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;IP %s Rejected by user acl %s\n&quot;, ip, auth_acl);
+                        ret = AUTH_FORBIDDEN;
+                        goto end;
+                }
+        }
+
+        if (switch_strlen_zero(passwd) &amp;&amp; switch_strlen_zero(a1_hash)) {
+                ret = AUTH_OK;
+                goto skip_auth;
+        }
+
+        if (!a1_hash) {
+                input = switch_mprintf(&quot;%s:%s:%s&quot;, username, realm, passwd);
+                su_md5_init(&amp;ctx);
+                su_md5_strupdate(&amp;ctx, input);
+                su_md5_hexdigest(&amp;ctx, hexdigest);
+                su_md5_deinit(&amp;ctx);
+                switch_safe_free(input);
+                a1_hash = hexdigest;
+
+        }
+
+  for_the_sake_of_interop:
+
+        if ((input = switch_mprintf(&quot;%s:%q&quot;, regstr, uri))) {
+                su_md5_init(&amp;ctx);
+                su_md5_strupdate(&amp;ctx, input);
+                su_md5_hexdigest(&amp;ctx, uridigest);
+                su_md5_deinit(&amp;ctx);
+        }
+
+        if (nc &amp;&amp; cnonce &amp;&amp; qop) {
+                input2 = switch_mprintf(&quot;%s:%s:%s:%s:%s:%s&quot;, a1_hash, nonce, nc, cnonce, qop, uridigest);
+        } else {
+                input2 = switch_mprintf(&quot;%s:%s:%s&quot;, a1_hash, nonce, uridigest);
+        }
+
+        switch_assert(input2);
+
+        memset(&amp;ctx, 0, sizeof(ctx));
+        su_md5_init(&amp;ctx);
+        su_md5_strupdate(&amp;ctx, input2);
+        su_md5_hexdigest(&amp;ctx, bigdigest);
+        su_md5_deinit(&amp;ctx);
+
+        if (!strcasecmp(bigdigest, response)) {
+                ret = AUTH_OK;
+        } else {
+                if ((profile-&gt;ndlb &amp; PFLAG_NDLB_BROKEN_AUTH_HASH) &amp;&amp; strcasecmp(regstr, &quot;REGISTER&quot;) &amp;&amp; strcasecmp(regstr, &quot;INVITE&quot;)) {
+                        /* 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 = &quot;INVITE&quot;;
+                        goto for_the_sake_of_interop;
+                }
+
+                ret = AUTH_FORBIDDEN;
+        }
+
+
+  skip_auth:
+
+        if (first &amp;&amp; ret == AUTH_OK) {
+                if (v_event) {
+                        switch_event_create_plain(v_event, SWITCH_EVENT_REQUEST_PARAMS);
+                }
+
+                
+                if (v_event &amp;&amp; *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, &quot;sip_number_alias&quot;, number_alias);
+                        switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, &quot;sip_auth_username&quot;, username);
+                        switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, &quot;sip_auth_realm&quot;, realm);
+                        switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, &quot;number_alias&quot;, number_alias);
+                        switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, &quot;user_name&quot;, username);
+                        switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, &quot;domain_name&quot;, domain_name);
+
+                        if ((uparams = switch_xml_child(user, &quot;params&quot;))) {
+                                xparams_type[i] = 0;
+                                xparams[i++] = uparams;
+                        }
+
+                        if (group &amp;&amp; (gparams = switch_xml_child(group, &quot;params&quot;))) {
+                                xparams_type[i] = 0;
+                                xparams[i++] = gparams;
+                        }
+
+                        if ((dparams = switch_xml_child(domain, &quot;params&quot;))) {
+                                xparams_type[i] = 0;
+                                xparams[i++] = dparams;
+                        }
+
+                        if ((uparams = switch_xml_child(user, &quot;variables&quot;))) {
+                                xparams_type[i] = 1;
+                                xparams[i++] = uparams;
+                        }
+
+                        if (group &amp;&amp; (gparams = switch_xml_child(group, &quot;variables&quot;))) {
+                                xparams_type[i] = 1;
+                                xparams[i++] = gparams;
+                        }
+
+                        if ((dparams = switch_xml_child(domain, &quot;variables&quot;))) {
+                                xparams_type[i] = 1;
+                                xparams[i++] = dparams;
+                        }
+
+                        if (i &lt;= 6) {
+                                int j = 0;
+
+                                for (j = 0; j &lt; i; j++) {
+                                        for (param = switch_xml_child(xparams[j], (xparams_type[j]?&quot;variable&quot;:&quot;param&quot;)); param; param = param-&gt;next) {
+                                                const char *var = switch_xml_attr_soft(param, &quot;name&quot;);
+                                                const char *val = switch_xml_attr_soft(param, &quot;value&quot;);
+                                                sofia_gateway_t *gateway_ptr = NULL;
+
+                                                if (!switch_strlen_zero(var) &amp;&amp; !switch_strlen_zero(val) &amp;&amp; (xparams_type[j] == 1 || !strncasecmp(var, &quot;sip-&quot;,4) || !strcasecmp(var, &quot;register-gateway&quot;)) ) {
+                                                        if (!switch_event_get_header(*v_event, var)) {
+                                                                if (profile-&gt;debug) {
+                                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;event_add_header -&gt; '%s' = '%s'\n&quot;,var, val);
+                                                                }
+                                                                switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, var, val);
+                                                        } else {
+                                                                continue;
+                                                        }
+
+                                                        if (!strcasecmp(var, &quot;register-gateway&quot;)) {
+                                                                if (!strcasecmp(val, &quot;all&quot;)) {
+                                                                        switch_xml_t gateways_tag, gateway_tag;
+                                                                        if ((gateways_tag = switch_xml_child(user, &quot;gateways&quot;))) {
+                                                                                for (gateway_tag = switch_xml_child(gateways_tag, &quot;gateway&quot;); gateway_tag; gateway_tag = gateway_tag-&gt;next) {
+                                                                                        char *name = (char *) switch_xml_attr_soft(gateway_tag, &quot;name&quot;);
+                                                                                        if (switch_strlen_zero(name)) {
+                                                                                                name = &quot;anonymous&quot;;
+                                                                                        }
+
+                                                                                        if ((gateway_ptr = sofia_reg_find_gateway(name))) {
+                                                                                                reg_state_t ostate = gateway_ptr-&gt;state;
+                                                                                                gateway_ptr-&gt;retry = 0;
+                                                                                                if (exptime) {
+                                                                                                        gateway_ptr-&gt;state = REG_STATE_UNREGED;
+                                                                                                } else {
+                                                                                                        gateway_ptr-&gt;state = REG_STATE_UNREGISTER;
+                                                                                                }
+                                                                                                if (ostate != gateway_ptr-&gt;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 &lt; argc; x++) {
+                                                                                if ((gateway_ptr = sofia_reg_find_gateway((char *) argv[x]))) {
+                                                                                        reg_state_t ostate = gateway_ptr-&gt;state;
+                                                                                        gateway_ptr-&gt;retry = 0;
+                                                                                        if (exptime) {
+                                                                                                gateway_ptr-&gt;state = REG_STATE_UNREGED;
+                                                                                        } else {
+                                                                                                gateway_ptr-&gt;state = REG_STATE_UNREGISTER;
+                                                                                        }
+                                                                                        if (ostate != gateway_ptr-&gt;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, &quot;Gateway '%s' not found.\n&quot;, argv[x]);
+                                                                                }
+                                                                        }
+
+                                                                        free(mydata);
+                                                                }
+                                                        }
+                                                }
+                                        }
+                                }
+                        }
+                }
+        }
+  end:
+
+        switch_event_destroy(&amp;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-&gt;profile, PFLAG_RUNNING) || gateway-&gt;deleted) {
+                        gateway = NULL;
+                        goto done;
+                }
+                if (switch_thread_rwlock_tryrdlock(gateway-&gt;profile-&gt;rwlock) != SWITCH_STATUS_SUCCESS) {
+                        switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, &quot;Profile %s is locked\n&quot;, gateway-&gt;profile-&gt;name);
+                        gateway = NULL;
+                }
+        }
+        if (gateway) {
+#ifdef SOFIA_DEBUG_RWLOCKS
+                switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, &quot;XXXXXXXXXXXXXX GW LOCK %s\n&quot;, gateway-&gt;profile-&gt;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-&gt;profile-&gt;rwlock);
+#ifdef SOFIA_DEBUG_RWLOCKS
+        switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, SWITCH_LOG_ERROR, &quot;XXXXXXXXXXXXXX GW UNLOCK %s\n&quot;, gateway-&gt;profile-&gt;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, &quot;Added gateway '%s' to profile '%s'\n&quot;, gateway-&gt;name, gateway-&gt;profile-&gt;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:
+ */
</ins></span></pre></div>
<a id="freeswitchbranchescseketsrcmodendpointsmod_sofiasofia_slacfromrev14389freeswitchtrunksrcmodendpointsmod_sofiasofia_slac"></a>
<div class="copfile"><h4>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)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,366 @@
</span><ins>+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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 &lt;anthm@freeswitch.org&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II &lt;anthm@freeswitch.org&gt;
+ * Ken Rice, Asteria Solutions Group, Inc &lt;ken@asteriasgi.com&gt;
+ * Paul D. Tinsley &lt;pdt at jackhammer.org&gt;
+ * Bret McDanel &lt;trixter AT 0xdecafbad.com&gt;
+ * Brian West &lt;brian@freeswitch.org&gt;
+ *
+ * sofia_sla.c -- SOFIA SIP Endpoint (support for shared line appearance)
+ *  This file (and calls into it) developed by Matthew T Kaufman &lt;matthew@matthew.at&gt;
+ *
+ */
+#include &quot;mod_sofia.h&quot;
+
+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-&gt;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] = &quot;&quot;;
+        char my_contact[256] = &quot;&quot;;
+        char *sql;
+        struct sla_helper sh = { { 0 } };
+        char *contact_str = sofia_glue_strip_uri(full_contact);
+        sofia_transport_t transport = sofia_glue_url2transport(sip-&gt;sip_contact-&gt;m_url);
+        char network_ip[80];
+        int network_port = 0;
+
+        sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &amp;network_port);
+
+        sql = switch_mprintf(&quot;select call_id from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'&quot;, 
+                                                 mod_sofia_globals.hostname, profile-&gt;name, contact_str);
+        sofia_glue_execute_sql_callback(profile, SWITCH_FALSE, profile-&gt;ireg_mutex, sql, get_call_id_callback, &amp;sh);
+
+        free(sql);
+        
+        if (*sh.call_id) {
+                if (!(nh = nua_handle_by_call_id(profile-&gt;nua, sh.call_id))) {
+                        if ((sql = switch_mprintf(&quot;delete from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'&quot;, 
+                                                                          mod_sofia_globals.hostname, profile-&gt;name, contact_str))) {
+                                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+                        }
+                }
+        }
+
+        if (!nh) {
+                nh = nua_handle(nua, NULL, NUTAG_URL(sip-&gt;sip_contact-&gt;m_url), TAG_NULL());
+        }
+
+        nua_handle_bind(nh, &amp;mod_sofia_globals.keep_private);
+
+        switch_snprintf(exp_str, sizeof(exp_str), &quot;%ld&quot;, exptime + 30);
+        if (sofia_glue_check_nat(profile, network_ip)) { 
+                switch_snprintf(my_contact, sizeof(my_contact), &quot;&lt;sip:%s@%s;transport=%s&gt;;expires=%s&quot;, profile-&gt;sla_contact, 
+                                                profile-&gt;extsipip, sofia_glue_transport2str(transport), exp_str);
+        } else {
+                switch_snprintf(my_contact, sizeof(my_contact), &quot;&lt;sip:%s@%s;transport=%s&gt;;expires=%s&quot;, profile-&gt;sla_contact, 
+                                                profile-&gt;sipip, sofia_glue_transport2str(transport), exp_str);
+        }
+        nua_subscribe(nh,
+                                  SIPTAG_TO(sip-&gt;sip_to),
+                                  SIPTAG_FROM(sip-&gt;sip_to),
+                                  SIPTAG_CONTACT_STR(my_contact),
+                                  SIPTAG_EXPIRES_STR(exp_str),
+                                  SIPTAG_EVENT_STR(&quot;dialog;sla&quot;),        /* 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 &quot;OK&quot; */
+        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-&gt;sip_contact-&gt;m_url);
+
+        sofia_glue_get_addr(nua_current_request(nua), network_ip,  sizeof(network_ip), &amp;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 &quot;terminated&quot; 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(&quot;sip:%s@%s&quot;, sip-&gt;sip_contact-&gt;m_url-&gt;url_user, profile-&gt;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(&quot;sip:%s@%s;transport=%s&quot;, sip-&gt;sip_from-&gt;a_url-&gt;url_user,
+                                                                sip-&gt;sip_contact-&gt;m_url-&gt;url_host, sofia_glue_transport2str(transport));

+        if ((sql =
+                switch_mprintf(&quot;delete from sip_shared_appearance_subscriptions where subscriber='%q' and profile_name='%q' and hostname='%q'&quot;,
+                        subscriber, profile-&gt;name, mod_sofia_globals.hostname
+                        ))) {
+                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+        }
+
+        if ((sql =
+                 switch_mprintf(&quot;insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname, contact_str, network_ip) &quot;
+                               &quot;values ('%q','%q','%q','%q','%q','%q','%q')&quot;,
+                                subscriber, sip-&gt;sip_call_id-&gt;i_id, aor, profile-&gt;name, mod_sofia_globals.hostname, contact_str, network_ip))) {
+                sofia_glue_execute_sql(profile, &amp;sql, SWITCH_TRUE);
+        }
+
+        if (strstr(contact_str, &quot;;fs_nat&quot;)) {
+                char *p;
+                route_uri = sofia_glue_get_url_from_contact((char *)contact_str, 1);
+                if ((p = strstr(contact_str, &quot;;fs_&quot;))) {
+                        *p = '\0';
+                }
+        }
+
+        if (route_uri) {
+                char *p;
+
+                while (route_uri &amp;&amp; *route_uri &amp;&amp; (*route_uri == '&lt;' || *route_uri == ' ')) {
+                        route_uri++;
+                }
+                if ((p = strchr(route_uri, '&gt;'))) {
+                        *p++ = '\0';
+                }
+        }
+        if (sofia_glue_check_nat(profile, network_ip)) { 
+                sla_contact = switch_mprintf(&quot;&lt;sip:%s@%s;transport=%s&gt;&quot;, profile-&gt;sla_contact, profile-&gt;extsipip, sofia_glue_transport2str(transport));
+        } else {
+                sla_contact = switch_mprintf(&quot;&lt;sip:%s@%s;transport=%s&gt;&quot;, profile-&gt;sla_contact, profile-&gt;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(&quot;active;expires=300&quot;), /* you thought the OTHER time was fake... need delta here FIXME XXX MTK */
+                                SIPTAG_EXPIRES_STR(&quot;300&quot;), /* 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 &gt;= 300) {
+                nua_handle_destroy(nh);
+                sofia_private_free(sofia_private);
+        } else {
+                char *full_contact = sip_header_as_string(nua_handle_home(nh), (void *) sip-&gt;sip_contact);
+                time_t expires = switch_epoch_time_now(NULL);
+                char *sql;
+                char *contact_str = sofia_glue_strip_uri(full_contact);
+
+                if (sip &amp;&amp; sip-&gt;sip_expires) {
+                        expires += sip-&gt;sip_expires-&gt;ex_delta + 30;
+                }
+
+                if ((sql = switch_mprintf(&quot;insert into sip_shared_appearance_dialogs (profile_name, hostname, contact_str, call_id, expires) &quot;
+                                                                  &quot;values ('%q','%q','%q','%q','%ld')&quot;, 
+                                                                  profile-&gt;name, mod_sofia_globals.hostname, contact_str, sip-&gt;sip_call_id-&gt;i_id, (long)expires))) {
+                        sofia_glue_execute_sql(profile, &amp;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-&gt;sip_contact-&gt;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
+     *     &quot;target&quot; 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 &quot;next free appearance&quot;. this can lead to race 
+         *     conditions where a call shows up on slightly different line key numbers at different phones, making
+         *     &quot;pick up on line X&quot; 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-&gt;sip_event) 
+           || (strcasecmp(sip-&gt;sip_event-&gt;o_type, &quot;dialog&quot;))
+           || !msg_params_find(sip-&gt;sip_event-&gt;o_params, &quot;sla&quot;) ) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,&quot;sent to sla-agent but not dialog;sla\n&quot;);
+                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(&quot;sip:%s@%s&quot;, sip-&gt;sip_to-&gt;a_url-&gt;url_user, profile-&gt;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&lt;&gt;'%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 &quot;boss&quot; config, but we do reflect it back at the &quot;secretary&quot;
+         * config. if that breaks the phone, just set them all up as the &quot;boss&quot; config where ext#==third-party#
+         */
+        contact = switch_mprintf(&quot;sip:%s@%s;transport=%s&quot;,sip-&gt;sip_contact-&gt;m_url-&gt;url_user,
+                                                         sip-&gt;sip_contact-&gt;m_url-&gt;url_host, sofia_glue_transport2str(transport));
+
+        if (sip-&gt;sip_payload &amp;&amp; sip-&gt;sip_payload-&gt;pl_data) {
+                sql = switch_mprintf(&quot;select subscriber,call_id,aor,profile_name,hostname,contact_str,network_ip from sip_shared_appearance_subscriptions where &quot;
+                &quot;aor='%q' and profile_name='%q' and hostname='%q'&quot;,
+                aor, profile-&gt;name, mod_sofia_globals.hostname); 
+
+                helper.profile = profile;
+                helper.payload = sip-&gt;sip_payload-&gt;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-&gt;ireg_mutex, sql, sofia_sla_sub_callback, &amp;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-&gt;profile-&gt;nua, call_id);  /* that's all you need to find the subscription's nh */
+
+        if (nh) {
+
+                if (strstr(contact_str, &quot;;fs_nat&quot;)) {
+                        char *p;
+                        route_uri = sofia_glue_get_url_from_contact(contact_str, 1);
+                        if ((p = strstr(contact_str, &quot;;fs_&quot;))) {
+                                *p = '\0';
+                        }
+                }
+
+                if (route_uri) {
+                        char *p;
+
+                        while (route_uri &amp;&amp; *route_uri &amp;&amp; (*route_uri == '&lt;' || *route_uri == ' ')) {
+                                route_uri++;
+                        }
+                        if ((p = strchr(route_uri, '&gt;'))) {
+                                *p++ = '\0';
+                        }
+                }
+
+                if (sofia_test_pflag(helper-&gt;profile, PFLAG_AUTO_NAT)) {
+                        if (sofia_glue_check_nat(helper-&gt;profile, network_ip)) { 
+                                fixup = switch_string_replace(helper-&gt;payload, helper-&gt;profile-&gt;sipip, helper-&gt;profile-&gt;extsipip);
+                        } else  {
+                                fixup = switch_string_replace(helper-&gt;payload, helper-&gt;profile-&gt;extsipip, helper-&gt;profile-&gt;sipip);
+                        }
+                        xml_fixup = fixup;
+                } else {
+                        xml_fixup = helper-&gt;payload;
+                }
+                
+                nua_notify(nh,
+                                   SIPTAG_SUBSCRIPTION_STATE_STR(&quot;active;expires=300&quot;), /* XXX MTK FIXME - this is totally fake calculation */
+                                   TAG_IF(route_uri, NUTAG_PROXY(route_uri)),
+                                   SIPTAG_CONTENT_TYPE_STR(&quot;application/dialog-info+xml&quot;),        /* could've just kept the type from the payload */
+                                   SIPTAG_PAYLOAD_STR(xml_fixup),
+                                   TAG_END());
+                switch_safe_free(route_uri);
+                if (fixup &amp;&amp; fixup != helper-&gt;payload) { 
+                        free(fixup);
+                }
+        }
+        return 0;
+}
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>