diff --git a/configure.ac b/configure.ac
index 6ee3762e618ee5c7ce25a1288598e6cf9831e7c6..3e9b849a9675dbbf322d1271250abdda647c9c8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -39,7 +39,8 @@ AC_CONFIG_FILES([src/Makefile \
   src/dbus/Makefile \
   src/zeroconf/Makefile \
   src/plug-in/audiorecorder/Makefile \
-  src/plug-in/Makefile]) 
+  src/plug-in/Makefile \
+  src/plug-in/test/Makefile]) 
   
   dnl Unitary test section
 AC_CONFIG_FILES([test/Makefile])
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/Makefile.am b/src/Makefile.am
index 53945f899e37795647d7067937524fd242832d6a..6da95b9e2502d7123005b4f27f570949ed0f4845 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,8 +39,7 @@ sflphoned_SOURCES = \
 		call.cpp \
 		account.cpp \
 		sipcall.cpp \
-		$(IAXSOURCES) \
-		useragent.cpp
+		$(IAXSOURCES) 
 
 sflphoned_CXXFLAGS = \
 		-DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\" \
@@ -60,7 +59,6 @@ sflphoned_LDADD = \
 		@CCRTP_LIBS@ \
 		@ALSA_LIBS@ \
 		@PULSEAUDIO_LIBS@ \
-		-luuid \
 		@SAMPLERATE_LIBS@ 
 
 #sflphoned_LDFLAGS=-pg
@@ -81,8 +79,7 @@ noinst_HEADERS = \
 		accountcreator.h \
         sipvoiplink.h \
 		call.h \
-		sipcall.h \
-		useragent.h
+		sipcall.h 
 		
 libsflphone_la_LIBADD = \
 	$(src)/libs/stund/libstun.la \
diff --git a/src/account.cpp b/src/account.cpp
index 5bc6ba36ebb8325da825c8e93d3e1fdfa30dc1a7..b50fc71fc49d5648d875ac8bc4cb99758b82a9d3 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -22,9 +22,10 @@
 #include "account.h"
 #include "manager.h"
 
-Account::Account(const AccountID& accountID) : 
-    _accountID(accountID), _link(NULL), _enabled(false)
+Account::Account(const AccountID& accountID, std::string type) : 
+    _accountID(accountID), _link(NULL), _enabled(false), _type(type)
 {
+    setRegistrationState(Unregistered);
 }
 
 Account::~Account()
@@ -46,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 571f7220315facc986953b1c7a9cc9a2cb2f7b89..764d4628e1c2d780eb18b9ce4cdc23046f150f95 100644
--- a/src/account.h
+++ b/src/account.h
@@ -38,6 +38,19 @@ class VoIPLink;
 
 typedef std::string AccountID;
 
+/** Contains all the state an Voip can be in */
+typedef enum RegistrationState {
+        Unregistered, 
+        Trying, 
+        Registered, 
+        Error, 
+        ErrorAuth , 
+        ErrorNetwork , 
+        ErrorHost, 
+        ErrorExistStun, 
+        ErrorConfStun
+} RegistrationState;
+
 #define AccountNULL ""
 
 // Common account parameters
@@ -59,7 +72,7 @@ class Account{
 
     public:
 
-        Account(const AccountID& accountID);
+        Account(const AccountID& accountID, std::string type);
 
         /**
          * Virtual destructor
@@ -106,10 +119,27 @@ class Account{
          * Get the registration state of the specified link
          * @return RegistrationState	The registration state of underlying VoIPLink
          */
-        VoIPLink::RegistrationState getRegistrationState() { return _link->getRegistrationState(); }
+        inline RegistrationState getRegistrationState() { return _registrationState; }
 
-    private:
+        void setRegistrationState( RegistrationState state );
+
+        //TODO inline?
+        inline std::string getUsername( void ) { return _username; }
+        inline void setUsername( std::string username) { _username = username; }
+
+        inline std::string getHostname( void ) { return _hostname; }
+        inline void setHostname( std::string hostname) { _hostname = hostname; }
+
+        inline std::string getPassword( void ) { return _password; }
+        inline void setPassword( std::string password ) { _password = password; }
+
+        inline std::string getAlias( void ) { return _alias; }
+        inline void setAlias( std::string alias ) { _alias = alias; }
 
+        inline std::string getType( void ) { return _type; }
+        inline void setType( std::string type ) { _type = type; }
+
+    private:
         // copy constructor
         Account(const Account& rh);
 
@@ -122,6 +152,32 @@ class Account{
          */
         AccountID _accountID;
 
+        /**
+         * Account login information: username
+         */
+        std::string _username;
+
+        /**
+         * Account login information: hostname
+         */
+        std::string _hostname;
+
+        /**
+         * Account login information: password
+         */
+        std::string _password;
+
+        /**
+         * Account login information: Alias
+         */
+        std::string _alias;
+
+        /*
+         * The account type
+         * IAX2 or SIP
+         */
+        std::string _type;
+
         /**
          * Voice over IP Link contains a listener thread and calls
          */
@@ -134,6 +190,11 @@ class Account{
          */
         bool _enabled;
 
+        /*
+         * The registration state of the account
+         */
+        RegistrationState _registrationState;
+
 };
 
 #endif
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/eventthread.cpp b/src/eventthread.cpp
index 66e6d441090be9d70a785ecc7fa0ff44a5256b44..d141505e7e6c04ba4c0301ec921390d7fbb163a0 100644
--- a/src/eventthread.cpp
+++ b/src/eventthread.cpp
@@ -1,8 +1,7 @@
 /*
- *  Copyright (C) 2004, 2005, 2006 Savoir-Faire Linux inc.
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
- *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
- *                                                                              
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Emmanuel Milou <emmanuel.milou@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
@@ -21,43 +20,22 @@
 #include "eventthread.h"
 #include "voiplink.h"
 
-EventThread::EventThread (VoIPLink* link) : Thread (),  _linkthread(link), stopIt(false)
+/********************************** Voiplink thread *************************************/
+EventThread::EventThread( VoIPLink *link ) 
+    : Thread(), _linkthread(link)
 {
-	setCancel(cancelDeferred);
+    setCancel( cancelDeferred );
 }
 
-EventThread::~EventThread (void) 
-{
-  terminate();
-}
 
 /**
  * Reimplementation of run() 
  */
-void
-EventThread::run (void) 
+void EventThread::run (void) 
 {
-  //stopIt = false;
   while(!testCancel()) {
     _linkthread->getEvent();
   }
-}
-
-void
-EventThread::stop( void )
-{
-  stopIt = true; 
-}
-
-void
-EventThread::startLoop( void )
-{
-  stopIt = false;
-  //start();
-}
+}	
 
-bool
-EventThread::isStopped( void )
-{
-  return stopIt;
-}
+/********************************************************************************************/
diff --git a/src/eventthread.h b/src/eventthread.h
index 8772c72043fec8d719b7c50aecf706dbdb241396..0d43a18d716f685388ebddec29e7e4edeb52abe2 100644
--- a/src/eventthread.h
+++ b/src/eventthread.h
@@ -1,7 +1,6 @@
 /*
- *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
- *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Emmanuel Milou <emmanuel.milou@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
@@ -31,24 +30,26 @@ class VoIPLink;
  */
 
 class EventThread : public ost::Thread {
-public:
-  /**
-   * Build a thread that call getEvents 
-   */
-	EventThread (VoIPLink*);
-	~EventThread (void);
-	virtual void 	 run ();
-	virtual void	 stop();
-	virtual void	 startLoop();
-	bool		 isStopped();
-
-private:
+
+    public:
+        /**
+         * Thread constructor 
+         */
+        EventThread (VoIPLink* link);        
+        
+        ~EventThread (void){
+            terminate();
+        }
+        
+        virtual void run () ;
+        
+    private:
         EventThread(const EventThread& rh); // copy constructor
         EventThread& operator=(const EventThread& rh);  // assignment operator	
 
         /** VoIPLink is the object being called by getEvents() method  */
-	VoIPLink*	_linkthread;
-	bool		stopIt;
+        VoIPLink*	_linkthread;
 };
 
+
 #endif // __EVENT_THREAD_H__
diff --git a/src/global.h b/src/global.h
index 0321db6e16948bb2d0449d0fcd201e1f56c83cf4..deb1cdfecd895eb7984e65714163a450c685c1ae 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 */
 
@@ -111,6 +114,7 @@ static const SOUND_FORMAT INT32 = 0x8;
 #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 364f0ab31b028944112bc177ce85e2b45e6e3b81..4de19c54cc995f4d39954775851299b67860451a 100644
--- a/src/iaxaccount.cpp
+++ b/src/iaxaccount.cpp
@@ -23,7 +23,7 @@
 #include "iaxvoiplink.h"
 
     IAXAccount::IAXAccount(const AccountID& accountID)
-: Account(accountID)
+: Account(accountID, "iax2")
 {
     _link = new IAXVoIPLink(accountID);
 }
@@ -35,8 +35,7 @@ IAXAccount::~IAXAccount()
     _link = NULL;
 }
 
-    int
-IAXAccount::registerVoIPLink()
+int IAXAccount::registerVoIPLink()
 {
     IAXVoIPLink *thislink;
 
@@ -50,7 +49,7 @@ IAXAccount::registerVoIPLink()
         thislink->setPass(Manager::instance().getConfigString(_accountID, PASSWORD));
     }
 
-    _link->sendRegister();
+    _link->sendRegister( _accountID );
 
     return SUCCESS;
 }
@@ -58,7 +57,7 @@ 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 6d04dffcaeae225d5d75207136262f3a36705b1c..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();
+    sendRegister("");
   }
 
   // thread wait 3 millisecond
@@ -308,48 +309,52 @@ IAXVoIPLink::getIAXCall(const CallID& id)
 
 
  int 
-IAXVoIPLink::sendRegister() 
+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();
 
-  _regSession = iax_session_new();
+    // Always use a brand new session
+    if (_regSession) {
+        iax_destroy(_regSession);
+    }
 
-  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);
+    _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;
+
+        account->setRegistrationState(Trying);
   }
 
   // unlock
@@ -361,7 +366,7 @@ IAXVoIPLink::sendRegister()
 
 
  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);
     }
 }
 
@@ -917,6 +923,8 @@ IAXVoIPLink::iaxCodecMapToFormat(IAXCall* call)
 
 void IAXVoIPLink::updateAudiolayer( void )
 {
+    _mutexIAX.enterMutex();
     audiolayer = NULL;
     audiolayer = Manager::instance().getAudioDriver();
+    _mutexIAX.leaveMutex();
 }
diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h
index fe8978c1b390724ea8a8d2e172a4e15ee359fc25..8ad4082882f41b731a610714172167bb94e15f95 100644
--- a/src/iaxvoiplink.h
+++ b/src/iaxvoiplink.h
@@ -76,7 +76,7 @@ class IAXVoIPLink : public VoIPLink
      * Send out registration
      * @return bool The new registration state (are we registered ?)
      */
-    int sendRegister (void);
+    int sendRegister (AccountID id);
 
     /**
      * Destroy registration session
@@ -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 626aca506c6114558d6a1db42fae6259e55a019b..c8c25d2b8432821c06f587c7b17ae0d3b38fa651 100644
--- a/src/managerimpl.cpp
+++ b/src/managerimpl.cpp
@@ -46,15 +46,8 @@
 #include "accountcreator.h" // create new account
 #include "sipvoiplink.h"
 
-#include "useragent.h"
-
 #include "user_cfg.h"
 
-#ifdef USE_ZEROCONF
-#include "zeroconf/DNSService.h"
-#include "zeroconf/DNSServiceTXTRecord.h"
-#endif
-
 #define fill_config_str(name, value) \
   (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
 #define fill_config_int(name, value) \
@@ -88,26 +81,10 @@ ManagerImpl::ManagerImpl (void)
         , _callAccountMap()
         //, _callAccountMapMutex()
         , _accountMap()
-        , _userAgent(NULL)
-        , _userAgentInitlized(false)
-        , _sipThreadStop()
- 
 {
-  /* Init private variables 
-     setup:    _path, _exist, _setupLoaded , _dbus
-     sound:    _audiodriver, _dtmfKey, 
-               _spkr_volume,_mic_volume  = 0;  // Initialize after by init() -> initVolume()
-     Call:     _nbIncomingWaitingCall, _hasTriedToRegister
-     SIP Link: _userAgent, _userAgentInitlized
-  */
-
-#ifdef USE_ZEROCONF
-  _hasZeroconf = true;
-  _DNSService = new DNSService();
-#endif
-
-  // initialize random generator for call id
-  srand (time(NULL));
+  
+    // initialize random generator for call id
+    srand (time(NULL));
 
 #ifdef TEST
   testAccountMap();
@@ -123,82 +100,60 @@ ManagerImpl::ManagerImpl (void)
 // never call if we use only the singleton...
 ManagerImpl::~ManagerImpl (void) 
 {
-  terminate();
-
-#ifdef USE_ZEROCONF
-  delete _DNSService; _DNSService = 0;
-#endif
-
-  _debug("%s stop correctly.\n", PROGNAME);
+    terminate();
+    _debug("%s stop correctly.\n", PROGNAME);
 }
 
   void 
 ManagerImpl::init() 
 {
-  // Load accounts, init map
-  loadAccountMap();
+    // Load accounts, init map
+    loadAccountMap();
  
-  //Initialize sip manager 
-  if(_userAgentInitlized) {
-    _userAgent->sipCreate();
-    _userAgent->sipInit();
-  }
-
-  initVolume();
-
-  if (_exist == 0) {
-    _debug("Cannot create config file in your home directory\n");
-  }
+    initVolume();
 
-  initAudioDriver();
-  selectAudioDriver();
+    if (_exist == 0) {
+        _debug("Cannot create config file in your home directory\n");
+    }
 
-  // Initialize the list of supported audio codecs
-  initAudioCodec();
+    initAudioDriver();
+    selectAudioDriver();
 
-  getAudioInputDeviceList();
+    // Initialize the list of supported audio codecs
+    initAudioCodec();
 
-  AudioLayer *audiolayer = getAudioDriver();
-  if (audiolayer!=0) {
-    unsigned int sampleRate = audiolayer->getSampleRate();
+    getAudioInputDeviceList();
 
-    _debugInit("Load Telephone Tone");
-    std::string country = getConfigString(PREFERENCES, ZONE_TONE);
-    _telephoneTone = new TelephoneTone(country, sampleRate);
+    AudioLayer *audiolayer = getAudioDriver();
+    if (audiolayer!=0) {
+        unsigned int sampleRate = audiolayer->getSampleRate();
 
-    _debugInit("Loading DTMF key");
-    _dtmfKey = new DTMF(sampleRate);
-  }
+        _debugInit("Load Telephone Tone");
+        std::string country = getConfigString(PREFERENCES, ZONE_TONE);
+        _telephoneTone = new TelephoneTone(country, sampleRate);
 
-  // initRegisterAccounts was here, but we doing it after the gui loaded... 
-  // the stun detection is long, so it's a better idea to do it after getEvents
-  initZeroconf();
-  
+        _debugInit("Loading DTMF key");
+        _dtmfKey = new DTMF(sampleRate);
+    }
 }
 
 void ManagerImpl::terminate()
 {
-  saveConfig();
+    saveConfig();
 
-  unloadAccountMap();
+    unloadAccountMap();
   
-  if(_userAgentInitlized) {
-      delete _userAgent;
-      _userAgent = NULL;
-      _userAgentInitlized = false;
-  }
-
-  _debug("Unload DTMF Key\n");
-  delete _dtmfKey;
+    _debug("Unload DTMF Key\n");
+    delete _dtmfKey;
 
-  _debug("Unload Audio Driver\n");
-  delete _audiodriver; _audiodriver = NULL;
+    _debug("Unload Audio Driver\n");
+    delete _audiodriver; _audiodriver = NULL;
 
-  _debug("Unload Telephone Tone\n");
-  delete _telephoneTone; _telephoneTone = NULL;
+    _debug("Unload Telephone Tone\n");
+    delete _telephoneTone; _telephoneTone = NULL;
 
-  _debug("Unload Audio Codecs\n");
-  _codecDescriptorMap.deleteHandlePointer();
+    _debug("Unload Audio Codecs\n");
+    _codecDescriptorMap.deleteHandlePointer();
 }
 
 bool
@@ -237,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
@@ -443,25 +402,29 @@ ManagerImpl::saveConfig (void)
  int 
 ManagerImpl::initRegisterAccounts() 
 {
-
     int status; 
+    //TODO What the flag is for ??
     bool flag = true;
     AccountMap::iterator iter;
 
     _debugInit("Initiate VoIP Links Registration");
     iter = _accountMap.begin();
 
+    /* Loop on the account map previously loaded */
     while( iter != _accountMap.end() ) {
-      if ( iter->second ) {
-        iter->second->loadConfig();
-        if ( iter->second->isEnabled() ) {
-	  status = iter->second->registerVoIPLink();
-	  if (status != SUCCESS)
-		flag = false;
+        if ( iter->second ) {
+            iter->second->loadConfig();
+            /* If the account is set as enabled, try to register */
+            if ( iter->second->isEnabled() ) {
+	            status = iter->second->registerVoIPLink();
+	            if (status != SUCCESS){
+		            flag = false;
+                }
+            }
         }
-      }
-      iter++;
+        iter++;
     }
+
     // calls the client notification here in case of errors at startup...
     if( _audiodriver -> getErrorMessage() != -1 )
       notifyErrClient( _audiodriver -> getErrorMessage() );
@@ -721,7 +684,7 @@ ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, int nb_ms
   if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, nb_msg) ;
 }
 
-void ManagerImpl::connectionStatusNotification( void )
+void ManagerImpl::connectionStatusNotification(  )
 {
     if (_dbus)
         _dbus->getConfigurationManager()->accountsChanged();
@@ -1012,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);
@@ -1402,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 );
@@ -1694,24 +1679,6 @@ ManagerImpl::switchAudioManager( void )
     notifyErrClient( _audiodriver -> getErrorMessage());
 } 
 
