diff --git a/sflphone-gtk/src/configurationmanager-glue.h b/sflphone-gtk/src/configurationmanager-glue.h
index ba2d46b61d762461b715f06ee93ec4d07afd6ede..1f3810ccc8a47fdc5c9ef8fb363a27dd39823a32 100644
--- a/sflphone-gtk/src/configurationmanager-glue.h
+++ b/sflphone-gtk/src/configurationmanager-glue.h
@@ -1,7 +1,6 @@
 /* Generated by dbus-binding-tool; do not edit! */
 
-#include <glib/gtypes.h>
-#include <glib/gerror.h>
+#include <glib.h>
 #include <dbus/dbus-glib.h>
 
 G_BEGIN_DECLS
@@ -2001,6 +2000,156 @@ org_sflphone_SFLphone_ConfigurationManager_get_sip_port_async (DBusGProxy *proxy
   stuff->userdata = userdata;
   return dbus_g_proxy_begin_call (proxy, "getSipPort", org_sflphone_SFLphone_ConfigurationManager_get_sip_port_async_callback, stuff, g_free, G_TYPE_INVALID);
 }
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_set_stun_server (DBusGProxy *proxy, const char * IN_server, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "setStunServer", error, G_TYPE_STRING, IN_server, G_TYPE_INVALID, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_set_stun_server_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_set_stun_server_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_set_stun_server_reply)data->cb) (proxy, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_set_stun_server_async (DBusGProxy *proxy, const char * IN_server, org_sflphone_SFLphone_ConfigurationManager_set_stun_server_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "setStunServer", org_sflphone_SFLphone_ConfigurationManager_set_stun_server_async_callback, stuff, g_free, G_TYPE_STRING, IN_server, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_get_stun_server (DBusGProxy *proxy, char ** OUT_server, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "getStunServer", error, G_TYPE_INVALID, G_TYPE_STRING, OUT_server, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_get_stun_server_reply) (DBusGProxy *proxy, char * OUT_server, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_get_stun_server_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  char * OUT_server;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_STRING, &OUT_server, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_get_stun_server_reply)data->cb) (proxy, OUT_server, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_get_stun_server_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_get_stun_server_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "getStunServer", org_sflphone_SFLphone_ConfigurationManager_get_stun_server_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_enable_stun (DBusGProxy *proxy, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "enableStun", error, G_TYPE_INVALID, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_enable_stun_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_enable_stun_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_enable_stun_reply)data->cb) (proxy, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_enable_stun_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_enable_stun_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "enableStun", org_sflphone_SFLphone_ConfigurationManager_enable_stun_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled (DBusGProxy *proxy, gint* OUT_state, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "isStunEnabled", error, G_TYPE_INVALID, G_TYPE_INT, OUT_state, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_reply) (DBusGProxy *proxy, gint OUT_state, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  gint OUT_state;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &OUT_state, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_reply)data->cb) (proxy, OUT_state, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "isStunEnabled", org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
 #endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_org_sflphone_SFLphone_ConfigurationManager */
 
 G_END_DECLS
diff --git a/sflphone-gtk/src/configwindow.c b/sflphone-gtk/src/configwindow.c
index be137c73cf4bc7c7e1f9257351c5e5c3eacc656e..a15290e3bfa511942377ca14416d7bd5397fe148 100644
--- a/sflphone-gtk/src/configwindow.c
+++ b/sflphone-gtk/src/configwindow.c
@@ -109,7 +109,7 @@ config_window_fill_account_list()
  * Delete an account
  */
     static void
-delete_account(GtkWidget *widget, gpointer data UNUSED)
+delete_account(GtkWidget *widget UNUSED, gpointer data UNUSED)
 {
     if(selectedAccount)
     {
@@ -449,24 +449,15 @@ create_accounts_tab()
 void stun_state( void )
 {
     
-    guint i, size;
-    gchar * stun_enabled = "FALSE";
-    account_t * account;
+    guint stun_enabled = 0;
 
     gboolean stunActive = (gboolean)gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( stunEnable ));
     gtk_widget_set_sensitive( GTK_WIDGET( stunServer ) , stunActive );
+
     // Check if we actually change the state
-    size = account_list_get_size();
-    for(i=0; i<size; i++)
-    {
-        account = account_list_get_nth(i);
-        if( strcmp(g_hash_table_lookup(account->properties, ACCOUNT_TYPE), "SIP" ) == 0 )
-        {
-            stun_enabled = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_ENABLED);
-            break;
-        }
-    }
-    if( (stunActive && strcmp(stun_enabled, "FALSE")==0) || (!stunActive && strcmp(stun_enabled, "TRUE")==0) )
+    stun_enabled = dbus_stun_is_enabled();
+    
+    if( (stunActive && stun_enabled ==0 ) || (!stunActive && stun_enabled ==1))
     {
         gtk_widget_set_sensitive( GTK_WIDGET( applyButton ) , TRUE );
     }
@@ -477,24 +468,8 @@ void stun_state( void )
 
 void update_registration( void )
 {
-    guint nb_accounts, i;
-    account_t *current;
-
-    nb_accounts = account_list_get_size();
-
-    for(i=0; i<nb_accounts;i++){
-        
-        current = account_list_get_nth(i);
-        // If SIP account, then set the new value
-        if( strcmp(g_hash_table_lookup(current->properties, ACCOUNT_TYPE), "SIP" ) == 0 )
-        {
-            g_hash_table_replace(current->properties, g_strdup(ACCOUNT_SIP_STUN_SERVER), 
-                                    g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(stunServer))));
-            g_hash_table_replace(current->properties, g_strdup(ACCOUNT_SIP_STUN_ENABLED), 
-                                    g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(stunEnable)) ? "TRUE": "FALSE"));
-            dbus_set_account_details(current);
-        }
-    }
+    dbus_set_stun_server((gchar *)gtk_entry_get_text(GTK_ENTRY(stunServer)));
+    dbus_enable_stun();
 
     gtk_widget_set_sensitive(GTK_WIDGET( applyButton ) , FALSE );
 }
@@ -505,23 +480,11 @@ GtkWidget* create_stun_tab()
     gchar * stun_server= "stun.fwdnet.net:3478";
     gchar * stun_enabled = "FALSE";
     GtkWidget * label;
-    account_t * account;
-    guint i, size;
 
-    // All SIP accounts are supposed to have the same STUN configuration
-    // So let's take the first SIP account we find
-    size = account_list_get_size();
-    for(i=0; i<size; i++)
-    {
-        account = account_list_get_nth(i);
-        if( strcmp(g_hash_table_lookup(account->properties, ACCOUNT_TYPE), "SIP" ) == 0 )
-        {
-            stun_enabled = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_ENABLED);
-            stun_server = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_SERVER);
-            break;
-        }
-    }
-    
+    /* Retrieve the STUN configuration */
+    stun_enabled = (dbus_stun_is_enabled()==1)?"TRUE":"FALSE";
+    stun_server = dbus_get_stun_server();
+
     tableNat = gtk_table_new ( 3, 2  , FALSE/* homogeneous */);
 
     // NAT detection code section
diff --git a/sflphone-gtk/src/dbus.c b/sflphone-gtk/src/dbus.c
index 68e0e2d423367cc834a682c13e40b233726aea64..a608749908d06706e08867979faf4fc470b3f899 100644
--- a/sflphone-gtk/src/dbus.c
+++ b/sflphone-gtk/src/dbus.c
@@ -1542,3 +1542,58 @@ dbus_get_sip_port( void )
         return (guint)portNum;
 }
 
+gchar* dbus_get_stun_server (void)
+{
+        GError* error = NULL;
+        gchar* server;
+        org_sflphone_SFLphone_ConfigurationManager_get_stun_server(
+                        configurationManagerProxy,
+                        &server,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+        return server;
+}
+
+void dbus_set_stun_server( gchar* server)
+{
+        GError* error = NULL;
+        org_sflphone_SFLphone_ConfigurationManager_set_stun_server(
+                        configurationManagerProxy,
+                        server,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+}
+
+guint dbus_stun_is_enabled (void)
+{
+    GError* error = NULL;
+    guint stun;
+    org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled(
+                        configurationManagerProxy,
+                        &stun,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+        return stun;
+}
+
+void dbus_enable_stun (void)
+{
+    
+    GError* error = NULL;
+    org_sflphone_SFLphone_ConfigurationManager_enable_stun(
+                        configurationManagerProxy,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+}
diff --git a/sflphone-gtk/src/dbus.h b/sflphone-gtk/src/dbus.h
index 4989443f06897300ebcd52e6cea87c6721cbcc58..f621cd04b10d75cf9bd98792b34bfa8d368f9432 100644
--- a/sflphone-gtk/src/dbus.h
+++ b/sflphone-gtk/src/dbus.h
@@ -429,4 +429,10 @@ void dbus_set_sip_port(const guint portNum);
 
 guint dbus_get_sip_port();
 
+gchar* dbus_get_stun_server (void);
+void dbus_set_stun_server( gchar* server);
+
+guint dbus_stun_is_enabled (void);
+void dbus_enable_stun (void);
+
 #endif
diff --git a/src/account.cpp b/src/account.cpp
index cb2d710a750c9a1da5229683608e6f289f4aece5..b50fc71fc49d5648d875ac8bc4cb99758b82a9d3 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -25,7 +25,7 @@
 Account::Account(const AccountID& accountID, std::string type) : 
     _accountID(accountID), _link(NULL), _enabled(false), _type(type)
 {
-    setRegistrationState(VoIPLink::Unregistered);
+    setRegistrationState(Unregistered);
 }
 
 Account::~Account()
@@ -47,3 +47,9 @@ void Account::loadConfig()
 #endif
 }
 
+void Account::setRegistrationState( RegistrationState state ) { 
+    _registrationState = state; 
+
+    // Notify the client
+    Manager::instance().connectionStatusNotification( );
+}
diff --git a/src/account.h b/src/account.h
index a71ffd775e31038c45a4fbead66696a4e4ec866b..764d4628e1c2d780eb18b9ce4cdc23046f150f95 100644
--- a/src/account.h
+++ b/src/account.h
@@ -39,7 +39,7 @@ class VoIPLink;
 typedef std::string AccountID;
 
 /** Contains all the state an Voip can be in */
-    typedef enum RegistrationState {
+typedef enum RegistrationState {
         Unregistered, 
         Trying, 
         Registered, 
@@ -49,7 +49,7 @@ typedef std::string AccountID;
         ErrorHost, 
         ErrorExistStun, 
         ErrorConfStun
-    } RegistrationState;
+} RegistrationState;
 
 #define AccountNULL ""
 
@@ -121,13 +121,9 @@ class Account{
          */
         inline RegistrationState getRegistrationState() { return _registrationState; }
 
-        inline void setRegistrationState( RegistrationState state ) { 
-            _registrationState = state; 
-        
-            // Notify the client
-            Manager::instance().connectionStatusNotification( );
-        }
+        void setRegistrationState( RegistrationState state );
 
+        //TODO inline?
         inline std::string getUsername( void ) { return _username; }
         inline void setUsername( std::string username) { _username = username; }
 
diff --git a/src/dbus/Makefile.am b/src/dbus/Makefile.am
index ee8355dbe90728906ece7ac3acf18622f5e9cecb..7e97ffc2dcd3771ed31fc020c23e1eb76b3bad0c 100644
--- a/src/dbus/Makefile.am
+++ b/src/dbus/Makefile.am
@@ -7,7 +7,6 @@ noinst_LTLIBRARIES = libdbus.la
 libdbus_la_SOURCES = \
 	callmanager.cpp \
 	configurationmanager.cpp  \
-	contactmanager.cpp \
 	instance.cpp  \
 	dbusmanagerimpl.cpp
 
@@ -20,8 +19,6 @@ noinst_HEADERS = \
 	callmanager.h  \
 	configurationmanager.h  \
 	configurationmanager-glue.h \
-	contactmanager.h \
-	contactmanager-glue.h \
 	instance.h  \
 	instance-glue.h \
 	dbusmanager.h \
diff --git a/src/dbus/configurationmanager-glue.h b/src/dbus/configurationmanager-glue.h
index 292756cdb7e2c1c6b476b25432d1d56ac29322df..673a0f5f4efe0240bc7d5a90673ae6ac30ba8381 100644
--- a/src/dbus/configurationmanager-glue.h
+++ b/src/dbus/configurationmanager-glue.h
@@ -73,6 +73,10 @@ public:
         register_method(ConfigurationManager_adaptor, getPulseAppVolumeControl, _getPulseAppVolumeControl_stub);
         register_method(ConfigurationManager_adaptor, setSipPort, _setSipPort_stub);
         register_method(ConfigurationManager_adaptor, getSipPort, _getSipPort_stub);
+        register_method(ConfigurationManager_adaptor, setStunServer, _setStunServer_stub);
+        register_method(ConfigurationManager_adaptor, getStunServer, _getStunServer_stub);
+        register_method(ConfigurationManager_adaptor, enableStun, _enableStun_stub);
+        register_method(ConfigurationManager_adaptor, isStunEnabled, _isStunEnabled_stub);
     }
 
     ::DBus::IntrospectedInterface *const introspect() const 
@@ -338,6 +342,25 @@ public:
             { "port", "i", false },
             { 0, 0, 0 }
         };
+        static ::DBus::IntrospectedArgument setStunServer_args[] = 
+        {
+            { "server", "s", true },
+            { 0, 0, 0 }
+        };
+        static ::DBus::IntrospectedArgument getStunServer_args[] = 
+        {
+            { "server", "s", false },
+            { 0, 0, 0 }
+        };
+        static ::DBus::IntrospectedArgument enableStun_args[] = 
+        {
+            { 0, 0, 0 }
+        };
+        static ::DBus::IntrospectedArgument isStunEnabled_args[] = 
+        {
+            { "state", "i", false },
+            { 0, 0, 0 }
+        };
         static ::DBus::IntrospectedArgument parametersChanged_args[] = 
         {
             { "list", "a{ss}", false },
@@ -407,6 +430,10 @@ public:
             { "getPulseAppVolumeControl", getPulseAppVolumeControl_args },
             { "setSipPort", setSipPort_args },
             { "getSipPort", getSipPort_args },
+            { "setStunServer", setStunServer_args },
+            { "getStunServer", getStunServer_args },
+            { "enableStun", enableStun_args },
+            { "isStunEnabled", isStunEnabled_args },
             { 0, 0 }
         };
         static ::DBus::IntrospectedMethod ConfigurationManager_adaptor_signals[] = 
@@ -494,6 +521,10 @@ public:
     virtual int32_t getPulseAppVolumeControl() = 0;
     virtual void setSipPort(const int32_t& port) = 0;
     virtual int32_t getSipPort() = 0;
+    virtual void setStunServer(const std::string& server) = 0;
+    virtual std::string getStunServer() = 0;
+    virtual void enableStun() = 0;
+    virtual int32_t isStunEnabled() = 0;
 
 public:
 
@@ -1027,6 +1058,43 @@ private:
         wi << argout1;
         return reply;
     }
+    ::DBus::Message _setStunServer_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        std::string argin1; ri >> argin1;
+        setStunServer(argin1);
+        ::DBus::ReturnMessage reply(call);
+        return reply;
+    }
+    ::DBus::Message _getStunServer_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        std::string argout1 = getStunServer();
+        ::DBus::ReturnMessage reply(call);
+        ::DBus::MessageIter wi = reply.writer();
+        wi << argout1;
+        return reply;
+    }
+    ::DBus::Message _enableStun_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        enableStun();
+        ::DBus::ReturnMessage reply(call);
+        return reply;
+    }
+    ::DBus::Message _isStunEnabled_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        int32_t argout1 = isStunEnabled();
+        ::DBus::ReturnMessage reply(call);
+        ::DBus::MessageIter wi = reply.writer();
+        wi << argout1;
+        return reply;
+    }
 };
 
 } } } 
diff --git a/src/dbus/configurationmanager-introspec.xml b/src/dbus/configurationmanager-introspec.xml
index df72d96e79c6ecf77b4c47ca27c2a4a90b94106c..0990b1443c15a7f53cb2bfee5388885a67e48697 100644
--- a/src/dbus/configurationmanager-introspec.xml
+++ b/src/dbus/configurationmanager-introspec.xml
@@ -218,6 +218,21 @@
       <arg type="i" name="port" direction="out"/>
     </method>
 
+    <method name="setStunServer">
+      <arg type="s" name="server" direction="in"/>
+    </method>
+
+    <method name="getStunServer">
+      <arg type="s" name="server" direction="out"/>
+    </method>
+
+    <method name="enableStun">
+    </method>
+
+    <method name="isStunEnabled">
+      <arg type="i" name="state" direction="out"/>
+    </method>
+
   <!--        /////////////////////////////       -->
     <signal name="parametersChanged">
       <arg type="a{ss}" name="list" direction="out"/>
diff --git a/src/dbus/configurationmanager.cpp b/src/dbus/configurationmanager.cpp
index 547afded01e9912d0e65923bf0ce193ba8830cce..8c1e5af8f5712bae4224d5942a77a6da9d08247e 100644
--- a/src/dbus/configurationmanager.cpp
+++ b/src/dbus/configurationmanager.cpp
@@ -395,3 +395,22 @@ ConfigurationManager::setSipPort( const int32_t& portNum )
   Manager::instance().setSipPort(portNum);
 }
 
+std::string ConfigurationManager::getStunServer( void )
+{
+    return Manager::instance().getStunServer();
+}
+    
+void ConfigurationManager::setStunServer( const std::string& server )
+{
+    Manager::instance().setStunServer( server );
+}
+
+void ConfigurationManager::enableStun (void)
+{
+    Manager::instance().enableStun();
+}
+
+int32_t ConfigurationManager::isStunEnabled (void)
+{
+    return Manager::instance().isStunEnabled();
+}
diff --git a/src/dbus/configurationmanager.h b/src/dbus/configurationmanager.h
index 86c6ee7dec89ae7352a8ea423ea401cfa4edab8f..20f01317d075b974fe8a85e9927976b854e155a2 100644
--- a/src/dbus/configurationmanager.h
+++ b/src/dbus/configurationmanager.h
@@ -96,7 +96,11 @@ public:
     int32_t getPulseAppVolumeControl( void );
     void setPulseAppVolumeControl( void );
     int32_t getSipPort( void );
-    void setSipPort( const int32_t& portNum );
+    void setSipPort( const int32_t& portNum);
+    std::string getStunServer( void );
+    void setStunServer( const std::string& server );
+    void enableStun (void);
+    int32_t isStunEnabled (void);
 
 };
 
diff --git a/src/global.h b/src/global.h
index e752d41b2f5ee4be78392cd0dd67308e19bf2b93..7a2a1b5793dcdb59213d5f3f684a57c864b40272 100644
--- a/src/global.h
+++ b/src/global.h
@@ -26,6 +26,9 @@
 #include <stdio.h>
 #include <libintl.h>
 #include <locale.h>
