diff --git a/src/Makefile.am b/src/Makefile.am
index 2d5e1af3133debef313b4a3046209c7bce46da23..311be41e02e478b31e549bd5a1a2e9c29cc6b65f 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\" \
@@ -80,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/eventthread.cpp b/src/eventthread.cpp
index 66e6d441090be9d70a785ecc7fa0ff44a5256b44..e7103908a6b2e8df05d0528c37c1cb1936b1a88e 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,31 @@
 #include "eventthread.h"
 #include "voiplink.h"
 
-EventThread::EventThread (VoIPLink* link) : Thread (),  _linkthread(link), stopIt(false)
-{
-	setCancel(cancelDeferred);
-}
-
-EventThread::~EventThread (void) 
-{
-  terminate();
-}
-
+/********************************** IAX Voiplink thread *************************************/
 /**
  * Reimplementation of run() 
  */
-void
-EventThread::run (void) 
+void IAXEventThread::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 )
+
+/********************************** SIP Voiplink thread *************************************/
+/**
+ * Reimplementation of run() 
+ */
+void SIPEventThread::run (void) 
+
 {
-  return stopIt;
+  while(!testCancel()) {
+    _linkthread->getEvent();
+  }
 }
+
+/********************************************************************************************/
diff --git a/src/eventthread.h b/src/eventthread.h
index 8772c72043fec8d719b7c50aecf706dbdb241396..f09afb016fc20c2de26ba9098de7987f1a7b2d67 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,52 @@ 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:
+
+    friend class SIPEventThread;
+    friend class IAXEventThread;
+
+    public:
+        /**
+         * Thread constructor 
+         */
+        EventThread (VoIPLink* link) : Thread(), _linkthread(link){
+            setCancel( cancelDeferred );
+        }
+        
+        
+        virtual ~EventThread (void){
+            terminate();
+        }
+        
+        virtual void run () = 0;
+        
+    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;
+};
+
+class IAXEventThread : public EventThread {
+    
+    public:
+        IAXEventThread( VoIPLink* voiplink )
+            : EventThread( voiplink ){
+        }
+
+        virtual void run();
 };
 
+class SIPEventThread : public EventThread {
+    
+    public:
+        SIPEventThread( VoIPLink* voiplink )
+            : EventThread( voiplink ){
+        }
+
+        virtual void run();
+};
+
+
 #endif // __EVENT_THREAD_H__
diff --git a/src/iaxvoiplink.cpp b/src/iaxvoiplink.cpp
index 6d04dffcaeae225d5d75207136262f3a36705b1c..464bf2b9cc7f477f60697b652845062ac819e0fc 100644
--- a/src/iaxvoiplink.cpp
+++ b/src/iaxvoiplink.cpp
@@ -45,7 +45,7 @@
   IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
 : VoIPLink(accountID)
 {
-  _evThread = new EventThread(this);
+  _evThread = new IAXEventThread(this);
   _regSession = NULL;
   _nextRefreshStamp = 0;
 
@@ -917,6 +917,8 @@ IAXVoIPLink::iaxCodecMapToFormat(IAXCall* call)
 
 void IAXVoIPLink::updateAudiolayer( void )
 {
+    _mutexIAX.enterMutex();
     audiolayer = NULL;
     audiolayer = Manager::instance().getAudioDriver();
+    _mutexIAX.leaveMutex();
 }
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
index 626aca506c6114558d6a1db42fae6259e55a019b..e7af691255f2101c6a2f637c2384271e2a088523 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();
 
-  initVolume();
-
-  if (_exist == 0) {
-    _debug("Cannot create config file in your home directory\n");
-  }
-
-  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
@@ -443,25 +398,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() );
@@ -1694,24 +1653,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,6 +1691,16 @@ void ManagerImpl::setMicVolume(unsigned short mic_vol)
     //}
 }
 
+void ManagerImpl::setSipPort( int port )
+{
+}
+
+int ManagerImpl::getSipPort( void )
+{
+    return 5060;
+}
+
+
 /**
  * configuration function requests
  * Main Thread
@@ -2021,26 +1972,17 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma
     if (accountType == "SIP") {
         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")
+        {
+           //TODO Replace:  _userAgent->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
+        }
+        else
+        {
+            //TODO: replace: _userAgent->setStunServer(NULL);
+        }
+        //restartPjsip();
+    }
 
     saveConfig();
   
@@ -2082,38 +2024,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 +2126,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 +2134,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 +2145,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 +2160,6 @@ ManagerImpl::loadAccountMap()
       nbAccount++;
     }
 
-    _debug("\n");
-
     iter++;
   }
 
@@ -2351,37 +2247,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..68a40075d5b0eda4dd3451cb47796e44757040f8 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;
@@ -795,10 +794,6 @@ class ManagerImpl {
      */
     void restartPjsip();
 