-/**
- * Initialize the Zeroconf scanning services loop
- * Informations will be store inside a map DNSService->_services
- * Initialization: Main Thread
- */
-  void 
-ManagerImpl::initZeroconf(void) 
-{
-#ifdef USE_ZEROCONF
-  _debugInit("Zeroconf Initialization");
-  int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
-
-  if (useZeroconf) {
-    _DNSService->startScanServices();
-  }
-#endif
-}
-
 /**
  * Init the volume for speakers/micro from 0 to 100 value
  * Initialization: Main Thread
@@ -1750,88 +1717,16 @@ void ManagerImpl::setMicVolume(unsigned short mic_vol)
     //}
 }
 
-/**
- * configuration function requests
- * Main Thread
- */
-  bool 
-ManagerImpl::getZeroconf(const std::string& sequenceId)
+void ManagerImpl::setSipPort( int port )
 {
-  bool returnValue = false;
-#ifdef USE_ZEROCONF
-  int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
-  if (useZeroconf && _dbus != NULL) {
-    TokenList arg;
-    TokenList argTXT;
-    std::string newService = "new service";
-    std::string newTXT = "new txt record";
-    if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
-    DNSServiceMap services = _DNSService->getServices();
-    DNSServiceMap::iterator iter = services.begin();
-    arg.push_back(newService);
-    while(iter!=services.end()) {
-      arg.push_front(iter->first);
-      //_gui->sendMessage("100",sequenceId,arg);
-      arg.pop_front(); // remove the first, the name
-
-      TXTRecordMap record = iter->second.getTXTRecords();
-      TXTRecordMap::iterator iterTXT = record.begin();
-      while(iterTXT!=record.end()) {
-	argTXT.clear();
-	argTXT.push_back(iter->first);
-	argTXT.push_back(iterTXT->first);
-	argTXT.push_back(iterTXT->second);
-	argTXT.push_back(newTXT);
-	// _gui->sendMessage("101",sequenceId,argTXT);
-	iterTXT++;
-      }
-      iter++;
-    }
-    returnValue = true;
-  }
-#else
-  (void)sequenceId;
-#endif
-  return returnValue;
 }
 
-/**
- * Main Thread
- */
-  bool 
-ManagerImpl::attachZeroconfEvents(const std::string& sequenceId, Pattern::Observer& observer)
-{
-  bool returnValue = false;
-  // don't need the _gui like getZeroconf function
-  // because Observer is here
-#ifdef USE_ZEROCONF
-  int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
-  if (useZeroconf) {
-    if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
-    _DNSService->attach(observer);
-    returnValue = true;
-  }
-#else
-  (void)sequenceId;
-  (void)observer;
-#endif
-  return returnValue;
-}
-  bool
-ManagerImpl::detachZeroconfEvents(Pattern::Observer& observer)
+int ManagerImpl::getSipPort( void )
 {
-  bool returnValue = false;
-#ifdef USE_ZEROCONF
-  if (_DNSService) {
-    _DNSService->detach(observer);
-    returnValue = true;
-  }
-#else
-  (void)observer;
-#endif
-  return returnValue;
+    return 5060;
 }
 
+
 // TODO: rewrite this
 /**
  * Main Thread
@@ -1964,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);
@@ -1973,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")))))))))
 	)
       );
  
@@ -2006,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;
 
@@ -2019,28 +1915,28 @@ 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(!_userAgentInitlized) {
-        	_userAgentInitlized = true;
-
-        	if((*details.find(SIP_USE_STUN)).second == "TRUE")
-            		_userAgent->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
-        	else
-            		_userAgent->setStunServer(NULL);
-
-        	_userAgent->sipCreate();
-        	_userAgent->sipInit();
-    	} else {
-        	if((*details.find(SIP_USE_STUN)).second == "TRUE")
-            		_userAgent->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
-        	else
-            		_userAgent->setStunServer(NULL);
 
-        	restartPjsip();
-    	}
-  }
+        if((*details.find(SIP_USE_STUN)).second == "TRUE")
+        {
+           link->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
+        }
+        else
+        {
+            link->setStunServer("");
+        }
+        //restartPjsip();
+    }
 
     saveConfig();
   
@@ -2056,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
@@ -2082,38 +1980,30 @@ ManagerImpl::sendRegister( const std::string& accountID , const int32_t& expire
 ManagerImpl::addAccount(const std::map< std::string, std::string >& details)
 {
 
-  /** @todo Deal with both the _accountMap and the Configuration */
-  std::string accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
-  Account* newAccount;
-  std::stringstream accountID;
-  accountID << "Account:" << time(NULL);
-  AccountID newAccountID = accountID.str();
-  /** @todo Verify the uniqueness, in case a program adds accounts, two in a row. */
+    /** @todo Deal with both the _accountMap and the Configuration */
+    std::string accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
+    Account* newAccount;
+    std::stringstream accountID;
+    accountID << "Account:" << time(NULL);
+    AccountID newAccountID = accountID.str();
+    /** @todo Verify the uniqueness, in case a program adds accounts, two in a row. */
 
-  if (accountType == "SIP") {
-     if(!_userAgentInitlized) {
-        // Initialize the SIP Manager
-        _userAgent = new UserAgent();
-        _userAgent->setSipPort(Manager::instance().getConfigInt(PREFERENCES , CONFIG_SIP_PORT));
-      }
-
-      newAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, newAccountID);
-  }
-  else if (accountType == "IAX") {
-    newAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, newAccountID);
-  }
-  else {
-    _debug("Unknown %s param when calling addAccount(): %s\n", CONFIG_ACCOUNT_TYPE, accountType.c_str());
-    return;
-  }
-  _accountMap[newAccountID] = newAccount;
-  setAccountDetails(accountID.str(), details);
-
-  saveConfig();
+    if (accountType == "SIP") {
+        newAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, newAccountID);
+    }
+    else if (accountType == "IAX") {
+        newAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, newAccountID);
+    }
+    else {
+        _debug("Unknown %s param when calling addAccount(): %s\n", CONFIG_ACCOUNT_TYPE, accountType.c_str());
+        return;
+    }
+    _accountMap[newAccountID] = newAccount;
+    setAccountDetails(accountID.str(), details);
 
-  if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
+    saveConfig();
 
-  //restartPjsip();
+    if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
 }
 
   void 
@@ -2192,20 +2082,6 @@ ManagerImpl::getNewCallID()
   return random_id.str();
 }
 
-  void 
-ManagerImpl::restartPjsip()
-{
-  if ( _userAgentInitlized ){
-    unregisterCurSIPAccounts();
-    _userAgent->sipDestory();
-    //_userAgent->setSipPort(Manager::instance().getConfigInt(PREFERENCES , CONFIG_SIP_PORT));
-
-    _userAgent->sipCreate();
-    _userAgent->sipInit();
-    registerCurSIPAccounts();
-  } 
-}
-
   short
 ManagerImpl::loadAccountMap()
 {
@@ -2214,7 +2090,6 @@ ManagerImpl::loadAccountMap()
   TokenList sections = _config.getSections();
   std::string accountType;
   Account* tmpAccount;
-  std::string port;
 
   TokenList::iterator iter = sections.begin();
   while(iter != sections.end()) {
@@ -2226,28 +2101,7 @@ ManagerImpl::loadAccountMap()
 
     accountType = getConfigString(*iter, CONFIG_ACCOUNT_TYPE);
     if (accountType == "SIP") {
-      if(!_userAgentInitlized) {
-        // Initialize the SIP Manager
-        _userAgent = new UserAgent();
-        _userAgentInitlized = true;
-        _userAgent->setSipPort(Manager::instance().getConfigInt(PREFERENCES , CONFIG_SIP_PORT));
-      }
-
       tmpAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, *iter);
-     
-      // Determine whether to use stun for the current account or not 
-      int useStun = Manager::instance().getConfigInt(tmpAccount->getAccountID(),SIP_USE_STUN);
-  
-      if(useStun == 1) {
-        _userAgent->setStunServer(Manager::instance().getConfigString(tmpAccount->getAccountID(), SIP_STUN_SERVER).data());
-      }
-      
-      /*// Set registration port for all accounts, The last non-5060 port will be recorded in _userAgent.
-      port = Manager::instance().getConfigString(tmpAccount->getAccountID(), SIP_PORT);
-      std::istringstream is(port);
-      is >> iPort;
-      if (iPort != DEFAULT_SIP_PORT)
-      	_userAgent->setRegPort(iPort);  */
     }
     else if (accountType == "IAX") {
       tmpAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, *iter);
@@ -2262,8 +2116,6 @@ ManagerImpl::loadAccountMap()
       nbAccount++;
     }
 
-    _debug("\n");
-
     iter++;
   }
 
@@ -2331,8 +2183,25 @@ ManagerImpl::getAccountIdFromNameAndServer(const std::string& userName, const st
   return AccountNULL;
 }
 
-  VoIPLink* 
-ManagerImpl::getAccountLink(const AccountID& accountID)
+AccountMap ManagerImpl::getSipAccountMap( void )
+{
+    
+    AccountMap::iterator iter;
+    AccountMap sipaccounts;
+    AccountID id;
+    Account *account;
+
+    for(iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) {
+        if( iter->second->getType() == "sip" ){
+            //id = iter->first;
+            //account = iter->second;
+            //sipaccounts.insert( std::pair<id, account> );
+        }
+    }
+    return sipaccounts;
+}
+
+VoIPLink* ManagerImpl::getAccountLink(const AccountID& accountID)
 {
   Account* acc = getAccount(accountID);
   if ( acc ) {
@@ -2351,37 +2220,6 @@ pjsip_regc
     return NULL;
 }
 
-
-/** 
- * Return the instance of sip manager
- */
-UserAgent *ManagerImpl::getUserAgent()
-{
-    return _userAgent;
-}
-
-int 
-ManagerImpl::getSipPort()
-{
-    if( _userAgent )
-        return _userAgent->getSipPort();
-    else
-    {
-        // It means that no SIP accounts are configured, so return a default value
-        return 0;
-    }
-}
-
-void 
-ManagerImpl::setSipPort(int portNum)
-{
-    if(portNum != _userAgent->getSipPort()) {
-        _userAgent->setSipPort(portNum);
-        restartPjsip();
-        setConfig( PREFERENCES , CONFIG_SIP_PORT , portNum );
-    }
-}
-
 void ManagerImpl::unregisterCurSIPAccounts()
 {
   AccountMap::iterator iter = _accountMap.begin();
diff --git a/src/managerimpl.h b/src/managerimpl.h
index b13fc911a88d79580e739ac8ea8b5439d5ad7424..222c7154788fd86d4cc79d2fd3ad16c048584f82 100644
--- a/src/managerimpl.h
+++ b/src/managerimpl.h
@@ -47,7 +47,6 @@ class CodecDescriptor;
 class GuiFramework;
 class TelephoneTone;
 class VoIPLink;
-class UserAgent;
 
 #ifdef USE_ZEROCONF
 class DNSService;
@@ -272,9 +271,6 @@ class ManagerImpl {
      */
     void sendRegister( const ::std::string& accountId , const int32_t& expire );
 
-    bool getZeroconf(const std::string& sequenceId);
-    bool attachZeroconfEvents(const std::string& sequenceId, Pattern::Observer& observer);
-    bool detachZeroconfEvents(Pattern::Observer& observer);
     bool getCallStatus(const std::string& sequenceId);
 
     /** 
@@ -795,14 +791,15 @@ class ManagerImpl {
      */
     void restartPjsip();
 
-    int getSipPort();
-    
-    void setSipPort(int port);
-    
     void unregisterCurSIPAccounts();
     
     void registerCurSIPAccounts();
     
+    /**
+     * Returns a map with only the existing SIP accounts
+     */
+    AccountMap getSipAccountMap( void );
+
   private:
     
     /**
@@ -1019,6 +1016,15 @@ public:
 
     AccountID getAccountIdFromNameAndServer(const std::string& userName, const std::string& server);
 
+    int getSipPort();
+
+    void setSipPort( int port );
+
+    std::string getStunServer (void);
+    void setStunServer (const std::string &server);
+
+    int isStunEnabled (void);
+    void enableStun (void);
 private:
 
     // Copy Constructor
@@ -1027,32 +1033,12 @@ private:
     // Assignment Operator
     ManagerImpl& operator=( const ManagerImpl& rh);
 
-    /**
-     * The UserAgent provides sip operation facilities for all sip accounts
-     */
-    UserAgent *_userAgent;
-
-    /** Whether the _UserAgent has been initialized */
-    bool _userAgentInitlized;
-    
-    bool _sipThreadStop;
-
 #ifdef TEST
     bool testCallAccountMap();
     bool testAccountMap();
 #endif
 
     friend class ConfigurationTest;
-
-public:
-    /**
-     * Retuun the instance of sip manager
-     */
-    UserAgent *getUserAgent();
-    
-    void setSipThreadStatus(bool status) {_sipThreadStop = status;}
-    
-    bool getSipThreadStatus() {return _sipThreadStop;}
 };
 
 #endif // __MANAGER_H__
diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am
index 7555fe7f3e45ab1427c068e716240af3c47f70ea..b69f39ca9cdca75d415b6470d84f7a371e8157c1 100644
--- a/src/plug-in/Makefile.am
+++ b/src/plug-in/Makefile.am
@@ -4,7 +4,9 @@ SUBDIRS=audiorecorder
 
 noinst_LTLIBRARIES = libplugin.la
 
+SUBDIRS=test
+
 libplugin_la_SOURCES = \
 		pluginmanager.cpp \
-		plugin.h
+		plugin.cpp
 
diff --git a/src/plug-in/plugin.cpp b/src/plug-in/plugin.cpp
index 495437076549dee7c9bafbdc5ca6782076400d97..deaf1a4818fbe8a01a720b0b856c36f1ac33a277 100644
--- a/src/plug-in/plugin.cpp
+++ b/src/plug-in/plugin.cpp
@@ -1,27 +1,15 @@
-#include "plugin.h"
+#include "plugin.h" 
 
-::sflphone::Plugin::Plugin( const std::string &filename UNUSED )
+::sflphone::Plugin::Plugin (void *handle, PluginInterface *interface)
+    :_handlePtr(handle), _interface(interface)
 {
-    //TODO IMPLEMENT
 }
 
-::sflphone::Plugin::Plugin( const Plugin &plugin UNUSED )
+::sflphone::Plugin::Plugin (PluginInterface *interface)
+    :_interface(interface)
 {
-    //TODO IMPLEMENT
 }
 
-::sflphone::Plugin::~Plugin()
+::sflphone::Plugin::~Plugin ()
 {
-    //TODO IMPLEMENT
-}
-
-int ::sflphone::Plugin::getCoreVersion( void ) const
-{
-    //TODO IMPLEMENT
-    return 1;
-}
-
-void ::sflphone::Plugin::registerPlugin( PluginManager & )
-{
-    //TODO IMPLEMENT
 }
diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h
index 100d6ea5b40bc618e3e6cae9c4435b9b192af676..fe548361eb1098e566ffacf00cb58d61ba31a236 100644
--- a/src/plug-in/plugin.h
+++ b/src/plug-in/plugin.h
@@ -1,43 +1,32 @@
 #ifndef PLUGIN_H
 #define PLUGIN_H
 
-#include <string> 
-
-#include "global.h" 
-
-/*
- * @file plugin.h
- * @brief Define a plugin object 
- */
+#include "plugininterface.h"
 
 namespace sflphone {
 
-class PluginManager;
+    class PluginInterface;
 
     class Plugin {
-    
-        public:
-            Plugin( const std::string &name );
-            //Plugin( const Plugin &plugin );
-            virtual ~Plugin()  {}
 
         public:
-            /**
-             * Return the minimal core version required so that the plugin could work
-             * @return int  The version required
-             */
-            virtual int getCoreVersion() const = 0;
-            
-            /**
-             * Register the plugin to the plugin manager
-             */
-            virtual void registerPlugin( PluginManager & ) = 0;
 
-        private:
-            Plugin &operator =(const Plugin &plugin);
+            Plugin (void*, PluginInterface *interface);
+            Plugin (PluginInterface *interface);
 
+            ~Plugin ();
+
+            void setName (std::string name);
+        private:
+            std::string _name;
+            int _version_major;
+            int _version_minor;
+            int _required;
+            void *_handlePtr;
+            PluginInterface *_interface;
+
+            friend class PluginTest;
+            friend class PluginManager;
     };
 }
-
 #endif //PLUGIN_H
-
diff --git a/src/plug-in/plugininterface.h b/src/plug-in/plugininterface.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef45d99dd9563a2c9d218a26a82c4485f04ae8d7
--- /dev/null
+++ b/src/plug-in/plugininterface.h
@@ -0,0 +1,50 @@
+#ifndef PLUGIN_INTERFACE_H
+#define PLUGIN_INTERFACE_H
+
+#include <string> 
+#include "global.h" 
+
+#include "plugin.h" 
+
+/*
+ * @file plugininterface.h
+ * @brief Define a plugin object 
+ */
+
+namespace sflphone {
+
+    class Plugin;
+
+    class PluginInterface {
+
+        public:
+            PluginInterface( const std::string &name ){
+                _name = name;
+            }
+
+            virtual ~PluginInterface()  {}
+
+            inline std::string getInterfaceName (void) { return _name; }
+
+            /**
+             * Return the minimal core version required so that the plugin could work
+             * @return int  The version required
+             */
+            virtual int initFunc ()  = 0;
+
+            virtual int registerFunc (Plugin **plugin) = 0;
+
+        private:
+            PluginInterface &operator =(const PluginInterface &plugin);
+
+            std::string _name;
+    };
+
+    typedef PluginInterface* createFunc (void);
+
+    typedef void destroyFunc( PluginInterface* );
+
+}
+
+#endif //PLUGIN_INTERFACE_H
+
diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp
index df88799a80d8f98a0af1290e03de65cdf759314d..f8135f57806590ea3c32f5c304f3de3be8814896 100644
--- a/src/plug-in/pluginmanager.cpp
+++ b/src/plug-in/pluginmanager.cpp
@@ -3,7 +3,19 @@
 
 #include "pluginmanager.h"
 
-::sflphone::PluginManager::PluginManager():_loadedPlugins()
+::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0;
+
+    ::sflphone::PluginManager* 
+::sflphone::PluginManager::instance()
+{
+    if(!_instance){
+        return new PluginManager();
+    }
+    return _instance;
+}
+
+::sflphone::PluginManager::PluginManager()
+    :_loadedPlugins()
 {
     _instance = this;
 }
@@ -13,22 +25,16 @@
     _instance = 0;
 }
 
-::sflphone::PluginManager* ::sflphone::PluginManager::instance()
-{
-    if(! _instance ){
-        _instance = new PluginManager();
-    }
-    return _instance;
-}   
-
-
-int ::sflphone::PluginManager::loadPlugins( const std::string &path )
+    int 
+::sflphone::PluginManager::loadPlugins (const std::string &path)
 {
     std::string pluginDir, current;
-    ::sflphone::Plugin *plugin;
+    ::sflphone::PluginInterface *interface;
     DIR *dir;
     dirent *dirStruct;
     int result=0;
+    void *handle;
+    createFunc* createPlugin;
     
     const std::string pDir = "..";
     const std::string cDir = ".";
@@ -46,18 +52,31 @@ int ::sflphone::PluginManager::loadPlugins( const std::string &path )
             current = dirStruct->d_name;
             /* Test if the current item is not the parent or the current directory */
             if( current != pDir && current != cDir ){
-                loadDynamicLibrary( current );
-                result++;
-	        }
+                handle = loadDynamicLibrary( pluginDir + current );
+                
+                if(instanciatePlugin (handle, &interface) != 0)       	        
+                {
+                    _debug("Error instanciating the plugin ...\n");
+                    return 1;
+                }
+                
+                if(registerPlugin (handle, interface) != 0)
+                    _debug("Error registering the plugin ...\n");
+                    return 1;
+            }
 	    }
     }