+#include <string>
+#include <stdlib.h>
+#include <sstream>
 
 #define SFLPHONED_VERSION "0.9.2-4"		/** Version number */
 
@@ -98,6 +101,7 @@ typedef short int16;
 #define WINDOW_POPUP		  1		/** Popup mode */
 #define NOTIFY_ALL		  1		/** Desktop notification level 0: never notify */
 #define NOTIFY_MAILS		  1		/** Desktop mail notification level 0: never notify */
+#define STUN_ENABLED         1
 
 // Error codes for error handling
 #define NO_ERROR		      0x0000	/** No error - Everything alright */
diff --git a/src/iaxaccount.cpp b/src/iaxaccount.cpp
index 22672437cb0e2bbaec42f7f7be1390dc4f4eb5ff..4de19c54cc995f4d39954775851299b67860451a 100644
--- a/src/iaxaccount.cpp
+++ b/src/iaxaccount.cpp
@@ -49,7 +49,7 @@ int IAXAccount::registerVoIPLink()
         thislink->setPass(Manager::instance().getConfigString(_accountID, PASSWORD));
     }
 
-    _link->sendRegister();
+    _link->sendRegister( _accountID );
 
     return SUCCESS;
 }
@@ -57,7 +57,7 @@ int IAXAccount::registerVoIPLink()
     int
 IAXAccount::unregisterVoIPLink()
 {
-    _link->sendUnregister();
+    _link->sendUnregister( _accountID );
     _link->terminate();
 
     return SUCCESS;
diff --git a/src/iaxvoiplink.cpp b/src/iaxvoiplink.cpp
index 035cb3675b7f0629ee857264541f0eac774a9203..679e2527ce887adab5dbaeefbf9ec043d17af82f 100644
--- a/src/iaxvoiplink.cpp
+++ b/src/iaxvoiplink.cpp
@@ -21,6 +21,7 @@
 #include "global.h" // for _debug
 #include "iaxcall.h"
 #include "eventthread.h"
+#include "iaxaccount.h"
 
 #include "manager.h"
 #include "audio/audiolayer.h"
@@ -207,7 +208,7 @@ IAXVoIPLink::getEvent()
 
   // Refresh registration.
   if (_nextRefreshStamp && _nextRefreshStamp - 2 < time(NULL)) {
-    sendRegister(-1);
+    sendRegister("");
   }
 
   // thread wait 3 millisecond
@@ -308,48 +309,52 @@ IAXVoIPLink::getIAXCall(const CallID& id)
 
 
  int 
-IAXVoIPLink::sendRegister(AccountID id UNUSED) 
+IAXVoIPLink::sendRegister(AccountID id) 
 {
-  bool result = false;
-  if (_host.empty()) {
-    return false;
-  }
-  if (_user.empty()) {
-    return false;
-  }
+    IAXAccount *account;
+    bool result;
 
-  // lock
-  _mutexIAX.enterMutex();
+    result = false;
+    account = dynamic_cast<IAXAccount *> (Manager::instance().getAccount(id));
+    if (_host.empty()) {
+        return false;
+    }
+    if (_user.empty()) {
+        return false;
+    }
 
-  // Always use a brand new session
-  if (_regSession) {
-    iax_destroy(_regSession);
-  }
+    // lock
+    _mutexIAX.enterMutex();
+
+    // Always use a brand new session
+    if (_regSession) {
+        iax_destroy(_regSession);
+    }
 
-  _regSession = iax_session_new();
+    _regSession = iax_session_new();
 
-  if (!_regSession) {
-    _debug("Error when generating new session for register");
-  } else {
-    // refresh
-    // last reg
-    char host[_host.length()+1]; 
-    strcpy(host, _host.c_str());
-    char user[_user.length()+1];
-    strcpy(user, _user.c_str());
-    char pass[_pass.length()+1]; 
-    strcpy(pass, _pass.c_str());
-    // iax_register doesn't use const char*
-
-    _debug("IAX Sending registration to %s with user %s\n", host, user);
-    int val = iax_register(_regSession, host, user, pass, 120);
-    _debug ("Return value: %d\n", val);
-    // set the time-out to 15 seconds, after that, resend a registration request.
-    // until we unregister.
-    _nextRefreshStamp = time(NULL) + 10;
-    result = true;
-
-    setRegistrationState(Trying);
+    if (!_regSession) {
+        _debug("Error when generating new session for register");
+    } else {
+        // refresh
+        // last reg
+        char host[_host.length()+1]; 
+        strcpy(host, _host.c_str());
+        char user[_user.length()+1];
+        strcpy(user, _user.c_str());
+        char pass[_pass.length()+1]; 
+        strcpy(pass, _pass.c_str());
+        // iax_register doesn't use const char*
+
+        _debug("IAX Sending registration to %s with user %s\n", host, user);
+        int val = iax_register(_regSession, host, user, pass, 120);
+        _debug ("Return value: %d\n", val);
+        // set the time-out to 15 seconds, after that, resend a registration request.
+        // until we unregister.
+        _nextRefreshStamp = time(NULL) + 10;
+        result = true;
+
+        account->setRegistrationState(Trying);
   }
 
   // unlock
@@ -361,7 +366,7 @@ IAXVoIPLink::sendRegister(AccountID id UNUSED)
 
 
  int 
-IAXVoIPLink::sendUnregister()
+IAXVoIPLink::sendUnregister(AccountID id)
 {
   _mutexIAX.enterMutex();
   if (_regSession) {
@@ -377,7 +382,7 @@ IAXVoIPLink::sendUnregister()
   _nextRefreshStamp = 0;
 
   _debug("IAX2 send unregister\n");
-  setRegistrationState(Unregistered);
+  //setRegistrationState(Unregistered);
 
   return SUCCESS;
 }
@@ -761,7 +766,8 @@ IAXVoIPLink::iaxHandleRegReply(iax_event* event)
         iax_destroy(_regSession);
         _mutexIAX.leaveMutex();
         _regSession = NULL;
-        setRegistrationState(ErrorAuth);
+        //TODO Restore that
+        //setRegistrationState(ErrorAuth);
     }
     
     else if (event->etype == IAX_EVENT_REGACK) {
@@ -783,7 +789,7 @@ IAXVoIPLink::iaxHandleRegReply(iax_event* event)
         // I mean, save the timestamp, so that we re-register again in the REFRESH time.
         // Defaults to 60, as per draft-guy-iax-03.
         _nextRefreshStamp = time(NULL) + (event->ies.refresh ? event->ies.refresh : 60);
-        setRegistrationState(Registered);
+        //nsetRegistrationState(Registered);
     }
 }
 
diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h
index bae6df69f55ca1e3dfd4fca245f14485c5a7ae3e..8ad4082882f41b731a610714172167bb94e15f95 100644
--- a/src/iaxvoiplink.h
+++ b/src/iaxvoiplink.h
@@ -85,7 +85,7 @@ class IAXVoIPLink : public VoIPLink
      * @return bool true if we're registered upstream
      *		  false otherwise
      */
-    int sendUnregister (void);
+    int sendUnregister (AccountID id);
 
     /**
      * Create a new outgoing call
@@ -183,6 +183,8 @@ class IAXVoIPLink : public VoIPLink
 
     void updateAudiolayer( void ); 
 
+    void setStunServer( const std::string &server ) {};
+
   private:
 
     /* 
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
index 619d494894b9ee5376732405a537ceb4ec938f1d..c8c25d2b8432821c06f587c7b17ae0d3b38fa651 100644
--- a/src/managerimpl.cpp
+++ b/src/managerimpl.cpp
@@ -192,27 +192,31 @@ ManagerImpl::switchCall(const CallID& id ) {
   bool
 ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to)
 {
-  if (!accountExists(accountid)) {
-    _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
-    return false;
-  }
-  if (getAccountFromCall(id) != AccountNULL) {
-    _debug("! Manager Error: Outgoing Call: call id already exists\n");
-    return false;
-  }
-  if (hasCurrentCall()) {
-    _debug("* Manager Info: there is currently a call, try to hold it\n");
-    onHoldCall(getCurrentCallId());
-  }
-  _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
-  if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
+    if (!accountExists(accountid)) {
+        _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
+        return false;
+    }
+  
+    if (getAccountFromCall(id) != AccountNULL) {
+        _debug("! Manager Error: Outgoing Call: call id already exists\n");
+        return false;
+    }
+  
+    if (hasCurrentCall()) {
+        _debug("* Manager Info: there is currently a call, try to hold it\n");
+        onHoldCall(getCurrentCallId());
+    }
+  
+    _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
     associateCallToAccount( id, accountid );
-    switchCall(id);
-    return true;
-  } else {
-    _debug("! Manager Error: An error occur, the call was not created\n");
-  }
-  return false;
+    if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
+        switchCall(id);
+        return true;
+    } else {
+        callFailure(id);
+        _debug("! Manager Error: An error occur, the call was not created\n");
+    }
+    return false;
 }
 
 //THREAD=Main : for outgoing Call
@@ -971,15 +975,17 @@ ManagerImpl::initConfigFile ( bool load_user_value )
   std::string type_int("int");
 
   std::string section;
-  section = SIGNALISATION;
 
   // Default values, that will be overwritten by the call to
   // 'populateFromFile' below.
+  section = SIGNALISATION;
   fill_config_int(SYMMETRIC, YES_STR);
   fill_config_int(PLAY_DTMF, YES_STR);
   fill_config_int(PLAY_TONES, YES_STR);
   fill_config_int(PULSE_LENGTH, DFT_PULSE_LENGTH_STR);
   fill_config_int(SEND_DTMF_AS, SIP_INFO_STR);
+  fill_config_int(STUN_ENABLE, DFT_STUN_ENABLE);
+  fill_config_int(STUN_SERVER, DFT_STUN_SERVER);
 
   section = AUDIO;
   fill_config_int(ALSA_CARD_ID_IN, ALSA_DFT_CARD);
@@ -1361,7 +1367,27 @@ ManagerImpl::setDialpad( void )
   ( getConfigInt( PREFERENCES , CONFIG_DIALPAD ) == DISPLAY_DIALPAD )? setConfig(PREFERENCES , CONFIG_DIALPAD , NO_STR ) : setConfig( PREFERENCES , CONFIG_DIALPAD , YES_STR );
 }
 
-int
+std::string ManagerImpl::getStunServer( void )
+{
+  return getConfigString(SIGNALISATION , STUN_SERVER);
+}
+
+void ManagerImpl::setStunServer( const std::string &server )
+{
+  setConfig(SIGNALISATION , STUN_SERVER, server );
+}
+
+int ManagerImpl::isStunEnabled (void)
+{
+    return getConfigInt(SIGNALISATION , STUN_ENABLE);
+}
+
+void ManagerImpl::enableStun (void)
+{
+  ( getConfigInt( SIGNALISATION , STUN_ENABLE ) == STUN_ENABLED )? setConfig(SIGNALISATION , STUN_ENABLE , NO_STR ) : setConfig( SIGNALISATION , STUN_ENABLE , YES_STR );
+}
+
+    int
 ManagerImpl::getVolumeControls( void )
 {
   return getConfigInt( PREFERENCES , CONFIG_VOLUME );
@@ -1833,7 +1859,7 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails(const Accoun
 
   std::map<std::string, std::string> a;
   std::string accountType;
-  enum VoIPLink::RegistrationState state;
+  RegistrationState state;
   
   state = _accountMap[accountID]->getRegistrationState();
   accountType = getConfigString(accountID, CONFIG_ACCOUNT_TYPE);
@@ -1842,15 +1868,15 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails(const Accoun
   a.insert( std::pair<std::string, std::string>( CONFIG_ACCOUNT_ENABLE, getConfigString(accountID, CONFIG_ACCOUNT_ENABLE) == "1" ? "TRUE": "FALSE"));
   a.insert( std::pair<std::string, std::string>(
 	"Status", 
-	(state == VoIPLink::Registered ? "REGISTERED":
-	(state == VoIPLink::Unregistered ? "UNREGISTERED":
-	(state == VoIPLink::Trying ? "TRYING":
-	(state == VoIPLink::ErrorAuth ? "ERROR_AUTH": 
-	(state == VoIPLink::ErrorNetwork ? "ERROR_NETWORK": 
-	(state == VoIPLink::ErrorHost ? "ERROR_HOST": 
-	(state == VoIPLink::ErrorExistStun ? "ERROR_EXIST_STUN": 
-	(state == VoIPLink::ErrorConfStun ? "ERROR_CONF_STUN": 
-	(state == VoIPLink::Error ? "ERROR": "ERROR")))))))))
+	(state == Registered ? "REGISTERED":
+	(state == Unregistered ? "UNREGISTERED":
+	(state == Trying ? "TRYING":
+	(state == ErrorAuth ? "ERROR_AUTH": 
+	(state == ErrorNetwork ? "ERROR_NETWORK": 
+	(state == ErrorHost ? "ERROR_HOST": 
+	(state == ErrorExistStun ? "ERROR_EXIST_STUN": 
+	(state == ErrorConfStun ? "ERROR_CONF_STUN": 
+	(state == Error ? "ERROR": "ERROR")))))))))
 	)
       );
  
@@ -1875,6 +1901,7 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma
 
     std::string accountType;
     Account *acc;
+    VoIPLink *link;
   
     accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
 
@@ -1888,16 +1915,25 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma
   
     // SIP SPECIFIC
     if (accountType == "SIP") {
+    
+        link =  Manager::instance().getAccountLink( accountID );
+        
+        if( link==0 )
+        {
+            _debug("Can not retrieve SIP link...\n");
+            return;
+        }
+    
         setConfig(accountID, SIP_STUN_SERVER,(*details.find(SIP_STUN_SERVER)).second);
         setConfig(accountID, SIP_USE_STUN, (*details.find(SIP_USE_STUN)).second == "TRUE" ? "1" : "0");
 
         if((*details.find(SIP_USE_STUN)).second == "TRUE")
         {
-           //TODO Replace:  _userAgent->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
+           link->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
         }
         else
         {
-            //TODO: replace: _userAgent->setStunServer(NULL);
+            link->setStunServer("");
         }
         //restartPjsip();
     }
@@ -1916,6 +1952,8 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma
     // Update account details to the client side
     if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
 
+    //delete link; link=0;
+
 }
 
 void
diff --git a/src/managerimpl.h b/src/managerimpl.h
index a556b9175cdda6677dc9624757a27d0cd8e27589..222c7154788fd86d4cc79d2fd3ad16c048584f82 100644
--- a/src/managerimpl.h
+++ b/src/managerimpl.h
@@ -1020,6 +1020,11 @@ public:
 
     void setSipPort( int port );
 
+    std::string getStunServer (void);
+    void setStunServer (const std::string &server);
+
+    int isStunEnabled (void);
+    void enableStun (void);
 private:
 
     // Copy Constructor
diff --git a/src/sipaccount.cpp b/src/sipaccount.cpp
index 5270e39df7a3aea627dd51bfac68e1b43e55f225..5880f927f00fd0708ed0a7f30fedea5ef140af24 100644
--- a/src/sipaccount.cpp
+++ b/src/sipaccount.cpp
@@ -2,8 +2,6 @@
  *  Copyright (C) 2006-2009 Savoir-Faire Linux inc.
  *  
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
- *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
  *                                                                              
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -28,18 +26,28 @@ SIPAccount::SIPAccount(const AccountID& accountID)
  : Account(accountID, "sip")
  , _cred(NULL)
  , _contact("")
+ , _bRegister(false)
+ , _regc()
 {
-  _link = new SIPVoIPLink(accountID);
-   //_link = SIPVoIPLink::instance( accountID ); 
+    /* SIPVoIPlink is used as a singleton, because we want to have only one link for all the SIP accounts created */
+    /* So instead of creating a new instance, we just fetch the static instance, or create one if it is not yet */
+    /* The SIP library initialization is done in the SIPVoIPLink constructor */
+    /* The SIP voip link is now independant of the account ID as it can manage several SIP accounts */
+    _link = SIPVoIPLink::instance("");
+    
+    /* Represents the number of SIP accounts connected the same link */
+    dynamic_cast<SIPVoIPLink*> (_link)->incrementClients();
+    
 }
 
 
 SIPAccount::~SIPAccount()
 {
-  delete _link;
-  _link = NULL;
-  delete _cred;
-  _cred = NULL;
+    /* One SIP account less connected to the sip voiplink */
+    dynamic_cast<SIPVoIPLink*> (_link)->decrementClients();
+    /* Delete accounts-related information */
+    _regc = NULL;
+    delete _cred; _cred = NULL;
 }
 
 int SIPAccount::registerVoIPLink()
@@ -56,12 +64,7 @@ int SIPAccount::registerVoIPLink()
     /* STUN configuration is attached to a voiplink because it is applied to every accounts (PJSIP limitation)*/
     thislink = dynamic_cast<SIPVoIPLink*> (_link);
     if (thislink) {
-        useStun = Manager::instance().getConfigInt(_accountID,SIP_USE_STUN);
-        thislink->setStunServer(Manager::instance().getConfigString(_accountID,SIP_STUN_SERVER));
-        thislink->setUseStun( useStun!=0 ? true : false);
     }
-    /* Link initialization */
-    _link->init();
 
     /* Start registration */
     status = _link->sendRegister( _accountID );
@@ -73,7 +76,7 @@ int SIPAccount::registerVoIPLink()
 int SIPAccount::unregisterVoIPLink()
 {
   _debug("SIPAccount: unregister account %s\n" , getAccountID().c_str());
-  return _link->sendUnregister();
+  return _link->sendUnregister( _accountID );
 }
 
 void SIPAccount::loadConfig() 
diff --git a/src/sipaccount.h b/src/sipaccount.h
index dfbc55774f4a9fcb19327ebdbb303f0ca0b97bc2..b716086fbe5fc94fe57146228d20d4605a92169d 100644
--- a/src/sipaccount.h
+++ b/src/sipaccount.h
@@ -26,8 +26,6 @@
 #include "account.h"
 #include "sipvoiplink.h"
 
-struct pjsip_cred_info;
-
 class SIPVoIPLink;
 
 /**
@@ -91,13 +89,31 @@ class SIPAccount : public Account
         inline std::string getType( void ) { return _type; }
         inline void setType( std::string type ) { _type = type; }
 
+        pjsip_regc* getRegistrationInfo( void ) { return _regc; }
+        void setRegistrationInfo( pjsip_regc *regc ) { _regc = regc; }
+
+        //TODO See if it useful
+        bool isRegister() {return _bRegister;}
+        void setRegister(bool result) {_bRegister = result;}
+
 
     private:
+
         /**
          * Credential information
          */
         pjsip_cred_info *_cred;
 
+        /**
+         * The pjsip client registration information
+         */
+        pjsip_regc *_regc;
+        
+        /**
+         * To check if the account is registered
+         */
+        bool _bRegister;
+        
         /*
          * SIP address
          */
diff --git a/src/sipcall.cpp b/src/sipcall.cpp
index bcc596ccf7f1f3a1b33a9befc4fccc2bc03167ce..d43ea938ac230ce691722de456a39a3dcaa7c32a 100644
--- a/src/sipcall.cpp
+++ b/src/sipcall.cpp
@@ -22,8 +22,6 @@
 
 #include "sipcall.h"
 #include "global.h" // for _debug
-#include <sstream> // for media buffer
-#include <string>
 
 #define _SENDRECV 0
 #define _SENDONLY 1
@@ -68,11 +66,6 @@ SIPCall::SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool)
   _localSDP->time.start = _localSDP->time.stop = 0;
   sdpAddMediaDescription(pool);
   