-    int getSipPort();
-    
-    void setSipPort(int port);
-    
     void unregisterCurSIPAccounts();
     
     void registerCurSIPAccounts();
@@ -1019,6 +1014,10 @@ public:
 
     AccountID getAccountIdFromNameAndServer(const std::string& userName, const std::string& server);
 
+    int getSipPort();
+
+    void setSipPort( int port );
+
 private:
 
     // Copy Constructor
@@ -1027,32 +1026,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/sipaccount.cpp b/src/sipaccount.cpp
index acce1bb66ed5fff56fad4d6a3d20b77c6ba146a0..27f1acacee36034d29c2af543c77d0da7cced26a 100644
--- a/src/sipaccount.cpp
+++ b/src/sipaccount.cpp
@@ -23,7 +23,6 @@
 #include "sipaccount.h"
 #include "manager.h"
 #include "user_cfg.h"
-#include "useragent.h"
 
 SIPAccount::SIPAccount(const AccountID& accountID)
  : Account(accountID)
@@ -33,6 +32,7 @@ SIPAccount::SIPAccount(const AccountID& accountID)
  , _contact("")
 {
   _link = new SIPVoIPLink(accountID);
+   //_link = SIPVoIPLink::instance( accountID ); 
 }
 
 
@@ -44,16 +44,15 @@ SIPAccount::~SIPAccount()
   _cred = NULL;
 }
 
-int
-SIPAccount::registerVoIPLink()
+int SIPAccount::registerVoIPLink()
 {
 
     int status, useStun;
     SIPVoIPLink *thislink;
 
+    /* Retrieve the account information */
     _link->setHostname(Manager::instance().getConfigString(_accountID,HOSTNAME));
     useStun = Manager::instance().getConfigInt(_accountID,SIP_USE_STUN);
-  
     thislink = dynamic_cast<SIPVoIPLink*> (_link);
     thislink->setStunServer(Manager::instance().getConfigString(_accountID,SIP_STUN_SERVER));
     thislink->setUseStun( useStun!=0 ? true : false);
@@ -65,6 +64,7 @@ SIPAccount::registerVoIPLink()
     thislink->setPassword(Manager::instance().getConfigString(_accountID, PASSWORD));
     thislink->setHostname(Manager::instance().getConfigString(_accountID, HOSTNAME));
 
+    // Start registration
     status = _link->sendRegister();
     ASSERT( status , SUCCESS );
 
@@ -76,7 +76,6 @@ SIPAccount::unregisterVoIPLink()
 {
   _debug("SIPAccount: unregister account %s\n" , getAccountID().c_str());
   _link->sendUnregister();
-  _link->terminate();
   
   return SUCCESS;
 }
diff --git a/src/sipcall.cpp b/src/sipcall.cpp
index 0e53bdd013d066744d80db93204ffbf14a46549f..bcc596ccf7f1f3a1b33a9befc4fccc2bc03167ce 100644
--- a/src/sipcall.cpp
+++ b/src/sipcall.cpp
@@ -51,13 +51,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 +68,11 @@ SIPCall::SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool)
   _localSDP->time.start = _localSDP->time.stop = 0;
   sdpAddMediaDescription(pool);
   
+    _debug("SDP: addr: %s\nuser: %s\nid: %i\nversion: %i\naddr: %s\nattr count: %i\n", 
+            _ipAddr.c_str(), _localSDP->origin.user, _localSDP->origin.id, _localSDP->origin.version, _localSDP->origin.addr.ptr, _localSDP->attr_count );
+
   _debug("Before validate SDP!\n");