+    else
+        return 1;
+
     /* Close the directory */
     closedir( dir );
 
-    return result;
+    return 0;
 }
 
-::sflphone::Plugin* ::sflphone::PluginManager::isPluginLoaded( const std::string &name )
+    ::sflphone::Plugin* 
+::sflphone::PluginManager::isPluginLoaded (const std::string &name)
 {
     if(_loadedPlugins.empty())    return NULL;  
 
@@ -77,31 +96,68 @@ int ::sflphone::PluginManager::loadPlugins( const std::string &path )
     return NULL;
 }
 
-void* ::sflphone::PluginManager::loadDynamicLibrary( const std::string& filename ) {
+
+    void* 
+::sflphone::PluginManager::loadDynamicLibrary (const std::string& filename) 
+{
 
     void *pluginHandlePtr = NULL;
     const char *error;
 
     _debug("Loading dynamic library %s\n", filename.c_str());
 
-#if defined(Q_OS_UNIX)
     /* Load the library */
     pluginHandlePtr = dlopen( filename.c_str(), RTLD_LAZY );
     if( !pluginHandlePtr ) {
         error = dlerror();
         _debug("Error while opening plug-in: %s\n", error);
+        return NULL;
     }
     dlerror();
-#endif
-
     return pluginHandlePtr;
+
+}
+
+    int 
+::sflphone::PluginManager::instanciatePlugin (void *handlePtr, ::sflphone::PluginInterface **plugin)
+{
+    createFunc *createPlugin;
+
+    createPlugin = (createFunc*)dlsym(handlePtr, "create");
+    if( dlerror() )
+    {
+        _debug("Error creating the plugin: %s\n", dlerror());
+        return 1;
+    }
+    *plugin = createPlugin();
+    return 0;
 }
 
-void ::sflphone::PluginManager::unloadDynamicLibrary( void * pluginHandlePtr ) {
+    int 
+::sflphone::PluginManager::registerPlugin (void *handlePtr, PluginInterface *interface)
+{
+    Plugin *myplugin;
+    std::string name;
+
+    if( !( handlePtr && interface!=0 ) )
+        return 1;
     
+    /* Fetch information from the loaded plugin interface */
+    if(interface->registerFunc (&myplugin) != 0)
+        return 1;
+    /* Creation of the plugin wrapper */
+    myplugin = new Plugin (handlePtr, interface);
+
+    /* Add the data in the loaded plugin map */
+    _loadedPlugins[ myplugin->_name ] = myplugin;
+    return 0;
+}
+
+    void 
+::sflphone::PluginManager::unloadDynamicLibrary (void * pluginHandlePtr) 
+{
     dlclose( pluginHandlePtr );
     dlerror();
 }
 
-::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0;
 
diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h
index 78d988cd0c9f51df87d19b5fd9b33822c3118fe1..671834369da67dc151cd24e8ab9ca62a0261d6c1 100644
--- a/src/plug-in/pluginmanager.h
+++ b/src/plug-in/pluginmanager.h
@@ -6,7 +6,7 @@
  * @brief   Base class of the plugin manager
  */
 
-#include "plugin.h"
+#include "plugininterface.h"
 #include "global.h"
 
 #include <map> 
@@ -16,56 +16,61 @@ namespace sflphone {
 
     class PluginManager {
 
+
         public:
-            /**
-             * Destructor
-             */
-            ~PluginManager();
-
-            /**
-             * Returns the unique instance of the plugin manager
-             */
-            static PluginManager* instance();
-
-            /**
-             * Load all the plugins found in a specific directory
-             * @param path  The absolute path to the directory
-             * @return int  The number of items loaded
-             */
-            int loadPlugins( const std::string &path = "" );
-
-            /**
-             * Check if a plugin has been already loaded
-             * @param name  The name of the plugin looked for
-             * @return Plugin*  The pointer on the plugin or NULL if not found
-             */
-            Plugin* isPluginLoaded( const std::string &name );
+        /**
+         * Destructor
+         */
+        ~PluginManager();
+
+        /**
+         * Returns the unique instance of the plugin manager
+         */
+        static PluginManager* instance();
+
+        /**
+         * Load all the plugins found in a specific directory
+         * @param path  The absolute path to the directory
+         * @return int  The number of items loaded
+         */
+        int loadPlugins( const std::string &path = "" );
+
+        int instanciatePlugin( void *handlePtr, PluginInterface** plugin );
+
+        /**
+         * Check if a plugin has been already loaded
+         * @param name  The name of the plugin looked for
+         * @return Plugin*  The pointer on the plugin or NULL if not found
+         */
+        Plugin* isPluginLoaded( const std::string &name );
+
+        int registerPlugin (void *handle, PluginInterface *interface);
 
         private:
-            /**
-             * Default constructor
-             */
-            PluginManager();
-
-            /**
-             * Load a unix dynamic/shared library 
-             * @param filename  The path to the dynamic/shared library
-             * @return void*    A pointer on it
-             */
-            void * loadDynamicLibrary( const std::string &filename );
-
-            /**
-             * Unload a unix dynamic/shared library 
-             * @param pluginHandleptr  The pointer on the loaded plugin
-             */
-            void unloadDynamicLibrary( void * pluginHandlePtr );
-
-            /* Map of plugins associated by their string name */
-            typedef std::map<std::string, ::sflphone::Plugin*> pluginMap;
-            pluginMap _loadedPlugins;
-
-            /* The unique static instance */
-            static PluginManager* _instance;
+        /**
+         * Default constructor
+         */
+        PluginManager();
+
+        /**
+         * Load a unix dynamic/shared library 
+         * @param filename  The path to the dynamic/shared library
+         * @return void*    A pointer on it
+         */
+        void * loadDynamicLibrary( const std::string &filename );
+
+        /**
+         * Unload a unix dynamic/shared library 
+         * @param pluginHandleptr  The pointer on the loaded plugin
+         */
+        void unloadDynamicLibrary( void * pluginHandlePtr );
+
+        /* Map of plugins associated by their string name */
+        typedef std::map<std::string, Plugin*> pluginMap;
+        pluginMap _loadedPlugins;
+
+        /* The unique static instance */
+        static PluginManager* _instance;
     };
 }
 
diff --git a/src/plug-in/test/Makefile.am b/src/plug-in/test/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..6809be2c0a185e16f72edcef1b57103fbcbea8f8
--- /dev/null
+++ b/src/plug-in/test/Makefile.am
@@ -0,0 +1,19 @@
+include $(top_srcdir)/globals.mak
+
+PLUGIN_LIB = libplugintest.so
+libplugintest_so_SOURCES = pluginTest.cpp
+libplugintest_so_CXXFLAGS = -fPIC -g -Wall
+libplugintest_so_LDFLAGS = --shared -lc
+INSTALL_PLUGIN_RULE = install-libplugintest_so
+
+noinst_PROGRAMS = libplugintest.so
+
+install-exec-local:  install-libplugintest_so
+uninstall-local:  uninstall-libplugintest_so
+
+install-libplugintest_so: libplugintest.so
+	mkdir -p $(sflplugindir)
+	$(INSTALL_PROGRAM) libplugintest.so $(sflplugindir)
+
+uninstall-libplugintest_so:
+	rm -f $(sflplugindir)/libplugintest.so
diff --git a/src/plug-in/test/pluginTest.cpp b/src/plug-in/test/pluginTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..066501d6588f7d02ced18d627160fd8a3b7da8ab
--- /dev/null
+++ b/src/plug-in/test/pluginTest.cpp
@@ -0,0 +1,40 @@
+#include "../plugininterface.h" 
+#include "../plugin.h"
+
+namespace sflphone {
+
+    class PluginTest : public PluginInterface {
+    
+        public:
+            PluginTest( const std::string &name ):PluginInterface( name ){
+            }
+
+            virtual int initFunc (void)
+            {
+                return 0;
+            }
+
+            virtual int registerFunc (Plugin **plugin)
+            {
+                Plugin *ret;
+
+                ret = new Plugin(this);
+                
+                ret->_name = getInterfaceName();
+                ret->_required = 1;
+                ret->_version_major=1;
+                ret->_version_minor=0;
+
+                *plugin = ret;
+                return 0;
+            }
+    };
+
+}
+extern "C" ::sflphone::PluginInterface* create (void){
+    return new ::sflphone::PluginTest("test");
+}
+
+extern "C" void* destroy( ::sflphone::PluginInterface *p ){
+    delete p;
+}
diff --git a/src/sipaccount.cpp b/src/sipaccount.cpp
index acce1bb66ed5fff56fad4d6a3d20b77c6ba146a0..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
@@ -23,80 +21,77 @@
 #include "sipaccount.h"
 #include "manager.h"
 #include "user_cfg.h"
-#include "useragent.h"
 
 SIPAccount::SIPAccount(const AccountID& accountID)
- : Account(accountID)
- , _userName("")
- , _server("")
+ : Account(accountID, "sip")
  , _cred(NULL)
  , _contact("")
+ , _bRegister(false)
+ , _regc()
 {
-  _link = new SIPVoIPLink(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()
+int SIPAccount::registerVoIPLink()
 {
-
     int status, useStun;
     SIPVoIPLink *thislink;
 
-    _link->setHostname(Manager::instance().getConfigString(_accountID,HOSTNAME));
-    useStun = Manager::instance().getConfigInt(_accountID,SIP_USE_STUN);
-  
+    /* Retrieve the account information */
+    /* Stuff needed for SIP registration */
+    setHostname(Manager::instance().getConfigString(_accountID,HOSTNAME));
+    setUsername(Manager::instance().getConfigString(_accountID, USERNAME));
+    setPassword(Manager::instance().getConfigString(_accountID, PASSWORD));
+    /* Retrieve STUN stuff */
+    /* STUN configuration is attached to a voiplink because it is applied to every accounts (PJSIP limitation)*/
     thislink = dynamic_cast<SIPVoIPLink*> (_link);
-    thislink->setStunServer(Manager::instance().getConfigString(_accountID,SIP_STUN_SERVER));
-    thislink->setUseStun( useStun!=0 ? true : false);
-    
-    _link->init();
-  
-    // Stuff needed for SIP registration.
-    thislink->setUsername(Manager::instance().getConfigString(_accountID, USERNAME));
-    thislink->setPassword(Manager::instance().getConfigString(_accountID, PASSWORD));
-    thislink->setHostname(Manager::instance().getConfigString(_accountID, HOSTNAME));
+    if (thislink) {
+    }
 
-    status = _link->sendRegister();
+    /* Start registration */
+    status = _link->sendRegister( _accountID );
     ASSERT( status , SUCCESS );
 
     return SUCCESS;
 }
 
-int
-SIPAccount::unregisterVoIPLink()
+int SIPAccount::unregisterVoIPLink()
 {
   _debug("SIPAccount: unregister account %s\n" , getAccountID().c_str());
-  _link->sendUnregister();
-  _link->terminate();
-  
-  return SUCCESS;
+  return _link->sendUnregister( _accountID );
 }
 
-void
-SIPAccount::loadConfig() 
+void SIPAccount::loadConfig() 
 {
   // Account generic
   Account::loadConfig();
 }
 
-bool 
-SIPAccount::fullMatch(const std::string& userName, const std::string& server)
+bool SIPAccount::fullMatch(const std::string& username, const std::string& hostname)
 {
-  return (userName == _userName && server == _server);
+  return (username == getUsername() && hostname == getHostname());
 }
 
-bool 
-SIPAccount::userMatch(const std::string& userName)
+bool SIPAccount::userMatch(const std::string& username)
 {
-  return (userName == _userName);
+  return (username == getUsername());
 }
 
diff --git a/src/sipaccount.h b/src/sipaccount.h
index 549d1a6d0d857326720e81b9863df9a4ca045083..b716086fbe5fc94fe57146228d20d4605a92169d 100644
--- a/src/sipaccount.h
+++ b/src/sipaccount.h
@@ -26,76 +26,98 @@
 #include "account.h"
 #include "sipvoiplink.h"
 
-struct pjsip_cred_info;
-
 class SIPVoIPLink;
 
 /**
  * @file sipaccount.h
  * @brief A SIP Account specify SIP specific functions and object (SIPCall/SIPVoIPLink)
-*/
+ */
 
 class SIPAccount : public Account
 {
-public:
-  /**
-   * Constructor
-   * @param accountID The account identifier
-   */
-  SIPAccount(const AccountID& accountID);
-
-  /* Copy Constructor */
-  SIPAccount(const SIPAccount& rh);
-
-  /* Assignment Operator */
-  SIPAccount& operator=( const SIPAccount& rh);
-  
-  /**
-   * Virtual destructor
-   */
-  virtual ~SIPAccount();
-
-  /** 
-   * Actually unuseful, since config loading is done in init() 
-   */
-  void loadConfig();
-
-  /**
-   * Initialize the SIP voip link with the account parameters and send registration
-   */ 
-  int registerVoIPLink();
-
-  /**
-   * Send unregistration and clean all related stuff ( calls , thread )
-   */
-  int unregisterVoIPLink();
-
-
-  void setUserName(const std::string &name) {_userName = name;}
-
-  std::string getUserName() {return _userName;}
-
-  void setServer(const std::string &server) {_server = server;}
-
-  std::string getServer() {return _server;}
-
-  void setCredInfo(pjsip_cred_info *cred) {_cred = cred;}
-
-  pjsip_cred_info *getCredInfo() {return _cred;}
-
-  void setContact(const std::string contact) {_contact = contact;}
-
-  std::string getContact() {return _contact;}
-
-  bool fullMatch(const std::string& userName, const std::string& server);
-
-  bool userMatch(const std::string& userName);
-
-private:
-  std::string _userName;
-  std::string _server;
-  pjsip_cred_info *_cred;
-  std::string _contact;
+    public:
+        /**
+         * Constructor
+         * @param accountID The account identifier
+         */
+        SIPAccount(const AccountID& accountID);
+
+        /* Copy Constructor */
+        SIPAccount(const SIPAccount& rh);
+
+        /* Assignment Operator */
+        SIPAccount& operator=( const SIPAccount& rh);
+
+        /**
+         * Virtual destructor
+         */
+        virtual ~SIPAccount();
+
+        /** 
+         * Actually unuseful, since config loading is done in init() 
+         */
+        void loadConfig();
+
+        /**
+         * Initialize the SIP voip link with the account parameters and send registration
+         */ 
+        int registerVoIPLink();
+
+        /**
+         * Send unregistration and clean all related stuff ( calls , thread )
+         */
+        int unregisterVoIPLink();
+
+        inline void setCredInfo(pjsip_cred_info *cred) {_cred = cred;}
+        inline pjsip_cred_info *getCredInfo() {return _cred;}
+
+        inline void setContact(const std::string &contact) {_contact = contact;}
+        inline std::string getContact() {return _contact;}
+
+        bool fullMatch(const std::string& username, const std::string& hostname);
+        bool userMatch(const std::string& username);
+
+        inline std::string getHostname( void ) { return _hostname; }
+        inline void setHostname( std::string hostname) { _hostname = hostname; }
+
+        inline std::string getPassword( void ) { return _password; }
+        inline void setPassword( std::string password ) { _password = password; }
+
+        inline std::string getAlias( void ) { return _alias; }
+        inline void setAlias( std::string alias ) { _alias = alias; }
+
+        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
+         */
+        std::string _contact;
 };
 
 #endif
diff --git a/src/sipcall.cpp b/src/sipcall.cpp
index 0e53bdd013d066744d80db93204ffbf14a46549f..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
@@ -51,13 +49,13 @@ SIPCall::SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool)
 {
   pj_status_t status;
   
+  // We retrieve the remote sdp offer in the rdata struct to begin the negociation
   pjmedia_sdp_session* remote_sdp = getRemoteSDPFromRequest(rdata);
   if (remote_sdp == 0) {
     return false;
   }
 
   // Have to do some stuff here with the SDP
-  // We retrieve the remote sdp offer in the rdata struct to begin the negociation
   _localSDP = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
   _localSDP->conn =  PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
   
@@ -68,7 +66,6 @@ SIPCall::SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool)
   _localSDP->time.start = _localSDP->time.stop = 0;
   sdpAddMediaDescription(pool);
   
-  _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/sipcall.h b/src/sipcall.h
index fe23553d5dcdd5edda45b80c6466ea3d6b124725..2ef3d2793451e85bd1fd48151428959cfd7db854 100644
--- a/src/sipcall.h
+++ b/src/sipcall.h
@@ -22,8 +22,8 @@
 #define SIPCALL_H
 
 #include "call.h"
+#include "sipvoiplink.h"
 #include "audio/codecDescriptor.h"
-#include "useragent.h"
 
 class AudioCodec;
 
diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp
index c71fd1da9eb1392f4074c80f29d88a3c6ea40327..a37e68318704433019f1836d553157ab4f0910c0 100644
--- a/src/sipvoiplink.cpp
+++ b/src/sipvoiplink.cpp
@@ -2,8 +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 : Laurielle Lea <laurielle.lea@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
@@ -19,264 +18,577 @@
  *  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 "useragent.h"
 #include "audio/audiortp.h"
-        
-#include "manager.h"
-#include "user_cfg.h" // SIGNALISATION / PULSE #define
-
-#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
-
-// 1XX responses
-#define DIALOG_ESTABLISHED 101
-// see: osip_const.h
-
-// need for hold/unhold
-#define INVITE_METHOD "INVITE"
-
-SIPVoIPLink::SIPVoIPLink(const AccountID& accountID)
- : VoIPLink(accountID)
- , _initDone(false)
- , _nbTryListenAddr(2) // number of times to try to start SIP listener
- , _useStun(false)
- , _stunServer("")
- , _localExternAddress("") 
- , _localExternPort(0)
- , _audiortp(new AudioRtp())
- , _regc()
- , _bRegister(false)
+
+/**************** EXTERN VARIABLES AND FUNCTIONS (callbacks) **************************/
+
+/*
+ *  The global pool factory
+ */
+pj_caching_pool _cp;
+
+/*
+ * The pool to allocate memory
+ */
+pj_pool_t *_pool;    
+
+/*
+ *	The SIP endpoint
+ */
+pjsip_endpoint *_endpt;
+
+/*
+ *	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 );
+
+/**
+ * Set audio (SDP) configuration for a call
+ * localport, localip, localexternalport
+ * @param call a SIPCall valid pointer
+ * @return bool True
+ */
+bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server);
+
+// Documentated from the PJSIP Developer's Guide, available on the pjsip website/
+
+/*
+ * 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("")
+    , _localExternAddress("") 
+    , _localExternPort(0)
+    , _audiortp(new AudioRtp())
+    ,_regPort(DEFAULT_SIP_PORT)
+    , _useStun(false)
+    , _clients(0)
 {
-  // to get random number for RANDOM_PORT
-  srand (time(NULL));
+    // to get random number for RANDOM_PORT
+    srand (time(NULL));
+
+    /* Instanciate the C++ thread */
+    _evThread = new EventThread(this);
+
+    /* Start pjsip initialization step */
+    init();
 }
 
 SIPVoIPLink::~SIPVoIPLink()
 {
-  terminate();
+    terminate();
+}
+
+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()
+bool SIPVoIPLink::init()
 {
-  _regc = NULL;
-  _initDone = true;
-  return true;
+    if(initDone())
+        return false;
+    /* Initialize the pjsip library */
+    pjsip_init();
+    initDone(true);
+
+    return true;
 }
 
-void 
+    void 
 SIPVoIPLink::terminate()
 {
-  _initDone = false;
+    delete _evThread; _evThread = NULL;
+
+    /* Clean shutdown of pjsip library */
+    if( initDone() )
+    {
+        pjsip_shutdown();
+    }
+    initDone(false);
 }
 
-void
+    void
 SIPVoIPLink::terminateSIPCall()
 {
-  
-  //ost::MutexLock m(_callMapMutex);
-  CallMap::iterator iter = _callMap.begin();
-  SIPCall *call;
-  while( iter != _callMap.end() ) {
-    call = dynamic_cast<SIPCall*>(iter->second);
-    if (call) {
-      //TODO terminate the sip call
-      delete call; call = 0;
+
+    //ost::MutexLock m(_callMapMutex);
+    CallMap::iterator iter = _callMap.begin();
+    SIPCall *call;
+    while( iter != _callMap.end() ) {
+        call = dynamic_cast<SIPCall*>(iter->second);
+        if (call) {
+            //TODO terminate the sip call
+            delete call; call = 0;
+        }
+        iter++;
     }
-    iter++;
-  }
-  _callMap.clear();
+    _callMap.clear();
 }
 
-void
+    void
 SIPVoIPLink::getEvent()
 {
-    // Nothing anymore. PJSIP is based on asynchronous events
+    // 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 );
+
+    // PJSIP polling
+    pj_time_val timeout = {0, 10};
+    pjsip_endpt_handle_events( _endpt, &timeout);
 }
 
-int
-SIPVoIPLink::sendRegister()
+int SIPVoIPLink::sendRegister( AccountID id )
 {
-  AccountID id;
-  pj_status_t status;
-  
-  id = getAccountID();
+    pj_status_t status;
+    int expire_value;
+    char contactTmp[256];
+    pj_str_t svr, aor, contact;
+    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();
+    username = account->getUsername();
+    password = account->getPassword();
+
+    _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;
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+    }
 
-  if(_regc) {
-      status = pjsip_regc_destroy(_regc);
-      _regc = NULL;
-      PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-  }
+    account->setRegister(true);
 
-  _bRegister = true;
-  
-  int expire_value = Manager::instance().getRegistrationExpireValue();
-  _debug("SIP Registration Expire Value = %i\n" , expire_value);
+    /* Set the expire value of the message from the config file */
+    expire_value = Manager::instance().getRegistrationExpireValue();
 
-  setRegistrationState(Trying);
+    /* Update the state of the voip link */
+    account->setRegistrationState(Trying);
 
-  return Manager::instance().getUserAgent()->addAccount(id, &_regc, getHostname(), getUsername(), getPassword(), expire_value);
-}
+    if (!validStunServer) {
+        account->setRegistrationState(ErrorExistStun);
+        account->setRegister(false);
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
 
-std::string
-SIPVoIPLink::SIPFromHeader(const std::string& userpart, const std::string& hostpart) 
-{
-  return ("\"" + getFullName() + "\"" + " <sip:" + userpart + "@" + hostpart + ">");
-}
+    /* Create the registration according to the account ID */
+    status = pjsip_regc_create(_endpt, (void*)account, &regc_cb, &regc);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create regc.\n");
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
 
-bool
-SIPVoIPLink::sendSIPAuthentification() 
-{
-  if (getUsername().empty()) {
-    /** @todo Ajouter ici un call à setRegistrationState(Error, "Fill balh") ? */
-    return false;
-  }
-  if (getPassword().empty()) {
-    /** @todo Même chose ici  ? */
-    return false;
-  }
+    tmp = "sip:" + hostname;
+    pj_strdup2(_pool, &svr, tmp.data());
+
+    tmp = "<sip:" + username + "@" + hostname + ">";
+    pj_strdup2(_pool, &aor, tmp.data());
 
-  return true;
+    sprintf(contactTmp, "<sip:%s@%s:%d>", username.data(), _localExternAddress.data(), _localExternPort);
+    pj_strdup2(_pool, &contact, contactTmp);
+    account->setContact(contactTmp);
+
+    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(); 
+        return false;
+    }
+
+    pjsip_cred_info *cred = account->getCredInfo();
+
+    if(!cred)
+        cred = new pjsip_cred_info();
+
+    pj_bzero(cred, sizeof (pjsip_cred_info));
+    pj_strdup2(_pool, &cred->username, username.data());
+    cred->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
+    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);
+
+    account->setCredInfo(cred);
+
+    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);
+    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()
+    int 
+SIPVoIPLink::sendUnregister( AccountID id )
 {
-  _debug("SEND UNREGISTER for account %s\n" , getAccountID().c_str());
-
-  if(!_bRegister){
-      setRegistrationState(VoIPLink::Unregistered); 
-      return true;
-  }
-  
-  _bRegister = false;
-  
-  Manager::instance().getUserAgent()->removeAccount(_regc);
-  
-  return true;
+    pj_status_t status = 0;
+    pjsip_tx_data *tdata = NULL;
+    SIPAccount *account;
+    pjsip_regc *regc;
+
+    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(status != PJ_SUCCESS) {
+            _debug("UserAgent: Unable to unregister regc.\n");
+            return false;
+        }
+
+        status = pjsip_regc_send( regc, tdata );
+        if(status != PJ_SUCCESS) {
+            _debug("UserAgent: Unable to send regc request.\n");
+            return false;
+        }
+    } else {
+        _debug("UserAgent: regc is null!\n");
+        return false;
+    }
+
+    account->setRegistrationInfo(regc);
+    account->setRegister(false);
+
+    return true;
 }
 