-    _debug("SDP: addr: %s\nuser: %s\nid: %i\nversion: %i\naddr: %s\nattr count: %i\n", 
-            _ipAddr.c_str(), _localSDP->origin.user, _localSDP->origin.id, _localSDP->origin.version, _localSDP->origin.addr.ptr, _localSDP->attr_count );
-
-  _debug("Before validate SDP!\n");
-
   status = pjmedia_sdp_validate( _localSDP );
   if (status != PJ_SUCCESS) {
     _debug("Can not generate valid local sdp\n");
diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp
index 42e9887e837d97ce43845f29bef36d9fa0f61958..a37e68318704433019f1836d553157ab4f0910c0 100644
--- a/src/sipvoiplink.cpp
+++ b/src/sipvoiplink.cpp
@@ -18,29 +18,45 @@
  *  along with this program; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/*
- * YM: 2006-11-15: changes unsigned int to std::string::size_type, thanks to Pierre Pomes (AMD64 compilation)
- */
+
 #include "sipvoiplink.h"
 #include "eventthread.h"
 #include "sipcall.h"
-#include <sstream> // for istringstream
 #include "sipaccount.h"
 #include "audio/audiortp.h"
 
-#include "manager.h"
-#include "user_cfg.h" // SIGNALISATION / PULSE #define
+/**************** EXTERN VARIABLES AND FUNCTIONS (callbacks) **************************/
 
-/** PJSIP related variables */
+/*
+ *  The global pool factory
+ */
 pj_caching_pool _cp;
+
+/*
+ * The pool to allocate memory
+ */
 pj_pool_t *_pool;    
+
+/*
+ *	The SIP endpoint
+ */
 pjsip_endpoint *_endpt;
-pjsip_module _mod_ua;       /** PJSIP module. */
+
+/*
+ *	The SIP module
+ */
+pjsip_module _mod_ua;  
+
+/*
+ * Thread related
+ */
 pj_thread_t *thread;
 pj_thread_desc desc;
 
-/*****************************/
 
+/**
+ * Get the number of voicemail waiting in a SIP message
+ */
 void set_voicemail_info( AccountID account, pjsip_msg_body *body );
 
 /**
@@ -49,84 +65,146 @@ void set_voicemail_info( AccountID account, pjsip_msg_body *body );
  * @param call a SIPCall valid pointer
  * @return bool True
  */
-bool setCallAudioLocal(SIPCall* call);
-
-
-/** Do we use stun? */
-bool _useStun;
+bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server);
 
-/** The current STUN server address */
-std::string _stunServer;
-    
-std::string _localIPAddress;
+// Documentated from the PJSIP Developer's Guide, available on the pjsip website/
 
-/** PJSIP callbacks */
+/*
+ * Session callback
+ * Called when the invite session state has changed.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	e	A pointer on a pjsip_event structure
+ */
 void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e);
+
+/*
+ * Session callback
+ * Called after SDP offer/answer session has completed.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	status	A pj_status_t structure
+ */
 void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED);
+
+/*
+ * Called when the invote usage module has created a new dialog and invite
+ * because of forked outgoing request.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	e	A pointer on a pjsip_event structure
+ */
 void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
+
+/*
+ * Session callback
+ * Called whenever any transactions within the session has changed their state.
+ * Useful to monitor the progress of an outgoing request.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	tsx	A pointer on a pjsip_transaction structure
+ * @param	e	A pointer on a pjsip_event structure
+ */
 void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e);
+
+/*
+ * Registration callback
+ */
 void regc_cb(struct pjsip_regc_cbparam *param);
+
+/*
+ * Called to handle incoming requests outside dialogs
+ * @param   rdata
+ * @return  pj_bool_t
+ */
 pj_bool_t mod_on_rx_request(pjsip_rx_data *rdata);
+
+/*
+ * Called to handle incoming response
+ * @param	rdata
+ * @return	pj_bool_t
+ */
 pj_bool_t mod_on_rx_response(pjsip_rx_data *rdata UNUSED) ;
+
+/*
+ * Transfer callbacks
+ */
 void xfer_func_cb( pjsip_evsub *sub, pjsip_event *event);
 void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event);
-
 void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata);
-/*******************************/
+
+/*************************************************************************************************/
+
+SIPVoIPLink* SIPVoIPLink::_instance = NULL;
+
 
     SIPVoIPLink::SIPVoIPLink(const AccountID& accountID)
     : VoIPLink(accountID)
-    , _nbTryListenAddr(2) // number of times to try to start SIP listener
-    , _stunServer("")
+      , _nbTryListenAddr(2) // number of times to try to start SIP listener
+      , _stunServer("")
     , _localExternAddress("") 
     , _localExternPort(0)
     , _audiortp(new AudioRtp())
-    , _regc()
-    , _bRegister(false)
     ,_regPort(DEFAULT_SIP_PORT)
+    , _useStun(false)
+    , _clients(0)
 {
     // to get random number for RANDOM_PORT
     srand (time(NULL));
-    _useStun = false;
-    _localIPAddress = "127.0.0.1"; 
 
+    /* Instanciate the C++ thread */
     _evThread = new EventThread(this);
+
+    /* Start pjsip initialization step */
+    init();
 }
 
 SIPVoIPLink::~SIPVoIPLink()
 {
-    delete _evThread; _evThread = NULL;
     terminate();
 }
 
-SIPVoIPLink* SIPVoIPLink::instance( const AccountID& id){
-    /*if(!_instance ){
-      _instance = new SIPVoIPLink( id );
-      }
-      return _instance;*/
+SIPVoIPLink* SIPVoIPLink::instance( const AccountID& id)
+{
+
+    if(!_instance ){
+        _instance = new SIPVoIPLink( id );
+    }
+
+    return _instance;
 }
 
+void SIPVoIPLink::decrementClients (void)
+{
+    _clients--;
+    if(_clients == 0){
+        terminate();
+        SIPVoIPLink::_instance=NULL;
+    }
+}
 
 bool SIPVoIPLink::init()
 {
-    if(_initDone)
+    if(initDone())
         return false;
     /* Initialize the pjsip library */
-    _regc = NULL;
-    if(!pjsip_init())
-        return false;
+    pjsip_init();
+    initDone(true);
 
-    _initDone = true;
     return true;
 }
 
     void 
 SIPVoIPLink::terminate()
 {
+    delete _evThread; _evThread = NULL;
+
     /* Clean shutdown of pjsip library */
-    if( _initDone )
+    if( initDone() )
+    {
         pjsip_shutdown();
-    _initDone = false;
+    }
+    initDone(false);
 }
 
     void
@@ -152,17 +230,11 @@ SIPVoIPLink::getEvent()
 {
     // We have to register the external thread so it could access the pjsip framework
     if(!pj_thread_is_registered())
-    {
         pj_thread_register( NULL, desc, &thread );
-    }
-
-    _mutexSIP.enterMutex(); 
 
     // PJSIP polling
     pj_time_val timeout = {0, 10};
     pjsip_endpt_handle_events( _endpt, &timeout);
-
-    _mutexSIP.leaveMutex(); 
 }
 
 int SIPVoIPLink::sendRegister( AccountID id )
@@ -174,6 +246,7 @@ int SIPVoIPLink::sendRegister( AccountID id )
     pjsip_tx_data *tdata;
     std::string tmp, hostname, username, password;
     SIPAccount *account;
+    pjsip_regc *regc;
 
     account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id));
     hostname = account->getHostname();
@@ -182,30 +255,32 @@ int SIPVoIPLink::sendRegister( AccountID id )
 
     _mutexSIP.enterMutex(); 
 
+    /* Get the client registration information for this particular account */
+    regc = account->getRegistrationInfo();
     /* If the registration already exists, delete it */
-    if(_regc) {
-        status = pjsip_regc_destroy(_regc);
-        _regc = NULL;
+    if(regc) {
+        status = pjsip_regc_destroy(regc);
+        regc = NULL;
         PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
     }
 
-    setRegister(true);
+    account->setRegister(true);
 
     /* Set the expire value of the message from the config file */
     expire_value = Manager::instance().getRegistrationExpireValue();
 
     /* Update the state of the voip link */
-    setRegistrationState(Trying);
+    account->setRegistrationState(Trying);
 
     if (!validStunServer) {
-        setRegistrationState(VoIPLink::ErrorExistStun);
-        setRegister(false);
+        account->setRegistrationState(ErrorExistStun);
+        account->setRegister(false);
         _mutexSIP.leaveMutex(); 
         return false;
     }
 
     /* Create the registration according to the account ID */
-    status = pjsip_regc_create(_endpt, (void*)new AccountID(id), &regc_cb, &_regc);
+    status = pjsip_regc_create(_endpt, (void*)account, &regc_cb, &regc);
     if (status != PJ_SUCCESS) {
         _debug("UserAgent: Unable to create regc.\n");
         _mutexSIP.leaveMutex(); 
@@ -222,7 +297,7 @@ int SIPVoIPLink::sendRegister( AccountID id )
     pj_strdup2(_pool, &contact, contactTmp);
     account->setContact(contactTmp);
 
-    status = pjsip_regc_init(_regc, &svr, &aor, &aor, 1, &contact, 600); //timeout);
+    status = pjsip_regc_init(regc, &svr, &aor, &aor, 1, &contact, 600); //timeout);
     if (status != PJ_SUCCESS) {
         _debug("UserAgent: Unable to initialize regc. %d\n", status); //, regc->str_srv_url.ptr);
         _mutexSIP.leaveMutex(); 
@@ -240,48 +315,55 @@ int SIPVoIPLink::sendRegister( AccountID id )
     pj_strdup2(_pool, &cred->data, password.data());
     pj_strdup2(_pool, &cred->realm, "*");
     pj_strdup2(_pool, &cred->scheme, "digest");
-    pjsip_regc_set_credentials(_regc, 1, cred);
+    pjsip_regc_set_credentials(regc, 1, cred);
 
     account->setCredInfo(cred);
 
-    status = pjsip_regc_register(_regc, PJ_TRUE, &tdata);
+    status = pjsip_regc_register(regc, PJ_TRUE, &tdata);
     if (status != PJ_SUCCESS) {
         _debug("UserAgent: Unable to register regc.\n");
         _mutexSIP.leaveMutex(); 
         return false;
     }
 
-    status = pjsip_regc_send(_regc, tdata);
+    status = pjsip_regc_send(regc, tdata);
     if (status != PJ_SUCCESS) {
         _debug("UserAgent: Unable to send regc request.\n");
         _mutexSIP.leaveMutex(); 
         return false;
     }
-    
+
     _mutexSIP.leaveMutex(); 
 
+    account->setRegistrationInfo(regc);
+
     return true;
 }
 
     int 
-SIPVoIPLink::sendUnregister()
+SIPVoIPLink::sendUnregister( AccountID id )
 {
     pj_status_t status = 0;
     pjsip_tx_data *tdata = NULL;
+    SIPAccount *account;
+    pjsip_regc *regc;
 
-    if(!isRegister()){
-        setRegistrationState(VoIPLink::Unregistered); 
+    account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id));
+    regc = account->getRegistrationInfo();
+
+    if(!account->isRegister()){
+        account->setRegistrationState(Unregistered); 
         return true;
     }
 
-    if(_regc) {
-        status = pjsip_regc_unregister(_regc, &tdata);
+    if(regc) {
+        status = pjsip_regc_unregister(regc, &tdata);
         if(status != PJ_SUCCESS) {
             _debug("UserAgent: Unable to unregister regc.\n");
             return false;
         }
 
-        status = pjsip_regc_send( _regc, tdata );
+        status = pjsip_regc_send( regc, tdata );
         if(status != PJ_SUCCESS) {
             _debug("UserAgent: Unable to send regc request.\n");
             return false;
@@ -291,7 +373,8 @@ SIPVoIPLink::sendUnregister()
         return false;
     }
 
-    setRegister(false);
+    account->setRegistrationInfo(regc);
+    account->setRegister(false);
 
     return true;
 }
@@ -302,9 +385,17 @@ SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
     Account* account;
 
     SIPCall* call = new SIPCall(id, Call::Outgoing);
-    
+
     if (call) {
         account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(Manager::instance().getAccountFromCall(id)));
+        if(!account)
+        {
+            _debug("Error retrieving the account to the make the call with\n");
+            call->setConnectionState(Call::Disconnected);
+            call->setState(Call::Error);
+            delete call; call=0;
+            return call;
+        }
         //call->setPeerNumber(toUrl);
         call->setPeerNumber(getSipTo(toUrl, account->getHostname()));
         _debug("Try to make a call to: %s with call ID: %s\n", toUrl.data(), id.data());
@@ -426,12 +517,17 @@ SIPVoIPLink::onhold(const CallID& id)
 
     if (call==0) { _debug("! SIP Error: call doesn't exist\n"); return false; }  
 
+    _mutexSIP.enterMutex();
+
     // Stop sound
     call->setAudioStart(false);
     call->setState(Call::Hold);
     _debug("* SIP Info: Stopping AudioRTP for onhold action\n");
     _audiortp->closeRtpSession();
     local_sdp = call->getLocalSDPSession();
+
+    _mutexSIP.leaveMutex();
+
     if( local_sdp == NULL ){
         _debug("! SIP Failure: unable to find local_sdp\n");
         return false;
@@ -703,7 +799,7 @@ SIPVoIPLink::SIPStartCall(SIPCall* call, const std::string& subject UNUSED)
     id = Manager::instance().getAccountFromCall(call->getCallId());
     // Get the basic information about the callee account
     account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(id));
-    
+
     strTo = getSipTo(call->getPeerNumber(), account->getHostname());
     _debug("            To: %s\n", strTo.data());
 
@@ -723,7 +819,7 @@ SIPVoIPLink::SIPStartCall(SIPCall* call, const std::string& subject UNUSED)
             &dialog);
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
 
-    setCallAudioLocal(call);
+    setCallAudioLocal(call, getLocalIPAddress(), useStun(), getStunServer());
     call->setIp(getLocalIP());
 
     // Building the local SDP offer
@@ -767,14 +863,14 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam
     return SIPToHeader(to_url);
     }
 
-std::string SIPVoIPLink::SIPToHeader(const std::string& to) 
-{
-    if (to.find("sip:") == std::string::npos) {
-        return ("sip:" + to );
-    } else {
-        return to;
+    std::string SIPVoIPLink::SIPToHeader(const std::string& to) 
+    {
+        if (to.find("sip:") == std::string::npos) {
+            return ("sip:" + to );
+        } else {
+            return to;
+        }
     }
-}
 
     bool
         SIPVoIPLink::SIPCheckUrl(const std::string& url UNUSED)
@@ -782,27 +878,27 @@ std::string SIPVoIPLink::SIPToHeader(const std::string& to)
             return true;
         }
 
-bool setCallAudioLocal(SIPCall* call) 
-{
-    // Setting Audio
-    unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
-    unsigned int callLocalExternAudioPort = callLocalAudioPort;
-    if (_useStun) {
-        // If use Stun server
-        if (Manager::instance().behindNat(_stunServer, callLocalAudioPort)) {
-            callLocalExternAudioPort = Manager::instance().getFirewallPort();
+    bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server) 
+    {
+        // Setting Audio
+        unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
+        unsigned int callLocalExternAudioPort = callLocalAudioPort;
+        if (stun) {
+            // If use Stun server
+            if (Manager::instance().behindNat(server, callLocalAudioPort)) {
+                callLocalExternAudioPort = Manager::instance().getFirewallPort();
+            }
         }
-    }
-            _debug("            Setting local audio port to: %d\n", callLocalAudioPort);
-            _debug("            Setting local audio port (external) to: %d\n", callLocalExternAudioPort);
+        _debug("            Setting local audio port to: %d\n", callLocalAudioPort);
+        _debug("            Setting local audio port (external) to: %d\n", callLocalExternAudioPort);
 
-            // Set local audio port for SIPCall(id)
-            call->setLocalIp(_localIPAddress);
-            call->setLocalAudioPort(callLocalAudioPort);
-            call->setLocalExternAudioPort(callLocalExternAudioPort);
+        // Set local audio port for SIPCall(id)
+        call->setLocalIp(localIP);
+        call->setLocalAudioPort(callLocalAudioPort);
+        call->setLocalExternAudioPort(callLocalExternAudioPort);
 
-            return true;
-        }
+        return true;
+    }
 
     void
         SIPVoIPLink::SIPCallServerFailure(SIPCall *call) 
@@ -901,18 +997,20 @@ bool setCallAudioLocal(SIPCall* call)
             return NULL;
         }
 
-    ///////////////////////////////////////////////////////////////////////////////
-    // Private functions
-    ///////////////////////////////////////////////////////////////////////////////
-
-    pj_str_t SIPVoIPLink::string2PJStr(const std::string &value)
+    void SIPVoIPLink::setStunServer( const std::string &server )
     {
-        char tmp[256];
-
-        strcpy(tmp, value.data());
-        return pj_str(tmp);
+         if(server != "") {
+            useStun(true);
+            _stunServer = server;
+        } else {
+            useStun(false);
+            _stunServer = std::string("");
+        }
     }
 