+
   status = pjmedia_sdp_validate( _localSDP );
   if (status != PJ_SUCCESS) {
     _debug("Can not generate valid local sdp\n");
diff --git a/src/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..d05ebd56f83ba2db81708bbee7b8d62d840ee778 100644
--- a/src/sipvoiplink.cpp
+++ b/src/sipvoiplink.cpp
@@ -27,256 +27,500 @@
 #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)
+/** PJSIP related variables */
+pj_caching_pool _cp;
+pj_pool_t *_pool;    
+pjsip_endpoint *_endpt;
+pjsip_module _mod_ua;       /** PJSIP module. */
+pj_thread_t *thread;
+pj_thread_desc desc;
+
+/*****************************/
+
+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);
+
+
+/** Do we use stun? */
+bool _useStun;
+
+/** The current STUN server address */
+std::string _stunServer;
+    
+std::string _localIPAddress;
+
+/** PJSIP callbacks */
+void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e);
+void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED);
+void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
+void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e);
+void regc_cb(struct pjsip_regc_cbparam *param);
+pj_bool_t mod_on_rx_request(pjsip_rx_data *rdata);
+pj_bool_t mod_on_rx_response(pjsip_rx_data *rdata UNUSED) ;
+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(const AccountID& accountID)
+    : VoIPLink(accountID)
+    , _initDone(false)
+    , _nbTryListenAddr(2) // number of times to try to start SIP listener
+      , _stunServer("")
+      , _localExternAddress("") 
+    , _localExternPort(0)
+    , _audiortp(new AudioRtp())
+    , _regc()
+    , _bRegister(false)
+      ,_regPort(DEFAULT_SIP_PORT)
 {
-  // to get random number for RANDOM_PORT
-  srand (time(NULL));
+    // to get random number for RANDOM_PORT
+    srand (time(NULL));
+    _useStun = false;
+    _localIPAddress = "127.0.0.1"; 
+
+    _evThread = new SIPEventThread(this);
 }
 
 SIPVoIPLink::~SIPVoIPLink()
 {
-  terminate();
+    delete _evThread; _evThread = NULL;
+    terminate();
+}
+
+SIPVoIPLink* SIPVoIPLink::instance( const AccountID& id){
+    /*if(!_instance ){
+      _instance = new SIPVoIPLink( id );
+      }
+      return _instance;*/
 }
 
-bool 
-SIPVoIPLink::init()
+
+bool SIPVoIPLink::init()
 {
-  _regc = NULL;
-  _initDone = true;
-  return true;
+    /* Initialize the pjsip library */
+    if( !isInitDone() ){
+        _regc = NULL;
+        pjsip_init();
+    }
+
+    setInitState(true);
+    return true;
 }
 
-void 
+    void 
 SIPVoIPLink::terminate()
 {
-  _initDone = false;
+    /* Clean shutdown of pjsip library */
+    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 );
+    }
+
+    _mutexSIP.enterMutex(); 
+
+    // PJSIP polling
+    pj_time_val timeout = {0, 10};
+    pjsip_endpt_handle_events( _endpt, &timeout);
+
+    _mutexSIP.leaveMutex(); 
 }
 
-int
-SIPVoIPLink::sendRegister()
+int SIPVoIPLink::sendRegister()
 {
-  AccountID id;
-  pj_status_t status;
-  
-  id = getAccountID();
 
-  if(_regc) {
-      status = pjsip_regc_destroy(_regc);
-      _regc = NULL;
-      PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-  }
+    AccountID id;
+    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;
+
+    /* Get the current account ID */
+    id = getAccountID();
+    hostname = getHostname();
+    username = getUsername();
+    password = getPassword();
+
+    _mutexSIP.enterMutex(); 
+
+    /* If the registration already exists, delete it */
+    if(_regc) {
+        status = pjsip_regc_destroy(_regc);
+        _regc = NULL;
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+    }
+
+    setRegister(true);
+
+    /* Set the expire value of the message from the config file */
+    expire_value = Manager::instance().getRegistrationExpireValue();
+
+    /* Update the state of the voip link */
+    setRegistrationState(Trying);
+
+    if (!validStunServer) {
+        setRegistrationState(VoIPLink::ErrorExistStun);
+        setRegister(false);
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
+
+    status = pjsip_regc_create(_endpt, (void*)new AccountID(id), &regc_cb, &_regc);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create regc.\n");
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
+
+    tmp = "sip:" + hostname;
+    pj_strdup2(_pool, &svr, tmp.data());
+
+    tmp = "<sip:" + username + "@" + hostname + ">";
+    pj_strdup2(_pool, &aor, tmp.data());
+
+    sprintf(contactTmp, "<sip:%s@%s:%d>", username.data(), _localExternAddress.data(), _localExternPort);
+    pj_strdup2(_pool, &contact, 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;
+    }
+
+    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, 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);
 
-  _bRegister = true;
-  
-  int expire_value = Manager::instance().getRegistrationExpireValue();
-  _debug("SIP Registration Expire Value = %i\n" , expire_value);
+    account->setCredInfo(cred);
 
-  setRegistrationState(Trying);
+    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;
+    }
 