-Call* 
+    Call* 
 SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
 {
-  SIPCall* call = new SIPCall(id, Call::Outgoing);
-  if (call) {
-    //call->setPeerNumber(toUrl);
-    call->setPeerNumber(getSipTo(toUrl));
-    _debug("Try to make a call to: %s with call ID: %s\n", toUrl.data(), id.data());
-    // we have to add the codec before using it in SIPOutgoingInvite...
-    call->setCodecMap(Manager::instance().getCodecDescriptorMap());
-    if ( SIPOutgoingInvite(call) ) {
-      call->setConnectionState(Call::Progressing);
-      call->setState(Call::Active);
-      addCall(call);
-    } else {
-      delete call; call = 0;
+    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());
+        // we have to add the codec before using it in SIPOutgoingInvite...
+        call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+        if ( SIPOutgoingInvite(call) ) {
+            call->setConnectionState(Call::Progressing);
+            call->setState(Call::Active);
+            addCall(call);
+        } else {
+            delete call; call = 0;
+        }
     }
-  }
-  return call;
+    return call;
 }
 
-bool
+    bool
 SIPVoIPLink::answer(const CallID& id)
 {
-  _debug("- SIP Action: start answering\n");
 
-  SIPCall* call = getSIPCall(id);
-  if (call==0) {
-    _debug("! SIP Failure: SIPCall doesn't exists\n");
-    return false;
-  }
-
-  int i = Manager::instance().getUserAgent()->answer(call);
-  
-  if (i != 0) {
-    _debug("< SIP Building Error: send 400 Bad Request\n");
-  } else {
-    // use exosip, bug locked
-    i = 0;
-    _debug("* SIP Info: Starting AudioRTP when answering\n");
-    if (_audiortp->createNewSession(call) >= 0) {
-      call->setAudioStart(true);
-      call->setConnectionState(Call::Connected);
-      call->setState(Call::Active);
-      return true;
-    } else {
-      _debug("! SIP Failure: Unable to start sound when answering %s/%d\n", __FILE__, __LINE__);
+    int i;
+    SIPCall *call;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+
+    _debug("- SIP Action: start answering\n");
+
+    call = getSIPCall(id);
+
+    if (call==0) {
+        _debug("! SIP Failure: SIPCall doesn't exists\n");
+        return false;
+    }
+
+    // User answered the incoming call, tell peer this news
+    if (call->startNegociation(_pool)) {
+        // Create and send a 200(OK) response
+        _debug("UserAgent: Negociation success!\n");
+        status = pjsip_inv_answer(call->getInvSession(), PJSIP_SC_OK, NULL, NULL, &tdata);
+        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+        status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+        _debug("* SIP Info: Starting AudioRTP when answering\n");
+        if (_audiortp->createNewSession(call) >= 0) {
+            call->setAudioStart(true);
+            call->setConnectionState(Call::Connected);
+            call->setState(Call::Active);
+            return true;
+        } else {
+            _debug("! SIP Failure: Unable to start sound when answering %s/%d\n", __FILE__, __LINE__);
+        }
     }
-  }
-  removeCall(call->getCallId());
-  return false;
+    removeCall(call->getCallId());
+    return false;
 }
 
-bool
+    bool
 SIPVoIPLink::hangup(const CallID& id)
 {
-    SIPCall* call = getSIPCall(id);
+    pj_status_t status;
+    pjsip_tx_data *tdata = NULL;
+    SIPCall* call;
+
+    call = getSIPCall(id);
+
     if (call==0) { _debug("! SIP Error: Call doesn't exist\n"); return false; }  
 
-    if(!Manager::instance().getUserAgent()->hangup(call))
+    // User hangup current call. Notify peer
+    status = pjsip_inv_end_session(call->getInvSession(), 404, NULL, &tdata);
+    if(status != PJ_SUCCESS)
         return false;
-  
+
+    if(tdata == NULL)
+        return true;
+
+    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+    if(status != PJ_SUCCESS)
+        return false;
+
+    call->getInvSession()->mod_data[getModId()] = NULL;
+    return true;
+
     // Release RTP thread
     if (Manager::instance().isCurrentCall(id)) {
         _debug("* SIP Info: Stopping AudioRTP for hangup\n");
         _audiortp->closeRtpSession();
     }
-    
+
     removeCall(id);
-    
+
     return true;
 }
 
-bool
+    bool
 SIPVoIPLink::cancel(const CallID& id)
 {
-  SIPCall* call = getSIPCall(id);
-  if (call==0) { _debug("! SIP Error: Call doesn't exist\n"); return false; }  
+    SIPCall* call = getSIPCall(id);
+    if (call==0) { _debug("! SIP Error: Call doesn't exist\n"); return false; }  
 
-  _debug("- SIP Action: Cancel call %s [cid: %3d]\n", id.data(), call->getCid()); 
+    _debug("- SIP Action: Cancel call %s [cid: %3d]\n", id.data(), call->getCid()); 
 
-  removeCall(id);
+    removeCall(id);
 
-  return true;
+    return true;
 }
 
-bool
+    bool
 SIPVoIPLink::onhold(const CallID& id)
 {
-  SIPCall* call = getSIPCall(id);
-  if (call==0) { _debug("! SIP Error: call doesn't exist\n"); return false; }  
 
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+    pjmedia_sdp_attr *attr;
+    pjmedia_sdp_session* local_sdp;
+    SIPCall* call;
+
+    call = getSIPCall(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();
 
-  // Stop sound
-  call->setAudioStart(false);
-  call->setState(Call::Hold);
-  _debug("* SIP Info: Stopping AudioRTP for onhold action\n");
-  _audiortp->closeRtpSession();
+    if( local_sdp == NULL ){
+        _debug("! SIP Failure: unable to find local_sdp\n");
+        return false;
+    }
+
+    /* Create re-INVITE with new offer */
+    // Remove all the attributes with the specified name
+    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendrecv");
+    attr = pjmedia_sdp_attr_create(_pool, "sendonly", NULL);
+    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
+
+    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp, &tdata);
+    if( status != PJ_SUCCESS )
+    {
+        _debug("On hold: creation of the Re-invite request failed\n");
+        return false;
+    }
+    /* Send the request */
+    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
 
-  return Manager::instance().getUserAgent()->onhold(call);
+    return (status == PJ_SUCCESS);
 }
 
-bool 
+    bool 
 SIPVoIPLink::offhold(const CallID& id)
 {
     SIPCall *call;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+    pjmedia_sdp_attr *attr;
+    pjmedia_sdp_session* local_sdp;
 
     call = getSIPCall(id);
+
     if (call==0) { 
         _debug("! SIP Error: Call doesn't exist\n"); 
         return false; 
     }
 
-    if(!Manager::instance().getUserAgent()->offhold(call))
+    local_sdp = call->getLocalSDPSession();
+    if( local_sdp == NULL ){
+        _debug("! SIP Failure: unable to find local_sdp\n");
+        return false;
+    }
+
+    /* Create re-INVITE with new offer */
+    // Remove all the attributes with the specified name
+    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendonly");
+    attr = pjmedia_sdp_attr_create(_pool, "sendrecv", NULL);
+    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
+
+    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp , &tdata);
+    if( status != PJ_SUCCESS )
+    {
+        _debug("Off hold: creation of the Re-invite request failed\n");
+        return false;
+    }
+
+    /* Send the request */
+    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
+    if( status != PJ_SUCCESS )
         return false;
 
     // Enable audio
@@ -287,17 +599,28 @@ SIPVoIPLink::offhold(const CallID& id)
         _debug("! SIP Failure: Unable to start sound (%s:%d)\n", __FILE__, __LINE__);
         return false;
     }
-    
+
     return true;
 }
 
-bool 
+    bool 
 SIPVoIPLink::transfer(const CallID& id, const std::string& to)
 {
     SIPCall *call;
     std::string tmp_to;
+    pjsip_evsub *sub;
+    pjsip_tx_data *tdata;
+    struct pjsip_evsub_user xfer_cb;
+    pj_status_t status;
+    pj_str_t dest;
+    AccountID account_id;
+    Account* account;
+
 
     call = getSIPCall(id);
+    account_id = Manager::instance().getAccountFromCall(id);
+    account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(account_id));
+
     if (call==0) { 
         _debug("! SIP Failure: Call doesn't exist\n"); 
         return false; 
@@ -305,16 +628,48 @@ SIPVoIPLink::transfer(const CallID& id, const std::string& to)
 
     tmp_to = SIPToHeader(to);
     if (tmp_to.find("@") == std::string::npos) {
-        tmp_to = tmp_to + "@" + getHostname();
+        tmp_to = tmp_to + "@" + account->getHostname();
     }
 
     _debug("In transfer, tmp_to is %s\n", tmp_to.data());
 
-    return Manager::instance().getUserAgent()->transfer(call, tmp_to);
+    pj_strdup2(_pool, &dest, to.data());
+
+    /* Create xfer client subscription. */
+    pj_bzero(&xfer_cb, sizeof(xfer_cb));
+    xfer_cb.on_evsub_state = &xfer_func_cb;
+
+    status = pjsip_xfer_create_uac(call->getInvSession()->dlg, &xfer_cb, &sub);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create xfer -- %d\n", status);
+        return false;
+    }
+
+    /* Associate this voiplink of call with the client subscription 
+     * We can not just associate call with the client subscription
+     * because after this function, we can not find the cooresponding
+     * voiplink from the call any more. But the voiplink is useful!
+     */
+    AccountID accId = Manager::instance().getAccountFromCall(call->getCallId());
+    pjsip_evsub_set_mod_data(sub, getModId(), this);
+
+    /*
+     * Create REFER request.
+     */
+    status = pjsip_xfer_initiate(sub, &dest, &tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create REFER request -- %d\n", status);
+        return false;
+    }
+
+    /* Send. */
+    status = pjsip_xfer_send_request(sub, tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to send REFER request -- %d\n", status);
+        return false;
+    }
 
-  //_audiortp->closeRtpSession();
-  // shall we delete the call?
-  //removeCall(id);
+    return true;
 }
 
 bool SIPVoIPLink::transferStep2()