+    ///////////////////////////////////////////////////////////////////////////////
+    // Private functions
+    ///////////////////////////////////////////////////////////////////////////////
 
     bool SIPVoIPLink::pjsip_init()
     {
@@ -922,7 +1020,7 @@ bool setCallAudioLocal(SIPCall* call)
         pjsip_inv_callback inv_cb;
         pj_str_t accepted;
         std::string name_mod;
-
+        bool useStun;
         validStunServer = true;
 
         name_mod = "sflphone";
@@ -968,9 +1066,14 @@ bool setCallAudioLocal(SIPCall* call)
 
         port = _regPort;
 
-        if (_useStun && !Manager::instance().behindNat(_stunServer, port)) {
+        /* Retrieve the STUN configuration */
+        useStun = Manager::instance().getConfigInt( SIGNALISATION, SIP_USE_STUN );
+        this->setStunServer(Manager::instance().getConfigString( SIGNALISATION, SIP_STUN_SERVER ));
+        this->useStun( useStun!=0 ? true : false);
+
+        if (useStun && !Manager::instance().behindNat(getStunServer(), port)) {
             port = RANDOM_SIP_PORT;
-            if (!Manager::instance().behindNat(_stunServer, port)) {
+            if (!Manager::instance().behindNat(getStunServer(), port)) {
                 _debug("UserAgent: Unable to check NAT setting\n");
                 validStunServer = false;		
                 return false; // hoho we can't use the random sip port too...
@@ -978,7 +1081,7 @@ bool setCallAudioLocal(SIPCall* call)
         }
 
         _localPort = port;
-        if (_useStun) {
+        if (useStun) {
             // set by last behindNat() call (ish)...
             stunServerResolve();
             _localExternAddress = Manager::instance().getFirewallAddress();
@@ -1037,17 +1140,6 @@ bool setCallAudioLocal(SIPCall* call)
         status = pjsip_evsub_init_module(_endpt);
         PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
 
-        // Init presence module. 
-        // TODO We probably do not need that extension
-        status = pjsip_pres_init_module(_endpt, pjsip_evsub_instance());
-        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-        // Init PUBLISH module 
-        // Provide an implementation of SIP Extension for Event State Publication (RFC 3903)
-        // TODO Check if it is necessary
-        status = pjsip_publishc_init_module(_endpt);
-        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
         // Init xfer/REFER module
         status = pjsip_xfer_init_module(_endpt);
         PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
@@ -1096,6 +1188,9 @@ bool setCallAudioLocal(SIPCall* call)
         size_t pos;
         std::string serverName, serverPort;
         int nPort;
+        std::string stun_server;
+
+        stun_server = getStunServer();
 
         // Initialize STUN configuration
         pj_stun_config_init(&stunCfg, &_cp.factory, 0, pjsip_endpt_get_ioqueue(_endpt), pjsip_endpt_get_timer_heap(_endpt));
@@ -1103,13 +1198,13 @@ bool setCallAudioLocal(SIPCall* call)
         stun_status = PJ_EPENDING;
 
         // Init STUN socket
-        pos = _stunServer.find(':');
+        pos = stun_server.find(':');
         if(pos == std::string::npos) {
-            pj_strdup2(_pool, &stun_adr, _stunServer.data());
+            pj_strdup2(_pool, &stun_adr, stun_server.data());
             stun_status = pj_sockaddr_in_init(&stun_srv.ipv4, &stun_adr, (pj_uint16_t) 3478);
         } else {
-            serverName = _stunServer.substr(0, pos);
-            serverPort = _stunServer.substr(pos + 1);
+            serverName = stun_server.substr(0, pos);
+            serverPort = stun_server.substr(pos + 1);
             nPort = atoi(serverPort.data());
             pj_strdup2(_pool, &stun_adr, serverName.data());
             stun_status = pj_sockaddr_in_init(&stun_srv.ipv4, &stun_adr, (pj_uint16_t) nPort);
@@ -1219,120 +1314,110 @@ bool setCallAudioLocal(SIPCall* call)
         return _mod_ua.id;
     }
 
-void set_voicemail_info( AccountID account, pjsip_msg_body *body ){
+    void set_voicemail_info( AccountID account, pjsip_msg_body *body ){
 
-    int voicemail, pos_begin, pos_end;
-    std::string voice_str = "Voice-Message: ";
-    std::string delimiter = "/";
-    std::string msg_body, voicemail_str;
+        int voicemail, pos_begin, pos_end;
+        std::string voice_str = "Voice-Message: ";
+        std::string delimiter = "/";
+        std::string msg_body, voicemail_str;
 
-    _debug("UserAgent: checking the voice message!\n");
-    // The voicemail message is formated like that:
-    // Voice-Message: 1/0  . 1 is the number we want to retrieve in this case
+        _debug("UserAgent: checking the voice message!\n");
+        // The voicemail message is formated like that:
+        // Voice-Message: 1/0  . 1 is the number we want to retrieve in this case
 
-    // We get the notification body
-    msg_body = (char*)body->data;
+        // We get the notification body
+        msg_body = (char*)body->data;
 
-    // We need the position of the first character of the string voice_str
-    pos_begin = msg_body.find(voice_str); 
-    // We need the position of the delimiter
-    pos_end = msg_body.find(delimiter); 
+        // We need the position of the first character of the string voice_str
+        pos_begin = msg_body.find(voice_str); 
+        // We need the position of the delimiter
+        pos_end = msg_body.find(delimiter); 
 
-    // So our voicemail number between the both index
-    try {
+        // So our voicemail number between the both index
+        try {
 
-        voicemail_str = msg_body.substr(pos_begin + voice_str.length(), pos_end - ( pos_begin + voice_str.length()));
-        std::cout << "voicemail number : " << voicemail_str << std::endl;
-        voicemail = atoi( voicemail_str.c_str() );
-    }
-    catch( std::out_of_range& e ){
-        std::cerr << e.what() << std::endl;
+            voicemail_str = msg_body.substr(pos_begin + voice_str.length(), pos_end - ( pos_begin + voice_str.length()));
+            std::cout << "voicemail number : " << voicemail_str << std::endl;
+            voicemail = atoi( voicemail_str.c_str() );
+        }
+        catch( std::out_of_range& e ){
+            std::cerr << e.what() << std::endl;
+        }
+
+        // We need now to notify the manager 
+        if( voicemail != 0 )
+            Manager::instance().startVoiceMessageNotification(account, voicemail);
     }
 
-    // We need now to notify the manager 
-    if( voicemail != 0 )
-        Manager::instance().startVoiceMessageNotification(account, voicemail);
-}
+    /*******************************/
+    /*   CALLBACKS IMPLEMENTATION  */
+    /*******************************/
 
-bool SIPVoIPLink::useStun( void ){
-    return _useStun;
-}
+    void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){
 
-void SIPVoIPLink::setUseStun( bool use )
-{
-    _useStun = use;
-}
+        PJ_UNUSED_ARG(inv);
 
+        SIPCall *call = reinterpret_cast<SIPCall*> (inv->mod_data[_mod_ua.id]);
+        if(!call)
+            return;
 
-    /*******************************/
-    /*   CALLBACKS IMPLEMENTATION  */
-    /*******************************/
+        /* If this is an outgoing INVITE that was created because of
+         * REFER/transfer, send NOTIFY to transferer.
+         */
+        if (call->getXferSub() && e->type==PJSIP_EVENT_TSX_STATE)  {
+            int st_code = -1;
+            pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
+
+            switch (call->getInvSession()->state) {
+                case PJSIP_INV_STATE_NULL:
+                case PJSIP_INV_STATE_CALLING:
+                    /* Do nothing */
+                    break;
 
-void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){
-        
-    PJ_UNUSED_ARG(inv);
+                case PJSIP_INV_STATE_EARLY:
+                case PJSIP_INV_STATE_CONNECTING:
+                    st_code = e->body.tsx_state.tsx->status_code;
+                    ev_state = PJSIP_EVSUB_STATE_ACTIVE;
+                    break;
 
-    SIPCall *call = reinterpret_cast<SIPCall*> (inv->mod_data[_mod_ua.id]);
-    if(!call)
-        return;
+                case PJSIP_INV_STATE_CONFIRMED:
+                    /* When state is confirmed, send the final 200/OK and terminate
+                     * subscription.
+                     */
+                    st_code = e->body.tsx_state.tsx->status_code;
+                    ev_state = PJSIP_EVSUB_STATE_TERMINATED;
+                    break;
 
-    /* If this is an outgoing INVITE that was created because of
-     * REFER/transfer, send NOTIFY to transferer.
-     */
-    if (call->getXferSub() && e->type==PJSIP_EVENT_TSX_STATE)  {
-        int st_code = -1;
-        pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
-
-        switch (call->getInvSession()->state) {
-            case PJSIP_INV_STATE_NULL:
-            case PJSIP_INV_STATE_CALLING:
-                /* Do nothing */
-                break;
-
-            case PJSIP_INV_STATE_EARLY:
-            case PJSIP_INV_STATE_CONNECTING:
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_ACTIVE;
-                break;
-
-            case PJSIP_INV_STATE_CONFIRMED:
-                /* When state is confirmed, send the final 200/OK and terminate
-                 * subscription.
-                 */
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_TERMINATED;
-                break;
-
-            case PJSIP_INV_STATE_DISCONNECTED:
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_TERMINATED;
-                break;
-
-            case PJSIP_INV_STATE_INCOMING:
-                /* Nothing to do. Just to keep gcc from complaining about
-                 * unused enums.
-                 */
-                break;
-        }
+                case PJSIP_INV_STATE_DISCONNECTED:
+                    st_code = e->body.tsx_state.tsx->status_code;
+                    ev_state = PJSIP_EVSUB_STATE_TERMINATED;
+                    break;
 
-        if (st_code != -1) {
-            pjsip_tx_data *tdata;
-            pj_status_t status;
+                case PJSIP_INV_STATE_INCOMING:
+                    /* Nothing to do. Just to keep gcc from complaining about
+                     * unused enums.
+                     */
+                    break;
+            }
 
-            status = pjsip_xfer_notify( call->getXferSub(),
-                    ev_state, st_code,
-                    NULL, &tdata);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to create NOTIFY -- %d\n", status);
-            } else {
-                status = pjsip_xfer_send_request(call->getXferSub(), tdata);
+            if (st_code != -1) {
+                pjsip_tx_data *tdata;
+                pj_status_t status;
+
+                status = pjsip_xfer_notify( call->getXferSub(),
+                        ev_state, st_code,
+                        NULL, &tdata);
                 if (status != PJ_SUCCESS) {
-                    _debug("UserAgent: Unable to send NOTIFY -- %d\n", status);
+                    _debug("UserAgent: Unable to create NOTIFY -- %d\n", status);
+                } else {
+                    status = pjsip_xfer_send_request(call->getXferSub(), tdata);
+                    if (status != PJ_SUCCESS) {
+                        _debug("UserAgent: Unable to send NOTIFY -- %d\n", status);
+                    }
                 }
             }
         }
     }
-}
 
     void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED) {
         _debug("call_on_media_updated\n");
@@ -1342,136 +1427,136 @@ void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){
         _debug("call_on_forked\n");
     }
 
-void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e){
+    void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e){
 
-    pjsip_rx_data *rdata;
-    AccountID accId;
-    SIPCall *call;
-    SIPVoIPLink *link;
-    pjsip_msg *msg;
+        pjsip_rx_data *rdata;
+        AccountID accId;
+        SIPCall *call;
+        SIPVoIPLink *link;
+        pjsip_msg *msg;
 
-    _debug("UserAgent: TSX Changed! The tsx->state is %d; tsx->role is %d; code is %d; method id is %.*s.\n",
-            tsx->state, tsx->role, tsx->status_code, (int)tsx->method.name.slen, tsx->method.name.ptr);
+        _debug("UserAgent: TSX Changed! The tsx->state is %d; tsx->role is %d; code is %d; method id is %.*s.\n",
+                tsx->state, tsx->role, tsx->status_code, (int)tsx->method.name.slen, tsx->method.name.ptr);
 
-    if(pj_strcmp2(&tsx->method.name, "INFO") == 0) {
-        // Receive a INFO message, ingore it!
-        return;
-    }
+        if(pj_strcmp2(&tsx->method.name, "INFO") == 0) {
+            // Receive a INFO message, ingore it!
+            return;
+        }
 
-    //Retrieve the body message
-    rdata = e->body.tsx_state.src.rdata;
+        //Retrieve the body message
+        rdata = e->body.tsx_state.src.rdata;
+
+        if (tsx->role == PJSIP_ROLE_UAC) {
+            switch (tsx->state) {
+                case PJSIP_TSX_STATE_TERMINATED:
+                    if (tsx->status_code == 200 &&
+                            pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) != 0) {
+                        // Peer answered the outgoing call
+                        _debug("UserAgent: Peer answered the outgoing call!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL)
+                            return;
+
+                        //_debug("UserAgent: The call id is %s\n", call->getCallId().data());
+
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link)
+                            link->SIPCallAnswered(call, rdata);
+                    } else if (tsx->status_code / 100 == 5) {
+                        _debug("UserAgent: 5xx error message received\n");
+                    }
+                    break;
+                case PJSIP_TSX_STATE_PROCEEDING:
+                    // Peer is ringing for the outgoing call
+                    msg = rdata->msg_info.msg;
 
-    if (tsx->role == PJSIP_ROLE_UAC) {
-        switch (tsx->state) {
-            case PJSIP_TSX_STATE_TERMINATED:
-                if (tsx->status_code == 200 &&
-                        pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) != 0) {
-                    // Peer answered the outgoing call
-                    _debug("UserAgent: Peer answered the outgoing call!\n");
                     call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
                     if (call == NULL)
                         return;
 
-                    //_debug("UserAgent: The call id is %s\n", call->getCallId().data());
-
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link)
-                        link->SIPCallAnswered(call, rdata);
-                } else if (tsx->status_code / 100 == 5) {
-                    _debug("UserAgent: 5xx error message received\n");
-                }
-                break;
-            case PJSIP_TSX_STATE_PROCEEDING:
-                // Peer is ringing for the outgoing call
-                msg = rdata->msg_info.msg;
-
-                call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                if (call == NULL)
-                    return;
-
-                if (msg->line.status.code == 180) {
-                    _debug("UserAgent: Peer is ringing!\n");
+                    if (msg->line.status.code == 180) {
+                        _debug("UserAgent: Peer is ringing!\n");
 
-                    call->setConnectionState(Call::Ringing);
-                    Manager::instance().peerRingingCall(call->getCallId());
-                }
-                break;
-            case PJSIP_TSX_STATE_COMPLETED:
-                if (tsx->status_code == 407 || tsx->status_code == 401) //FIXME
-                    break;
-                if (tsx->status_code / 100 == 6 || tsx->status_code / 100 == 4) {
-                    // We get error message of outgoing call from server
-                    _debug("UserAgent: Server error message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
+                        call->setConnectionState(Call::Ringing);
+                        Manager::instance().peerRingingCall(call->getCallId());
                     }
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallServerFailure(call);
+                    break;
+                case PJSIP_TSX_STATE_COMPLETED:
+                    if (tsx->status_code == 407 || tsx->status_code == 401) //FIXME
+                        break;
+                    if (tsx->status_code / 100 == 6 || tsx->status_code / 100 == 4) {
+                        // We get error message of outgoing call from server
+                        _debug("UserAgent: Server error message is received!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL) {
+                            _debug("UserAgent: Call has been removed!\n");
+                            return;
+                        }
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link) {
+                            link->SIPCallServerFailure(call);
+                        }
                     }
-                }
-                break;
-            default:
-                break;
-        } // end of switch
+                    break;
+                default:
+                    break;
+            } // end of switch
 
-    } else {
-        switch (tsx->state) {
-            case PJSIP_TSX_STATE_TRYING:
-                if (pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) == 0) {
-                    // Peer ask me to transfer call to another number.
-                    _debug("UserAgent: Incoming REFER request!\n");
-                    //onCallTransfered(inv, e->body.tsx_state.src.rdata);
-                }
-                break;
-            case PJSIP_TSX_STATE_COMPLETED:
-                if (tsx->status_code == 200 && tsx->method.id == PJSIP_BYE_METHOD) {
-                    // Peer hangup the call
-                    _debug("UserAgent: Peer hangup(bye) message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
-                    }
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallClosed(call);
-                    }
-                } else if (tsx->status_code == 200 && tsx->method.id == PJSIP_CANCEL_METHOD) {
-                    // Peer refuse the call
-                    _debug("UserAgent: Cancel message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
+        } else {
+            switch (tsx->state) {
+                case PJSIP_TSX_STATE_TRYING:
+                    if (pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) == 0) {
+                        // Peer ask me to transfer call to another number.
+                        _debug("UserAgent: Incoming REFER request!\n");
+                        //onCallTransfered(inv, e->body.tsx_state.src.rdata);
                     }
-
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallClosed(call);
+                    break;
+                case PJSIP_TSX_STATE_COMPLETED:
+                    if (tsx->status_code == 200 && tsx->method.id == PJSIP_BYE_METHOD) {
+                        // Peer hangup the call
+                        _debug("UserAgent: Peer hangup(bye) message is received!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL) {
+                            _debug("UserAgent: Call has been removed!\n");
+                            return;
+                        }
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link) {
+                            link->SIPCallClosed(call);
+                        }
+                    } else if (tsx->status_code == 200 && tsx->method.id == PJSIP_CANCEL_METHOD) {
+                        // Peer refuse the call
+                        _debug("UserAgent: Cancel message is received!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL) {
+                            _debug("UserAgent: Call has been removed!\n");
+                            return;
+                        }
+
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link) {
+                            link->SIPCallClosed(call);
+                        }
                     }
-                }
-                break;
-            default:
-                break;
-        } // end of switch
+                    break;
+                default:
+                    break;
+            } // end of switch
+        }
     }
-}
 
     void regc_cb(struct pjsip_regc_cbparam *param){
 
-        AccountID *id = static_cast<AccountID *> (param->token);
-        SIPVoIPLink *voipLink;
+        //AccountID *id = static_cast<AccountID *> (param->token);
+        SIPAccount *account;
 
         //_debug("UserAgent: Account ID is %s, Register result: %d, Status: %d\n", id->data(), param->status, param->code);
-        voipLink = dynamic_cast<SIPVoIPLink *>(Manager::instance().getAccountLink(*id));
-        if(!voipLink)
+        account = static_cast<SIPAccount *>(param->token);
+        if(!account)
             return;
 
         if (param->status == PJ_SUCCESS) {
@@ -1483,584 +1568,602 @@ void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_e
                 switch(param->code) {
                     case 408:
                     case 606:
-                        voipLink->setRegistrationState(VoIPLink::ErrorConfStun);
+                        account->setRegistrationState(ErrorConfStun);
                         break;
                     case 503:
-                        voipLink->setRegistrationState(VoIPLink::ErrorHost);
+                        account->setRegistrationState(ErrorHost);
                         break;
                     case 401:
                     case 403:
                     case 404:
-                        voipLink->setRegistrationState(VoIPLink::ErrorAuth);
+                        account->setRegistrationState(ErrorAuth);
                         break;
                     default:
-                        voipLink->setRegistrationState(VoIPLink::Error);
+                        account->setRegistrationState(Error);
                         break;
                 }
-                voipLink->setRegister(false);
+                account->setRegister(false);
             } else {
                 // Registration/Unregistration is success
 
-                if(voipLink->isRegister())
-                    voipLink->setRegistrationState(VoIPLink::Registered);
+                if(account->isRegister())
+                    account->setRegistrationState(Registered);
                 else {
-                    voipLink->setRegistrationState(VoIPLink::Unregistered);
-                    voipLink->setRegister(false);
+                    account->setRegistrationState(Unregistered);
+                    account->setRegister(false);
                 }
             }
         } else {
-            voipLink->setRegistrationState(VoIPLink::ErrorAuth);
-            voipLink->setRegister(false);
+            account->setRegistrationState(ErrorAuth);
+            account->setRegister(false);
         }
 
     }
 