-  return Manager::instance().getUserAgent()->addAccount(id, &_regc, getHostname(), getUsername(), getPassword(), expire_value);
+    account->setUserName(username);
+    account->setServer(hostname);
+    account->setContact(contactTmp);
+
+    _mutexSIP.leaveMutex(); 
+
+    return true;
 }
 
-std::string
+
+    std::string
 SIPVoIPLink::SIPFromHeader(const std::string& userpart, const std::string& hostpart) 
 {
-  return ("\"" + getFullName() + "\"" + " <sip:" + userpart + "@" + hostpart + ">");
+    return ("\"" + getFullName() + "\"" + " <sip:" + userpart + "@" + hostpart + ">");
 }
 
-bool
+    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;
-  }
+    if (getUsername().empty()) {
+        /** @todo Ajouter ici un call à setRegistrationState(Error, "Fill balh") ? */
+        return false;
+    }
+    if (getPassword().empty()) {
+        /** @todo Même chose ici  ? */
+        return false;
+    }
 
-  return true;
+    return true;
 }
 
-int
+    int 
 SIPVoIPLink::sendUnregister()
 {
-  _debug("SEND UNREGISTER for account %s\n" , getAccountID().c_str());
+    pj_status_t status = 0;
+    pjsip_tx_data *tdata = NULL;
+
+    _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;
+    if(!isRegister()){
+        setRegistrationState(VoIPLink::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;
+    }
+
+    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;
+    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;
+        }
     }
-  }
-  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;
 
-  // Stop sound
-  call->setAudioStart(false);
-  call->setState(Call::Hold);
-  _debug("* SIP Info: Stopping AudioRTP for onhold action\n");
-  _audiortp->closeRtpSession();
+    call = getSIPCall(id);
+
+    if (call==0) { _debug("! SIP Error: call doesn't exist\n"); return false; }  
 
-  return Manager::instance().getUserAgent()->onhold(call);
+    // Stop sound
+    call->setAudioStart(false);
+    call->setState(Call::Hold);
+    _debug("* SIP Info: Stopping AudioRTP for onhold action\n");
+    _audiortp->closeRtpSession();
+    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 
+    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 +531,23 @@ 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;
 
     call = getSIPCall(id);
+
     if (call==0) { 
         _debug("! SIP Failure: Call doesn't exist\n"); 
         return false; 
@@ -310,11 +560,43 @@ SIPVoIPLink::transfer(const CallID& id, const std::string& to)
 
     _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;
+    }
 
-  //_audiortp->closeRtpSession();
-  // shall we delete the call?
-  //removeCall(id);
+    /* 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;
+    }
+
+    return true;
 }
 
 bool SIPVoIPLink::transferStep2()
@@ -323,10 +605,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 +626,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 +647,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 +662,1443 @@ 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());
+    strTo = getSipTo(call->getPeerNumber());
+    _debug("            To: %s\n", strTo.data());
+
+    id = getAccountID();
+    // Get the basic information about the callee account
+    account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(id));
+
+    // Generate the from URI
+    strFrom = "sip:" + account->getUserName() + "@" + account->getServer();
+
+    // 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(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);
 
-    return Manager::instance().getUserAgent()->makeOutgoingCall(to, call, getAccountID());
+    // Set auth information
+    pjsip_auth_clt_set_credentials(&dialog->auth_sess, 1, account->getCredInfo());
+
+    // Associate current call in the invite session
+    inv->mod_data[getModId()] = 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);
+    if(status != PJ_SUCCESS) {
+        return false;
+    }
+
+    return true;
 }
 
 std::string
 SIPVoIPLink::getSipFrom() {
 
-  // Form the From header field basis on configuration panel
-  std::string hostname;
-  
-  hostname = getHostname();
+    // Form the From header field basis on configuration panel
+    std::string hostname;
 
-  if ( hostname.empty() ) {
-    hostname = _localIPAddress;
-  }
-  return SIPFromHeader(getUsername(), hostname);
+    hostname = getHostname();
+
+    if ( hostname.empty() ) {
+        hostname = _localIPAddress;
+    }
+    return SIPFromHeader(getUsername(), hostname);
 }
 
-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) {
+    // 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);
+        std::string host = getHostname();
+        if(!host.empty()) {
+            return SIPToHeader(to_url + "@" + host);
+        }
+    }
+    return SIPToHeader(to_url);
     }
-  }
-  return SIPToHeader(to_url);
-}
 
-std::string
-SIPVoIPLink::SIPToHeader(const std::string& 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 setCallAudioLocal(SIPCall* call) 
 {
-  if (to.find("sip:") == std::string::npos) {
-    return ("sip:" + to );
-  } else {
-    return to;
-  }
+    // 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;
+        }
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // Private functions
+    ///////////////////////////////////////////////////////////////////////////////
+
+    pj_str_t SIPVoIPLink::string2PJStr(const std::string &value)
+    {
+        char tmp[256];
+
+        strcpy(tmp, value.data());
+        return pj_str(tmp);
+    }
+
+
+    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;
+
+        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;
+
+        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
+        _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 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 );
+
+        // 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;
+    }
+
+    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;
+
+        // 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 = _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 {
+            serverName = _stunServer.substr(0, pos);
+            serverPort = _stunServer.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;
+    }
+
+    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;
+    }
+
+    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;
+    }
+
+    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. */    
+    }
+
+    int SIPVoIPLink::getModId(){
+        return _mod_ua.id;
+    }
+
+void set_voicemail_info( AccountID account, pjsip_msg_body *body ){
+
+    int voicemail, pos_begin, pos_end;
+    std::string voice_str = "Voice-Message: ";
+    std::string delimiter = "/";
+    std::string msg_body, voicemail_str;
+
+    _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);
 }
 