@@ -323,10 +678,13 @@ bool SIPVoIPLink::transferStep2()
     return true;
 }
 
-bool
+    bool
 SIPVoIPLink::refuse (const CallID& id)
 {
     SIPCall *call;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+
 
     call = getSIPCall(id);
 
@@ -341,10 +699,20 @@ SIPVoIPLink::refuse (const CallID& id)
         return false; 
     }
 
-    return Manager::instance().getUserAgent()->refuse(call);
+    // User refuse current call. Notify peer
+    status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_DECLINE, NULL, &tdata); //603
+    if(status != PJ_SUCCESS)
+        return false;
+
+    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+    if(status != PJ_SUCCESS)
+        return false;
+
+    call->getInvSession()->mod_data[getModId()] = NULL;
+    return true;
 }
 
-bool 
+    bool 
 SIPVoIPLink::carryingDTMFdigits(const CallID& id, char code)
 {
 
@@ -352,8 +720,14 @@ SIPVoIPLink::carryingDTMFdigits(const CallID& id, char code)
     int duration;
     const int body_len = 1000;
     char *dtmf_body;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+    pj_str_t methodName, content;
+    pjsip_method method;
+    pjsip_media_type ctype;
 
     call = getSIPCall(id);
+
     if (call==0) { 
         _debug("Call doesn't exist\n"); 
         return false; 
@@ -361,210 +735,1435 @@ SIPVoIPLink::carryingDTMFdigits(const CallID& id, char code)
 
     duration = Manager::instance().getConfigInt(SIGNALISATION, PULSE_LENGTH);
     dtmf_body = new char[body_len];
- 
+
     snprintf(dtmf_body, body_len - 1, "Signal=%c\r\nDuration=%d\r\n", code, duration);
- 
-    return Manager::instance().getUserAgent()->carryingDTMFdigits(call, dtmf_body);
+
+    pj_strdup2(_pool, &methodName, "INFO");
+    pjsip_method_init_np(&method, &methodName);
+
+    /* Create request message. */
+    status = pjsip_dlg_create_request( call->getInvSession()->dlg, &method, -1, &tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create INFO request -- %d\n", status);
+        return false;
+    }
+
+    /* Get MIME type */
+    pj_strdup2(_pool, &ctype.type, "application");
+    pj_strdup2(_pool, &ctype.subtype, "dtmf-relay");
+
+    /* Create "application/dtmf-relay" message body. */
+    pj_strdup2(_pool, &content, dtmf_body);
+    tdata->msg->body = pjsip_msg_body_create( tdata->pool, &ctype.type, &ctype.subtype, &content);
+    if (tdata->msg->body == NULL) {
+        _debug("UserAgent: Unable to create msg body!\n");
+        pjsip_tx_data_dec_ref(tdata);
+        return false;
+    }
+
+    /* Send the request. */
+    status = pjsip_dlg_send_request( call->getInvSession()->dlg, tdata, getModId(), NULL);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to send MESSAGE request -- %d\n", status);
+        return false;
+    }
+
+    return true;
 }
 
-bool
+    bool
 SIPVoIPLink::SIPOutgoingInvite(SIPCall* call) 
 {
-  // If no SIP proxy setting for direct call with only IP address
-  if (!SIPStartCall(call, "")) {
-    _debug("! SIP Failure: call not started\n");
-    return false;
-  }
-  return true;
+    // If no SIP proxy setting for direct call with only IP address
+    if (!SIPStartCall(call, "")) {
+        _debug("! SIP Failure: call not started\n");
+        return false;
+    }
+    return true;
 }
 
-bool
+    bool
 SIPVoIPLink::SIPStartCall(SIPCall* call, const std::string& subject UNUSED) 
 {
-    std::string to;
+    std::string strTo, strFrom;
+    pj_status_t status;
+    pjsip_dialog *dialog;
+    pjsip_tx_data *tdata;
+    pj_str_t from, to, contact;
+    AccountID id;
+    SIPAccount *account;
 
     if (!call) 
         return false;
 
-    to = getSipTo(call->getPeerNumber());
-    _debug("            To: %s\n", to.data());
+    id = Manager::instance().getAccountFromCall(call->getCallId());
+    // Get the basic information about the callee account
+    account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(id));
 
-    return Manager::instance().getUserAgent()->makeOutgoingCall(to, call, getAccountID());
-}
+    strTo = getSipTo(call->getPeerNumber(), account->getHostname());
+    _debug("            To: %s\n", strTo.data());
+
+    // Generate the from URI
+    strFrom = "sip:" + account->getUsername() + "@" + account->getHostname();
+
+    // pjsip need the from and to information in pj_str_t format
+    pj_strdup2(_pool, &from, strFrom.data());
+    pj_strdup2(_pool, &to, strTo.data());
+    pj_strdup2(_pool, &contact, account->getContact().data());
+
+    // create the dialog (UAC)
+    status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from,
+            &contact,
+            &to,
+            NULL,
+            &dialog);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
+
+    setCallAudioLocal(call, getLocalIPAddress(), useStun(), getStunServer());
+    call->setIp(getLocalIP());
+
+    // Building the local SDP offer
+    call->createInitialOffer(_pool);
+
+    // Create the invite session for this call
+    pjsip_inv_session *inv;
+    status = pjsip_inv_create_uac(dialog, call->getLocalSDPSession(), 0, &inv);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
 
-std::string
-SIPVoIPLink::getSipFrom() {
+    // Set auth information
+    pjsip_auth_clt_set_credentials(&dialog->auth_sess, 1, account->getCredInfo());
 
-  // Form the From header field basis on configuration panel
-  std::string hostname;
-  
-  hostname = getHostname();
+    // Associate current call in the invite session
+    inv->mod_data[getModId()] = call;
 
-  if ( hostname.empty() ) {
-    hostname = _localIPAddress;
-  }
-  return SIPFromHeader(getUsername(), hostname);
+    status = pjsip_inv_invite(inv, &tdata);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
+
+    // Associate current invite session in the call
+    call->setInvSession(inv);
+
+    status = pjsip_inv_send_msg(inv, tdata);
+    if(status != PJ_SUCCESS) {
+        return false;
+    }
+
+    return true;
 }
 
-std::string
-SIPVoIPLink::getSipTo(const std::string& to_url) {
-  // Form the From header field basis on configuration panel
-  //bool isRegistered = (_eXosipRegID == EXOSIP_ERROR_STD) ? false : true;
+std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostname) {
+    // Form the From header field basis on configuration panel
+    //bool isRegistered = (_eXosipRegID == EXOSIP_ERROR_STD) ? false : true;
 
-  // add a @host if we are registered and there is no one inside the url
+    // add a @host if we are registered and there is no one inside the url
     if (to_url.find("@") == std::string::npos) {// && isRegistered) {
-    std::string host = getHostname();
-    if(!host.empty()) {
-      return SIPToHeader(to_url + "@" + host);
+        if(!hostname.empty()) {
+            return SIPToHeader(to_url + "@" + hostname);
+        }
+    }
+    return SIPToHeader(to_url);
     }
-  }
-  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)
-{
-  return true;
-}
+    bool
+        SIPVoIPLink::SIPCheckUrl(const std::string& url UNUSED)
+        {
+            return true;
+        }
+
+    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);
+
+        // Set local audio port for SIPCall(id)
+        call->setLocalIp(localIP);
+        call->setLocalAudioPort(callLocalAudioPort);
+        call->setLocalExternAudioPort(callLocalExternAudioPort);
+
+        return true;
+    }
 
-bool
-SIPVoIPLink::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();
-    }
-  }
-  _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);
-
-  return true;
-}
+    void
+        SIPVoIPLink::SIPCallServerFailure(SIPCall *call) 
+        {
+            //if (!event->response) { return; }
+            //switch(event->response->status_code) {
+            //case SIP_SERVICE_UNAVAILABLE: // 500
+            //case SIP_BUSY_EVRYWHERE:     // 600
+            //case SIP_DECLINE:             // 603
+            //SIPCall* call = findSIPCallWithCid(event->cid);
+            if (call != 0) {
+                _debug("Server error!\n");
+                CallID id = call->getCallId();
+                Manager::instance().callFailure(id);
+                removeCall(id);
+            }
+            //break;
+            //}
+        }
+
+    void
+        SIPVoIPLink::SIPCallClosed(SIPCall *call) 
+        {
+            // it was without did before
+            //SIPCall* call = findSIPCallWithCid(event->cid);
+            if (!call) { return; }
+
+            CallID id = call->getCallId();
+            //call->setDid(event->did);
+            if (Manager::instance().isCurrentCall(id)) {
+                call->setAudioStart(false);
+                _debug("* SIP Info: Stopping AudioRTP when closing\n");
+                _audiortp->closeRtpSession();
+            }
+            _debug("After close RTP\n");
+            Manager::instance().peerHungupCall(id);
+            removeCall(id);
+            _debug("After remove call ID\n");
+        }
+
+    void
+        SIPVoIPLink::SIPCallReleased(SIPCall *call)
+        {
+            // do cleanup if exists
+            // only cid because did is always 0 in these case..
+            //SIPCall* call = findSIPCallWithCid(event->cid);
+            if (!call) { return; }
+
+            // if we are here.. something when wrong before...
+            _debug("SIP call release\n");
+            CallID id = call->getCallId();
+            Manager::instance().callFailure(id);
+            removeCall(id);
+        }
+
+    void
+        SIPVoIPLink::SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata)
+        {
+            //SIPCall* call = dynamic_cast<SIPCall *>(theCall);//findSIPCallWithCid(event->cid);
+            if (!call) {
+                _debug("! SIP Failure: unknown call\n");
+                return;
+            }
+            //call->setDid(event->did);
+
+            if (call->getConnectionState() != Call::Connected) {
+                //call->SIPCallAnswered(event);
+                call->SIPCallAnsweredWithoutHold(rdata);
+
+                call->setConnectionState(Call::Connected);
+                call->setState(Call::Active);
+
+                Manager::instance().peerAnsweredCall(call->getCallId());
+                if (Manager::instance().isCurrentCall(call->getCallId())) {
+                    _debug("* SIP Info: Starting AudioRTP when answering\n");
+                    if ( _audiortp->createNewSession(call) < 0) {
+                        _debug("RTP Failure: unable to create new session\n");
+                    } else {
+                        call->setAudioStart(true);
+                    }
+                }
+            } else {
+                _debug("* SIP Info: Answering call (on/off hold to send ACK)\n");
+                //call->SIPCallAnswered(event);
+            }
+        }
+
+
+    SIPCall*
+        SIPVoIPLink::getSIPCall(const CallID& id) 
+        {
+            Call* call = getCall(id);
+            if (call) {
+                return dynamic_cast<SIPCall*>(call);
+            }
+            return NULL;
+        }
+
+    void SIPVoIPLink::setStunServer( const std::string &server )
+    {
+         if(server != "") {
+            useStun(true);
+            _stunServer = server;
+        } else {
+            useStun(false);
+            _stunServer = std::string("");
+        }
+    }
 
-void
-SIPVoIPLink::SIPCallServerFailure(SIPCall *call) 
-{
-  //if (!event->response) { return; }
-  //switch(event->response->status_code) {
-  //case SIP_SERVICE_UNAVAILABLE: // 500
-  //case SIP_BUSY_EVRYWHERE:     // 600
-  //case SIP_DECLINE:             // 603
-    //SIPCall* call = findSIPCallWithCid(event->cid);
-    if (call != 0) {
-        _debug("Server error!\n");
-        CallID id = call->getCallId();
-        Manager::instance().callFailure(id);
-        removeCall(id);
-    }
-  //break;
-  //}
-}
+    ///////////////////////////////////////////////////////////////////////////////
+    // Private functions
+    ///////////////////////////////////////////////////////////////////////////////
+
+    bool SIPVoIPLink::pjsip_init()
+    {
+        pj_status_t status;
+        int errPjsip = 0;
+        int port;
+        pjsip_inv_callback inv_cb;
+        pj_str_t accepted;
+        std::string name_mod;
+        bool useStun;
+        validStunServer = true;
+
+        name_mod = "sflphone";
+
+        // Init PJLIB: must be called before any call to the pjsip library
+        status = pj_init();
+        // Use pjsip macros for sanity check
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Init PJLIB-UTIL library 
+        status = pjlib_util_init();
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Set the pjsip log level
+        pj_log_set_level( PJ_LOG_LEVEL );
+
+        // Init PJNATH 
+        status = pjnath_init();
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Create a pool factory to allocate memory
+        pj_caching_pool_init(&_cp, &pj_pool_factory_default_policy, 0);
+
+        // Create memory pool for application. 
+        _pool = pj_pool_create(&_cp.factory, "sflphone", 4000, 4000, NULL);
+
+        if (!_pool) {
+            _debug("UserAgent: Could not initialize memory pool\n");
+            return PJ_ENOMEM;
+        }
+
+        // Create the SIP endpoint 
+        status = pjsip_endpt_create(&_cp.factory, pj_gethostname()->ptr, &_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        /* Start resolving STUN server */
+        // if we useStun and we failed to receive something on port 5060, we try a random port
+        // If use STUN server, firewall address setup
+        if (!loadSIPLocalIP()) {
+            _debug("UserAgent: Unable to determine network capabilities\n");
+            return false;
+        }
+
+        port = _regPort;
+
+        /* 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(getStunServer(), port)) {
+                _debug("UserAgent: Unable to check NAT setting\n");
+                validStunServer = false;		
+                return false; // hoho we can't use the random sip port too...
+            }
+        }
+
+        _localPort = port;
+        if (useStun) {
+            // set by last behindNat() call (ish)...
+            stunServerResolve();
+            _localExternAddress = Manager::instance().getFirewallAddress();
+            _localExternPort = Manager::instance().getFirewallPort();
+            errPjsip = createUDPServer();
+            if (errPjsip != 0) {
+                _debug("UserAgent: Could not initialize SIP listener on port %d\n", port);
+                return errPjsip;
+            }
+        } else {
+            _localExternAddress = _localIPAddress;
+            _localExternPort = _localPort;
+            errPjsip = createUDPServer();
+            if (errPjsip != 0) {
+                _debug("UserAgent: Could not initialize SIP listener on port %d\n", _localExternPort);
+                _localExternPort = _localPort = RANDOM_SIP_PORT;
+                _debug("UserAgent: Try to initialize SIP listener on port %d\n", _localExternPort);
+                errPjsip = createUDPServer();
+                if (errPjsip != 0) {
+                    _debug("UserAgent: Fail to initialize SIP listener on port %d\n", _localExternPort);
+                    return errPjsip;
+                }
+            }
+        }
+
+        _debug("UserAgent: SIP Init -- listening on port %d\n", _localExternPort);
+
+        // Initialize transaction layer
+        status = pjsip_tsx_layer_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize UA layer module
+        status = pjsip_ua_init_module(_endpt, NULL);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize Replaces support. See the Replaces specification in RFC 3891
+        status = pjsip_replaces_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize 100rel support 
+        status = pjsip_100rel_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize and register sflphone module
+        _mod_ua.name = pj_str((char*)name_mod.c_str());
+        _mod_ua.id = -1;
+        _mod_ua.priority = PJSIP_MOD_PRIORITY_APPLICATION;
+        _mod_ua.on_rx_request = &mod_on_rx_request;
+        _mod_ua.on_rx_response = &mod_on_rx_response;
+
+        status = pjsip_endpt_register_module(_endpt, &_mod_ua);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Init the event subscription module.
+        // It extends PJSIP by supporting SUBSCRIBE and NOTIFY methods
+        status = pjsip_evsub_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 );
+
+        // Init the callback for INVITE session: 
+        // TODO The invite session as global ?
+        pj_bzero(&inv_cb, sizeof (inv_cb));
+
+        inv_cb.on_state_changed = &call_on_state_changed;
+        inv_cb.on_new_session = &call_on_forked;
+        inv_cb.on_media_update = &call_on_media_update;
+        inv_cb.on_tsx_state_changed = &call_on_tsx_changed;
+
+        // Initialize session invite module 
+        status = pjsip_inv_usage_init(_endpt, &inv_cb);
+        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+        _debug("UserAgent: VOIP callbacks initialized\n");
+
+        // Add endpoint capabilities (INFO, OPTIONS, etc) for this UA
+        pj_str_t allowed[] = { {(char*)"INFO", 4}, {(char*)"REGISTER", 8} }; //  //{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},  {"OPTIONS", 7}, 
+        accepted = pj_str((char*)"application/sdp");
+
+        // Register supported methods
+        pjsip_endpt_add_capability(_endpt, &_mod_ua, PJSIP_H_ALLOW, NULL, PJ_ARRAY_SIZE(allowed), allowed);
+
+        // Register "application/sdp" in ACCEPT header
+        pjsip_endpt_add_capability(_endpt, &_mod_ua, PJSIP_H_ACCEPT, NULL, 1, &accepted);
+
+        _debug("UserAgent: pjsip version %s for %s initialized\n", pj_get_version(), PJ_OS_NAME);
+
+        //TODO Create the secondary thread to poll sip events
+        _evThread->start();
+
+        /* Done! */
+        return PJ_SUCCESS;
+    }
 
-void
-SIPVoIPLink::SIPCallClosed(SIPCall *call) 
-{
-  // it was without did before
-  //SIPCall* call = findSIPCallWithCid(event->cid);
-  if (!call) { return; }
+    pj_status_t SIPVoIPLink::stunServerResolve( void )
+    {
+        pj_str_t stun_adr;
+        pj_hostent he;
+        pj_stun_config stunCfg;
+        pj_status_t stun_status;
+        pj_sockaddr stun_srv;
+        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));
+
+        stun_status = PJ_EPENDING;
+
+        // Init STUN socket
+        pos = stun_server.find(':');
+        if(pos == std::string::npos) {
+            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 = 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);
+        }
+
+        if (stun_status != PJ_SUCCESS) {
+            _debug("UserAgent: Unresolved stun server!\n");
+            stun_status = pj_gethostbyname(&stun_adr, &he);
+
+            if (stun_status == PJ_SUCCESS) {
+                pj_sockaddr_in_init(&stun_srv.ipv4, NULL, 0);
+                stun_srv.ipv4.sin_addr = *(pj_in_addr*) he.h_addr;
+                stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t) 3478);
+            }
+        }
+
+        return stun_status;
+    }
 