-    pj_bool_t mod_on_rx_request(pjsip_rx_data *rdata){
+    pj_bool_t 
+        mod_on_rx_request(pjsip_rx_data *rdata)
+        {
 
-        pj_status_t status;
-        pj_str_t reason;
-        unsigned options = 0;
-        pjsip_dialog* dialog;
-        pjsip_tx_data *tdata;
-        //pjmedia_sdp_session *r_sdp;
-        AccountID account_id;
-        pjsip_uri *uri;
-        pjsip_sip_uri *sip_uri;
-        std::string userName, server, caller, callerServer, peerNumber;
-
-        // voicemail part
-        std::string method_name;
-        std::string request;
-        
-        // Handle the incoming call invite in this function 
-        _debug("UserAgent: Callback on_rx_request is involved!\n");
-
-        /* First, let's got the username and server name from the invite.
-         * We will use them to detect which account is the callee.
-         */ 
-        uri = rdata->msg_info.to->uri;
-        sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
-
-        userName = std::string(sip_uri->user.ptr, sip_uri->user.slen);
-        server = std::string(sip_uri->host.ptr, sip_uri->host.slen) ;
-
-        // Get the account id of callee from username and server
-        account_id = Manager::instance().getAccountIdFromNameAndServer(userName, server);
-        if(account_id == AccountNULL) {
-            _debug("UserAgent: Username %s doesn't match any account!\n",userName.c_str());
-            return false;
-        }
-        
-        _debug("UserAgent: The receiver is : %s@%s\n", userName.data(), server.data());
-        _debug("UserAgent: The callee account id is %s\n", account_id.c_str());
+            pj_status_t status;
+            pj_str_t reason;
+            unsigned options = 0;
+            pjsip_dialog* dialog;
+            pjsip_tx_data *tdata;
+            AccountID account_id;
+            pjsip_uri *uri;
+            pjsip_sip_uri *sip_uri;
+            std::string userName, server, caller, callerServer, peerNumber;
+            SIPVoIPLink *link;
+            CallID id;
+            SIPCall* call;
+
+            // voicemail part
+            std::string method_name;
+            std::string request;
+
+            // Handle the incoming call invite in this function 
+            _debug("UserAgent: Callback on_rx_request is involved!\n");
+
+            /* First, let's got the username and server name from the invite.
+             * We will use them to detect which account is the callee.
+             */ 
+            uri = rdata->msg_info.to->uri;
+            sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
+
+            userName = std::string(sip_uri->user.ptr, sip_uri->user.slen);
+            server = std::string(sip_uri->host.ptr, sip_uri->host.slen) ;
+
+            // Get the account id of callee from username and server
+            account_id = Manager::instance().getAccountIdFromNameAndServer(userName, server);
+
+            /* If we don't find any account to receive the call */
+            if(account_id == AccountNULL) {
+                _debug("UserAgent: Username %s doesn't match any account!\n",userName.c_str());
+                return false;
+            }
+
+            /* Get the voip link associated to the incoming call */
+            /* The account must before have been associated to the call in ManagerImpl */
+            link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(account_id));
+            
+            /* If we can't find any voIP link to handle the incoming call */
+            if( link == 0 )
+            {
+                _debug("ERROR: can not retrieve the voiplink from the account ID...\n");
+                return false;
+            }
 
-        /* Now, it is the time to find the information of the caller */
-        uri = rdata->msg_info.from->uri;
-        sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
+            _debug("UserAgent: The receiver is : %s@%s\n", userName.data(), server.data());
+            _debug("UserAgent: The callee account id is %s\n", account_id.c_str());
 
-        caller = sip_uri->user.ptr;
-        callerServer = sip_uri->host.ptr;
-        peerNumber = caller + "@" + callerServer;
+            /* Now, it is the time to find the information of the caller */
+            uri = rdata->msg_info.from->uri;
+            sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
 
-        // Get the server voicemail notification
-        // Catch the NOTIFY message
-        if( rdata->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD )
-        {
-            method_name = "NOTIFY";
-            // Retrieve all the message. Should contains only the method name but ...
-            request =  rdata->msg_info.msg->line.req.method.name.ptr;
-            // Check if the message is a notification
-            if( request.find( method_name ) != (size_t)-1 ) {
-                set_voicemail_info( account_id, rdata->msg_info.msg->body );
+            /* Retrieve only the fisrt characters */
+            caller = std::string(sip_uri->user.ptr, sip_uri->user.slen);
+            callerServer = std::string(sip_uri->host.ptr, sip_uri->host.slen);
+            peerNumber = caller + "@" + callerServer;
+
+            // Get the server voicemail notification
+            // Catch the NOTIFY message
+            if( rdata->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD )
+            {
+                method_name = "NOTIFY";
+                // Retrieve all the message. Should contains only the method name but ...
+                request =  rdata->msg_info.msg->line.req.method.name.ptr;
+                // Check if the message is a notification
+                if( request.find( method_name ) != (size_t)-1 ) {
+                    /* Notify the right account */
+                    set_voicemail_info( account_id, rdata->msg_info.msg->body );
+                }
+                pjsip_endpt_respond_stateless(_endpt, rdata, PJSIP_SC_OK, NULL, NULL, NULL);
+                return true;
+            }
+
+            // Respond statelessly any non-INVITE requests with 500
+            if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
+                if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
+                    pj_strdup2(_pool, &reason, "user agent unable to handle this request ");
+                    pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
+                            NULL);
+                    return true;
+                }
             }
-            pjsip_endpt_respond_stateless(_endpt, rdata, PJSIP_SC_OK, NULL, NULL, NULL);
-            return true;
-        }
 
-        // Respond statelessly any non-INVITE requests with 500
-        if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
-            if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
-                pj_strdup2(_pool, &reason, "user agent unable to handle this request ");
+            // Verify that we can handle the request
+            status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, _endpt, NULL);
+            if (status != PJ_SUCCESS) {
+                pj_strdup2(_pool, &reason, "user agent unable to handle this INVITE ");
                 pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
                         NULL);
                 return true;
             }
-        }
 
-        // Verify that we can handle the request
-        status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, _endpt, NULL);
-        if (status != PJ_SUCCESS) {
-            pj_strdup2(_pool, &reason, "user agent unable to handle this INVITE ");
-            pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
-                    NULL);
-            return true;
-        }
-
-        // Generate a new call ID for the incoming call!
-        CallID id = Manager::instance().getNewCallID();
-
-        _debug("UserAgent: The call id of the incoming call is %s\n", id.c_str());
-        SIPCall* call = new SIPCall(id, Call::Incoming);
-        if (!call) {
-            _debug("UserAgent: unable to create an incoming call");
-            return false;
-        }
-
-        // Set the codec map, IP, peer number and so on... for the SIPCall object
-        setCallAudioLocal(call);
-        call->setCodecMap(Manager::instance().getCodecDescriptorMap());
-        call->setConnectionState(Call::Progressing);
-        call->setIp("127.0.0.1");
-        call->setPeerNumber(peerNumber);
-
-        /* Call the SIPCallInvite function to generate the local sdp,
-         * remote sdp and negociator.
-         * This function is also used to set the parameters of audio RTP, including:
-         *     local IP and port number 
-         *     remote IP and port number
-         *     possilbe audio codec will be used in this call
-         */
-        if (call->SIPCallInvite(rdata, _pool)) {
+            // Generate a new call ID for the incoming call!
+            id = Manager::instance().getNewCallID();
+            call = new SIPCall(id, Call::Incoming);
+            
+            /* If an error occured at the call creation */
+            if (!call) {
+                _debug("UserAgent: unable to create an incoming call");
+                return false;
+            }
 
-            // Notify UI there is an incoming call
-            if (Manager::instance().incomingCall(call, account_id)) {
-                // Add this call to the callAccountMap in ManagerImpl
-                Manager::instance().getAccountLink(account_id)->addCall(call);
-                _debug("UserAgent: Notify UI success!\n");
+            // Set the codec map, IP, peer number and so on... for the SIPCall object
+            setCallAudioLocal(call, link->getLocalIPAddress(), link->useStun(), link->getStunServer());
+            call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+            call->setConnectionState(Call::Progressing);
+            call->setIp(link->getLocalIPAddress());
+            call->setPeerNumber(peerNumber);
+
+            /* Call the SIPCallInvite function to generate the local sdp,
+             * remote sdp and negociator.
+             * This function is also used to set the parameters of audio RTP, including:
+             *     local IP and port number 
+             *     remote IP and port number
+             *     possilbe audio codec will be used in this call
+             */
+            if (call->SIPCallInvite(rdata, _pool)) {
+
+                // Notify UI there is an incoming call
+                if (Manager::instance().incomingCall(call, account_id)) {
+                    // Add this call to the callAccountMap in ManagerImpl
+                    Manager::instance().getAccountLink(account_id)->addCall(call);
+                } else {
+                    // Fail to notify UI
+                    delete call;
+                    call = NULL;
+                    _debug("UserAgent: Fail to notify UI!\n");
+                    return false;
+                }
             } else {
-                // Fail to notify UI
+                // Fail to collect call information
                 delete call;
                 call = NULL;
-                _debug("UserAgent: Fail to notify UI!\n");
+                _debug("UserAgent: Call SIPCallInvite failed!\n");
                 return false;
             }
-        } else {
-            // Fail to collect call information
-            delete call;
-            call = NULL;
-            _debug("UserAgent: Call SIPCallInvite failed!\n");
-            return false;
-        }
 
-        /* Create the local dialog (UAS) */
-        status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dialog);
-        if (status != PJ_SUCCESS) {
-            pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, &reason, NULL,
-                    NULL);
-            return true;
-        }
+            /* Create the local dialog (UAS) */
+            status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dialog);
+            if (status != PJ_SUCCESS) {
+                pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, &reason, NULL,
+                        NULL);
+                return true;
+            }
 
-        // Specify media capability during invite session creation
-        pjsip_inv_session *inv;
-        status = pjsip_inv_create_uas(dialog, rdata, call->getLocalSDPSession(), 0, &inv);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+            // Specify media capability during invite session creation
+            pjsip_inv_session *inv;
+            status = pjsip_inv_create_uas(dialog, rdata, call->getLocalSDPSession(), 0, &inv);
+            PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
-        // Associate the call in the invite session
-        inv->mod_data[_mod_ua.id] = call;
+            // Associate the call in the invite session
+            inv->mod_data[_mod_ua.id] = call;
 
-        // Send a 180/Ringing response
-        status = pjsip_inv_initial_answer(inv, rdata, PJSIP_SC_RINGING, NULL, NULL, &tdata);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-        status = pjsip_inv_send_msg(inv, tdata);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+            // Send a 180/Ringing response
+            status = pjsip_inv_initial_answer(inv, rdata, PJSIP_SC_RINGING, NULL, NULL, &tdata);
+            PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+            status = pjsip_inv_send_msg(inv, tdata);
+            PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
 
-        // Associate invite session to the current call
-        call->setInvSession(inv);
+            // Associate invite session to the current call
+            call->setInvSession(inv);
 
-        // Update the connection state
-        call->setConnectionState(Call::Ringing);
+            // Update the connection state
+            call->setConnectionState(Call::Ringing);
 
-        /* Done */
-        return true;
+            /* Done */
+            return true;
 
-    }
+        }
 
     pj_bool_t mod_on_rx_response(pjsip_rx_data *rdata UNUSED) {
         _debug("mod_on_rx_response\n");
         return PJ_SUCCESS;
     }
 
-void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
-{
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    SIPCall *existing_call;
-    const pj_str_t str_refer_to = { (char*)"Refer-To", 8};
-    const pj_str_t str_refer_sub = { (char*)"Refer-Sub", 9 };
-    const pj_str_t str_ref_by = { (char*)"Referred-By", 11 };
-    pjsip_generic_string_hdr *refer_to;
-    pjsip_generic_string_hdr *refer_sub;
-    pjsip_hdr *ref_by_hdr;
-    pj_bool_t no_refer_sub = PJ_FALSE;
-    char *uri;
-    std::string tmp;
-    pjsip_status_code code;
-    pjsip_evsub *sub;
-
-    existing_call = (SIPCall *) inv->mod_data[_mod_ua.id];
-
-    /* Find the Refer-To header */
-    refer_to = (pjsip_generic_string_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
-
-    if (refer_to == NULL) {
-        /* Invalid Request.
-         * No Refer-To header!
-         */
-        _debug("UserAgent: Received REFER without Refer-To header!\n");
-        pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
-        return;
-    }
-
-    /* Find optional Refer-Sub header */
-    refer_sub = (pjsip_generic_string_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
-
-    if (refer_sub) {
-        if (!pj_strnicmp2(&refer_sub->hvalue, "true", 4)==0)
-            no_refer_sub = PJ_TRUE;
-    }
-
-    /* Find optional Referred-By header (to be copied onto outgoing INVITE
-     * request.
-     */
-    ref_by_hdr = (pjsip_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_ref_by,
-                NULL);
-
-    /* Notify callback */
-    code = PJSIP_SC_ACCEPTED;
-
-    _debug("UserAgent: Call to %.*s is being transfered to %.*s\n",
-            (int)inv->dlg->remote.info_str.slen,
-            inv->dlg->remote.info_str.ptr,
-            (int)refer_to->hvalue.slen,
-            refer_to->hvalue.ptr);
-
-    if (no_refer_sub) {
-        /*
-         * Always answer with 2xx.
-         */
+    void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
+    {
+        pj_status_t status;
         pjsip_tx_data *tdata;
-        const pj_str_t str_false = { (char*)"false", 5};
-        pjsip_hdr *hdr;
-
-        status = pjsip_dlg_create_response(inv->dlg, rdata, code, NULL,
-                &tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
+        SIPCall *existing_call;
+        const pj_str_t str_refer_to = { (char*)"Refer-To", 8};
+        const pj_str_t str_refer_sub = { (char*)"Refer-Sub", 9 };
+        const pj_str_t str_ref_by = { (char*)"Referred-By", 11 };
+        pjsip_generic_string_hdr *refer_to;
+        pjsip_generic_string_hdr *refer_sub;
+        pjsip_hdr *ref_by_hdr;
+        pj_bool_t no_refer_sub = PJ_FALSE;
+        char *uri;
+        std::string tmp;
+        pjsip_status_code code;
+        pjsip_evsub *sub;
+
+        existing_call = (SIPCall *) inv->mod_data[_mod_ua.id];
+
+        /* Find the Refer-To header */
+        refer_to = (pjsip_generic_string_hdr*)
+            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
+
+        if (refer_to == NULL) {
+            /* Invalid Request.
+             * No Refer-To header!
+             */
+            _debug("UserAgent: Received REFER without Refer-To header!\n");
+            pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
             return;
         }
 
-        /* Add Refer-Sub header */
-        hdr = (pjsip_hdr*)
-            pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub,
-                    &str_false);
-        pjsip_msg_add_hdr(tdata->msg, hdr);
-
+        /* Find optional Refer-Sub header */
+        refer_sub = (pjsip_generic_string_hdr*)
+            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
 
-        /* Send answer */
-        status = pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata),
-                tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
-            return;
+        if (refer_sub) {
+            if (!pj_strnicmp2(&refer_sub->hvalue, "true", 4)==0)
+                no_refer_sub = PJ_TRUE;
         }
 
-        /* Don't have subscription */
-        sub = NULL;
-
-    } else {
-        struct pjsip_evsub_user xfer_cb;
-        pjsip_hdr hdr_list;
+        /* Find optional Referred-By header (to be copied onto outgoing INVITE
+         * request.
+         */
+        ref_by_hdr = (pjsip_hdr*)
+            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_ref_by,
+                    NULL);
 
-        /* Init callback */
-        pj_bzero(&xfer_cb, sizeof(xfer_cb));
-        xfer_cb.on_evsub_state = &xfer_svr_cb;
+        /* Notify callback */
+        code = PJSIP_SC_ACCEPTED;
 
-        /* Init addiTHIS_FILE, THIS_FILE, tional header list to be sent with REFER response */
-        pj_list_init(&hdr_list);
+        _debug("UserAgent: Call to %.*s is being transfered to %.*s\n",
+                (int)inv->dlg->remote.info_str.slen,
+                inv->dlg->remote.info_str.ptr,
+                (int)refer_to->hvalue.slen,
+                refer_to->hvalue.ptr);
 
-        /* Create transferee event subscription */
-        status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create xfer uas -- %d\n", status);
-            pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
-            return;
-        }
-
-        /* If there's Refer-Sub header and the value is "true", send back
-         * Refer-Sub in the response with value "true" too.
-         */
-        if (refer_sub) {
-            const pj_str_t str_true = { (char*)"true", 4 };
+        if (no_refer_sub) {
+            /*
+             * Always answer with 2xx.
+             */
+            pjsip_tx_data *tdata;
+            const pj_str_t str_false = { (char*)"false", 5};
             pjsip_hdr *hdr;
 
+            status = pjsip_dlg_create_response(inv->dlg, rdata, code, NULL,
+                    &tdata);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
+                return;
+            }
+
+            /* Add Refer-Sub header */
             hdr = (pjsip_hdr*)
-                pjsip_generic_string_hdr_create(inv->dlg->pool,
-                        &str_refer_sub,
-                        &str_true);
-            pj_list_push_back(&hdr_list, hdr);
+                pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub,
+                        &str_false);
+            pjsip_msg_add_hdr(tdata->msg, hdr);
 
-        }
 
-        /* Accept the REFER request, send 2xx. */
-        pjsip_xfer_accept(sub, rdata, code, &hdr_list);
+            /* Send answer */
+            status = pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata),
+                    tdata);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
+                return;
+            }
 
-        /* Create initial NOTIFY request */
-        status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
-                100, NULL, &tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create NOTIFY to REFER -- %d", status);
-            return;
-        }
+            /* Don't have subscription */
+            sub = NULL;
 
-        /* Send initial NOTIFY request */
-        status = pjsip_xfer_send_request( sub, tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
-            return;
-        }
-    }
+        } else {
+            struct pjsip_evsub_user xfer_cb;
+            pjsip_hdr hdr_list;
 
-    /* We're cheating here.
-     * We need to get a null terminated string from a pj_str_t.
-     * So grab the pointer from the hvalue and NULL terminate it, knowing
-     * that the NULL position will be occupied by a newline. 
-     */
-    uri = refer_to->hvalue.ptr;
-    uri[refer_to->hvalue.slen] = '\0';
+            /* Init callback */
+            pj_bzero(&xfer_cb, sizeof(xfer_cb));
+            xfer_cb.on_evsub_state = &xfer_svr_cb;
 
-    /* Now make the outgoing call. */
-    tmp = std::string(uri);
+            /* Init addiTHIS_FILE, THIS_FILE, tional header list to be sent with REFER response */
+            pj_list_init(&hdr_list);
 
-    if(existing_call == NULL) {
-        _debug("UserAgent: Call doesn't exist!\n");
-        return;
-    }
+            /* Create transferee event subscription */
+            status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to create xfer uas -- %d\n", status);
+                pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
+                return;
+            }
 