-bool
-SIPVoIPLink::SIPCheckUrl(const std::string& url UNUSED)
-{
-  return true;
+bool SIPVoIPLink::useStun( void ){
+    return _useStun;
 }
 
-bool
-SIPVoIPLink::setCallAudioLocal(SIPCall* call) 
+void SIPVoIPLink::setUseStun( bool use )
 {
-  // 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; }
+    _useStun = use;
+}
 
-  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");
+
+    /*******************************/
+    /*   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
-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; }
+    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){
 
-  // if we are here.. something when wrong before...
-  _debug("SIP call release\n");
-  CallID id = call->getCallId();
-  Manager::instance().callFailure(id);
-  removeCall(id);
+    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
-SIPVoIPLink::SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata)
+    void 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:
+                        voipLink->setRegistrationState(VoIPLink::ErrorConfStun);
+                        break;
+                    case 503:
+                        voipLink->setRegistrationState(VoIPLink::ErrorHost);
+                        break;
+                    case 401:
+                    case 403:
+                    case 404:
+                        voipLink->setRegistrationState(VoIPLink::ErrorAuth);
+                        break;
+                    default:
+                        voipLink->setRegistrationState(VoIPLink::Error);
+                        break;
+                }
+                voipLink->setRegister(false);
+            } else {
+                // Registration/Unregistration is success
+
+                if(voipLink->isRegister())
+                    voipLink->setRegistrationState(VoIPLink::Registered);
+                else {
+                    voipLink->setRegistrationState(VoIPLink::Unregistered);
+                    voipLink->setRegister(false);
+                }
+            }
+        } else {
+            voipLink->setRegistrationState(VoIPLink::ErrorAuth);
+            voipLink->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;
+        //pjmedia_sdp_session *r_sdp;
+        AccountID account_id;
+        pjsip_uri *uri;
+        pjsip_sip_uri *sip_uri;
+        std::string userName, server, caller, callerServer, peerNumber;
+
+        // voicemail part
+        std::string method_name;
+        std::string request;
+        
+        // Handle the incoming call invite in this function 
+        _debug("UserAgent: Callback on_rx_request is involved!\n");
+
+        /* First, let's got the username and server name from the invite.
+         * We will use them to detect which account is the callee.
+         */ 
+        uri = rdata->msg_info.to->uri;
+        sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
+
+        userName = std::string(sip_uri->user.ptr, sip_uri->user.slen);
+        server = std::string(sip_uri->host.ptr, sip_uri->host.slen) ;
+
+        // Get the account id of callee from username and server
+        account_id = Manager::instance().getAccountIdFromNameAndServer(userName, server);
+        if(account_id == AccountNULL) {
+            _debug("UserAgent: Username %s doesn't match any account!\n",userName.c_str());
+            return false;
+        }
+        
+        _debug("UserAgent: The receiver is : %s@%s\n", userName.data(), server.data());
+        _debug("UserAgent: The callee account id is %s\n", account_id.c_str());
+
+        /* 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);
+
+        caller = sip_uri->user.ptr;
+        callerServer = sip_uri->host.ptr;
+        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(_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!
+        CallID id = Manager::instance().getNewCallID();
+
+        _debug("UserAgent: The call id of the incoming call is %s\n", id.c_str());
+        SIPCall* call = new SIPCall(id, Call::Incoming);
+        if (!call) {
+            _debug("UserAgent: unable to create an incoming call");
+            return false;
+        }
+
+        // Set the codec map, IP, peer number and so on... for the SIPCall object
+        setCallAudioLocal(call);
+        call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+        call->setConnectionState(Call::Progressing);
+        call->setIp("127.0.0.1");
+        call->setPeerNumber(peerNumber);
+
+        /* Call the SIPCallInvite function to generate the local sdp,
+         * remote sdp and negociator.
+         * This function is also used to set the parameters of audio RTP, including:
+         *     local IP and port number 
+         *     remote IP and port number
+         *     possilbe audio codec will be used in this call
+         */
+        if (call->SIPCallInvite(rdata, _pool)) {
+
+            // 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 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)
 {
-  //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);
+    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;
+    }
 
-    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);
-      }
+    /* 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;
     }
-  } else {
-     _debug("* SIP Info: Answering call (on/off hold to send ACK)\n");
-     //call->SIPCallAnswered(event);
-  }
+
+    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);
+    }    
 }
 
 
-SIPCall*
-SIPVoIPLink::getSIPCall(const CallID& id) 
-{
-  Call* call = getCall(id);
-  if (call) {
-    return dynamic_cast<SIPCall*>(call);
-  }
-  return NULL;
+
+
+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);
+        }
+    }
+
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Private functions
-///////////////////////////////////////////////////////////////////////////////
 
-pj_str_t SIPVoIPLink::string2PJStr(const std::string &value)
+void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event)
 {
-    char tmp[256];
-    
-    strcpy(tmp, value.data());
-    return pj_str(tmp);
+    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..c00479a5b2983ebd8699f94061d87a101e527109 100644
--- a/src/sipvoiplink.h
+++ b/src/sipvoiplink.h
@@ -23,12 +23,24 @@
 #define SIPVOIPLINK_H
 
 #include "voiplink.h"
-#include "useragent.h"
+
+#include <pjsip.h>
+#include <pjlib-util.h>
+#include <pjlib.h>
+#include <pjnath/stun_config.h>
+#include <pjsip_simple.h>
+#include <pjsip_ua.h>
+#include <pjmedia/sdp.h>
+#include <pjmedia/sdp_neg.h>
 
 class EventThread;
 class SIPCall;
 class AudioRtp;
 
+#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
+#define RANDOM_SIP_PORT   rand() % 64000 + 1024
+#define PJ_LOG_LEVEL 5
+
 /**
  * @file sipvoiplink.h
  * @brief Specific VoIPLink for SIP (SIP core for incoming and outgoing events)
@@ -44,6 +56,8 @@ class SIPVoIPLink : public VoIPLink
      */
     SIPVoIPLink(const AccountID& accountID);
 