-  CallID id = call->getCallId();
-  //call->setDid(event->did);
-  if (Manager::instance().isCurrentCall(id)) {
-    call->setAudioStart(false);
-    _debug("* SIP Info: Stopping AudioRTP when closing\n");
-    _audiortp->closeRtpSession();
-  }
-  _debug("After close RTP\n");
-  Manager::instance().peerHungupCall(id);
-  removeCall(id);
-  _debug("After remove call ID\n");
-}
+    int SIPVoIPLink::createUDPServer( void ) 
+    {
+
+        pj_status_t status;
+        pj_sockaddr_in bound_addr;
+        pjsip_host_port a_name;
+        char tmpIP[32];
+        pj_sock_t sock;
+
+        // Init bound address to ANY
+        pj_memset(&bound_addr, 0, sizeof (bound_addr));
+        bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
+
+        // Create UDP server socket
+        status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock);
+        if (status != PJ_SUCCESS) {
+            _debug("UserAgent: (%d) UDP socket() error\n", status);
+            return status;
+        }
+
+        status = pj_sock_bind_in(sock, pj_ntohl(bound_addr.sin_addr.s_addr), (pj_uint16_t) _localPort);
+        if (status != PJ_SUCCESS) {
+            _debug("UserAgent: (%d) UDP bind() error\n", status);
+            pj_sock_close(sock);
+            return status;
+        }
+
+        _debug("UserAgent: Use IP: %s\n", _localExternAddress.data());
+
+        // Create UDP-Server (default port: 5060)
+        strcpy(tmpIP, _localExternAddress.data());
+        pj_strdup2(_pool, &a_name.host, tmpIP);
+        a_name.port = (pj_uint16_t) _localExternPort;
+
+        _debug("a_name: host: %s  - port : %i\n", a_name.host.ptr, a_name.port);
+
+        status = pjsip_udp_transport_attach(_endpt, sock, &a_name, 1, NULL);
+        if (status != PJ_SUCCESS) {
+            _debug("UserAgent: (%d) Unable to start UDP transport!\n", status);
+            return -1;
+        } else {
+            _debug("UserAgent: UDP server listening on port %d\n", _localExternPort);
+        }
+
+        return PJ_SUCCESS;
+    }
 
-void
-SIPVoIPLink::SIPCallReleased(SIPCall *call)
-{
-  // do cleanup if exists
-  // only cid because did is always 0 in these case..
-  //SIPCall* call = findSIPCallWithCid(event->cid);
-  if (!call) { return; }
-
-  // if we are here.. something when wrong before...
-  _debug("SIP call release\n");
-  CallID id = call->getCallId();
-  Manager::instance().callFailure(id);
-  removeCall(id);
-}
+    bool SIPVoIPLink::loadSIPLocalIP() {
+
+        bool returnValue = true;
+
+        if (_localIPAddress == "127.0.0.1") {
+            pj_sockaddr ip_addr;
+            if (pj_gethostip(pj_AF_INET(), &ip_addr) != PJ_SUCCESS) {
+                // Update the registration state if no network capabilities found
+                _debug("UserAgent: Get host ip failed!\n");
+                returnValue = false;
+            } else {
+                _localIPAddress = std::string(pj_inet_ntoa(ip_addr.ipv4.sin_addr));
+                _debug("UserAgent: Checking network, setting local IP address to: %s\n", _localIPAddress.data());
+            }
+        }
+        return returnValue;
+    }
 
-void
-SIPVoIPLink::SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata)
-{
-  //SIPCall* call = dynamic_cast<SIPCall *>(theCall);//findSIPCallWithCid(event->cid);
-  if (!call) {
-    _debug("! SIP Failure: unknown call\n");
-    return;
-  }
-  //call->setDid(event->did);
-
-  if (call->getConnectionState() != Call::Connected) {
-    //call->SIPCallAnswered(event);
-    call->SIPCallAnsweredWithoutHold(rdata);
-
-    call->setConnectionState(Call::Connected);
-    call->setState(Call::Active);
+    bool SIPVoIPLink::pjsip_shutdown( void )
+    {
+        /* Destroy endpoint. */
+        if (_endpt) {
+            pjsip_endpt_destroy(_endpt);
+            _endpt = NULL;
+        }
+
+        /* Destroy pool and pool factory. */
+        if (_pool) {
+            pj_pool_release(_pool);
+            _pool = NULL;
+            pj_caching_pool_destroy(&_cp);
+        }
+
+        /* Shutdown PJLIB */
+        pj_shutdown();
+
+        /* Done. */    
+    }
 
-    Manager::instance().peerAnsweredCall(call->getCallId());
-    if (Manager::instance().isCurrentCall(call->getCallId())) {
-      _debug("* SIP Info: Starting AudioRTP when answering\n");
-      if ( _audiortp->createNewSession(call) < 0) {
-        _debug("RTP Failure: unable to create new session\n");
-      } else {
-        call->setAudioStart(true);
-      }
-    }
-  } else {
-     _debug("* SIP Info: Answering call (on/off hold to send ACK)\n");
-     //call->SIPCallAnswered(event);
-  }
-}
+    int SIPVoIPLink::getModId(){
+        return _mod_ua.id;
+    }
 