-    AccountID accId = Manager::instance().getAccountFromCall(existing_call->getCallId());
-    CallID newCallId = Manager::instance().getNewCallID();
+            /* If there's Refer-Sub header and the value is "true", send back
+             * Refer-Sub in the response with value "true" too.
+             */
+            if (refer_sub) {
+                const pj_str_t str_true = { (char*)"true", 4 };
+                pjsip_hdr *hdr;
 
-    if(!Manager::instance().outgoingCall(accId, newCallId, tmp)) {
+                hdr = (pjsip_hdr*)
+                    pjsip_generic_string_hdr_create(inv->dlg->pool,
+                            &str_refer_sub,
+                            &str_true);
+                pj_list_push_back(&hdr_list, hdr);
 
-        /* Notify xferer about the error (if we have subscription) */
-        if (sub) {
-            status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
-                    500, NULL, &tdata);
+            }
+
+            /* Accept the REFER request, send 2xx. */
+            pjsip_xfer_accept(sub, rdata, code, &hdr_list);
+
+            /* Create initial NOTIFY request */
+            status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
+                    100, NULL, &tdata);
             if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to create NOTIFY to REFER -- %d\n", status);
+                _debug("UserAgent: Unable to create NOTIFY to REFER -- %d", status);
                 return;
             }
-            status = pjsip_xfer_send_request(sub, tdata);
+
+            /* Send initial NOTIFY request */
+            status = pjsip_xfer_send_request( sub, tdata);
             if (status != PJ_SUCCESS) {
                 _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
                 return;
             }
         }
-        return;
-    }
 
-    SIPCall* newCall;
-    SIPVoIPLink *link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-    if(link) {
-        newCall = dynamic_cast<SIPCall *>(link->getCall(newCallId));
-        if(!newCall) {
-            _debug("UserAgent: can not find the call from sipvoiplink!\n");
+        /* We're cheating here.
+         * We need to get a null terminated string from a pj_str_t.
+         * So grab the pointer from the hvalue and NULL terminate it, knowing
+         * that the NULL position will be occupied by a newline. 
+         */
+        uri = refer_to->hvalue.ptr;
+        uri[refer_to->hvalue.slen] = '\0';
+
+        /* Now make the outgoing call. */
+        tmp = std::string(uri);
+
+        if(existing_call == NULL) {
+            _debug("UserAgent: Call doesn't exist!\n");
             return;
         }
-    }
 
-    if (sub) {
-        /* Put the server subscription in inv_data.
-         * Subsequent state changed in pjsua_inv_on_state_changed() will be
-         * reported back to the server subscription.
-         */
-        newCall->setXferSub(sub);
-
-        /* Put the invite_data in the subscription. */
-        pjsip_evsub_set_mod_data(sub, _mod_ua.id,
-                newCall);
-    }    
-}
+        AccountID accId = Manager::instance().getAccountFromCall(existing_call->getCallId());
+        CallID newCallId = Manager::instance().getNewCallID();
 
+        if(!Manager::instance().outgoingCall(accId, newCallId, tmp)) {
 
+            /* Notify xferer about the error (if we have subscription) */
+            if (sub) {
+                status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
+                        500, NULL, &tdata);
+                if (status != PJ_SUCCESS) {
+                    _debug("UserAgent: Unable to create NOTIFY to REFER -- %d\n", status);
+                    return;
+                }
+                status = pjsip_xfer_send_request(sub, tdata);
+                if (status != PJ_SUCCESS) {
+                    _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
+                    return;
+                }
+            }
+            return;
+        }
 
+        SIPCall* newCall;
+        SIPVoIPLink *link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+        if(link) {
+            newCall = dynamic_cast<SIPCall *>(link->getCall(newCallId));
+            if(!newCall) {
+                _debug("UserAgent: can not find the call from sipvoiplink!\n");
+                return;
+            }
+        }
 
-void xfer_func_cb( pjsip_evsub *sub, pjsip_event *event){
+        if (sub) {
+            /* Put the server subscription in inv_data.
+             * Subsequent state changed in pjsua_inv_on_state_changed() will be
+             * reported back to the server subscription.
+             */
+            newCall->setXferSub(sub);
 
-     PJ_UNUSED_ARG(event);
+            /* Put the invite_data in the subscription. */
+            pjsip_evsub_set_mod_data(sub, _mod_ua.id,
+                    newCall);
+        }    
+    }
 
-    _debug("UserAgent: Transfer callback is involved!\n");
-    /*
-     * When subscription is accepted (got 200/OK to REFER), check if 
-     * subscription suppressed.
-     */
-    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
 
-        pjsip_rx_data *rdata;
-        pjsip_generic_string_hdr *refer_sub;
-        const pj_str_t REFER_SUB = {(char*)"Refer-Sub", 9 };
 
-        SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub,
-                    _mod_ua.id));
 
-        /* Must be receipt of response message */
-        pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&
-                event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
-        rdata = event->body.tsx_state.src.rdata;
+    void xfer_func_cb( pjsip_evsub *sub, pjsip_event *event){
 
-        /* Find Refer-Sub header */
-        refer_sub = (pjsip_generic_string_hdr*)
-            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
-                    &REFER_SUB, NULL);
+        PJ_UNUSED_ARG(event);
 
-        /* Check if subscription is suppressed */
-        if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) {
-            /* Since no subscription is desired, assume that call has been
-             * transfered successfully.
-             */
-            if (link) {
-                // It's the time to stop the RTP
-                link->transferStep2();
-            }
+        _debug("UserAgent: Transfer callback is involved!\n");
+        /*
+         * When subscription is accepted (got 200/OK to REFER), check if 
+         * subscription suppressed.
+         */
+        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
 
-            /* Yes, subscription is suppressed.
-             * Terminate our subscription now.
-             */
-            _debug("UserAgent: Xfer subscription suppressed, terminating event subcription...\n");
-            pjsip_evsub_terminate(sub, PJ_TRUE);
+            pjsip_rx_data *rdata;
+            pjsip_generic_string_hdr *refer_sub;
+            const pj_str_t REFER_SUB = {(char*)"Refer-Sub", 9 };
 
-        } else {
-            /* Notify application about call transfer progress. 
-             * Initially notify with 100/Accepted status.
-             */
-            _debug("UserAgent: Xfer subscription 100/Accepted received...\n");
-        }
-    }
-    /*
-     * On incoming NOTIFY, notify application about call transfer progress.
-     */
-    else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
-            pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)
-    {
-        pjsip_msg *msg;
-        pjsip_msg_body *body;
-        pjsip_status_line status_line;
-        pj_bool_t is_last;
-        pj_bool_t cont;
-        pj_status_t status;
+            SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub,
+                        _mod_ua.id));
 
-        SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub, 
-                    _mod_ua.id));
+            /* Must be receipt of response message */
+            pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&
+                    event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
+            rdata = event->body.tsx_state.src.rdata;
 
-        /* When subscription is terminated, clear the xfer_sub member of 
-         * the inv_data.
-         */
-        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
-            pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
-            _debug("UserAgent: Xfer client subscription terminated\n");
+            /* Find Refer-Sub header */
+            refer_sub = (pjsip_generic_string_hdr*)
+                pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
+                        &REFER_SUB, NULL);
 
-        }
+            /* Check if subscription is suppressed */
+            if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) {
+                /* Since no subscription is desired, assume that call has been
+                 * transfered successfully.
+                 */
+                if (link) {
+                    // It's the time to stop the RTP
+                    link->transferStep2();
+                }
 
-        if (!link || !event) {
-            /* Application is not interested with call progress status */
-            _debug("UserAgent: Either link or event is empty!\n");
-            return;
-        }
+                /* Yes, subscription is suppressed.
+                 * Terminate our subscription now.
+                 */
+                _debug("UserAgent: Xfer subscription suppressed, terminating event subcription...\n");
+                pjsip_evsub_terminate(sub, PJ_TRUE);
 
-        // Get current call
-        SIPCall *call = dynamic_cast<SIPCall *>(link->getCall(Manager::instance().getCurrentCallId()));
-        if(!call) {
-            _debug("UserAgent: Call doesn't exit!\n");
-            return;
+            } else {
+                /* Notify application about call transfer progress. 
+                 * Initially notify with 100/Accepted status.
+                 */
+                _debug("UserAgent: Xfer subscription 100/Accepted received...\n");
+            }
         }
-
-        /* This better be a NOTIFY request */
-        if (event->type == PJSIP_EVENT_TSX_STATE &&
-                event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+        /*
+         * On incoming NOTIFY, notify application about call transfer progress.
+         */
+        else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
+                pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)
         {
-            pjsip_rx_data *rdata;
+            pjsip_msg *msg;
+            pjsip_msg_body *body;
+            pjsip_status_line status_line;
+            pj_bool_t is_last;
+            pj_bool_t cont;
+            pj_status_t status;
 
-            rdata = event->body.tsx_state.src.rdata;
+            SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub, 
+                        _mod_ua.id));
+
+            /* When subscription is terminated, clear the xfer_sub member of 
+             * the inv_data.
+             */
+            if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
+                pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
+                _debug("UserAgent: Xfer client subscription terminated\n");
 
-            /* Check if there's body */
-            msg = rdata->msg_info.msg;
-            body = msg->body;
-            if (!body) {
-                _debug("UserAgent: Warning! Received NOTIFY without message body\n");
-                return;
             }
 
-            /* Check for appropriate content */
-            if (pj_stricmp2(&body->content_type.type, "message") != 0 ||
-                    pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0)
-            {
-                _debug("UserAgent: Warning! Received NOTIFY with non message/sipfrag content\n");
+            if (!link || !event) {
+                /* Application is not interested with call progress status */
+                _debug("UserAgent: Either link or event is empty!\n");
                 return;
             }
 
-            /* Try to parse the content */
-            status = pjsip_parse_status_line((char*)body->data, body->len,
-                    &status_line);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Warning! Received NOTIFY with invalid message/sipfrag content\n");
+            // Get current call
+            SIPCall *call = dynamic_cast<SIPCall *>(link->getCall(Manager::instance().getCurrentCallId()));
+            if(!call) {
+                _debug("UserAgent: Call doesn't exit!\n");
                 return;
             }
 
-        } else {
-            _debug("UserAgent: Set code to 500!\n");
-            status_line.code = 500;
-            status_line.reason = *pjsip_get_status_text(500);
-        }
+            /* This better be a NOTIFY request */
+            if (event->type == PJSIP_EVENT_TSX_STATE &&
+                    event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+            {
+                pjsip_rx_data *rdata;
 
-        /* Notify application */
-        is_last = (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED);
-        cont = !is_last;
+                rdata = event->body.tsx_state.src.rdata;
 
-        if(status_line.code/100 == 2) {
-            _debug("UserAgent: Try to stop rtp!\n");
-            pjsip_tx_data *tdata;
+                /* Check if there's body */
+                msg = rdata->msg_info.msg;
+                body = msg->body;
+                if (!body) {
+                    _debug("UserAgent: Warning! Received NOTIFY without message body\n");
+                    return;
+                }
+
+                /* Check for appropriate content */
+                if (pj_stricmp2(&body->content_type.type, "message") != 0 ||
+                        pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0)
+                {
+                    _debug("UserAgent: Warning! Received NOTIFY with non message/sipfrag content\n");
+                    return;
+                }
+
+                /* Try to parse the content */
+                status = pjsip_parse_status_line((char*)body->data, body->len,
+                        &status_line);
+                if (status != PJ_SUCCESS) {
+                    _debug("UserAgent: Warning! Received NOTIFY with invalid message/sipfrag content\n");
+                    return;
+                }
 
-            status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_GONE, NULL, &tdata);
-            if(status != PJ_SUCCESS) {
-                _debug("UserAgent: Fail to create end session msg!\n");
             } else {
-                status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-                if(status != PJ_SUCCESS) 
-                    _debug("UserAgent: Fail to send end session msg!\n");
+                _debug("UserAgent: Set code to 500!\n");
+                status_line.code = 500;
+                status_line.reason = *pjsip_get_status_text(500);
             }
 
-            link->transferStep2();
-            cont = PJ_FALSE;
-        }
+            /* Notify application */
+            is_last = (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED);
+            cont = !is_last;
+
+            if(status_line.code/100 == 2) {
+                _debug("UserAgent: Try to stop rtp!\n");
+                pjsip_tx_data *tdata;
+
+                status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_GONE, NULL, &tdata);
+                if(status != PJ_SUCCESS) {
+                    _debug("UserAgent: Fail to create end session msg!\n");
+                } else {
+                    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+                    if(status != PJ_SUCCESS) 
+                        _debug("UserAgent: Fail to send end session msg!\n");
+                }
 
-        if (!cont) {
-            pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
+                link->transferStep2();
+                cont = PJ_FALSE;
+            }
+
+            if (!cont) {
+                pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
+            }
         }
-    }
 
-}
+    }
 
 
-void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event);
+    void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event)
+    {
+        PJ_UNUSED_ARG(event);
 
-    /*
-     * When subscription is terminated, clear the xfer_sub member of 
-     * the inv_data.
-     */
-    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
-        SIPCall *call;
+        /*
+         * When subscription is terminated, clear the xfer_sub member of 
+         * the inv_data.
+         */
+        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
+            SIPCall *call;
 
-        call = (SIPCall*) pjsip_evsub_get_mod_data(sub, _mod_ua.id);
-        if (!call)
-            return;
+            call = (SIPCall*) pjsip_evsub_get_mod_data(sub, _mod_ua.id);
+            if (!call)
+                return;
 
-        pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
-        call->setXferSub(NULL);
+            pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
+            call->setXferSub(NULL);
 
-        _debug("UserAgent: Xfer server subscription terminated\n");
-    }    
-}
+            _debug("UserAgent: Xfer server subscription terminated\n");
+        }    
+    }
diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h
index cf67cd7ca47c3692bf3f557646a9ea5e3efd3e8d..0aca792fc392fd6ab2a84bea7760c5d6a7870d01 100644
--- a/src/sipvoiplink.h
+++ b/src/sipvoiplink.h
@@ -2,7 +2,7 @@
  *  Copyright (C) 2004-2009 Savoir-Faire Linux inc.
  *
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author: Yun Liu <yun.liu@savoirfairelinux.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -24,14 +24,15 @@
 
 #include "voiplink.h"
 
+//////////////////////////////
+/* PJSIP imports */
 #include <pjsip.h>
-#include <pjlib-util.h>
 #include <pjlib.h>
-#include <pjnath/stun_config.h>
-#include <pjsip_simple.h>
 #include <pjsip_ua.h>
-#include <pjmedia/sdp.h>
-#include <pjmedia/sdp_neg.h>
+#include <pjlib-util.h>
+#include <pjnath/stun_config.h>
+///////////////////////////////
+
 
 class EventThread;
 class SIPCall;
@@ -39,11 +40,15 @@ class AudioRtp;
 
 #define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
 #define RANDOM_SIP_PORT   rand() % 64000 + 1024
+
+// To set the verbosity. From 0 (min) to 6 (max)
 #define PJ_LOG_LEVEL 5
 
 /**
  * @file sipvoiplink.h
- * @brief Specific VoIPLink for SIP (SIP core for incoming and outgoing events)
+ * @brief Specific VoIPLink for SIP (SIP core for incoming and outgoing events).
+ *          This class is based on the singleton design pattern.
+ *          One SIPVoIPLink can handle multiple SIP accounts, but all the SIP accounts have all the same SIPVoIPLink
  */
 
 class SIPVoIPLink : public VoIPLink
@@ -51,11 +56,9 @@ class SIPVoIPLink : public VoIPLink
     public:
 
         /**
-         * Constructor
-         * @param accountID The account identifier
+         * Singleton method. Enable to retrieve the unique static instance
+         * @return SIPVoIPLink* A pointer on the object
          */
-        SIPVoIPLink(const AccountID& accountID);
-
         static SIPVoIPLink* instance( const AccountID& id );
 
         /**
@@ -75,6 +78,9 @@ class SIPVoIPLink : public VoIPLink
          */
         bool init(void);
 
+        /**
+         * Shut the library and clean up
+         */
         void terminate( void );
 
         /**
@@ -94,7 +100,7 @@ class SIPVoIPLink : public VoIPLink
          * @return bool True on success
          *		  false otherwise
          */
-        int sendUnregister(void);
+        int sendUnregister(AccountID id);
 
         /**
          * Place a new call
@@ -169,19 +175,17 @@ class SIPVoIPLink : public VoIPLink
          * If set to true, we check for a firewall
          * @param use true if we use STUN
          */
-        void setUseStun(bool use);
+        inline void useStun(bool use) { _useStun=use; }
 
-        bool useStun( void );
+        inline bool useStun( void ) { return _useStun; }
 
         /** 
          * The name of the STUN server
          * @param server Server FQDN/IP
          */
-        void setStunServer(const std::string& server) { _stunServer = server; }
+        void setStunServer(const std::string& server);
 
-        bool isRegister() {return _bRegister;}
-
-        void setRegister(bool result) {_bRegister = result;}
+        std::string getStunServer (void) { return _stunServer; }
 
         /** 
          * Terminate every call not hangup | brutal | Protected by mutex 
@@ -264,12 +268,24 @@ class SIPVoIPLink : public VoIPLink
         /** Starting sound */
         AudioRtp* _audiortp;
 
-        pj_str_t string2PJStr(const std::string &value);
+        /** Increment the number of SIP account connected to this link */
+        void incrementClients (void) { _clients++; }
+
+        /** Decrement the number of SIP account connected to this link */
+        void decrementClients (void);
 
     private:
+        /**
+         * Constructor
+         * @param accountID The account identifier
+         */
+        SIPVoIPLink(const AccountID& accountID);
+
+        /* The singleton instance */
         static SIPVoIPLink* _instance;
 
         int getModId();
+
         /** 
          * Initialize the PJSIP library
          * Must be called before any other calls to the SIP layer
@@ -283,6 +299,9 @@ class SIPVoIPLink : public VoIPLink
          */
         bool pjsip_shutdown(void);
 
+        /** Do we use stun? */
+        bool _useStun;
+
         pj_status_t stunServerResolve();
 
         /** Create SIP UDP Listener */
@@ -292,8 +311,6 @@ class SIPVoIPLink : public VoIPLink
 
         std::string getLocalIP() {return _localExternAddress;}
 
-        pjsip_regc *_regc;
-
         /** For registration use only */
         int _regPort;
 
@@ -313,7 +330,9 @@ class SIPVoIPLink : public VoIPLink
         EventThread* _evThread;
         ost::Mutex _mutexSIP;
 
-        bool _bRegister;
+        /* Number of SIP accounts connected to the link */
+        int _clients;
+
 };
 
 #endif