+    static SIPVoIPLink* instance( const AccountID& id );
+
     /**
      * Destructor
      */
@@ -61,10 +75,7 @@ class SIPVoIPLink : public VoIPLink
      */
     bool init(void);
 
-    /**
-     * Delete link-related stuuf like calls
-     */
-    void terminate(void);
+    void terminate( void );
 
     /**
      * Event listener. Each event send by the call manager is received and handled from here
@@ -158,8 +169,10 @@ class SIPVoIPLink : public VoIPLink
      * If set to true, we check for a firewall
      * @param use true if we use STUN
      */
-    void setUseStun(bool use) { _useStun = use; }
+    void setUseStun(bool use);
 
+    bool useStun( void );
+    
     /** 
      * The name of the STUN server
      * @param server Server FQDN/IP
@@ -235,15 +248,7 @@ class SIPVoIPLink : public VoIPLink
      */
     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
      */
@@ -268,6 +273,10 @@ class SIPVoIPLink : public VoIPLink
      */
     void SIPCallReleased(SIPCall *call);
 
+    bool isInitDone() { return _initDone; }
+
+    void setInitState( bool state ){ _initDone = state; }
+
     /**
      * SIPCall accessor
      * @param id  The call identifier
@@ -275,31 +284,66 @@ class SIPVoIPLink : public VoIPLink
      */
     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? */
+        /** when we init the listener, how many times we try to bind a port? */
     int _nbTryListenAddr;
 
-    /** Do we use stun? */
-    bool _useStun;
+    /** Starting sound */
+    AudioRtp* _audiortp;
+    
+    pj_str_t string2PJStr(const std::string &value);
 