+    void set_voicemail_info( AccountID account, pjsip_msg_body *body ){
 
-SIPCall*
-SIPVoIPLink::getSIPCall(const CallID& id) 
-{
-  Call* call = getCall(id);
-  if (call) {
-    return dynamic_cast<SIPCall*>(call);
-  }
-  return NULL;
-}
+        int voicemail, pos_begin, pos_end;
+        std::string voice_str = "Voice-Message: ";
+        std::string delimiter = "/";
+        std::string msg_body, voicemail_str;
 
-///////////////////////////////////////////////////////////////////////////////
-// Private functions
-///////////////////////////////////////////////////////////////////////////////
+        _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
 
-pj_str_t SIPVoIPLink::string2PJStr(const std::string &value)
-{
-    char tmp[256];
-    
-    strcpy(tmp, value.data());
-    return pj_str(tmp);
-}
+        // 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);
+    }
+
+    /*******************************/
+    /*   CALLBACKS IMPLEMENTATION  */
+    /*******************************/
+
+    void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){
+
+        PJ_UNUSED_ARG(inv);
+
+        SIPCall *call = reinterpret_cast<SIPCall*> (inv->mod_data[_mod_ua.id]);
+        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 call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED) {
+        _debug("call_on_media_updated\n");
+    }
+
+    void call_on_forked(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){
+
+        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[_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");
+
+                        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;
+                        }
+                        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");
+                        //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;
+                        }
+
+                        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 regc_cb(struct pjsip_regc_cbparam *param){
+
+        //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);
+        account = static_cast<SIPAccount *>(param->token);
+        if(!account)
+            return;
+
+        if (param->status == PJ_SUCCESS) {
+            if (param->code < 0 || param->code >= 300) {
+                /* Sometimes, the status is OK, but we still failed.
+                 * So checking the code for real result
+                 */
+                _debug("UserAgent: The error is: %d\n", param->code);
+                switch(param->code) {
+                    case 408:
+                    case 606:
+                        account->setRegistrationState(ErrorConfStun);
+                        break;
+                    case 503:
+                        account->setRegistrationState(ErrorHost);
+                        break;
+                    case 401:
+                    case 403:
+                    case 404:
+                        account->setRegistrationState(ErrorAuth);
+                        break;
+                    default:
+                        account->setRegistrationState(Error);
+                        break;
+                }
+                account->setRegister(false);
+            } else {
+                // Registration/Unregistration is success
+
+                if(account->isRegister())
+                    account->setRegistrationState(Registered);
+                else {
+                    account->setRegistrationState(Unregistered);
+                    account->setRegister(false);
+                }
+            }
+        } else {
+            account->setRegistrationState(ErrorAuth);
+            account->setRegister(false);
+        }
+
+    }
+
+    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;
+            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;
+            }
+
+            _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);
+
+            /* 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;
+                }
+            }
+
+            // 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!
+            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;
+            }
+
+            // 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 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;
+            }
+
+            // 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;
+
+            // 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 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.
+             */
+            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_ua.id,
+                    newCall);
+        }    
+    }
+
+
+
+
+    void 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,
+                        _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;
+
+            /* 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, 
+                        _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");
+
+            }
+
+            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, _mod_ua.id, NULL);
+            }
+        }
+
+    }
+
+
+    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;
+
+            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/sipvoiplink.h b/src/sipvoiplink.h
index 865703e2151eb4345c40e178b5fa2187aa06230a..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
@@ -23,284 +23,316 @@
 #define SIPVOIPLINK_H
 
 #include "voiplink.h"
-#include "useragent.h"
+
+//////////////////////////////
+/* PJSIP imports */
+#include <pjsip.h>
+#include <pjlib.h>
+#include <pjsip_ua.h>
+#include <pjlib-util.h>
+#include <pjnath/stun_config.h>
+///////////////////////////////
+
 
 class EventThread;
 class SIPCall;
 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
 {
-  public:
-
-    /**
-     * Constructor
-     * @param accountID The account identifier
-     */
-    SIPVoIPLink(const AccountID& accountID);
-
-    /**
-     * Destructor
-     */
-    ~SIPVoIPLink();
-
-    /* Copy Constructor */
-    SIPVoIPLink(const SIPVoIPLink& rh);
-
-    /* Assignment Operator */
-    SIPVoIPLink& operator=( const SIPVoIPLink& rh);
-   
-    /** 
-     * Try to initiate the pjsip engine/thread and set config 
-     * @return bool True if OK
-     */
-    bool init(void);
-
-    /**
-     * Delete link-related stuuf like calls
-     */
-    void terminate(void);
-
-    /**
-     * Event listener. Each event send by the call manager is received and handled from here
-     */
-    void getEvent(void);
-
-    /**
-     * Build and send SIP registration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    int sendRegister(void);
-
-    /**
-     * Build and send SIP unregistration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    int sendUnregister(void);
-
-    /**
-     * Place a new call
-     * @param id  The call identifier
-     * @param toUrl  The Sip address of the recipient of the call
-     * @return Call* The current call
-     */
-    Call* newOutgoingCall(const CallID& id, const std::string& toUrl);
-
-    /**
-     * Answer the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool answer(const CallID& id);
-
-    /**
-     * Hang up the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool hangup(const CallID& id);
-
-    /**
-     * Cancel the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool cancel(const CallID& id);
-
-    /**
-     * Put the call on hold
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool onhold(const CallID& id);
-
-    /**
-     * Put the call off hold
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool offhold(const CallID& id);
-
-    /**
-     * Transfer the call
-     * @param id The call identifier
-     * @param to The recipient of the transfer
-     * @return bool True on success
-     */
-    bool transfer(const CallID& id, const std::string& to);
-
-    /** Handle the incoming refer msg, not finished yet */
-    bool transferStep2();
-
-    /**
-     * Refuse the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool refuse (const CallID& id);
-
-    /**
-     * Send DTMF
-     * @param id The call identifier
-     * @param code  The char code
-     * @return bool True on success
-     */
-    bool carryingDTMFdigits(const CallID& id, char code);
-
-    /** 
-     * If set to true, we check for a firewall
-     * @param use true if we use STUN
-     */
-    void setUseStun(bool use) { _useStun = use; }
-
-    /** 
-     * The name of the STUN server
-     * @param server Server FQDN/IP
-     */
-    void setStunServer(const std::string& server) { _stunServer = server; }
-
-    bool isRegister() {return _bRegister;}
-    
-    void setRegister(bool result) {_bRegister = result;}
-
-  public:
-
-    /** 
-     * Terminate every call not hangup | brutal | Protected by mutex 
-     */
-    void terminateSIPCall(); 
-    
-    /**
-     * send SIP authentification
-     * @return bool true if sending succeed
-     */
-    bool sendSIPAuthentification();
-
-    /**
-     * Get a SIP From header ("fullname" <sip:userpart@hostpart>)
-     * @param userpart User part
-     * @param hostpart Host name
-     * @return std::string  SIP URI for from Header
-     */
-    std::string SIPFromHeader(const std::string& userpart, const std::string& hostpart);
-
-    /**
-     * Build a sip address with the number that you want to call
-     * Example: sip:124@domain.com
-     * @param to  The header of the recipient
-     * @return std::string  Result as a string
-     */
-    std::string SIPToHeader(const std::string& to);
-
-    /**
-     * Check if an url is sip-valid
-     * @param url The url to check
-     * @return bool True if osip tell that is valid
-     */
-    bool SIPCheckUrl(const std::string& url);
-
-
-    /**
-     * Send an outgoing call invite
-     * @param call  The current call
-     * @return bool True if all is correct
-     */
-    bool SIPOutgoingInvite(SIPCall* call);
-
-    /**
-     * Start a SIP Call
-     * @param call  The current call
-     * @param subject Undocumented
-     * @return true if all is correct
-     */
-    bool SIPStartCall(SIPCall* call, const std::string& subject);
-
-    /**
-     * Get the Sip FROM url (add sip:, add @host, etc...)
-     * @return std::string  The From url
-     */
-    std::string getSipFrom();
-
-    /**
-     * Get the Sip TO url (add sip:, add @host, etc...)
-     * @param to_url  The To url
-     * @return std::string  The SIP to address
-     */
-    std::string getSipTo(const std::string& to_url);
-
-    /**
-     * Set audio (SDP) configuration for a call
-     * localport, localip, localexternalport
-     * @param call a SIPCall valid pointer
-     * @return bool True
-     */
-    bool setCallAudioLocal(SIPCall* call);
-
-    /**
-     * Tell the user that the call was answered
-     * @param
-     */
-    void SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata);
-    
-    /**
-     * Handling 5XX/6XX error
-     * @param 
-     */
-    void SIPCallServerFailure(SIPCall *call);
-
-    /**
-     * Peer close the connection
-     * @param
-     */
-    void SIPCallClosed(SIPCall *call);
-
-    /**
-     * The call pointer was released
-     * If the call was not cleared before, report an error
-     * @param
-     */
-    void SIPCallReleased(SIPCall *call);
-
-    /**
-     * SIPCall accessor
-     * @param id  The call identifier
-     * @return SIPCall*	  A pointer on SIPCall object
-     */
-    SIPCall* getSIPCall(const CallID& id);
-
-    /** Tell if the initialisation was done */
-    bool _initDone;
-
-    /** when we init the listener, how many times we try to bind a port? */
-    int _nbTryListenAddr;
-
-    /** Do we use stun? */
-    bool _useStun;
-
-    /** What is the stun server? */
-    std::string _stunServer;
-
-    /** Local Extern Address is the IP address seen by peers for SIP listener */
-    std::string _localExternAddress;
-
-    /** Local Extern Port is the port seen by peers for SIP listener */
-    unsigned int _localExternPort;  
-
-    /** Starting sound */
-    AudioRtp* _audiortp;
-    
-    pj_str_t string2PJStr(const std::string &value);
-
-private:
-    pjsip_regc *_regc;
-    bool _bRegister;
+    public:
+
+        /**
+         * Singleton method. Enable to retrieve the unique static instance
+         * @return SIPVoIPLink* A pointer on the object
+         */
+        static SIPVoIPLink* instance( const AccountID& id );
+
+        /**
+         * Destructor
+         */
+        ~SIPVoIPLink();
+
+        /* Copy Constructor */
+        SIPVoIPLink(const SIPVoIPLink& rh);
+
+        /* Assignment Operator */
+        SIPVoIPLink& operator=( const SIPVoIPLink& rh);
+
+        /** 
+         * Try to initiate the pjsip engine/thread and set config 
+         * @return bool True if OK
+         */
+        bool init(void);
+
+        /**
+         * Shut the library and clean up
+         */
+        void terminate( void );
+
+        /**
+         * Event listener. Each event send by the call manager is received and handled from here
+         */
+        void getEvent(void);
+
+        /**
+         * Build and send SIP registration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        int sendRegister(AccountID id);
+
+        /**
+         * Build and send SIP unregistration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        int sendUnregister(AccountID id);
+
+        /**
+         * Place a new call
+         * @param id  The call identifier
+         * @param toUrl  The Sip address of the recipient of the call
+         * @return Call* The current call
+         */
+        Call* newOutgoingCall(const CallID& id, const std::string& toUrl);
+
+        /**
+         * Answer the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool answer(const CallID& id);
+
+        /**
+         * Hang up the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool hangup(const CallID& id);
+
+        /**
+         * Cancel the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool cancel(const CallID& id);
+
+        /**
+         * Put the call on hold
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool onhold(const CallID& id);
+
+        /**
+         * Put the call off hold
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool offhold(const CallID& id);
+
+        /**
+         * Transfer the call
+         * @param id The call identifier
+         * @param to The recipient of the transfer
+         * @return bool True on success
+         */
+        bool transfer(const CallID& id, const std::string& to);
+
+        /** Handle the incoming refer msg, not finished yet */
+        bool transferStep2();
+
+        /**
+         * Refuse the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool refuse (const CallID& id);
+
+        /**
+         * Send DTMF
+         * @param id The call identifier
+         * @param code  The char code
+         * @return bool True on success
+         */
+        bool carryingDTMFdigits(const CallID& id, char code);
+
+        /** 
+         * If set to true, we check for a firewall
+         * @param use true if we use STUN
+         */
+        inline void useStun(bool use) { _useStun=use; }
+
+        inline bool useStun( void ) { return _useStun; }
+
+        /** 
+         * The name of the STUN server
+         * @param server Server FQDN/IP
+         */
+        void setStunServer(const std::string& server);
+
+        std::string getStunServer (void) { return _stunServer; }
+
+        /** 
+         * Terminate every call not hangup | brutal | Protected by mutex 
+         */
+        void terminateSIPCall(); 
+
+        /**
+         * Build a sip address with the number that you want to call
+         * Example: sip:124@domain.com
+         * @param to  The header of the recipient
+         * @return std::string  Result as a string
+         */
+        std::string SIPToHeader(const std::string& to);
+
+        /**
+         * Check if an url is sip-valid
+         * @param url The url to check
+         * @return bool True if osip tell that is valid
+         */
+        bool SIPCheckUrl(const std::string& url);
+
+
+        /**
+         * Send an outgoing call invite
+         * @param call  The current call
+         * @return bool True if all is correct
+         */
+        bool SIPOutgoingInvite(SIPCall* call);
+
+        /**
+         * Start a SIP Call
+         * @param call  The current call
+         * @param subject Undocumented
+         * @return true if all is correct
+         */
+        bool SIPStartCall(SIPCall* call, const std::string& subject);
+
+        /**
+         * Get the Sip TO url (add sip:, add @host, etc...)
+         * @param to_url  The To url
+         * @return std::string  The SIP to address
+         */
+        std::string getSipTo(const std::string& to_url, std::string hostname);
+
+        /**
+         * Tell the user that the call was answered
+         * @param
+         */
+        void SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata);
+
+        /**
+         * Handling 5XX/6XX error
+         * @param 
+         */
+        void SIPCallServerFailure(SIPCall *call);
+
+        /**
+         * Peer close the connection
+         * @param
+         */
+        void SIPCallClosed(SIPCall *call);
+
+        /**
+         * The call pointer was released
+         * If the call was not cleared before, report an error
+         * @param
+         */
+        void SIPCallReleased(SIPCall *call);
+
+        /**
+         * SIPCall accessor
+         * @param id  The call identifier
+         * @return SIPCall*	  A pointer on SIPCall object
+         */
+        SIPCall* getSIPCall(const CallID& id);
+
+        /** when we init the listener, how many times we try to bind a port? */
+        int _nbTryListenAddr;
+
+        /** Starting sound */
+        AudioRtp* _audiortp;
+
+        /** 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
+         *
+         * @return bool True on success
+         */
+        bool pjsip_init();
+
+        /**
+         * Delete link-related stuuf like calls
+         */
+        bool pjsip_shutdown(void);
+
+        /** Do we use stun? */
+        bool _useStun;
+
+        pj_status_t stunServerResolve();
+
+        /** Create SIP UDP Listener */
+        int createUDPServer();
+
+        bool loadSIPLocalIP();
+
+        std::string getLocalIP() {return _localExternAddress;}
+
+        /** For registration use only */
+        int _regPort;
+
+        /* Flag to check if the STUN server is valid or not */
+        bool validStunServer;
+
+        /** The current STUN server address */
+        std::string _stunServer;
+
+        /** Local Extern Address is the IP address seen by peers for SIP listener */
+        std::string _localExternAddress;
+
+        /** Local Extern Port is the port seen by peers for SIP listener */
+        unsigned int _localExternPort;
+
+        /** Threading object */
+        EventThread* _evThread;
+        ost::Mutex _mutexSIP;
+
+        /* 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 6e0e104cec4ada90606d980fbf15212e2870e450..0000000000000000000000000000000000000000
--- a/src/useragent.cpp
+++ /dev/null
@@ -1,1704 +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;
-}
-
-UserAgent::~UserAgent() {
-    _debug("UserAgent: In dtor!\n");
-    sipDestory();
-}
-
-pj_status_t UserAgent::sipCreate() {
-
-    pj_status_t status;
-
-    // Init PJLIB: must be called before any call to the pjsip library
-    status = pj_init();
-    // Use pjsip macros for sanity check
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Init PJLIB-UTIL library 
-    status = pjlib_util_init();
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Set the pjsip log level
-    pj_log_set_level( PJ_LOG_LEVEL );
-
-    // Init PJNATH 
-    status = pjnath_init();
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-    
-    // Create a pool factory to allocate memory
-    pj_caching_pool_init(&_cp, &pj_pool_factory_default_policy, 0);
-
-    // Create memory pool for application. 
-    _pool = pj_pool_create(&_cp.factory, "sflphone", 4000, 4000, NULL);
-
-    if (!_pool) {
-        _debug("UserAgent: Could not initialize memory pool\n");
-        return PJ_ENOMEM;
-    }
-
-    // Create a recursive mutex. Simple wrapper for pj_mutex_create 
-    status = pj_mutex_create_recursive(_pool, "sflphone", &_mutex);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Create the SIP endpoint 
-    status = pjsip_endpt_create(&_cp.factory, pj_gethostname()->ptr, &_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    return PJ_SUCCESS;
-}
-
-pj_status_t UserAgent::sipInit() {
-    
-    pj_status_t status;
-    int errPjsip = 0;
-    int port;
-    
-    validStunServer = true;
-    /* Init SIP UA: */
-
-    //FIXME! DNS initialize here! */
-
-    /* Start resolving STUN server */
-    // if we useStun and we failed to receive something on port 5060, we try a random port
-    // If use STUN server, firewall address setup
-    if (!loadSIPLocalIP()) {
-        _debug("UserAgent: Unable to determine network capabilities\n");
-        return false;
-    }
-    errPjsip = 0;
-    port = _regPort;
-
-    //_debug("stun host is %s\n", _stunHost.ptr);
-    if (_useStun && !Manager::instance().behindNat(_stunServer, port)) {
-        port = RANDOM_SIP_PORT;
-        if (!Manager::instance().behindNat(_stunServer, port)) {
-            _debug("UserAgent: Unable to check NAT setting\n");
-	    validStunServer = false;		
-            return false; // hoho we can't use the random sip port too...
-        }
-    }
-
-    _localPort = port;
-    if (_useStun) {
-        // set by last behindNat() call (ish)...
-        stunServerResolve();
-        _localExternAddress = Manager::instance().getFirewallAddress();
-        _localExternPort = Manager::instance().getFirewallPort();
-        errPjsip = createUDPServer();
-        if (errPjsip != 0) {
-            _debug("UserAgent: Could not initialize SIP listener on port %d\n", port);
-            return errPjsip;
-        }
-    } else {
-        _localExternAddress = _localIPAddress;
-        _localExternPort = _localPort;
-        errPjsip = createUDPServer();
-        if (errPjsip != 0) {
-            _debug("UserAgent: Could not initialize SIP listener on port %d\n", _localExternPort);
-            _localExternPort = _localPort = RANDOM_SIP_PORT;
-            _debug("UserAgent: Try to initialize SIP listener on port %d\n", _localExternPort);
-            errPjsip = createUDPServer();
-            if (errPjsip != 0) {
-                _debug("UserAgent: Fail to initialize SIP listener on port %d\n", _localExternPort);
-                return errPjsip;
-            }
-        }
-    }
-    
-    _debug("UserAgent: SIP Init -- listening on port %d\n", _localExternPort);
-
-    // Initialize transaction layer
-    status = pjsip_tsx_layer_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize UA layer module
-    status = pjsip_ua_init_module(_endpt, NULL);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize Replaces support. See the Replaces specification in RFC 3891
-    status = pjsip_replaces_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize 100rel support 
-    status = pjsip_100rel_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize and register sflphone module
-    {
-        const pjsip_module mod_initializer ={
-            NULL, NULL, 			// prev, next.			
-            { (char*)"mod-sflphone", 9}, 	// Name.				
-            -1,		 			// Id				
-            PJSIP_MOD_PRIORITY_APPLICATION, 	// Priority			
-            NULL, 				// load()				
-            NULL, 				// start()				
-            NULL, 				// stop()				
-            NULL, 				// unload()				
-            &mod_on_rx_request, 		// on_rx_request()			
-            &mod_on_rx_response, 		// on_rx_response()			
-            NULL, 				// on_tx_request.			
-            NULL, 				// on_tx_response()			
-            NULL, 				// on_tsx_state()			
-        };
-
-        _mod = mod_initializer;
-
-        status = pjsip_endpt_register_module(_endpt, &_mod);
-    	PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-        
-    }
-
-    // Init the event subscription module.
-    // It extends PJSIP by supporting SUBSCRIBE and NOTIFY methods
-    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 );
-        
-    // Initialize invite session module
-    // These callbacks will be called on incoming requests, media session state, etc.
-    {
-        pjsip_inv_callback inv_cb;
-
-        // Init the callback for INVITE session: 
-        pj_bzero(&inv_cb, sizeof (inv_cb));
-
-        inv_cb.on_state_changed = &call_on_state_changed;
-        inv_cb.on_new_session = &call_on_forked;
-        inv_cb.on_media_update = &call_on_media_update;
-        inv_cb.on_tsx_state_changed = &call_on_tsx_changed;
-
-        _debug("UserAgent: VOIP callbacks initialized\n");
-
-        // Initialize session invite module 
-        status = pjsip_inv_usage_init(_endpt, &inv_cb);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-    }
-
-
-    // Add endpoint capabilities (INFO, OPTIONS, etc) for this UA
-    {
-        pj_str_t allowed[] = {
-            			{(char*)"INFO", 4},
-            			{(char*)"REGISTER", 8}
-			      }; //  //{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},  {"OPTIONS", 7}, 
-        pj_str_t accepted = {(char*)"application/sdp", 15};
-
-        // Register supported methods
-        pjsip_endpt_add_capability(_endpt, &_mod, PJSIP_H_ALLOW, NULL, PJ_ARRAY_SIZE(allowed), allowed);
-
-        // Register "application/sdp" in ACCEPT header
-        pjsip_endpt_add_capability(_endpt, &_mod, PJSIP_H_ACCEPT, NULL, 1, &accepted);
-    }
-
-    _debug("UserAgent: pjsip version %s for %s initialized\n", pj_get_version(), PJ_OS_NAME);
-
-    Manager::instance().setSipThreadStatus(false);
-    
-    // Create the secondary thread to poll sip events
-    status = pj_thread_create(_pool, "sflphone", &start_thread, NULL, PJ_THREAD_DEFAULT_STACK_SIZE, 0, 
-			    	&_thread);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    /* Done! */
-    return PJ_SUCCESS;
-
-}
-
-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
-}
-
-bool UserAgent::addAccount(AccountID id, pjsip_regc **regc2, const std::string& server, const std::string& user, const std::string& passwd, const int& timeout UNUSED) {
-    
-    pj_status_t status;
-    AccountID *currentId = new AccountID(id);
-    char contactTmp[256];
-    pjsip_regc *regc;
-    pj_str_t svr;
-    pj_str_t aor;
-    pj_str_t contact;
-    pjsip_tx_data *tdata;
-
-    //pj_mutex_lock(_mutex);
-    std::string tmp;
-
-
-    SIPAccount *account;
-
-    if (!validStunServer) {
-
-    	SIPVoIPLink *voipLink;
-        voipLink = dynamic_cast<SIPVoIPLink *>(Manager::instance().getAccountLink(id));
-        Manager::instance().getAccountLink(id)->setRegistrationState(VoIPLink::ErrorExistStun);
-        voipLink->setRegister(false);
-	return false;
-    }
-
-    status = pjsip_regc_create(_endpt, (void *) currentId, &regc_cb, &regc);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create regc.\n");
-        return false;
-    }
-
-    tmp = "sip:" + server;
-    pj_strdup2(_pool, &svr, tmp.data());
-    
-    tmp = "<sip:" + user + "@" + server + ">";
-    pj_strdup2(_pool, &aor, tmp.data());
-
-
-    sprintf(contactTmp, "<sip:%s@%s:%d>", user.data(), _localExternAddress.data(), _localExternPort);
-    pj_strdup2(_pool, &contact, contactTmp);
-
-    //_debug("UserAgent: Get in %s %d %s\n", svr.ptr, svr.slen, aor.ptr);
-    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);
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-
-
-    account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id));
-    pjsip_cred_info *cred = account->getCredInfo();
-
-    if(!cred)
-        cred = new pjsip_cred_info();
-
-    pj_bzero(cred, sizeof (pjsip_cred_info));
-    pj_strdup2(_pool, &cred->username, user.data());
-    cred->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
-    pj_strdup2(_pool, &cred->data, passwd.data());
-    pj_strdup2(_pool, &cred->realm, "*");
-    pj_strdup2(_pool, &cred->scheme, "digest");
-    pjsip_regc_set_credentials(regc, 1, cred);
-
-    account->setCredInfo(cred);
-
-    status = pjsip_regc_register(regc, PJ_TRUE, &tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to register regc.\n");
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-
-    status = pjsip_regc_send(regc, tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to send regc request.\n");
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-
-    account->setUserName(user);
-    account->setServer(server);
-    account->setContact(contactTmp);
-
-    // associate regc with account
-    *regc2 = regc;
-    
-    //pj_mutex_unlock(_mutex);
-
-    return true;
-}
-
-bool UserAgent::removeAccount(pjsip_regc *regc)
-{
-    pj_status_t status = 0;
-    pjsip_tx_data *tdata = NULL;
-    
-    //pj_mutex_lock(_mutex);
-    if(regc) {
-        status = pjsip_regc_unregister(regc, &tdata);
-        if(status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to unregister regc.\n");
-            //pj_mutex_unlock(_mutex);
-            return false;
-        }
-        
-        status = pjsip_regc_send( regc, tdata );
-        if(status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to send regc request.\n");
-            //pj_mutex_unlock(_mutex);
-            return false;
-        }
-    } else {
-        _debug("UserAgent: regc is null!\n");
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-    
-    //pj_mutex_unlock(_mutex);
-    return true;
-}
-
-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);
-}
-
-pj_status_t UserAgent::stunServerResolve() {
-    pj_str_t stun_adr;
-    pj_hostent he;
-    pj_stun_config stunCfg;
-    pj_status_t stun_status;
-    pj_sockaddr stun_srv;
-
-    // Initialize STUN configuration
-    pj_stun_config_init(&stunCfg, &_cp.factory, 0, pjsip_endpt_get_ioqueue(_endpt), pjsip_endpt_get_timer_heap(_endpt));
-
-    stun_status = PJ_EPENDING;
-
-    // Init STUN socket
-    size_t pos = _stunServer.find(':');
-    if(pos == std::string::npos) {
-        pj_strdup2(_pool, &stun_adr, _stunServer.data());
-        stun_status = pj_sockaddr_in_init(&stun_srv.ipv4, &stun_adr, (pj_uint16_t) 3478);
-    } else {
-        std::string serverName = _stunServer.substr(0, pos);
-        std::string serverPort = _stunServer.substr(pos + 1);
-        int 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);
-    }
-    
-    if (stun_status != PJ_SUCCESS) {
-        _debug("UserAgent: Unresolved stun server!\n");
-        stun_status = pj_gethostbyname(&stun_adr, &he);
-
-        if (stun_status == PJ_SUCCESS) {
-            pj_sockaddr_in_init(&stun_srv.ipv4, NULL, 0);
-            stun_srv.ipv4.sin_addr = *(pj_in_addr*) he.h_addr;
-            stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t) 3478);
-        }
-    }
-
-    return stun_status;
-}
-
-int UserAgent::createUDPServer() {
-    pj_status_t status;
-    //pj_str_t ipAddr;
-    pj_sockaddr_in bound_addr;
-    pjsip_host_port a_name;
-    char tmpIP[32];
-
-    // Init bound address to ANY
-    pj_memset(&bound_addr, 0, sizeof (bound_addr));
-    bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
-
-    // Create UDP server socket
-    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &_sock);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: (%d) UDP socket() error\n", status);
-        return status;
-    }
-
-    status = pj_sock_bind_in(_sock, pj_ntohl(bound_addr.sin_addr.s_addr), (pj_uint16_t) _localPort);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: (%d) UDP bind() error\n", status);
-        pj_sock_close(_sock);
-        return status;
-    }
-
-    _debug("UserAgent: Use IP: %s\n", _localExternAddress.data());
-
-    // Create UDP-Server (default port: 5060)
-    strcpy(tmpIP, _localExternAddress.data());
-    pj_strdup2(_pool, &a_name.host, tmpIP);
-    a_name.port = (pj_uint16_t) _localExternPort;
-
-    status = pjsip_udp_transport_attach(_endpt, _sock, &a_name, 1, NULL);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: (%d) Unable to start UDP transport!\n", status);
-        return -1;
-    } else {
-        _debug("UserAgent: UDP server listening on port %d\n", _localExternPort);
-    }
-
-    return 0;
-}
-
-void UserAgent::setStunServer(const char *server) {
-    if(server != NULL) {
-        _useStun = true;
-        _stunServer = std::string(server);
-    } else {
-        _useStun = false;
-        _stunServer = std::string("");
-    }
-}
-
-void UserAgent::regc_cb(struct pjsip_regc_cbparam *param) {
-    
-    AccountID *id = static_cast<AccountID *> (param->token);
-    SIPVoIPLink *voipLink;
-    
-    _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)
-        return;
-   
-    if (param->status == PJ_SUCCESS) {
-        if (param->code < 0 || param->code >= 300) {
-            /* Sometimes, the status is OK, but we still failed.
-             * So checking the code for real result
-             */
-            _debug("UserAgent: The error is: %d\n", param->code);
-            switch(param->code) {
-		case 408:
-                case 606:
-                     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorConfStun);
-                     break;
-                case 503:
-                     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorHost);
-                     break;
-                case 401:
-		case 403:
-		case 404:
-		     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorAuth);
-		     break;
-                default:
-                     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::Error);
-                     break;
-            }
-            voipLink->setRegister(false);
-        } else {
-            // Registration/Unregistration is success
-        
-            if(voipLink->isRegister())
-                Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::Registered);
-            else {
-                Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::Unregistered);
-                voipLink->setRegister(false);
-            }
-        }
-    } else {
-        Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorAuth);
-        voipLink->setRegister(false);
-    }
-}
-
-bool
-UserAgent::loadSIPLocalIP() {
-    bool returnValue = true;
-    if (_localIPAddress == "127.0.0.1") {
-        pj_sockaddr ip_addr;
-        if (pj_gethostip(pj_AF_INET(), &ip_addr) != PJ_SUCCESS) {
-            // Update the registration state if no network capabilities found
-            _debug("UserAgent: Get host ip failed!\n");
-            returnValue = false;
-        } else {
-            _localIPAddress = std::string(pj_inet_ntoa(ip_addr.ipv4.sin_addr));
-            _debug("UserAgent: Checking network, setting local IP address to: %s\n", _localIPAddress.data());
-        }
-    }
-    return returnValue;
-}
-
-/* Thread entry point function. */
-int UserAgent::start_thread(void *arg) {
-
-    PJ_UNUSED_ARG(arg);
-
-    // FIXME! maybe we should add a flag for exiting!
-    // TODO Add the flag. We have to stop the thread when destroying the instance 
-    while (!Manager::instance().getSipThreadStatus()) {
-        pj_time_val timeout = {0, 10};
-        pjsip_endpt_handle_events(getInstance()->getEndPoint(), &timeout);
-    }
-
-    return 0;
-}
-
-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;
-}
-
-bool UserAgent::setCallAudioLocal(SIPCall* call) {
-    // Firstly, we use the local IP and port number
-    unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
-    unsigned int callLocalExternAudioPort = callLocalAudioPort;
-    
-    if (_useStun) {
-        // If use Stun server, modify them
-        if (Manager::instance().behindNat(_stunServer, callLocalAudioPort)) {
-            callLocalExternAudioPort = Manager::instance().getFirewallPort();
-        }
-    }
-    _debug("UserAgent: Setting local audio port to: %d\n", callLocalAudioPort);
-    _debug("UserAgent: 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);
-
-    return true;
-}
-
-int UserAgent::answer(SIPCall *call) {
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-
-    // User answered the incoming call, tell peer this news
-    if (call->startNegociation(_pool)) {
-        // Create and send a 200(OK) response
-        _debug("UserAgent: Negociation success!\n");
-        status = pjsip_inv_answer(call->getInvSession(), PJSIP_SC_OK, NULL, NULL, &tdata);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-        status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-        return 0;
-    }
-
-    return 1;
-}
-
-bool UserAgent::makeOutgoingCall(const std::string& strTo, SIPCall* call, const AccountID& id) {
-    pj_status_t status;
-    pjsip_dialog *dialog;
-    pjsip_tx_data *tdata;
-    pj_str_t from, to, contact;
-
-    _debug("*******************AccountId is %s\n", id.data());
-    // Get the basic information about the callee account
-    SIPAccount* account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(id));
-    
-    // Generate the from URI
-    std::string strFrom = "sip:" + account->getUserName() + "@" + account->getServer();
-
-    _debug("UserAgent: Make a new call from:%s to %s. Contact is %s\n", 
-            strFrom.data(), strTo.data(), account->getContact().data());
-
-    // pjsip need the from and to information in pj_str_t format
-    pj_strdup2(_pool, &from, strFrom.data());
-    pj_strdup2(_pool, &to, strTo.data());
-    pj_strdup2(_pool, &contact, account->getContact().data());
-
-    // create the dialog (UAC)
-    status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from,
-                                    &contact,
-                                    &to,
-                                    NULL,
-                                    &dialog);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
-
-    setCallAudioLocal(call);
-    call->setIp(getInstance()->getLocalIP());
-
-    // Building the local SDP offer
-    call->createInitialOffer(_pool);
-
-    // Create the invite session for this call
-    pjsip_inv_session *inv;
-    status = pjsip_inv_create_uac(dialog, call->getLocalSDPSession(), 0, &inv);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
-
-    // Set auth information
-    pjsip_auth_clt_set_credentials(&dialog->auth_sess, 1, account->getCredInfo());
-
-    // Associate current call in the invite session
-    inv->mod_data[_mod.id] = call;
-
-    status = pjsip_inv_invite(inv, &tdata);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
-
-    // Associate current invite session in the call
-    call->setInvSession(inv);
-    
-    status = pjsip_inv_send_msg(inv, tdata);
-    //PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-    if(status != PJ_SUCCESS) {
-	return false;
-    }
-
-    return true;
-}
-
-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);
-                }
-            }
-        }
-    }
-
-}
-
-bool UserAgent::onhold(SIPCall *call) {
-
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    pjmedia_sdp_attr *attr;
-    pjmedia_sdp_session* local_sdp;
-
-    local_sdp = call->getLocalSDPSession();
-    if( local_sdp == NULL ){
-        _debug("! SIP Failure: unable to find local_sdp\n");
-        return false;
-    }
-
-    /* Create re-INVITE with new offer */
-    // Remove all the attributes with the specified name
-    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendrecv");
-    attr = pjmedia_sdp_attr_create(_pool, "sendonly", NULL);
-    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
-
-    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp, &tdata);
-    if( status != PJ_SUCCESS )
-    {
-        _debug("On hold: creation of the Re-invite request failed\n");
-        return false;
-    }
-    /* Send the request */
-    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
- 
-    return (status == PJ_SUCCESS);
-}
-
-bool UserAgent::offhold(SIPCall *call) {
-
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    pjmedia_sdp_attr *attr;
-    pjmedia_sdp_session* local_sdp;
-
-    local_sdp = call->getLocalSDPSession();
-    if( local_sdp == NULL ){
-        _debug("! SIP Failure: unable to find local_sdp\n");
-        return false;
-    }
-
-    /* Create re-INVITE with new offer */
-    // Remove all the attributes with the specified name
-    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendonly");
-    attr = pjmedia_sdp_attr_create(_pool, "sendrecv", NULL);
-    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
-
-    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp , &tdata);
-    if( status != PJ_SUCCESS )
-    {
-        _debug("Off hold: creation of the Re-invite request failed\n");
-        return false;
-    }
-
-    /* Send the request */
-    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
- 
-    return (status == PJ_SUCCESS);
-}
-
-bool UserAgent::hangup(SIPCall* call) {
-    pj_status_t status;
-    pjsip_tx_data *tdata = NULL;
-    
-    // User hangup current call. Notify peer
-    status = pjsip_inv_end_session(call->getInvSession(), 404, NULL, &tdata);
-    if(status != PJ_SUCCESS)
-	    return false;
-
-    _debug("UserAgent: Before send msg!\n");
-
-    if(tdata == NULL)
-	    return true;
-
-    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-    if(status != PJ_SUCCESS)
-	    return false;
-
-    call->getInvSession()->mod_data[getInstance()->getModId()] = NULL;
-    return true;
-}
-
-bool UserAgent::refuse(SIPCall* call)
-{
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    
-    // User refuse current call. Notify peer
-    status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_DECLINE, NULL, &tdata); //603
-    if(status != PJ_SUCCESS)
-        return false;
-
-    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-    if(status != PJ_SUCCESS)
-        return false;
-
-    call->getInvSession()->mod_data[getInstance()->getModId()] = NULL;
-    return true;
-}
-
-
-bool UserAgent::carryingDTMFdigits(SIPCall* call, char *msgBody)
-{
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    pj_str_t methodName, content;
-    pjsip_method method;
-    pjsip_media_type ctype;
-
-    pj_strdup2(_pool, &methodName, "INFO");
-    pjsip_method_init_np(&method, &methodName);
-   
-    /* Create request message. */
-    status = pjsip_dlg_create_request( call->getInvSession()->dlg, &method,
-                                       -1, &tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create INFO request -- %d\n", status);
-        return false;
-    }
-
-    /* Get MIME type */
-    pj_strdup2(_pool, &ctype.type, "application");
-    pj_strdup2(_pool, &ctype.subtype, "dtmf-relay");
-
-    /* Create "application/dtmf-relay" message body. */
-    pj_strdup2(_pool, &content, msgBody);
-    tdata->msg->body = pjsip_msg_body_create( tdata->pool, &ctype.type,
-                                              &ctype.subtype, &content);
-    if (tdata->msg->body == NULL) {
-        _debug("UserAgent: Unable to create msg body!\n");
-        pjsip_tx_data_dec_ref(tdata);
-        return false;
-    }
-
-    /* Send the request. */
-    status = pjsip_dlg_send_request( call->getInvSession()->dlg, tdata,
-                                     _mod.id, NULL);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to send MESSAGE request -- %d\n", status);
-        return false;
-    }
-   
-    return true;
-
-}
-
-bool UserAgent::transfer(SIPCall *call, const std::string& to)
-{
-    pjsip_evsub *sub;
-    pjsip_tx_data *tdata;
-    struct pjsip_evsub_user xfer_cb;
-    pj_status_t status;
-    pj_str_t dest;
-    
-    pj_strdup2(_pool, &dest, to.data());
-
-    /* Create xfer client subscription. */
-    pj_bzero(&xfer_cb, sizeof(xfer_cb));
-    xfer_cb.on_evsub_state = &xfer_func_cb;
-    
-    status = pjsip_xfer_create_uac(call->getInvSession()->dlg, &xfer_cb, &sub);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create xfer -- %d\n", status);
-        return false;
-    }
-    
-    /* Associate this voiplink of call with the client subscription 
-     * We can not just associate call with the client subscription
-     * because after this function, we can not find the cooresponding
-     * voiplink from the call any more. But the voiplink is useful!
-     */
-    AccountID accId = Manager::instance().getAccountFromCall(call->getCallId());
-    SIPVoIPLink *link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-    pjsip_evsub_set_mod_data(sub, _mod.id, link);
-
-    /*
-     * Create REFER request.
-     */
-    status = pjsip_xfer_initiate(sub, &dest, &tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create REFER request -- %d\n", status);
-        return false;
-    }
-
-    /* Send. */
-    status = pjsip_xfer_send_request(sub, tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to send REFER request -- %d\n", status);
-        return false;
-    }
-
-    return true;
-}
-
-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, getInstance()->getModId());
-        if (!call)
-            return;
-
-        pjsip_evsub_set_mod_data(sub, getInstance()->getModId(), NULL);
-        call->setXferSub(NULL);
-
-        _debug("UserAgent: Xfer server subscription terminated\n");
-    }    
-}
diff --git a/src/useragent.h b/src/useragent.h
index b37257aeae33bd46bf9fae99a5a841fc655e013e..728b074cd70eb9fb14d09256cfabeaa36cd653c0 100644
--- a/src/useragent.h
+++ b/src/useragent.h
@@ -56,20 +56,8 @@ private:
     pjsip_module _options_handler;
     bool _useStun;
     pj_str_t _stunHost;