diff --git a/src/user_cfg.h b/src/user_cfg.h
index 57201f084be7353e84750920d6b4aa74909b64f6..438911822771e894d8c42decabc4a88c8c46be28 100644
--- a/src/user_cfg.h
+++ b/src/user_cfg.h
@@ -69,6 +69,8 @@
 #define PULSE_LENGTH		"DTMF.pulseLength"    /** Length of the DTMF in millisecond */
 #define SEND_DTMF_AS		"DTMF.sendDTMFas"     /** DTMF send mode */
 #define SYMMETRIC		"VoIPLink.symmetric"  /** VoIP link type */
+#define STUN_ENABLE     "STUN.enable"
+#define STUN_SERVER     "STUN.server"
 
 #define EMPTY_FIELD		""			/** Default value for empty field */
 #define DFT_STUN_SERVER 	"stun.fwdnet.net:3478"	/** Default STUN server address */
@@ -89,6 +91,7 @@
 #define DFT_EXPIRE_VALUE	"180"			/** Default expire value for registration */
 #define DFT_AUDIO_MANAGER	"1"			/** Default audio manager */
 #define DFT_SIP_PORT            "5060"
+#define DFT_STUN_ENABLE     "0"
 
 #ifdef USE_ZEROCONF
 #define CONFIG_ZEROCONF_DEFAULT_STR "1"			/** Default Zero configuration networking module value */
diff --git a/src/useragent.cpp b/src/useragent.cpp
deleted file mode 100644
index 59a370dfab70abe8b6f6f911cdbad76fd6da3948..0000000000000000000000000000000000000000
--- a/src/useragent.cpp
+++ /dev/null
@@ -1,906 +0,0 @@
-/*
- *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
- *  Author: Yun Liu <yun.liu@savoirfairelinux.com>
- *                                                                              
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *                                                                              
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *                                                                              
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <string>
-#include <iostream>
-
-#include "manager.h"
-#include "sipcall.h"
-#include "useragent.h"
-#include "sipvoiplink.h"
-#include "sipaccount.h"
-
-#define RANDOM_SIP_PORT   rand() % 64000 + 1024
-#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
-
-UserAgent *UserAgent::_current;
-
-UserAgent::UserAgent():_endpt(NULL) ,_sock(NULL), _cp(), _pool(NULL), _mutex(NULL), _mod(), _useStun(false), _stunHost(),
-    _stunServer(""), _localExternAddress(""), _localIPAddress("127.0.0.1"), _localExternPort(0), _localPort(0), _regPort(DEFAULT_SIP_PORT), _thread(NULL) {
-        //_useStun = false;
-        //_localIPAddress = "127.0.0.1";
-        UserAgent::_current = this;
-    }
-
-
-void UserAgent::sipDestory() {
-    /* Signal threads to quit: */
-    Manager::instance().setSipThreadStatus(true);
-
-    /* Wait worker thread to quit: */
-    if (_thread) {
-        pj_thread_join(_thread);
-        pj_thread_destroy(_thread);
-        _thread = NULL;
-    }
-
-    if (_endpt) {
-        /* Terminate all presence subscriptions. */
-        //pjsua_pres_shutdown();
-
-        /* Wait for some time to allow unregistration to complete: */
-        _debug("UserAgent: Shutting down...\n");
-        busy_sleep(1000);
-    }
-
-    /* Destroy endpoint. */
-    if (_endpt) {
-        pjsip_endpt_destroy(_endpt);
-        _endpt = NULL;
-    }
-
-    /* Destroy mutex */
-    if (_mutex) {
-        pj_mutex_destroy(_mutex);
-        _mutex = NULL;
-    }
-
-    /* Destroy pool and pool factory. */
-    if (_pool) {
-        pj_pool_release(_pool);
-        _pool = NULL;
-        pj_caching_pool_destroy(&_cp);
-
-        /* Shutdown PJLIB */
-        pj_shutdown();
-    }
-
-    /* Done. */    
-}
-
-void UserAgent::busy_sleep(unsigned msec)
-{
-#if defined(PJ_SYMBIAN) && PJ_SYMBIAN != 0
-    /* Ideally we shouldn't call pj_thread_sleep() and rather
-     * CActiveScheduler::WaitForAnyRequest() here, but that will
-     * drag in Symbian header and it doesn't look pretty.
-     */
-    pj_thread_sleep(msec);
-#else
-    pj_time_val timeout, now, tv;
-
-    pj_gettimeofday(&timeout);
-    timeout.msec += msec;
-    pj_time_val_normalize(&timeout);
-
-    tv.sec = 0;
-    tv.msec = 10;
-    pj_time_val_normalize(&tv);
-
-    do {
-        pjsip_endpt_handle_events(_endpt, &tv);
-        pj_gettimeofday(&now);
-    } while (PJ_TIME_VAL_LT(now, timeout));
-#endif
-}
-
-
-
-pj_str_t UserAgent::buildContact(char *userName) {
-    //pj_str_t contact;
-    char tmp[256];
-
-    //FIXME: IPV6 issue!!
-    _debug("In build Contact %s %s %d\n", userName, _localExternAddress.data(), _localExternPort);
-    sprintf(tmp, "<sip:%s@%s:%d>", userName, _localExternAddress.data(), _localExternPort);
-    //_debug("get tmp\n");
-    return pj_str(tmp);
-}
-
-void UserAgent::setStunServer(const char *server) {
-    if(server != NULL) {
-        _useStun = true;
-        _stunServer = std::string(server);
-    } else {
-        _useStun = false;
-        _stunServer = std::string("");
-    }
-}
-
-void UserAgent::set_voicemail_info( AccountID account, pjsip_msg_body *body ){
-
-    int voicemail, pos_begin, pos_end;
-    std::string voice_str = "Voice-Message: ";
-    std::string delimiter = "/";
-    std::string msg_body, voicemail_str;
-
-    _debug("UserAgent: checking the voice message!\n");
-    // The voicemail message is formated like that:
-    // Voice-Message: 1/0  . 1 is the number we want to retrieve in this case
-
-    // We get the notification body
-    msg_body = (char*)body->data;
-
-    // We need the position of the first character of the string voice_str
-    pos_begin = msg_body.find(voice_str); 
-    // We need the position of the delimiter
-    pos_end = msg_body.find(delimiter); 
-
-    // So our voicemail number between the both index
-    try {
-
-        voicemail_str = msg_body.substr(pos_begin + voice_str.length(), pos_end - ( pos_begin + voice_str.length()));
-        std::cout << "voicemail number : " << voicemail_str << std::endl;
-        voicemail = atoi( voicemail_str.c_str() );
-    }
-    catch( std::out_of_range& e ){
-        std::cerr << e.what() << std::endl;
-    }
-
-    // We need now to notify the manager 
-    if( voicemail != 0 )
-        Manager::instance().startVoiceMessageNotification(account, voicemail);
-}
-
-
-pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
-
-    pj_status_t status;
-    pj_str_t reason;
-    unsigned options = 0;
-    pjsip_dialog* dialog;
-    pjsip_tx_data *tdata;
-    //pjmedia_sdp_session *r_sdp;
-    AccountID account_id;
-
-    // voicemail part
-    std::string method_name;
-    std::string request;
-
-    // Handle the incoming call invite in this function 
-    _debug("UserAgent: Callback on_rx_request is involved!\n");
-
-    /* First, let's got the username and server name from the invite.
-     * We will use them to detect which account is the callee.
-     */ 
-    pjsip_uri *uri = rdata->msg_info.to->uri;
-    pjsip_sip_uri *sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
-
-    std::string userName = std::string(sip_uri->user.ptr, sip_uri->user.slen);
-    std::string server = std::string(sip_uri->host.ptr, sip_uri->host.slen);
-
-    // Get the account id of callee from username and server
-    account_id = Manager::instance().getAccountIdFromNameAndServer(userName, server);
-    if(account_id == AccountNULL) {
-        _debug("UserAgent: Username %s doesn't match any account!\n",userName.c_str());
-        return PJ_FALSE;
-    }
-    _debug("UserAgent: The receiver is : %s@%s\n", userName.data(), server.data());
-    _debug("UserAgent: The callee account id is %s\n", account_id.c_str());
-
-    /* Now, it is the time to find the information of the caller */
-    uri = rdata->msg_info.from->uri;
-    sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
-
-    std::string caller = std::string(sip_uri->user.ptr, sip_uri->user.slen);
-    std::string callerServer = std::string(sip_uri->host.ptr, sip_uri->host.slen);
-    std::string peerNumber = caller + "@" + callerServer;
-
-
-    // Get the server voicemail notification
-    // Catch the NOTIFY message
-    if( rdata->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD )
-    {
-        method_name = "NOTIFY";
-        // Retrieve all the message. Should contains only the method name but ...
-        request =  rdata->msg_info.msg->line.req.method.name.ptr;
-        // Check if the message is a notification
-        if( request.find( method_name ) != (size_t)-1 ) {
-            set_voicemail_info( account_id, rdata->msg_info.msg->body );
-        }
-        pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_OK, NULL, NULL, NULL);
-        return PJ_SUCCESS;
-    }
-
-    // Respond statelessly any non-INVITE requests with 500
-    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
-        if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
-            pj_strdup2(getInstance()->getAppPool(), &reason, "user agent unable to handle this request ");
-            pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
-                    NULL);
-            return PJ_TRUE;
-        }
-    }
-
-    // Verify that we can handle the request
-    status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, getInstance()->getEndPoint(), NULL);
-    if (status != PJ_SUCCESS) {
-        pj_strdup2(getInstance()->getAppPool(), &reason, "user agent unable to handle this INVITE ");
-        pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
-                NULL);
-        return PJ_TRUE;
-    }
-
-    // Generate a new call ID for the incoming call!
-    CallID id = Manager::instance().getNewCallID();
-
-    _debug("UserAgent: The call id of the incoming call is %s\n", id.c_str());
-    SIPCall* call = new SIPCall(id, Call::Incoming);
-    if (!call) {
-        _debug("UserAgent: unable to create an incoming call");
-        return PJ_FALSE;
-    }
-
-    // Set the codec map, IP, peer number and so on... for the SIPCall object
-    getInstance()->setCallAudioLocal(call);
-    call->setCodecMap(Manager::instance().getCodecDescriptorMap());
-    call->setConnectionState(Call::Progressing);
-    call->setIp(getInstance()->getLocalIP());
-    call->setPeerNumber(peerNumber);
-
-    /* Call the SIPCallInvite function to generate the local sdp,
-     * remote sdp and negociator.
-     * This function is also used to set the parameters of audio RTP, including:
-     *     local IP and port number 
-     *     remote IP and port number
-     *     possilbe audio codec will be used in this call
-     */
-    if (call->SIPCallInvite(rdata, getInstance()->getAppPool())) {
-
-        // Notify UI there is an incoming call
-        if (Manager::instance().incomingCall(call, account_id)) {
-            // Add this call to the callAccountMap in ManagerImpl
-            Manager::instance().getAccountLink(account_id)->addCall(call);
-            _debug("UserAgent: Notify UI success!\n");
-        } else {
-            // Fail to notify UI
-            delete call;
-            call = NULL;
-            _debug("UserAgent: Fail to notify UI!\n");
-            return PJ_FALSE;
-        }
-    } else {
-        // Fail to collect call information
-        delete call;
-        call = NULL;
-        _debug("UserAgent: Call SIPCallInvite failed!\n");
-        return PJ_FALSE;
-    }
-
-    /* Create the local dialog (UAS) */
-    status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dialog);
-    if (status != PJ_SUCCESS) {
-        pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, &reason, NULL,
-                NULL);
-        return PJ_TRUE;
-    }
-
-    // Specify media capability during invite session creation
-    pjsip_inv_session *inv;
-    status = pjsip_inv_create_uas(dialog, rdata, call->getLocalSDPSession(), 0, &inv);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    // Associate the call in the invite session
-    inv->mod_data[getInstance()->getModId()] = call;
-
-    // Send a 180/Ringing response
-    status = pjsip_inv_initial_answer(inv, rdata, PJSIP_SC_RINGING, NULL, NULL, &tdata);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-    status = pjsip_inv_send_msg(inv, tdata);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    // Associate invite session to the current call
-    call->setInvSession(inv);
-
-    // Update the connection state
-    call->setConnectionState(Call::Ringing);
-
-    /* Done */
-    return PJ_SUCCESS;
-}
-
-
-
-
-void UserAgent::call_on_forked(pjsip_inv_session *inv, pjsip_event *e) {
-    PJ_UNUSED_ARG(inv);
-    PJ_UNUSED_ARG(e);
-}
-
-void UserAgent::call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) {
-
-    pjsip_rx_data *rdata;
-    AccountID accId;
-    SIPCall *call;
-    SIPVoIPLink *link;
-    pjsip_msg *msg;
-
-    _debug("UserAgent: TSX Changed! The tsx->state is %d; tsx->role is %d; code is %d; method id is %.*s.\n",
-            tsx->state, tsx->role, tsx->status_code, (int)tsx->method.name.slen, tsx->method.name.ptr);
-
-    if(pj_strcmp2(&tsx->method.name, "INFO") == 0) {
-        // Receive a INFO message, ingore it!
-        return;
-    }
-
-    //Retrieve the body message
-    rdata = e->body.tsx_state.src.rdata;
-
-    if (tsx->role == PJSIP_ROLE_UAC) {
-        switch (tsx->state) {
-            case PJSIP_TSX_STATE_TERMINATED:
-                if (tsx->status_code == 200 &&
-                        pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) != 0) {
-                    // Peer answered the outgoing call
-                    _debug("UserAgent: Peer answered the outgoing call!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL)
-                        return;
-
-                    //_debug("UserAgent: The call id is %s\n", call->getCallId().data());
-
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link)
-                        link->SIPCallAnswered(call, rdata);
-                } else if (tsx->status_code / 100 == 5) {
-                    _debug("UserAgent: 5xx error message received\n");
-                }
-                break;
-            case PJSIP_TSX_STATE_PROCEEDING:
-                // Peer is ringing for the outgoing call
-                msg = rdata->msg_info.msg;
-
-                call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                if (call == NULL)
-                    return;
-
-                if (msg->line.status.code == 180) {
-                    _debug("UserAgent: Peer is ringing!\n");
-
-                    call->setConnectionState(Call::Ringing);
-                    Manager::instance().peerRingingCall(call->getCallId());
-                }
-                break;
-            case PJSIP_TSX_STATE_COMPLETED:
-                if (tsx->status_code == 407 || tsx->status_code == 401) //FIXME
-                    break;
-                if (tsx->status_code / 100 == 6 || tsx->status_code / 100 == 4) {
-                    // We get error message of outgoing call from server
-                    _debug("UserAgent: Server error message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
-                    }
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallServerFailure(call);
-                    }
-                }
-                break;
-            default:
-                break;
-        } // end of switch
-
-    } else {
-        switch (tsx->state) {
-            case PJSIP_TSX_STATE_TRYING:
-                if (pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) == 0) {
-                    // Peer ask me to transfer call to another number.
-                    _debug("UserAgent: Incoming REFER request!\n");
-                    getInstance()->onCallTransfered(inv, e->body.tsx_state.src.rdata);
-                }
-                break;
-            case PJSIP_TSX_STATE_COMPLETED:
-                if (tsx->status_code == 200 && tsx->method.id == PJSIP_BYE_METHOD) {
-                    // Peer hangup the call
-                    _debug("UserAgent: Peer hangup(bye) message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
-                    }
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallClosed(call);
-                    }
-                } else if (tsx->status_code == 200 && tsx->method.id == PJSIP_CANCEL_METHOD) {
-                    // Peer refuse the call
-                    _debug("UserAgent: Cancel message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
-                    }
-
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallClosed(call);
-                    }
-                }
-                break;
-            default:
-                break;
-        } // end of switch
-    }
-
-}
-
-void UserAgent::call_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) {
-
-    PJ_UNUSED_ARG(inv);
-
-    SIPCall *call = reinterpret_cast<SIPCall*> (inv->mod_data[getInstance()->getModId()]);
-    if(!call)
-        return;
-
-    /* If this is an outgoing INVITE that was created because of
-     * REFER/transfer, send NOTIFY to transferer.
-     */
-    if (call->getXferSub() && e->type==PJSIP_EVENT_TSX_STATE)  {
-        int st_code = -1;
-        pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
-
-
-        switch (call->getInvSession()->state) {
-            case PJSIP_INV_STATE_NULL:
-            case PJSIP_INV_STATE_CALLING:
-                /* Do nothing */
-                break;
-
-            case PJSIP_INV_STATE_EARLY:
-            case PJSIP_INV_STATE_CONNECTING:
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_ACTIVE;
-                break;
-
-            case PJSIP_INV_STATE_CONFIRMED:
-                /* When state is confirmed, send the final 200/OK and terminate
-                 * subscription.
-                 */
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_TERMINATED;
-                break;
-
-            case PJSIP_INV_STATE_DISCONNECTED:
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_TERMINATED;
-                break;
-
-            case PJSIP_INV_STATE_INCOMING:
-                /* Nothing to do. Just to keep gcc from complaining about
-                 * unused enums.
-                 */
-                break;
-        }
-
-        if (st_code != -1) {
-            pjsip_tx_data *tdata;
-            pj_status_t status;
-
-            status = pjsip_xfer_notify( call->getXferSub(),
-                    ev_state, st_code,
-                    NULL, &tdata);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to create NOTIFY -- %d\n", status);
-            } else {
-                status = pjsip_xfer_send_request(call->getXferSub(), tdata);
-                if (status != PJ_SUCCESS) {
-                    _debug("UserAgent: Unable to send NOTIFY -- %d\n", status);
-                }
-            }
-        }
-    }
-
-}
-
-void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event);
-
-    _debug("UserAgent: Transfer callback is involved!\n");
-    /*
-     * When subscription is accepted (got 200/OK to REFER), check if 
-     * subscription suppressed.
-     */
-    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
-
-        pjsip_rx_data *rdata;
-        pjsip_generic_string_hdr *refer_sub;
-        const pj_str_t REFER_SUB = {(char*)"Refer-Sub", 9 };
-
-        SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub,
-                    getInstance()->getModId()));
-
-        /* Must be receipt of response message */
-        pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&
-                event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
-        rdata = event->body.tsx_state.src.rdata;
-
-        /* Find Refer-Sub header */
-        refer_sub = (pjsip_generic_string_hdr*)
-            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
-                    &REFER_SUB, NULL);
-
-        /* Check if subscription is suppressed */
-        if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) {
-            /* Since no subscription is desired, assume that call has been
-             * transfered successfully.
-             */
-            if (link) {
-                // It's the time to stop the RTP
-                link->transferStep2();
-            }
-
-            /* Yes, subscription is suppressed.
-             * Terminate our subscription now.
-             */
-            _debug("UserAgent: Xfer subscription suppressed, terminating event subcription...\n");
-            pjsip_evsub_terminate(sub, PJ_TRUE);
-
-        } else {
-            /* Notify application about call transfer progress. 
-             * Initially notify with 100/Accepted status.
-             */
-            _debug("UserAgent: Xfer subscription 100/Accepted received...\n");
-        }
-    }
-    /*
-     * On incoming NOTIFY, notify application about call transfer progress.
-     */
-    else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
-            pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)
-    {
-        pjsip_msg *msg;
-        pjsip_msg_body *body;
-        pjsip_status_line status_line;
-        pj_bool_t is_last;
-        pj_bool_t cont;
-        pj_status_t status;
-
-        SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub, 
-                    getInstance()->getModId()));
-
-        /* When subscription is terminated, clear the xfer_sub member of 
-         * the inv_data.
-         */
-        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
-            pjsip_evsub_set_mod_data(sub, getInstance()->getModId(), NULL);
-            _debug("UserAgent: Xfer client subscription terminated\n");
-
-        }
-
-        if (!link || !event) {
-            /* Application is not interested with call progress status */
-            _debug("UserAgent: Either link or event is empty!\n");
-            return;
-        }
-
-        // Get current call
-        SIPCall *call = dynamic_cast<SIPCall *>(link->getCall(Manager::instance().getCurrentCallId()));
-        if(!call) {
-            _debug("UserAgent: Call doesn't exit!\n");
-            return;
-        }
-
-        /* This better be a NOTIFY request */
-        if (event->type == PJSIP_EVENT_TSX_STATE &&
-                event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
-        {
-            pjsip_rx_data *rdata;
-
-            rdata = event->body.tsx_state.src.rdata;
-
-            /* Check if there's body */
-            msg = rdata->msg_info.msg;
-            body = msg->body;
-            if (!body) {
-                _debug("UserAgent: Warning! Received NOTIFY without message body\n");
-                return;
-            }
-
-            /* Check for appropriate content */
-            if (pj_stricmp2(&body->content_type.type, "message") != 0 ||
-                    pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0)
-            {
-                _debug("UserAgent: Warning! Received NOTIFY with non message/sipfrag content\n");
-                return;
-            }
-
-            /* Try to parse the content */
-            status = pjsip_parse_status_line((char*)body->data, body->len,
-                    &status_line);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Warning! Received NOTIFY with invalid message/sipfrag content\n");
-                return;
-            }
-
-        } else {
-            _debug("UserAgent: Set code to 500!\n");
-            status_line.code = 500;
-            status_line.reason = *pjsip_get_status_text(500);
-        }
-
-        /* Notify application */
-        is_last = (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED);
-        cont = !is_last;
-
-        if(status_line.code/100 == 2) {
-            _debug("UserAgent: Try to stop rtp!\n");
-            pjsip_tx_data *tdata;
-
-            status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_GONE, NULL, &tdata);
-            if(status != PJ_SUCCESS) {
-                _debug("UserAgent: Fail to create end session msg!\n");
-            } else {
-                status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-                if(status != PJ_SUCCESS) 
-                    _debug("UserAgent: Fail to send end session msg!\n");
-            }
-
-            link->transferStep2();
-            cont = PJ_FALSE;
-        }
-
-        if (!cont) {
-            pjsip_evsub_set_mod_data(sub, getInstance()->getModId(), NULL);
-        }
-    }
-
-}
-
-void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
-{
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    SIPCall *existing_call;
-    const pj_str_t str_refer_to = { (char*)"Refer-To", 8};
-    const pj_str_t str_refer_sub = { (char*)"Refer-Sub", 9 };
-    const pj_str_t str_ref_by = { (char*)"Referred-By", 11 };
-    pjsip_generic_string_hdr *refer_to;
-    pjsip_generic_string_hdr *refer_sub;
-    pjsip_hdr *ref_by_hdr;
-    pj_bool_t no_refer_sub = PJ_FALSE;
-    char *uri;
-    std::string tmp;
-    pjsip_status_code code;
-    pjsip_evsub *sub;
-
-    existing_call = (SIPCall *) inv->mod_data[getInstance()->getModId()];
-
-    /* Find the Refer-To header */
-    refer_to = (pjsip_generic_string_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
-
-    if (refer_to == NULL) {
-        /* Invalid Request.
-         * No Refer-To header!
-         */
-        _debug("UserAgent: Received REFER without Refer-To header!\n");
-        pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
-        return;
-    }
-
-    /* Find optional Refer-Sub header */
-    refer_sub = (pjsip_generic_string_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
-
-    if (refer_sub) {
-        if (!pj_strnicmp2(&refer_sub->hvalue, "true", 4)==0)
-            no_refer_sub = PJ_TRUE;
-    }
-
-    /* Find optional Referred-By header (to be copied onto outgoing INVITE
-     * request.
-     */
-    ref_by_hdr = (pjsip_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_ref_by,
-                NULL);
-
-    /* Notify callback */
-    code = PJSIP_SC_ACCEPTED;
-
-    _debug("UserAgent: Call to %.*s is being transfered to %.*s\n",
-            (int)inv->dlg->remote.info_str.slen,
-            inv->dlg->remote.info_str.ptr,
-            (int)refer_to->hvalue.slen,
-            refer_to->hvalue.ptr);
-
-    if (no_refer_sub) {
-        /*
-         * Always answer with 2xx.
-         */
-        pjsip_tx_data *tdata;
-        const pj_str_t str_false = { (char*)"false", 5};
-        pjsip_hdr *hdr;
-
-        status = pjsip_dlg_create_response(inv->dlg, rdata, code, NULL,
-                &tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
-            return;
-        }
-
-        /* Add Refer-Sub header */
-        hdr = (pjsip_hdr*)
-            pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub,
-                    &str_false);
-        pjsip_msg_add_hdr(tdata->msg, hdr);
-
-
-        /* Send answer */
-        status = pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata),
-                tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
-            return;
-        }
-
-        /* Don't have subscription */
-        sub = NULL;
-
-    } else {
-        struct pjsip_evsub_user xfer_cb;
-        pjsip_hdr hdr_list;
-
-        /* Init callback */
-        pj_bzero(&xfer_cb, sizeof(xfer_cb));
-        xfer_cb.on_evsub_state = &xfer_svr_cb;
-
-        /* Init addiTHIS_FILE, THIS_FILE, tional header list to be sent with REFER response */
-        pj_list_init(&hdr_list);
-
-        /* Create transferee event subscription */
-        status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create xfer uas -- %d\n", status);
-            pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
-            return;
-        }
-
-        /* If there's Refer-Sub header and the value is "true", send back
-         * Refer-Sub in the response with value "true" too.
-         */
-        if (refer_sub) {
-            const pj_str_t str_true = { (char*)"true", 4 };
-            pjsip_hdr *hdr;
-
-            hdr = (pjsip_hdr*)
-                pjsip_generic_string_hdr_create(inv->dlg->pool,
-                        &str_refer_sub,
-                        &str_true);
-            pj_list_push_back(&hdr_list, hdr);
-
-        }
-
-        /* Accept the REFER request, send 2xx. */
-        pjsip_xfer_accept(sub, rdata, code, &hdr_list);
-
-        /* Create initial NOTIFY request */
-        status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
-                100, NULL, &tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create NOTIFY to REFER -- %d", status);
-            return;
-        }
-
-        /* Send initial NOTIFY request */
-        status = pjsip_xfer_send_request( sub, tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
-            return;
-        }
-    }
-
-    /* We're cheating here.
-     * We need to get a null terminated string from a pj_str_t.
-     * So grab the pointer from the hvalue and NULL terminate it, knowing
-     * that the NULL position will be occupied by a newline. 
-     */
-    uri = refer_to->hvalue.ptr;
-    uri[refer_to->hvalue.slen] = '\0';
-
-    /* Now make the outgoing call. */
-    tmp = std::string(uri);
-
-    if(existing_call == NULL) {
-        _debug("UserAgent: Call doesn't exist!\n");
-        return;
-    }
-
-    AccountID accId = Manager::instance().getAccountFromCall(existing_call->getCallId());
-    CallID newCallId = Manager::instance().getNewCallID();
-
-    if(!Manager::instance().outgoingCall(accId, newCallId, tmp)) {
-
-        /* Notify xferer about the error (if we have subscription) */
-        if (sub) {
-            status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
-                    500, NULL, &tdata);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to create NOTIFY to REFER -- %d\n", status);
-                return;
-            }
-            status = pjsip_xfer_send_request(sub, tdata);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
-                return;
-            }
-        }
-        return;
-    }
-
-    SIPCall* newCall;
-    SIPVoIPLink *link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-    if(link) {
-        newCall = dynamic_cast<SIPCall *>(link->getCall(newCallId));
-        if(!newCall) {
-            _debug("UserAgent: can not find the call from sipvoiplink!\n");
-            return;
-        }
-    }
-
-    if (sub) {
-        /* Put the server subscription in inv_data.
-         * Subsequent state changed in pjsua_inv_on_state_changed() will be
-         * reported back to the server subscription.
-         */
-        newCall->setXferSub(sub);
-
-        /* Put the invite_data in the subscription. */
-        pjsip_evsub_set_mod_data(sub, _mod.id,
-                newCall);
-    }    
-}
-
-void UserAgent::xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event);
-
-    /*
-     * When subscription is terminated, clear the xfer_sub member of 
-     * the inv_data.
-     */
-    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
-        SIPCall *call;
-
-        call = (SIPCall*) pjsip_evsub_get_mod_data(sub, _mod_ua.id);
-        if (!call)
-            return;
-
-        pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
-        call->setXferSub(NULL);
-
-        _debug("UserAgent: Xfer server subscription terminated\n");
-    }    
-}
diff --git a/src/voiplink.cpp b/src/voiplink.cpp
index 46b69582329a1302a77a1c705d3713df98ba0ec8..e4ff653d48211f0912f639bc8da37a75ada65593 100644
--- a/src/voiplink.cpp
+++ b/src/voiplink.cpp
@@ -76,10 +76,3 @@ bool VoIPLink::clearCallMap()
   return true;
 }
 