-    /** What is the stun server? */
-    std::string _stunServer;
+private:
+    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);
+
+    pj_status_t stunServerResolve();
 
+    /** Create SIP UDP Listener */
+    int createUDPServer();
+
+    bool loadSIPLocalIP();
+    
+    std::string getLocalIP() {return _localExternAddress;}
+
+    pjsip_regc *_regc;
+    
+    /** For registration use only */
+    int _regPort;
+    
+    /** Tell if the initialisation has been done */
+    bool _initDone;
+
+    /* 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;
+    std::string _localIPAddress;
 
     /** Local Extern Port is the port seen by peers for SIP listener */
-    unsigned int _localExternPort;  
+    unsigned int _localExternPort;
+    unsigned int _localPort;
 
-    /** Starting sound */
-    AudioRtp* _audiortp;
-    
-    pj_str_t string2PJStr(const std::string &value);
+    /** Threading object */
+    EventThread* _evThread;
+    ost::Mutex _mutexSIP;
 
-private:
-    pjsip_regc *_regc;
     bool _bRegister;
 };
 
diff --git a/src/useragent.cpp b/src/useragent.cpp
index 6e0e104cec4ada90606d980fbf15212e2870e450..59a370dfab70abe8b6f6f911cdbad76fd6da3948 100644
--- a/src/useragent.cpp
+++ b/src/useragent.cpp
@@ -32,230 +32,13 @@
 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);
+    _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;
     }
 
 
-    // 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);
@@ -319,7 +102,7 @@ void UserAgent::busy_sleep(unsigned msec)
     tv.sec = 0;
     tv.msec = 10;
     pj_time_val_normalize(&tv);
-    
+
     do {
         pjsip_endpt_handle_events(_endpt, &tv);
         pj_gettimeofday(&now);
@@ -327,128 +110,7 @@ void UserAgent::busy_sleep(unsigned msec)
 #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;
@@ -461,88 +123,6 @@ pj_str_t UserAgent::buildContact(char *userName) {
     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;
@@ -553,88 +133,6 @@ void UserAgent::setStunServer(const char *server) {
     }
 }
 
-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;
@@ -657,17 +155,17 @@ void UserAgent::set_voicemail_info( AccountID account, pjsip_msg_body *body ){
     // 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() );
+        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;
+        std::cerr << e.what() << std::endl;
     }
 
     // We need now to notify the manager 
     if( voicemail != 0 )
-	Manager::instance().startVoiceMessageNotification(account, voicemail);
+        Manager::instance().startVoiceMessageNotification(account, voicemail);
 }
 
 
@@ -700,8 +198,8 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
     // 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: 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());
@@ -709,25 +207,25 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
     /* 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 );
-	}
+        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;
+        return PJ_SUCCESS;
     }
 
     // Respond statelessly any non-INVITE requests with 500
@@ -739,7 +237,7 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
             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) {
@@ -765,7 +263,7 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
     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:
@@ -774,7 +272,7 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
      *     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
@@ -802,7 +300,7 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
                 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);
@@ -810,7 +308,7 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
 
     // 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);
@@ -827,107 +325,8 @@ pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
     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);
@@ -946,8 +345,8 @@ void UserAgent::call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *t
             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;
+        // Receive a INFO message, ingore it!
+        return;
     }
 
     //Retrieve the body message
@@ -971,7 +370,7 @@ void UserAgent::call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *t
                     if (link)
                         link->SIPCallAnswered(call, rdata);
                 } else if (tsx->status_code / 100 == 5) {
-		    _debug("UserAgent: 5xx error message received\n");
+                    _debug("UserAgent: 5xx error message received\n");
                 }
                 break;
             case PJSIP_TSX_STATE_PROCEEDING:
@@ -990,7 +389,7 @@ void UserAgent::call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *t
                 }
                 break;
             case PJSIP_TSX_STATE_COMPLETED:
-		if (tsx->status_code == 407 || tsx->status_code == 401) //FIXME
+                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
@@ -1010,7 +409,7 @@ void UserAgent::call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *t
             default:
                 break;
         } // end of switch
-        
+
     } else {
         switch (tsx->state) {
             case PJSIP_TSX_STATE_TRYING:
@@ -1060,11 +459,11 @@ void UserAgent::call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *t
 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.
      */