-    std::string _stunServer;
-    bool validStunServer;
 
-    /** Local Extern Address is the IP address seen by peers for SIP listener */
-    std::string _localExternAddress;
-    std::string _localIPAddress;
-
-    /** Local Extern Port is the port seen by peers for SIP listener */
-    unsigned int _localExternPort;
-    unsigned int _localPort;
-
-    /** For registration use only */
-    int _regPort;
-    
+        
     pj_thread_t *_thread;
     
     static UserAgent *_current;
@@ -90,9 +78,6 @@ public:
 
     void sipDestory();
 
-    /** Create SIP UDP Listener */
-    int createUDPServer();
-
     /** Set whether it will use stun server */
     void setStunServer(const char *server); 
 
@@ -111,7 +96,6 @@ public:
     
     bool loadSIPLocalIP();
     
-    pj_status_t stunServerResolve();
     
     pjsip_endpoint* getEndPoint() {return _endpt;}
     
diff --git a/src/voiplink.cpp b/src/voiplink.cpp
index fe62b20467a1047fa2a1965618de1bff4abeea79..e4ff653d48211f0912f639bc8da37a75ada65593 100644
--- a/src/voiplink.cpp
+++ b/src/voiplink.cpp
@@ -26,7 +26,6 @@
 
 VoIPLink::VoIPLink(const AccountID& accountID) : _accountID(accountID), _localIPAddress("127.0.0.1"), _localPort(0),  _initDone(false) 
 {
-    setRegistrationState(VoIPLink::Unregistered);
 }
 
 VoIPLink::~VoIPLink (void) 
@@ -64,8 +63,7 @@ Call* VoIPLink::getCall(const CallID& id)
   return 0;
 }
 
-bool
-VoIPLink::clearCallMap()
+bool VoIPLink::clearCallMap()
 {
   ost::MutexLock m(_callMapMutex);
   CallMap::iterator iter = _callMap.begin();
@@ -78,9 +76,3 @@ VoIPLink::clearCallMap()
   return true;
 }
 
-void VoIPLink::setRegistrationState(const RegistrationState state)
-{
-    _registrationState = state;
-    // Notify the client
-    Manager::instance().connectionStatusNotification( );
-}
diff --git a/src/voiplink.h b/src/voiplink.h
index e095c1922ccc24af99754eddd5ed79b1d2ebc83a..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,218 +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);
-
-    /** Contains all the state an Voip can be in */
-    enum RegistrationState {Unregistered, Trying, Registered, Error, ErrorAuth , ErrorNetwork , ErrorHost, ErrorExistStun, ErrorConfStun};
-    typedef enum RegistrationState RegistrationState;
-
-    /**
-     * 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 pjsip engine/thread and set config 
-     * @return bool True if OK
-     */
-    virtual bool init (void) = 0;
-    
-    /**
-     * Virtual method
-     * Delete link-related stuuf like calls
-     */
-    virtual void terminate (void) = 0;
-    
-    /**
-     * Virtual method
-     * Build and send SIP registration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    virtual int sendRegister (void) = 0;
-    
-    /**
-     * Virtual method
-     * Build and send SIP 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 Sip 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;
-
-    /* Accessors */
-    std::string& getFullName (void) { return _fullname; }
-    void setFullName (const std::string& fullname) { _fullname = fullname; }
-
-    std::string& getHostname (void) { return _hostname; }
-    void setHostname (const std::string& hostname) {  _hostname = hostname; }
-
-    std::string& getUsername (void) { return _username; }
-    void setUsername (const std::string& username) {  _username = username; }
-
-    std::string& getPassword (void) { return _password; }
-    void setPassword (const std::string& password) {  _password = password; }
-
-    /**
-     * @return AccountID  parent Account's ID
-     */
-    AccountID& getAccountID(void) { return _accountID; }
-
-    /**
-     * @param accountID The account identifier
-     */
-    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 connection status
-     * @return Connection status
-     */
-    RegistrationState getRegistrationState() { return _registrationState; }
-
-    /**
-     * Set new registration state
-     * @param state The registration state
-     */
-    void setRegistrationState(const RegistrationState state);
-
-  private:
-    std::string _hostname;
-    std::string _username;
-    std::string _password;
-    std::string _fullname;
-
-    /**
-     * ID of parent's Account
-     */
-    AccountID _accountID;
-
-    /**
-     * State of registration
-     */
-    RegistrationState _registrationState;
-
-public:
-    /** 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();
-    
-    
-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;
+
+    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 ( 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__
diff --git a/test/Makefile.am b/test/Makefile.am
index b3aaf8805dc1637d23086fb4406fff4d1eb696aa..5c684888b422490c0e15316692bc4fcee3eceb78 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,7 +15,6 @@ OBJECT_FILES= \
 	../src/sflphoned-sipaccount.o \
 	../src/sflphoned-iaxaccount.o \
 	../src/sflphoned-eventthread.o \
-	../src/sflphoned-useragent.o \
 	../src/plug-in/pluginmanager.o \
 	../src/plug-in/audiorecorder/audiorecord.o \
 	../src/sflphoned-samplerateconverter.o
@@ -48,7 +47,6 @@ configurationTester_LDADD = \
 		@DBUSCPP_LIBS@ \
 		@SAMPLERATE_LIBS@ \
 		$(PJSIP_LIBS) \
-		-luuid \
 		$(OBJECT_FILES)
 	
 pluginmanagerTester_LDADD = \
@@ -63,7 +61,6 @@ pluginmanagerTester_LDADD = \
 		@DBUSCPP_LIBS@ \
 		@SAMPLERATE_LIBS@ \
 		$(PJSIP_LIBS) \
-		-luuid \
 		$(OBJECT_FILES)
 	
 audiorecorderTester_LDADD = \
@@ -78,6 +75,5 @@ audiorecorderTester_LDADD = \
 		@DBUSCPP_LIBS@ \
 		@SAMPLERATE_LIBS@ \
 		$(PJSIP_LIBS) \
-		-luuid \
 		$(OBJECT_FILES)
 							
diff --git a/test/pluginmanagerTest.cpp b/test/pluginmanagerTest.cpp
index e5dfff8e1172c7d9afb18342983906c8d675008b..7fd16c28cd0e8c46d185830d1781df2819aea429 100644
--- a/test/pluginmanagerTest.cpp
+++ b/test/pluginmanagerTest.cpp
@@ -26,19 +26,25 @@ using std::cout;
 using std::endl;
 
 void PluginManagerTest::setUp(){
-    // Instanciate the plugin manager object
     _pm = ::sflphone::PluginManager::instance();
 }
 
 void PluginManagerTest::testLoadPluginDirectory(){
-    _pm->loadPlugins();
+    CPPUNIT_ASSERT(_pm->loadPlugins() == 0);
+}
+
+void PluginManagerTest::testLoadPlugin(){
+    CPPUNIT_ASSERT(_pm->loadPlugins() == 0);
+    //CPPUNIT_ASSERT( _pm->isPluginLoaded("test") == NULL );
 }
 
-void PluginManagerTest::testNonloadedPlugin(){
-    CPPUNIT_ASSERT( _pm->isPluginLoaded("test") == NULL );
+void PluginManagerTest::testRegisterPlugin(){
+    // First load the default directory
+    _pm->loadPlugins();
+    // Resolve the symbol
 }
 
 void PluginManagerTest::tearDown(){
     // Delete the plugin manager object
-    delete _pm; _pm=NULL;
+    delete _pm; _pm=0;
 }
diff --git a/test/pluginmanagerTest.h b/test/pluginmanagerTest.h
index e43ba8f7ab09262243fddd3edc21130ddca5dd80..0cd92da42ce87ff50b2eb399975a68da9abd2f4f 100644
--- a/test/pluginmanagerTest.h
+++ b/test/pluginmanagerTest.h
@@ -43,7 +43,8 @@ class PluginManagerTest : public CppUnit::TestCase {
      */
     CPPUNIT_TEST_SUITE( PluginManagerTest );
         CPPUNIT_TEST( testLoadPluginDirectory );
-        CPPUNIT_TEST( testNonloadedPlugin );
+        CPPUNIT_TEST( testLoadPlugin );
+        CPPUNIT_TEST( testRegisterPlugin );
     CPPUNIT_TEST_SUITE_END();
 
     public:
@@ -63,7 +64,9 @@ class PluginManagerTest : public CppUnit::TestCase {
 
         void testLoadPluginDirectory();
         
-        void testNonloadedPlugin();
+        void testLoadPlugin();
+
+        void testRegisterPlugin();
 
     private:
         ::sflphone::PluginManager *_pm;