-void VoIPLink::setRegistrationState(AccountID id, const RegistrationState state)
-{
-    Account *account;
-
-    account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(id));
-    account->setRegistrationState( state );
-}
diff --git a/src/voiplink.h b/src/voiplink.h
index 2261211edc5ad86a1e0ca65f5251478a63dd92cf..45f0c0e34e4f25fdd02e6574966f7fce637d6f99 100644
--- a/src/voiplink.h
+++ b/src/voiplink.h
@@ -24,6 +24,7 @@
 #define __VOIP_LINK_H__
 
 #include "call.h"
+#include "account.h"
 
 class AudioCodec;
 
@@ -38,197 +39,187 @@ typedef std::map<CallID, Call*> CallMap;
  * @brief Listener and manager interface for each VoIP protocol
  */
 class VoIPLink {
-  
+
     public:
-    /**
-     * Constructor
-     * @param accountID The account identifier
-     */
-    VoIPLink(const AccountID& accountID);
-
-    /**
-     * Virtual destructor
-     */
-    virtual ~VoIPLink (void);
-
-    
-    /**
-     * Virtual method
-     * Event listener. Each event send by the call manager is received and handled from here
-     */
-    virtual void getEvent (void) = 0;
-
-    /** 
-     * Virtual method
-     * Try to initiate the communication layer and set config 
-     * @return bool True if OK
-     */
-    virtual bool init (void) = 0;
-    
-    /**
-     * Virtual method
-     * Delete link-related stuff like calls
-     */
-    virtual void terminate (void) = 0;
-    
-    /**
-     * Virtual method
-     * Build and send account registration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    virtual int sendRegister ( AccountID id ) = 0;
-    
-    /**
-     * Virtual method
-     * Build and send account unregistration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    virtual int sendUnregister (void) = 0;
-
-    /**
-     * Place a new call
-     * @param id  The call identifier
-     * @param toUrl  The address of the recipient of the call
-     * @return Call* The current call
-     */
-    virtual Call* newOutgoingCall(const CallID& id, const std::string& toUrl) = 0;
-
-    /**
-     * Answer the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool answer(const CallID& id) = 0;
-
-    /**
-     * Hang up a call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool hangup(const CallID& id) = 0;
-
-    /**
-     * Cancel the call dialing
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool cancel(const CallID& id) = 0;
-
-    /**
-     * Put a call on hold
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool onhold(const CallID& id) = 0;
-
-    /**
-     * Resume a call from hold state
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool offhold(const CallID& id) = 0;
-
-    /**
-     * Transfer a call to specified URI
-     * @param id The call identifier
-     * @param to The recipient of the call
-     * @return bool True on success
-     */
-    virtual bool transfer(const CallID& id, const std::string& to) = 0;
-
-    /**
-     * Refuse incoming call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool refuse(const CallID& id) = 0;
-
-    /**
-     * Send DTMF
-     * @param id The call identifier
-     * @param code  The char code
-     * @return bool True on success
-     */
-    virtual bool carryingDTMFdigits(const CallID& id, char code) = 0;
-
-    /** Add a call to the call map (protected by mutex)
-     * @param call A call pointer with a unique pointer
-     * @return bool True if the call was unique and added
-     */
-    bool addCall(Call* call);
-
-    /** Remove a call from the call map (protected by mutex)
-     * @param id A Call ID
-     * @return bool True if the call was correctly removed
-     */
-    bool removeCall(const CallID& id);
-
-    /**
-     * Remove all the call from the map
-     * @return bool True on success
-     */
-    bool clearCallMap();
- 
-    /**
-     * @return AccountID  parent Account's ID
-     */
-    inline AccountID& getAccountID(void) { return _accountID; }
-
-    /**
-     * @param accountID The account identifier
-     */
-    inline void setAccountID( const AccountID& accountID) { _accountID = accountID; }
-
-    /** 
-     * Get the call pointer from the call map (protected by mutex)
-     * @param id A Call ID
-     * @return Call*  Call pointer or 0
-     */
-    Call* getCall(const CallID& id);
-
-    /**
-     * Get an account connection status
-     * @return Connection status
-     */
-    RegistrationState getRegistrationState( void );
-
-    /**
-     * Set new registration state
-     * @param state The registration state
-     */
-    void setRegistrationState(AccountID id, const RegistrationState state);
-
-  private:
-    /**
-     * ID of parent's Account
-     */
-    AccountID _accountID;
-
-    /**
-     * State of registration
-     */
-    RegistrationState _registrationState;
-
-protected:
-    /** Contains all the calls for this Link, protected by mutex */
-    CallMap _callMap;
-
-    /** Mutex to protect call map */
-    ost::Mutex _callMapMutex;
-
-    /** Get Local IP Address (ie: 127.0.0.1, 192.168.0.1, ...) */
-    std::string _localIPAddress;
-
-    /** Get local listening port (5060 for SIP, ...) */
-    unsigned int _localPort;
-
-    /** Whether init() was called already or not
-     * This should be used in [IAX|SIP]VoIPLink::init() and terminate(), to
-     * indicate that init() was called, or reset by terminate().
-     */
-    bool _initDone;
+        /**
+         * Constructor
+         * @param accountID The account identifier
+         */
+        VoIPLink(const AccountID& accountID);
+
+        /**
+         * Virtual destructor
+         */
+        virtual ~VoIPLink (void);
+
+
+        /**
+         * Virtual method
+         * Event listener. Each event send by the call manager is received and handled from here
+         */
+        virtual void getEvent (void) = 0;
+
+        /** 
+         * Virtual method
+         * Try to initiate the communication layer and set config 
+         * @return bool True if OK
+         */
+        virtual bool init (void) = 0;
+
+        /**
+         * Virtual method
+         * Delete link-related stuff like calls
+         */
+        virtual void terminate (void) = 0;
+
+        /**
+         * Virtual method
+         * Build and send account registration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        virtual int sendRegister ( AccountID id ) = 0;
+
+        /**
+         * Virtual method
+         * Build and send account unregistration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        virtual int sendUnregister ( AccountID id ) = 0;
+
+        /**
+         * Place a new call
+         * @param id  The call identifier
+         * @param toUrl  The address of the recipient of the call
+         * @return Call* The current call
+         */
+        virtual Call* newOutgoingCall(const CallID& id, const std::string& toUrl) = 0;
+
+        /**
+         * Answer the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool answer(const CallID& id) = 0;
+
+        /**
+         * Hang up a call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool hangup(const CallID& id) = 0;
+
+        /**
+         * Cancel the call dialing
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool cancel(const CallID& id) = 0;
+
+        /**
+         * Put a call on hold
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool onhold(const CallID& id) = 0;
+
+        /**
+         * Resume a call from hold state
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool offhold(const CallID& id) = 0;
+
+        /**
+         * Transfer a call to specified URI
+         * @param id The call identifier
+         * @param to The recipient of the call
+         * @return bool True on success
+         */
+        virtual bool transfer(const CallID& id, const std::string& to) = 0;
+
+        /**
+         * Refuse incoming call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool refuse(const CallID& id) = 0;
+
+        /**
+         * Send DTMF
+         * @param id The call identifier
+         * @param code  The char code
+         * @return bool True on success
+         */
+        virtual bool carryingDTMFdigits(const CallID& id, char code) = 0;
+
+        bool initDone (void) { return _initDone; }
+        void initDone (bool state) { _initDone = state; }
+
+        std::string getLocalIPAddress (void) { return _localIPAddress; }
+
+        /** Add a call to the call map (protected by mutex)
+         * @param call A call pointer with a unique pointer
+         * @return bool True if the call was unique and added
+         */
+        bool addCall(Call* call);
+
+        /** Remove a call from the call map (protected by mutex)
+         * @param id A Call ID
+         * @return bool True if the call was correctly removed
+         */
+        bool removeCall(const CallID& id);
+
+        /**
+         * Remove all the call from the map
+         * @return bool True on success
+         */
+        bool clearCallMap();
+
+        /**
+         * @return AccountID  parent Account's ID
+         */
+        inline AccountID& getAccountID(void) { return _accountID; }
+
+        /**
+         * @param accountID The account identifier
+         */
+        inline void setAccountID( const AccountID& accountID) { _accountID = accountID; }
+
+        /** 
+         * Get the call pointer from the call map (protected by mutex)
+         * @param id A Call ID
+         * @return Call*  Call pointer or 0
+         */
+        Call* getCall(const CallID& id);
+
+        virtual void setStunServer( const std::string &server ) = 0;
+
+    private:
+        /**
+         * ID of parent's Account
+         */
+        AccountID _accountID;
+
+    protected:
+        /** Contains all the calls for this Link, protected by mutex */
+        CallMap _callMap;
+
+        /** Mutex to protect call map */
+        ost::Mutex _callMapMutex;
+
+        /** Get Local IP Address (ie: 127.0.0.1, 192.168.0.1, ...) */
+        std::string _localIPAddress;
+
+        /** Get local listening port (5060 for SIP, ...) */
+        unsigned int _localPort;
+
+        /** Whether init() was called already or not
+         * This should be used in [IAX|SIP]VoIPLink::init() and terminate(), to
+         * indicate that init() was called, or reset by terminate().
+         */
+        bool _initDone;
 };
 
 #endif // __VOIP_LINK_H__