@@ -1110,8 +509,8 @@ void UserAgent::call_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) {
             pj_status_t status;
 
             status = pjsip_xfer_notify( call->getXferSub(),
-                                        ev_state, st_code,
-                                        NULL, &tdata);
+                    ev_state, st_code,
+                    NULL, &tdata);
             if (status != PJ_SUCCESS) {
                 _debug("UserAgent: Unable to create NOTIFY -- %d\n", status);
             } else {
@@ -1125,203 +524,6 @@ void UserAgent::call_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) {
 
 }
 
-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);
@@ -1338,17 +540,17 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
         const pj_str_t REFER_SUB = {(char*)"Refer-Sub", 9 };
 
         SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub,
-                getInstance()->getModId()));
+                    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);
+                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);
+            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) {
@@ -1377,7 +579,7 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
      * 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_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)
     {
         pjsip_msg *msg;
         pjsip_msg_body *body;
@@ -1387,7 +589,7 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
         pj_status_t status;
 
         SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub, 
-                getInstance()->getModId()));
+                    getInstance()->getModId()));
 
         /* When subscription is terminated, clear the xfer_sub member of 
          * the inv_data.
@@ -1410,10 +612,10 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
             _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)
+                event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
         {
             pjsip_rx_data *rdata;
 
@@ -1429,7 +631,7 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
 
             /* Check for appropriate content */
             if (pj_stricmp2(&body->content_type.type, "message") != 0 ||
-                pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0)
+                    pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0)
             {
                 _debug("UserAgent: Warning! Received NOTIFY with non message/sipfrag content\n");
                 return;
@@ -1437,7 +639,7 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
 
             /* Try to parse the content */
             status = pjsip_parse_status_line((char*)body->data, body->len,
-                                             &status_line);
+                    &status_line);
             if (status != PJ_SUCCESS) {
                 _debug("UserAgent: Warning! Received NOTIFY with invalid message/sipfrag content\n");
                 return;
@@ -1452,11 +654,11 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
         /* 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");
@@ -1465,16 +667,16 @@ void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
                 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)
@@ -1522,17 +724,17 @@ void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
      * request.
      */
     ref_by_hdr = (pjsip_hdr*)
-                 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_ref_by,
-                                            NULL);
+        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);
+            (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) {
         /*
@@ -1543,7 +745,7 @@ void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
         pjsip_hdr *hdr;
 
         status = pjsip_dlg_create_response(inv->dlg, rdata, code, NULL,
-                                           &tdata);
+                &tdata);
         if (status != PJ_SUCCESS) {
             _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
             return;
@@ -1551,14 +753,14 @@ void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
 
         /* Add Refer-Sub header */
         hdr = (pjsip_hdr*)
-               pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub,
-                                              &str_false);
+            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);
+                tdata);
         if (status != PJ_SUCCESS) {
             _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
             return;
@@ -1594,9 +796,9 @@ void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
             pjsip_hdr *hdr;
 
             hdr = (pjsip_hdr*)
-                   pjsip_generic_string_hdr_create(inv->dlg->pool,
-                                                   &str_refer_sub,
-                                                   &str_true);
+                pjsip_generic_string_hdr_create(inv->dlg->pool,
+                        &str_refer_sub,
+                        &str_true);
             pj_list_push_back(&hdr_list, hdr);
 
         }
@@ -1606,7 +808,7 @@ void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
 
         /* Create initial NOTIFY request */
         status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
-                                    100, NULL, &tdata);
+                100, NULL, &tdata);
         if (status != PJ_SUCCESS) {
             _debug("UserAgent: Unable to create NOTIFY to REFER -- %d", status);
             return;
@@ -1635,16 +837,16 @@ void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
         _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);
+                    500, NULL, &tdata);
             if (status != PJ_SUCCESS) {
                 _debug("UserAgent: Unable to create NOTIFY to REFER -- %d\n", status);
                 return;
@@ -1677,7 +879,7 @@ void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
 
         /* Put the invite_data in the subscription. */
         pjsip_evsub_set_mod_data(sub, _mod.id,
-                                 newCall);
+                newCall);
     }    
 }
 
@@ -1692,11 +894,11 @@ void UserAgent::xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event)
     if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
         SIPCall *call;
 
-        call = (SIPCall*) pjsip_evsub_get_mod_data(sub, getInstance()->getModId());
+        call = (SIPCall*) pjsip_evsub_get_mod_data(sub, _mod_ua.id);
         if (!call)
             return;
 
-        pjsip_evsub_set_mod_data(sub, getInstance()->getModId(), NULL);
+        pjsip_evsub_set_mod_data(sub, _mod_ua.id, 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;}