Skip to content
Snippets Groups Projects
Select Git revision
  • d1e9d14cb47981a3634802784d4a85b216aa31d4
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/releaseWindowsTestOne
  • release/windowsReleaseTest
  • release/releaseTest
  • release/releaseWindowsTest
  • release/201910
  • release/qt/201910
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • 4.0.0
  • 2.2.0
  • 2.1.0
  • 2.0.1
  • 2.0.0
  • 1.4.1
  • 1.4.0
  • 1.3.0
  • 1.2.0
  • 1.1.0
31 results

managerimpl.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    managerimpl.cpp 69.56 KiB
    /*
     *  Copyright (C) 2004-2007 Savoir-Faire Linux inc.
     *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
     *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
     *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
     *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
     *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; either version 3 of the License, or
     *  (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License
     *  along with this program; if not, write to the Free Software
     *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    #include <errno.h>
    #include <time.h>
    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <sstream>  
    #include <sys/types.h> // mkdir(2)
    #include <sys/stat.h>	// mkdir(2)
    
    #include <cc++/socket.h>   // why do I need this here?
    #include <ccrtp/channel.h> // why do I need this here?
    #include <ccrtp/rtp.h>     // why do I need this here?
    #include <cc++/file.h>
    
    #include "manager.h"
    #include "account.h"
    #include "sipaccount.h"
    #include "audio/audiolayer.h"
    #include "audio/alsalayer.h"
    #include "audio/pulselayer.h"
    #include "audio/tonelist.h"
    
    #include "accountcreator.h" // create new account
    #include "sipvoiplink.h"
    
    #include "user_cfg.h"
    
    #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) \
      (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))
    
    ManagerImpl::ManagerImpl (void) 
    	: _hasTriedToRegister(false)
            , _config()
    	, _currentCallId2()
            , _currentCallMutex()
            , _codecBuilder(NULL)
            , _audiodriver(NULL)
            , _dtmfKey(NULL)
            , _codecDescriptorMap()
            , _toneMutex()
            , _telephoneTone(NULL)
            , _audiofile()
            , _spkr_volume(0)
            , _mic_volume(0)
            , _mutex()
    	, _dbus(NULL)
            , _waitingCall()
            , _waitingCallMutex()
            , _nbIncomingWaitingCall(0)
            , _path("")
            , _exist(0)
            , _setupLoaded(false)
            , _firewallPort()
            , _firewallAddr("")
            , _hasZeroconf(false)
            , _callAccountMap()
            , _callAccountMapMutex()
            , _callConfigMap()
            , _accountMap()
    {
      
        // initialize random generator for call id
        srand (time(NULL));
    
    #ifdef TEST
      testAccountMap();
      loadAccountMap();
      testCallAccountMap();
      unloadAccountMap();
    #endif
    
      // should be call before initConfigFile
      // loadAccountMap();, called in init() now.
    }
    
    // never call if we use only the singleton...
    ManagerImpl::~ManagerImpl (void) 
    {
        // terminate();
        _debug("%s stop correctly.\n", PROGNAME);
    }
    
      void 
    ManagerImpl::init() 
    {
        // Load accounts, init map
        loadAccountMap();
     
        initVolume();
    
        if (_exist == 0) {
            _debug("Cannot create config file in your home directory\n");
        }
    
        initAudioDriver();
        selectAudioDriver();
    
        // Initialize the list of supported audio codecs
        initAudioCodec();
    
        AudioLayer *audiolayer = getAudioDriver();
        
        if (audiolayer != 0) {
            unsigned int sampleRate = audiolayer->getSampleRate();
    
            _debugInit("Load Telephone Tone");
            std::string country = getConfigString(PREFERENCES, ZONE_TONE);
            _telephoneTone = new TelephoneTone(country, sampleRate);
    
            _debugInit("Loading DTMF key");
            _dtmfKey = new DTMF(sampleRate);
        }
    
        if (audiolayer == 0)
          audiolayer->stopStream();
    }
    
    void ManagerImpl::terminate()
    {
        _debug("ManagerImpl::terminate \n");
        saveConfig();
    
        unloadAccountMap();
      
        _debug("Unload DTMF Key \n");
        delete _dtmfKey;
    
        _debug("Unload Audio Driver \n");
        delete _audiodriver; _audiodriver = NULL;
    
        _debug("Unload Telephone Tone \n");
        delete _telephoneTone; _telephoneTone = NULL;
    
        _debug("Unload Audio Codecs \n");
        _codecDescriptorMap.deleteHandlePointer();
        
    }
    
    bool
    ManagerImpl::isCurrentCall(const CallID& callId) {
      return (_currentCallId2 == callId ? true : false);
    }
    
    bool
    ManagerImpl::hasCurrentCall() {
      _debug("Current call ID = %s\n", _currentCallId2.c_str());
      if ( _currentCallId2 != "") {
        return true;
      }
      return false;
    }
    
    const CallID& 
    ManagerImpl::getCurrentCallId() {
      return _currentCallId2;
    }
    
    void
    ManagerImpl::switchCall(const CallID& id ) {
      ost::MutexLock m(_currentCallMutex);
      _currentCallId2 = id;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // Management of events' IP-phone user
    ///////////////////////////////////////////////////////////////////////////////
    /* Main Thread */ 
    
      bool
    ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to)
    {
        std::string pattern;
        Call::CallConfiguration callConfig;
        SIPVoIPLink *siplink;
        
        _debug("ManagerImpl::outgoingCall() method \n");
    
        // stopTone(false);
        // playTone();
    
        /* Check what kind of call we are dealing with */
        check_call_configuration (id, to, &callConfig);
        
        if (callConfig == Call::IPtoIP) {
            _debug ("Start IP to IP call\n");
            /* We need to retrieve the sip voiplink instance */
            siplink = SIPVoIPLink::instance("");     
            if (siplink->new_ip_to_ip_call (id, to)) {
                switchCall (id);
                return true;
            }
            else {
                callFailure (id);
            }
            return false;
        } 
    
        if (!accountExists(accountid)) {
            _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
            return false;
        }
      
        if (getAccountFromCall(id) != AccountNULL) {
            _debug("! Manager Error: Outgoing Call: call id already exists\n");
            return false;
        }
      
        if (hasCurrentCall()) {
            _debug("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall(getCurrentCallId());
        }
      
        _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
        associateCallToAccount( id, accountid );
        if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
            switchCall(id);
            return true;
        } else {
            callFailure(id);
            _debug("! Manager Error: An error occur, the call was not created\n");
        }
        return false;
    }
    
    //THREAD=Main : for outgoing Call
      bool
    ManagerImpl::answerCall(const CallID& id)
    {
      bool isActive = false;
    
      stopTone(true);
    
      AccountID currentaccountid = getAccountFromCall( id );
      Call* currentcall = getAccountLink(currentaccountid)->getCall(getCurrentCallId());
      _debug("ManagerImpl::answerCall :: current call->getState %i \n",currentcall->getState());
    
      if (currentcall->getState() == 1)
          isActive = true;
    
      // stopTone(false); 
      _debug("Try to answer call: %s\n", id.data());
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("Answering Call: Call doesn't exists\n");
        return false;
      }
      
      //  if (id != getCurrentCallId()) {
      if (isActive) { 
        _debug("* Manager Info: there is currently a call, try to hold it\n");
    
        onHoldCall(getCurrentCallId());
      }
      
    
      if (!getAccountLink(accountid)->answer(id)) {
        // error when receiving...
        removeCallAccount(id);
        return false;
      }
    
      // if it was waiting, it's waiting no more
      if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
      removeWaitingCall(id);
      switchCall(id);
     
      // std::string codecName = getCurrentCodecName(id);
      // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
      // if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
    
      return true;
    }
    
    //THREAD=Main
      bool
    ManagerImpl::hangupCall(const CallID& id)
    {
        _debug("ManagerImpl::hangupCall(): This function is called when user hangup \n");
        PulseLayer *pulselayer;
        AccountID accountid;
        bool returnValue;
    
        stopTone(false);
    
        /* Broadcast a signal over DBus */
        if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
        
        /* Direct IP to IP call */
        if (getConfigFromCall (id) == Call::IPtoIP) {
            returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);        
        }
    
        /* Classic call, attached to an account */
        else { 
            accountid = getAccountFromCall( id );
            if (accountid == AccountNULL) {
                _debug("! Manager Hangup Call: Call doesn't exists\n");
                return false;
            }
            returnValue = getAccountLink(accountid)->hangup(id);
            removeCallAccount(id);
        }
    
        switchCall("");
    
        if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
            pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
            if(pulselayer)  pulselayer->restorePulseAppsVolume();
        }
      
        return returnValue;
    }
    
    //THREAD=Main
      bool
    ManagerImpl::cancelCall (const CallID& id)
    {
        AccountID accountid;
        bool returnValue;
    
        stopTone(true);
    
        /* Direct IP to IP call */
        if (getConfigFromCall (id) == Call::IPtoIP) {
            returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);        
        }
    
        /* Classic call, attached to an account */
        else { 
            accountid = getAccountFromCall( id );
            if (accountid == AccountNULL) {
                _debug("! Manager Cancel Call: Call doesn't exists\n");
                return false;
            }
            returnValue = getAccountLink(accountid)->cancel(id);
            removeCallAccount(id);
        }
            
        // it could be a waiting call?
        removeWaitingCall(id);
        switchCall("");
    
        return returnValue;
    }
    
    //THREAD=Main
      bool
    ManagerImpl::onHoldCall(const CallID& id)
    {
        AccountID accountid;
        bool returnValue;
        CallID call_id;
    
        stopTone(true);
    
        call_id = id;
    
        /* Direct IP to IP call */
        if (getConfigFromCall (id) == Call::IPtoIP) {
            returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id);        
        }
    
        /* Classic call, attached to an account */
        else { 
            accountid = getAccountFromCall( id );
            if (accountid == AccountNULL) {
                _debug("Manager On Hold Call: Account ID %s or callid %s doesn't exists\n", accountid.c_str(), id.c_str());
                return false;
            }
            returnValue = getAccountLink(accountid)->onhold(id);
        }
    
        removeWaitingCall(id);
        switchCall("");
      
        if (_dbus) _dbus->getCallManager()->callStateChanged(call_id, "HOLD");
    
        return returnValue;
    }
    
    //THREAD=Main
      bool
    ManagerImpl::offHoldCall(const CallID& id)
    {
      
        AccountID accountid;
        bool returnValue, rec;
        std::string codecName;
        CallID call_id;
    
        stopTone(false);
    
        call_id = id;
        //Place current call on hold if it isn't
        if (hasCurrentCall()) 
        { 
            _debug ("Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
            onHoldCall(getCurrentCallId());
        }
    
        /* Direct IP to IP call */
        if (getConfigFromCall (id) == Call::IPtoIP) {
            rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
            returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);        
        }
    
        /* Classic call, attached to an account */
        else { 
            accountid = getAccountFromCall( id );
            if (accountid == AccountNULL) {
                _debug("Manager OffHold Call: Call doesn't exists\n");
                return false;
            }
            _debug("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());
            rec = getAccountLink(accountid)->isRecording(id);
            returnValue = getAccountLink(accountid)->offhold(id);
        }
    
        if (_dbus){ 
            if (rec)
                _dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_RECORD");
            else 
                _dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_CURRENT");
        }
      
        switchCall(id);
    
        codecName = getCurrentCodecName(id);
        // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
        if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
    
        return returnValue;
    }
    
    //THREAD=Main
      bool
    ManagerImpl::transferCall(const CallID& id, const std::string& to)
    {
        AccountID accountid;
        bool returnValue;
      
        stopTone(true);
      
        /* Direct IP to IP call */
        if (getConfigFromCall (id) == Call::IPtoIP) {
            returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);        
        }
    
        /* Classic call, attached to an account */
        else { 
            accountid = getAccountFromCall( id );
            if (accountid == AccountNULL) {
                _debug("! Manager Transfer Call: Call doesn't exists\n");
                return false;
            }
            returnValue = getAccountLink(accountid)->transfer(id, to);
            removeCallAccount(id);
        }
            
        removeWaitingCall(id);
        switchCall("");
      
        if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
        return returnValue;
    }
    
    //THREAD=Main : Call:Incoming
      bool
    ManagerImpl::refuseCall (const CallID& id)
    {
        AccountID accountid;
        bool returnValue;
      
        stopTone(true);
    
         /* Direct IP to IP call */
        if (getConfigFromCall (id) == Call::IPtoIP) {
            returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);        
        }
    
        /* Classic call, attached to an account */
        else { 
            accountid = getAccountFromCall( id );
            if (accountid == AccountNULL) {
                _debug("! Manager OffHold Call: Call doesn't exists\n");
                return false;
            }
            returnValue = getAccountLink(accountid)->refuse(id);
            removeCallAccount(id);
        } 
        
        // if the call was outgoing or established, we didn't refuse it
        // so the method did nothing
        if (returnValue) {
            removeWaitingCall(id);
            if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
            switchCall("");
        }
        return returnValue;
    }
    
    //THREAD=Main
      bool
    ManagerImpl::saveConfig (void)
    {
      _debug("Saving Configuration...\n");
      setConfig(AUDIO, VOLUME_SPKR, getSpkrVolume());
      setConfig(AUDIO, VOLUME_MICRO, getMicVolume());
    
      _setupLoaded = _config.saveConfigTree(_path.data());
      return _setupLoaded;
    }
    
    //THREAD=Main
     int 
    ManagerImpl::initRegisterAccounts() 
    {
        int status; 
        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 the account is set as enabled, try to register */
                if ( iter->second->isEnabled() ) {
    	            status = iter->second->registerVoIPLink();
    	            if (status != SUCCESS){
    		            flag = false;
                    }
                }
            }
            iter++;
        }
    
        // calls the client notification here in case of errors at startup...
        if( _audiodriver -> getErrorMessage() != -1 )
          notifyErrClient( _audiodriver -> getErrorMessage() );
        
        ASSERT( flag, true );
        return SUCCESS;
    }
    
    //THREAD=Main
      bool 
    ManagerImpl::sendDtmf(const CallID& id, char code)
    {
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        //_debug("Send DTMF: call doesn't exists\n");
        playDtmf(code, false);
        return false;
      }
    
      int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
      bool returnValue = false;
      switch (sendType) {
        case 0: // SIP INFO
          playDtmf(code , true);
          returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
          break;
    
        case 1: // Audio way
          break;
        case 2: // rfc 2833
          break;
        default: // unknown - error config?
          break;
      }
      return returnValue;
    }
    
    //THREAD=Main | VoIPLink
      bool
    ManagerImpl::playDtmf(char code, bool isTalking)
    {
        int hasToPlayTone, pulselen, layer, size;
        bool ret = false;
        AudioLayer *audiolayer;
        SFLDataFormat *buf;
      
        stopTone(false);
        
        hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
        if (!hasToPlayTone) 
            return false;
    
        // length in milliseconds
        pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
        if (!pulselen)
            return false;
    
        // numbers of int = length in milliseconds / 1000 (number of seconds)
        //                = number of seconds * SAMPLING_RATE by SECONDS
        audiolayer = getAudioDriver();
        layer = audiolayer->getLayerType();
    
        // fast return, no sound, so no dtmf
        if (audiolayer==0 || _dtmfKey == 0)
            return false;
    
        // number of data sampling in one pulselen depends on samplerate
        // size (n sampling) = time_ms * sampling/s 
        //                     ---------------------
        //                            ms/s
        size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));
    
        // this buffer is for mono
        // TODO <-- this should be global and hide if same size
        buf = new SFLDataFormat[size];
    
        // Handle dtmf
        _dtmfKey->startTone(code);
    
        // copy the sound
        if ( _dtmfKey->generateDTMF(buf, size) ) {
            // Put buffer to urgentRingBuffer 
            // put the size in bytes...
            // so size * 1 channel (mono) * sizeof (bytes for the data)
            audiolayer->startStream();
            audiolayer->putUrgent (buf, size * sizeof(SFLDataFormat));
        }
        ret = true;
    
        // TODO Cache the DTMF
    
        delete[] buf; buf = 0;
        
        return ret;
    }
    
    // Multi-thread 
    bool
    ManagerImpl::incomingCallWaiting() {
      return (_nbIncomingWaitingCall > 0) ? true : false;
    }
    
    void
    ManagerImpl::addWaitingCall(const CallID& id) {
      ost::MutexLock m(_waitingCallMutex);
      _waitingCall.insert(id);
      _nbIncomingWaitingCall++;
    }
    
    void
    ManagerImpl::removeWaitingCall(const CallID& id) {
      ost::MutexLock m(_waitingCallMutex);
      // should return more than 1 if it erase a call
      if (_waitingCall.erase(id)) {
        _nbIncomingWaitingCall--;
      }
    }
    
    bool
    ManagerImpl::isWaitingCall(const CallID& id) {
      CallIDSet::iterator iter = _waitingCall.find(id);
      if (iter != _waitingCall.end()) {
        return false;
      }
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    // Management of event peer IP-phone 
    ////////////////////////////////////////////////////////////////////////////////
    // SipEvent Thread 
    bool 
    ManagerImpl::incomingCall(Call* call, const AccountID& accountId) 
    {
        PulseLayer *pulselayer;
        std::string from, number;
    
        stopTone(true);
    
        _debug("Incoming call %s\n", call->getCallId().data());
    
        associateCallToAccount(call->getCallId(), accountId);
    
        _debug("ManagerImpl::incomingCall :: hasCurrentCall() %i \n",hasCurrentCall());
    
        if ( !hasCurrentCall() ) {
            call->setConnectionState(Call::Ringing);
            ringtone();
            switchCall(call->getCallId());
        
        }
        /* 
        else {
            addWaitingCall(call->getCallId());
        }
        */
    
        addWaitingCall(call->getCallId());
    
        from = call->getPeerName();
        number = call->getPeerNumber();
    
        if (from != "" && number != "") {
            from.append(" <");
            from.append(number);
            from.append(">");
        } else if ( from.empty() ) {
            from.append("<");
            from.append(number);
            from.append(">");
        }
    
        /*
        CallIDSet::iterator iter = _waitingCall.begin();
        while (iter != _waitingCall.end()) {
            CallID ident = *iter;
            _debug("ManagerImpl::incomingCall :: CALL iteration: %s \n",ident.c_str());
            ++iter;
        }
        */
      
        /* Broadcast a signal over DBus */
        if (_dbus) _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);
    
        //if (_dbus) _dbus->getCallManager()->callStateChanged(call->getCallId(), "INCOMING");
      
        // Reduce volume of the other pulseaudio-connected audio applications
        if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
            pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
            if(pulselayer)  pulselayer->reducePulseAppsVolume();
        }
      
        return true;
    }
    
    //THREAD=VoIP
    void
    ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
      if (_dbus) {
        _dbus->getCallManager()->incomingMessage(accountId, message);
      }
    }
    
    //THREAD=VoIP CALL=Outgoing
      void
    ManagerImpl::peerAnsweredCall(const CallID& id)
    {
        if (isCurrentCall(id)) {
            stopTone(false);
        }
      
        if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
      
      std::string codecName = getCurrentCodecName(id);
      // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
      if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
    }
    
    //THREAD=VoIP Call=Outgoing
      void
    ManagerImpl::peerRingingCall(const CallID& id)
    {
      if (isCurrentCall(id)) {
        ringback();
      }
      if (_dbus) _dbus->getCallManager()->callStateChanged(id, "RINGING");
    }
    
    //THREAD=VoIP Call=Outgoing/Ingoing
      void
    ManagerImpl::peerHungupCall(const CallID& id)
    {
        PulseLayer *pulselayer;
        AccountID accountid;
        bool returnValue;
    
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("peerHungupCall: Call doesn't exists\n");
            return;
        }
      
        /* Broadcast a signal over DBus */
        if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
        
        if (isCurrentCall(id)) {
            stopTone(true);
            switchCall("");
        }
    
        returnValue = getAccountLink(accountid)->peerHungup(id);
    
        removeWaitingCall(id);
        removeCallAccount(id);
      
        if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
            pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
            if(pulselayer)  pulselayer->restorePulseAppsVolume();
        }
    }
    
    //THREAD=VoIP
    void
    ManagerImpl::callBusy(const CallID& id) {
      _debug("Call busy\n");
    
      if (_dbus) _dbus->getCallManager()->callStateChanged(id, "BUSY");
      if (isCurrentCall(id) ) {
        playATone(Tone::TONE_BUSY);
        switchCall("");
      }
      removeCallAccount(id);
      removeWaitingCall(id);
    }
    
    //THREAD=VoIP
      void
    ManagerImpl::callFailure(const CallID& id) 
    {
      if (_dbus) _dbus->getCallManager()->callStateChanged(id, "FAILURE");
      _debug("CALL ID = %s\n" , id.c_str());
      if (isCurrentCall(id) ) {
        playATone(Tone::TONE_BUSY);
        switchCall("");
      }
      removeCallAccount(id);
      removeWaitingCall(id);
    
    }
    
    //THREAD=VoIP
      void
    ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, int nb_msg)
    {
      if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, nb_msg) ;
    }
    
    void ManagerImpl::connectionStatusNotification(  )
    {
        if (_dbus)
            _dbus->getConfigurationManager()->accountsChanged();
        else
            _debug("Error: DBus connection not found\n");
    }
    
    /**
     * Multi Thread
     */
    bool ManagerImpl::playATone(Tone::TONEID toneId) 
    {
        int hasToPlayTone;
        AudioLoop *audioloop;
        AudioLayer *audiolayer;
        unsigned int nbSamples;
    
        hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
        if (!hasToPlayTone) 
            return false;
        
        audiolayer = getAudioDriver();
       
        if (_telephoneTone != 0) {
            _toneMutex.enterMutex();
            _telephoneTone->setCurrentTone(toneId);
            _toneMutex.leaveMutex();
    
            audioloop = getTelephoneTone();
            nbSamples = audioloop->getSize();
            SFLDataFormat buf[nbSamples];
        
            if ( audiolayer ){ 
                audiolayer->putUrgent( buf, nbSamples );
            } else 
                return false;
      }
      return true;
    }
    
    /**
     * Multi Thread
     */
    void ManagerImpl::stopTone (bool stopAudio=true)
    {
        int hasToPlayTone;
        AudioLayer *audiolayer;
    
        hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
        if (!hasToPlayTone) 
            return;
    
        if (stopAudio) {
            audiolayer = getAudioDriver();
            if (audiolayer) audiolayer->stopStream();
        }
    
        _toneMutex.enterMutex();
        if (_telephoneTone != 0) {
            _telephoneTone->setCurrentTone(Tone::TONE_NULL);
        }
        _toneMutex.leaveMutex();
    
        // for ringing tone..
        _toneMutex.enterMutex();
        _audiofile.stop();
        _toneMutex.leaveMutex();
    }
    
    /**
     * Multi Thread
     */
      bool
    ManagerImpl::playTone()
    {
      playATone(Tone::TONE_DIALTONE);
      return true;
    }
    
    /**
     * Multi Thread
     */
      bool
    ManagerImpl::playToneWithMessage()
    {
      playATone(Tone::TONE_CONGESTION);
      return true;
    }
    
    /**
     * Multi Thread
     */
    void
    ManagerImpl::congestion () {
      playATone(Tone::TONE_CONGESTION);
    }
    
    /**
     * Multi Thread
     */
    void
    ManagerImpl::ringback () {
      playATone(Tone::TONE_RINGTONE);
    }
    
    /**
     * Multi Thread
     */
      void
    ManagerImpl::ringtone() 
    {
        std::string ringchoice;
        AudioLayer *audiolayer;
        AudioCodec *codecForTone;
        int layer, samplerate;
        bool loadFile;
    
        // stopTone(true);
    
        if( isRingtoneEnabled() )
        {
            //TODO Comment this because it makes the daemon crashes since the main thread
            //synchronizes the ringtone thread.
            
            ringchoice = getConfigString(AUDIO, RING_CHOICE);
            //if there is no / inside the path
            if ( ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos ) {
                // check inside global share directory
                ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + ringchoice; 
            }
    
            audiolayer = getAudioDriver();
            layer = audiolayer->getLayerType();
            if (audiolayer == 0)
                return;
    
    
            samplerate  = audiolayer->getSampleRate();
            codecForTone = _codecDescriptorMap.getFirstCodecAvailable();
    
            _toneMutex.enterMutex(); 
            loadFile = _audiofile.loadFile(ringchoice, codecForTone , samplerate);
            _toneMutex.leaveMutex(); 
    
            if (loadFile) {
                
                _toneMutex.enterMutex(); 
                _audiofile.start();
                _toneMutex.leaveMutex(); 
                if(CHECK_INTERFACE( layer, ALSA )){
                    //ringback();
                
                }
                else{
                    audiolayer->startStream();
                }
            } else {
                ringback();
            }
        
        }
        else
        {
            ringback();
        }
    }
    
      AudioLoop*
    ManagerImpl::getTelephoneTone()
    {
      if(_telephoneTone != 0) {
        ost::MutexLock m(_toneMutex);
        return _telephoneTone->getCurrentTone();
      }
      else {
        return 0;
      }
    }
    
      AudioLoop*
    ManagerImpl::getTelephoneFile()
    {
      ost::MutexLock m(_toneMutex);
      if(_audiofile.isStarted()) {
        return &_audiofile;
      } else {
        return 0;
      }
    }
    
    void ManagerImpl::notificationIncomingCall(void) 
    {
        AudioLayer *audiolayer;
        std::ostringstream frequency;
        unsigned int samplerate, nbSampling;
    
        audiolayer = getAudioDriver();
        if (audiolayer != 0) {
            samplerate = audiolayer->getSampleRate();
            frequency << "440/" << FRAME_PER_BUFFER;
            Tone tone(frequency.str(), samplerate);
            nbSampling = tone.getSize();
            SFLDataFormat buf[nbSampling];
            tone.getNext(buf, tone.getSize());
            /* Put the data in the urgent ring buffer */
            audiolayer->putUrgent (buf, sizeof(SFLDataFormat)*nbSampling);
        }
    }
    
    /**
     * Multi Thread
     */
      bool
    ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr, int port) 
    {
      StunAddress4 mappedAddr;
      struct in_addr in;
      char* addr;
    
      //int fd3, fd4;
      // bool ok = stunOpenSocketPair(stunSvrAddr, &mappedAddr, &fd3, &fd4, port);
      int fd1 = stunOpenSocket(stunSvrAddr, &mappedAddr, port);
      bool ok = (fd1 == -1 || fd1 == INVALID_SOCKET) ? false : true;
      if (ok) {
        closesocket(fd1);
        //closesocket(fd3);
        //closesocket(fd4);
        _firewallPort = mappedAddr.port;
        // Convert ipv4 address to host byte ordering
        in.s_addr = ntohl (mappedAddr.addr);
        addr = inet_ntoa(in);
        _firewallAddr = std::string(addr);
        _debug("STUN Firewall: [%s:%d]\n", _firewallAddr.data(), _firewallPort);
        return true;
      } else {
        _debug("Opening a stun socket pair failed\n");
      }
      return false;
    }
    
      bool
    ManagerImpl::behindNat(const std::string& svr, int port)
    {
      StunAddress4 stunSvrAddr;
      stunSvrAddr.addr = 0;
    
      // Convert char* to StunAddress4 structure
      bool ret = stunParseServerName ((char*)svr.data(), stunSvrAddr);
      if (!ret) {
        _debug("SIP: Stun server address (%s) is not valid\n", svr.data());
        return 0;
      }
    
      // Firewall address
      _debug("STUN server: %s\n", svr.data());
      return getStunInfo(stunSvrAddr, port);
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // Private functions
    ///////////////////////////////////////////////////////////////////////////////
    /**
     * Initialization: Main Thread
     * @return 1: ok
     -1: error directory
     */
    int
    ManagerImpl::createSettingsPath (void) {
      _path = std::string(HOMEDIR) + DIR_SEPARATOR_STR + "." + PROGDIR;
    
      if (mkdir (_path.data(), 0755) != 0) {
        // If directory	creation failed
        if (errno != EEXIST) {
          _debug("Cannot create directory: %s\n", strerror(errno));
          return -1;
        }
      }
    
      // Load user's configuration
      _path = _path + DIR_SEPARATOR_STR + PROGNAME + "rc";
      return 1;
    }
    
    /**
     * Initialization: Main Thread
     */
      void
    ManagerImpl::initConfigFile ( bool load_user_value ) 
    {
      std::string mes = gettext("Init config file\n");
      _debug("%s",mes.c_str());
    
      std::string type_str("string");
      std::string type_int("int");
    
      std::string section;
    
      // Default values, that will be overwritten by the call to
      // 'populateFromFile' below.
      section = SIGNALISATION;
      fill_config_int(SYMMETRIC, YES_STR);
      fill_config_int(PLAY_DTMF, YES_STR);
      fill_config_int(PLAY_TONES, YES_STR);
      fill_config_int(PULSE_LENGTH, DFT_PULSE_LENGTH_STR);
      fill_config_int(SEND_DTMF_AS, SIP_INFO_STR);
      fill_config_int(STUN_ENABLE, DFT_STUN_ENABLE);
      fill_config_int(STUN_SERVER, DFT_STUN_SERVER);
    
      section = AUDIO;
      fill_config_int(ALSA_CARD_ID_IN, ALSA_DFT_CARD);
      fill_config_int(ALSA_CARD_ID_OUT, ALSA_DFT_CARD);
      fill_config_int(ALSA_SAMPLE_RATE, DFT_SAMPLE_RATE);
      fill_config_int(ALSA_FRAME_SIZE, DFT_FRAME_SIZE);
      fill_config_str(ALSA_PLUGIN, PCM_DEFAULT); 
      fill_config_str(RING_CHOICE, DFT_RINGTONE);
      fill_config_int(VOLUME_SPKR, DFT_VOL_SPKR_STR);
      fill_config_int(VOLUME_MICRO, DFT_VOL_MICRO_STR);
      fill_config_str(RECORD_PATH,DFT_RECORD_PATH);
    
      section = PREFERENCES;
      fill_config_str(ZONE_TONE, DFT_ZONE);
      fill_config_int(CONFIG_ZEROCONF, CONFIG_ZEROCONF_DEFAULT_STR);
      fill_config_int(CONFIG_RINGTONE, YES_STR);
      fill_config_int(CONFIG_DIALPAD, YES_STR);
      fill_config_int(CONFIG_SEARCHBAR, YES_STR);
      fill_config_int(CONFIG_START, NO_STR);
      fill_config_int(CONFIG_POPUP, YES_STR);
      fill_config_int(CONFIG_NOTIFY , YES_STR);
      fill_config_int(CONFIG_MAIL_NOTIFY , NO_STR);
      fill_config_int(CONFIG_VOLUME , YES_STR);
      fill_config_int(CONFIG_HISTORY , DFT_MAX_CALLS);
      fill_config_int(REGISTRATION_EXPIRE , DFT_EXPIRE_VALUE);
      fill_config_int(CONFIG_AUDIO , DFT_AUDIO_MANAGER);
      fill_config_int(CONFIG_PA_VOLUME_CTRL , YES_STR);
      fill_config_int(CONFIG_SIP_PORT, DFT_SIP_PORT);
    
      section = ADDRESSBOOK;
      fill_config_int (ADDRESSBOOK_MAX_RESULTS, "25");
      fill_config_int (ADDRESSBOOK_DISPLAY_CONTACT_PHOTO, NO_STR);
      fill_config_int (ADDRESSBOOK_DISPLAY_PHONE_BUSINESS, YES_STR);
      fill_config_int (ADDRESSBOOK_DISPLAY_PHONE_HOME, NO_STR);
      fill_config_int (ADDRESSBOOK_DISPLAY_PHONE_MOBILE, NO_STR);
    
      section = HOOKS;
      fill_config_str (URLHOOK_SIP_FIELD, HOOK_DEFAULT_SIP_FIELD);
      fill_config_str (URLHOOK_COMMAND, HOOK_DEFAULT_URL_COMMAND);
      fill_config_str (URLHOOK_SIP_ENABLED, NO_STR);
    
      // Loads config from ~/.sflphone/sflphonedrc or so..
      if (createSettingsPath() == 1 && load_user_value) {
        _exist = _config.populateFromFile(_path);
      }
    
      _setupLoaded = (_exist == 2 ) ? false : true;
    }
    
    /**
     * Initialization: Main Thread
     */
      void
    ManagerImpl::initAudioCodec (void)
    {
      _debugInit("Active Codecs List");
      // init list of all supported codecs
      _codecDescriptorMap.init();
      // if the user never set the codec list, use the default configuration
      if(getConfigString(AUDIO, "ActiveCodecs") == ""){
        _codecDescriptorMap.setDefaultOrder();
      }
      // else retrieve the one set in the user config file
      else{
        std::vector<std::string> active_list = retrieveActiveCodecs(); 
        setActiveCodecList(active_list);
      }
    }
    
    std::vector<std::string>
    ManagerImpl::retrieveActiveCodecs()
    {
      std::vector<std::string> order;
      std::string  temp;
      std::string s = getConfigString(AUDIO, "ActiveCodecs");
    
      while (s.find("/", 0) != std::string::npos)
      {
        size_t  pos = s.find("/", 0);
        temp = s.substr(0, pos);
        s.erase(0, pos + 1);
        order.push_back(temp);
      }
    
      return order;
    }
    
      void
    ManagerImpl::setActiveCodecList(const std::vector<  std::string >& list)
    {
      _debug("Set active codecs list\n");
      _codecDescriptorMap.saveActiveCodecs(list);
      // setConfig
      std::string s = serialize(list);
      printf("%s\n", s.c_str());
      setConfig("Audio", "ActiveCodecs", s);
    }
    
      std::string
    ManagerImpl::serialize(std::vector<std::string> v)
    {
      unsigned int i;
      std::string res;
      for(i=0;i<v.size();i++)
      {
        res += v[i] + "/";
      }
      return res;
    }
    
    
      std::vector <std::string>
    ManagerImpl::getActiveCodecList( void )
    {
      _debug("Get Active codecs list\n");
      std::vector< std::string > v;
      CodecOrder active = _codecDescriptorMap.getActiveCodecs();
      unsigned int i=0;
      size_t size = active.size();
      while(i<size)
      {
        std::stringstream ss;
        ss << active[i];
        v.push_back((ss.str()).data());
        _debug("%s\n", ss.str().data());
        i++;
      }
      return v;
    }
    
    
    /**
     * Send the list of codecs to the client through DBus.
     */
      std::vector< std::string >
    ManagerImpl::getCodecList( void )
    {
      std::vector<std::string> list;
      //CodecMap codecs = _codecDescriptorMap.getCodecMap();
      CodecsMap codecs = _codecDescriptorMap.getCodecsMap();
      CodecOrder order = _codecDescriptorMap.getActiveCodecs();
      CodecsMap::iterator iter = codecs.begin();  
    
      while(iter!=codecs.end())
      {
        std::stringstream ss;
        if( iter->second != NULL )
        {
          ss << iter->first;
          list.push_back((ss.str()).data());
        }
        iter++;
      }
      return list;
    }
    
      std::vector<std::string>
    ManagerImpl::getCodecDetails( const int32_t& payload )
    {
    
      std::vector<std::string> v;
      std::stringstream ss;
    
      v.push_back(_codecDescriptorMap.getCodecName((AudioCodecType)payload));
      ss << _codecDescriptorMap.getSampleRate((AudioCodecType)payload);
      v.push_back((ss.str()).data()); 
      ss.str("");
      ss << _codecDescriptorMap.getBitRate((AudioCodecType)payload);
      v.push_back((ss.str()).data());
      ss.str("");
      ss << _codecDescriptorMap.getBandwidthPerCall((AudioCodecType)payload);
      v.push_back((ss.str()).data());
      ss.str("");
    
      return v;
    }
    
    std::string
    ManagerImpl::getCurrentCodecName(const CallID& id)
    {
      // _debug("ManagerImpl::getCurrentCodecName method called \n");
      AccountID accountid = getAccountFromCall(id);
      // _debug("ManagerImpl::getCurrentCodecName : %s \n",getAccountLink(accountid)->getCurrentCodecName().c_str());
      return getAccountLink(accountid)->getCurrentCodecName();
    }
    
    /**
     * Get list of supported input audio plugin
     */
      std::vector<std::string>
    ManagerImpl::getInputAudioPluginList(void)
    {
      std::vector<std::string> v;
      _debug("Get input audio plugin list");
    
      v.push_back("default");
      v.push_back("surround40");
      v.push_back("plug:hw");
    
      return v;
    }
    
    /**
     * Get list of supported output audio plugin
     */
      std::vector<std::string>
    ManagerImpl::getOutputAudioPluginList(void)
    {
      std::vector<std::string> v;
      _debug("Get output audio plugin list");
    
      v.push_back( PCM_DEFAULT );
      v.push_back( PCM_DMIX );
    
      return v;
    }
    
    /**
     * Set input audio plugin
     */
      void
    ManagerImpl::setInputAudioPlugin(const std::string& audioPlugin)
    {
      int layer = _audiodriver -> getLayerType();
      if(CHECK_INTERFACE( layer , ALSA ))
      {
      _debug("Set input audio plugin\n");
      _audiodriver -> setErrorMessage( -1 );
      _audiodriver -> openDevice( _audiodriver -> getIndexIn(),
          _audiodriver -> getIndexOut(),
          _audiodriver -> getSampleRate(),
          _audiodriver -> getFrameSize(),
          SFL_PCM_CAPTURE,
          audioPlugin);
      if( _audiodriver -> getErrorMessage() != -1)
        notifyErrClient( _audiodriver -> getErrorMessage() );
    }else{}
    
    }
    
    /**
     * Set output audio plugin
     */
      void
    ManagerImpl::setOutputAudioPlugin(const std::string& audioPlugin)
    {
    
        int res;
    
      _debug("Set output audio plugin\n");
      _audiodriver -> setErrorMessage( -1 );
      res = _audiodriver -> openDevice( _audiodriver -> getIndexIn(),
    			      _audiodriver -> getIndexOut(),
    			      _audiodriver -> getSampleRate(),
    			      _audiodriver -> getFrameSize(),
    			      SFL_PCM_BOTH,
    			      audioPlugin);
      if( _audiodriver -> getErrorMessage() != -1)
        notifyErrClient( _audiodriver -> getErrorMessage() );
      // set config
      if(res)   setConfig( AUDIO , ALSA_PLUGIN , audioPlugin );
    }
    
    /**
     * Get list of supported audio output device
     */
      std::vector<std::string>
    ManagerImpl::getAudioOutputDeviceList(void)
    {
      _debug("Get audio output device list\n");
      AlsaLayer *layer;
    
      layer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
      if (layer)    return layer -> getSoundCardsInfo(SFL_PCM_PLAYBACK);
    }
    
    /**
     * Set audio output device
     */
      void
    ManagerImpl::setAudioOutputDevice(const int index)
    {
        AlsaLayer *alsalayer;
        std::string alsaplugin;
        _debug("Set audio output device: %i\n", index);
      
        _audiodriver -> setErrorMessage( -1 );
        
        alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
        alsaplugin = alsalayer->getAudioPlugin ();
    
        _audiodriver->openDevice(_audiodriver->getIndexIn(), index, _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), SFL_PCM_PLAYBACK, alsaplugin );
      
        if( _audiodriver -> getErrorMessage() != -1)
            notifyErrClient( _audiodriver -> getErrorMessage() );
        
        // set config
        setConfig( AUDIO , ALSA_CARD_ID_OUT , index );
    }
    
    /**
     * Get list of supported audio input device
     */
      std::vector<std::string>
    ManagerImpl::getAudioInputDeviceList(void)
    {
      _debug("Get audio input device list\n");
      AlsaLayer *audiolayer;
    
      audiolayer = dynamic_cast<AlsaLayer *> ( getAudioDriver());
      if(audiolayer)    return audiolayer->getSoundCardsInfo(SFL_PCM_CAPTURE);
    }
    
    /**
     * Set audio input device
     */
      void
    ManagerImpl::setAudioInputDevice(const int index)
    {
        AlsaLayer *alsalayer;
        std::string alsaplugin;
      
        _debug("Set audio input device %i\n", index);
      
        _audiodriver -> setErrorMessage( -1 );
      
        alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
        alsaplugin = alsalayer->getAudioPlugin ();
        
        _audiodriver->openDevice(index, _audiodriver->getIndexOut(), _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), SFL_PCM_CAPTURE, alsaplugin );
    
        if( _audiodriver -> getErrorMessage() != -1)
            notifyErrClient( _audiodriver -> getErrorMessage() );
      
        // set config
        setConfig( AUDIO , ALSA_CARD_ID_IN , index );
    }
    
    /**
     * Get string array representing integer indexes of output and input device
     */
      std::vector<std::string>
    ManagerImpl::getCurrentAudioDevicesIndex()
    {
      _debug("Get current audio devices index\n");
      std::vector<std::string> v;
      std::stringstream ssi , sso;
      sso << _audiodriver->getIndexOut();
      v.push_back( sso.str() );
      ssi << _audiodriver->getIndexIn();
      v.push_back( ssi.str() );
      return v;
    }
    
      int 
    ManagerImpl::isIax2Enabled( void )
    {
      //return ( IAX2_ENABLED ) ? true : false;
    #ifdef USE_IAX
      return true;
    #else
      return false;
    #endif
    }
    
      int
    ManagerImpl::isRingtoneEnabled( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_RINGTONE );
    }
    
      void
    ManagerImpl::ringtoneEnabled( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_RINGTONE ) == RINGTONE_ENABLED )? setConfig(PREFERENCES , CONFIG_RINGTONE , NO_STR ) : setConfig( PREFERENCES , CONFIG_RINGTONE , YES_STR );
    }
    
    std::string
    ManagerImpl::getRingtoneChoice( void )
    {
      // we need the absolute path
      std::string tone_name = getConfigString( AUDIO , RING_CHOICE );
      std::string tone_path ;
      if( tone_name.find( DIR_SEPARATOR_CH ) == std::string::npos )
      {
        // check in ringtone directory ($(PREFIX)/share/sflphone/ringtones)
        tone_path = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + tone_name ; 
      }
      else
      {
        // the absolute has been saved; do nothing
        tone_path = tone_name ;
      }   
      _debug("%s\n", tone_path.c_str());
      return tone_path;
    }
    
    void
    ManagerImpl::setRingtoneChoice( const std::string& tone )
    {
      // we save the absolute path 
      setConfig( AUDIO , RING_CHOICE , tone ); 
    }
    
    std::string
    ManagerImpl::getRecordPath( void )
    {
      return getConfigString( AUDIO, RECORD_PATH );
    }
    
    void 
    ManagerImpl::setRecordPath( const std::string& recPath)
    {
      setConfig( AUDIO, RECORD_PATH, recPath.substr(7));
    }
    
    int
    ManagerImpl::getDialpad( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_DIALPAD );
    }
    
    void
    ManagerImpl::setDialpad( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_DIALPAD ) == DISPLAY_DIALPAD )? setConfig(PREFERENCES , CONFIG_DIALPAD , NO_STR ) : setConfig( PREFERENCES , CONFIG_DIALPAD , YES_STR );
    }
    
    std::string ManagerImpl::getStunServer( void )
    {
      return getConfigString(SIGNALISATION , STUN_SERVER);
    }
    
    void ManagerImpl::setStunServer( const std::string &server )
    {
      setConfig(SIGNALISATION , STUN_SERVER, server );
    }
    
    int ManagerImpl::isStunEnabled (void)
    {
        return getConfigInt(SIGNALISATION , STUN_ENABLE);
    }
    
    void ManagerImpl::enableStun (void)
    {
        /* Update the config */
        ( getConfigInt( SIGNALISATION , STUN_ENABLE ) == STUN_ENABLED )? setConfig(SIGNALISATION , STUN_ENABLE , NO_STR ) : setConfig( SIGNALISATION , STUN_ENABLE , YES_STR );
    
        /* Restart PJSIP */
        this->restartPJSIP (); 
    }
    
    
        int
    ManagerImpl::getVolumeControls( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_VOLUME );
    }
    
    void
    ManagerImpl::setVolumeControls( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_VOLUME ) == DISPLAY_VOLUME_CONTROLS )? setConfig(PREFERENCES , CONFIG_VOLUME , NO_STR ) : setConfig( PREFERENCES , CONFIG_VOLUME , YES_STR );
    }
    
    void
    ManagerImpl::setRecordingCall(const CallID& id)
    {
      _debug("ManagerImpl::setRecording()! \n");
      AccountID accountid = getAccountFromCall( id );
    
      getAccountLink(accountid)->setRecording(id);
    }
    
    bool
    ManagerImpl::isRecording(const CallID& id)
    {
      _debug("ManagerImpl::isRecording()! \n");
      AccountID accountid = getAccountFromCall( id );
    
      return getAccountLink(accountid)->isRecording(id);
    }
    
    void 
    ManagerImpl::startHidden( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_START ) ==  START_HIDDEN)? setConfig(PREFERENCES , CONFIG_START , NO_STR ) : setConfig( PREFERENCES , CONFIG_START , YES_STR );
    }
    
    int 
    ManagerImpl::isStartHidden( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_START );
    }
    
    void 
    ManagerImpl::switchPopupMode( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_POPUP ) ==  WINDOW_POPUP)? setConfig(PREFERENCES , CONFIG_POPUP , NO_STR ) : setConfig( PREFERENCES , CONFIG_POPUP , YES_STR );
    }
    
    void
    ManagerImpl::setMaxCalls( const int& calls )
    {
      setConfig( PREFERENCES , CONFIG_HISTORY , calls );
    }
    
    int
    ManagerImpl::getMaxCalls( void )
    {
      _debug("Max calls =  %i\n" , getConfigInt( PREFERENCES , CONFIG_HISTORY ));
      return getConfigInt( PREFERENCES , CONFIG_HISTORY );
    }
    
    int
    ManagerImpl::getSearchbar( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_SEARCHBAR );
    }
    
    void
    ManagerImpl::setSearchbar( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_SEARCHBAR ) ==  1)? setConfig(PREFERENCES , CONFIG_SEARCHBAR , NO_STR ) : setConfig( PREFERENCES , CONFIG_SEARCHBAR , YES_STR );
    }
    
    int 
    ManagerImpl::popupMode( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_POPUP );
    }
    
    int32_t
    ManagerImpl::getNotify( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_NOTIFY );
    }
    
    void
    ManagerImpl::setNotify( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_NOTIFY ) == NOTIFY_ALL )?  setConfig( PREFERENCES , CONFIG_NOTIFY , NO_STR ) : setConfig( PREFERENCES , CONFIG_NOTIFY , YES_STR ); 
    }
    
    int32_t
    ManagerImpl::getMailNotify( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_MAIL_NOTIFY );
    }
    
    int32_t
    ManagerImpl::getPulseAppVolumeControl( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL );
    }
    
    void
    ManagerImpl::setPulseAppVolumeControl( void )
    {
      (getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) == 1)? setConfig( PREFERENCES , CONFIG_PA_VOLUME_CTRL , NO_STR) : setConfig( PREFERENCES , CONFIG_PA_VOLUME_CTRL , YES_STR) ;
    }
    
    void ManagerImpl::setAudioManager( const int32_t& api )
    {
        int manager;
    
        _debug(" ManagerImpl::setAudioManager :: %i \n",api);
    
        manager = api;
        if( manager == PULSEAUDIO )
        {
            if(app_is_running("pulseaudio") != 0)
            {
                // The pulseaudio daemon is not running
                manager = ALSA;
                notifyErrClient(PULSEAUDIO_NOT_RUNNING);
            }
        }
        
        if(manager == api)
        {
            // it means that we can change the audio manager
            setConfig( PREFERENCES , CONFIG_AUDIO , api) ;
            switchAudioManager();
        }
    }
    
    int32_t
    ManagerImpl::getAudioManager( void )
    {
      return getConfigInt( PREFERENCES , CONFIG_AUDIO );
    }
    
    int
    ManagerImpl::getRegistrationExpireValue( void)
    {
      return getConfigInt( PREFERENCES , REGISTRATION_EXPIRE );
    }
    
    void
    ManagerImpl::setMailNotify( void )
    {
      ( getConfigInt( PREFERENCES , CONFIG_MAIL_NOTIFY ) == NOTIFY_ALL )?  setConfig( PREFERENCES , CONFIG_MAIL_NOTIFY , NO_STR ) : setConfig( PREFERENCES , CONFIG_MAIL_NOTIFY , YES_STR ); 
    }
    
    void
    ManagerImpl::notifyErrClient( const int32_t& errCode )
    {
      if( _dbus ){
        _debug("NOTIFY ERR NUMBER %i\n" , errCode); 
        _dbus -> getConfigurationManager() -> errorAlert( errCode );
      }
    }
    
      int
    ManagerImpl::getAudioDeviceIndex(const std::string name)
    {
        AlsaLayer *alsalayer;
    
        _debug("Get audio device index\n");
        
        alsalayer = dynamic_cast<AlsaLayer *> (getAudioDriver());
        if(alsalayer)   return alsalayer -> soundCardGetIndex( name );
    }
    
      std::string 
    ManagerImpl::getCurrentAudioOutputPlugin( void )
    {
        AlsaLayer *alsalayer;
      
        _debug("Get alsa plugin\n");
        
        alsalayer = dynamic_cast<AlsaLayer *> (getAudioDriver());
        if(alsalayer)   return alsalayer -> getAudioPlugin ();
    }
    
    int ManagerImpl::app_is_running( std::string process )
    {
        std::ostringstream cmd;
    
        cmd << "ps -C " << process;
        return system(cmd.str().c_str());
    }
    
    
    /**
     * Initialization: Main Thread
     */
      void
    ManagerImpl::initAudioDriver(void) 
    {
      
        int error;
        
        _debugInit("AudioLayer Creation");
    
        if( getConfigInt( PREFERENCES , CONFIG_AUDIO ) == ALSA ) 
        {
            _audiodriver = new AlsaLayer( this );
        }
        else if( getConfigInt( PREFERENCES , CONFIG_AUDIO ) == PULSEAUDIO )
        {
            if( app_is_running("pulseaudio") == 0 )
            {
                _audiodriver = new PulseLayer( this );
            } else
            {
                _audiodriver = new AlsaLayer( this );
                setConfig( PREFERENCES, CONFIG_AUDIO, ALSA);
            }
        }
        else
            _debug("Error - Audio API unknown\n");
    
      if (_audiodriver == 0) {
        _debug("Init audio driver error\n");
      } else {
        error = getAudioDriver()->getErrorMessage();
        if (error == -1) {
          _debug("Init audio driver: %i\n", error);
        }
      }
     
    }
    
    /**
     * Initialization: Main Thread and gui
     */
      void
    ManagerImpl::selectAudioDriver (void)
    {
        int layer, numCardIn, numCardOut, sampleRate, frameSize;
        std::string alsaPlugin;
        AlsaLayer *alsalayer;
    
        layer = _audiodriver->getLayerType();
        _debug("Audio layer type: %i\n" , layer);
    
        /* Retrieve the global devices info from the user config */
        alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
        numCardIn  = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
        numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
        sampleRate = getConfigInt( AUDIO , ALSA_SAMPLE_RATE );
        if (sampleRate <=0 || sampleRate > 48000) {
            sampleRate = 44100;
        }
        frameSize = getConfigInt( AUDIO , ALSA_FRAME_SIZE );
    
        /* Only for the ALSA layer, we check the sound card information */
        if (layer == ALSA)
        {
            alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
            if( !alsalayer -> soundCardIndexExist( numCardIn , SFL_PCM_CAPTURE ) )
            {
                _debug(" Card with index %i doesn't exist or cannot capture. Switch to 0.\n", numCardIn);
                numCardIn = ALSA_DFT_CARD_ID ;
                setConfig( AUDIO , ALSA_CARD_ID_IN , ALSA_DFT_CARD_ID );
            }
            if( !alsalayer -> soundCardIndexExist( numCardOut , SFL_PCM_PLAYBACK ) )
            {  
                _debug(" Card with index %i doesn't exist or cannot playback . Switch to 0.\n", numCardOut);
                numCardOut = ALSA_DFT_CARD_ID ;
                setConfig( AUDIO , ALSA_CARD_ID_OUT , ALSA_DFT_CARD_ID );
            }
        }
      
        _audiodriver->setErrorMessage(-1);
        /* Open the audio devices */
        _audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin ); 
        /* Notify the error if there is one */
        if( _audiodriver -> getErrorMessage() != -1 )
            notifyErrClient( _audiodriver -> getErrorMessage());
    
    }
    
    void ManagerImpl::switchAudioManager (void) 
    {
        int type, samplerate, framesize, numCardIn, numCardOut;
        std::string alsaPlugin;
    
        _debug( "Switching audio manager \n");
    
        if(!_audiodriver)
            return;
    
        type = _audiodriver->getLayerType();
        samplerate = getConfigInt( AUDIO , ALSA_SAMPLE_RATE );
        framesize = getConfigInt( AUDIO , ALSA_FRAME_SIZE );
        alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
        numCardIn  = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
        numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
    
        _debug("Deleting current layer... \n" );
        //_audiodriver->closeLayer();
        delete _audiodriver; _audiodriver = NULL;
      
        switch( type ){
            case ALSA:
                _debug("Creating Pulseaudio layer...\n");
                _audiodriver = new PulseLayer( this );
                break;
            case PULSEAUDIO:
                _debug("Creating ALSA layer...\n");
                _audiodriver = new AlsaLayer( this );
                break;
            default:
                _debug("Error: audio layer unknown\n");
        }
      
        _audiodriver->setErrorMessage(-1);
        _audiodriver->openDevice( numCardIn , numCardOut, samplerate, framesize, SFL_PCM_BOTH, alsaPlugin ); 
        if( _audiodriver -> getErrorMessage() != -1 )
            notifyErrClient( _audiodriver -> getErrorMessage());
       
        _debug("Current device: %i \n", type);
        _debug("has current call: %i \n", hasCurrentCall());
    
        // need to stop audio streams if there is currently no call
        if( (type != PULSEAUDIO) && (!hasCurrentCall())) {
            _debug("There is currently a call!!\n");
            _audiodriver->stopStream();
            
        }
    } 
    
    /**
     * Init the volume for speakers/micro from 0 to 100 value
     * Initialization: Main Thread
     */
      void
    ManagerImpl::initVolume()
    {
      _debugInit("Initiate Volume");
      setSpkrVolume(getConfigInt(AUDIO, VOLUME_SPKR));
      setMicVolume(getConfigInt(AUDIO, VOLUME_MICRO));
    }
    
    
    void ManagerImpl::setSpkrVolume(unsigned short spkr_vol) 
    {  
        PulseLayer *pulselayer = NULL;
    
        /* Set the manager sound volume */
        _spkr_volume = spkr_vol; 
    
        /* Only for PulseAudio */
        pulselayer = dynamic_cast<PulseLayer*> (getAudioDriver());
        if (pulselayer)
        {
            if( pulselayer->getLayerType() == PULSEAUDIO )
            {
                if(pulselayer)  pulselayer->setPlaybackVolume (spkr_vol);
            }
        }
    }
    
    void ManagerImpl::setMicVolume(unsigned short mic_vol) 
    {    
        _mic_volume = mic_vol;   
    }
    
    void ManagerImpl::setSipPort( int port )
    {
    }
    
    int ManagerImpl::getSipPort( void )
    {
        return 5060;
    }
    
    
    // TODO: rewrite this
    /**
     * Main Thread
     */
      bool 
    ManagerImpl::getCallStatus(const std::string& sequenceId UNUSED)
    {
      if (!_dbus) { return false; }
      ost::MutexLock m(_callAccountMapMutex);
      CallAccountMap::iterator iter = _callAccountMap.begin();
      TokenList tk;
      std::string code;
      std::string status;
      std::string destination;  
      std::string number;
    
      while (iter != _callAccountMap.end())
      {
        Call* call = getAccountLink(iter->second)->getCall(iter->first);
        Call::ConnectionState state = call->getConnectionState();
        if (state != Call::Connected) {
          switch(state) {
    	case Call::Trying:       code="110"; status = "Trying";       break;
    	case Call::Ringing:      code="111"; status = "Ringing";      break;
    	case Call::Progressing:  code="125"; status = "Progressing";  break;
    	case Call::Disconnected: code="125"; status = "Disconnected"; break;
    	default: code=""; status= "";
          }
        } else {
          switch (call->getState()) {
    	case Call::Active:       code="112"; status = "Established";  break;
    	case Call::Hold:         code="114"; status = "Held";         break;
    	case Call::Busy:         code="113"; status = "Busy";         break;
    	case Call::Refused:      code="125"; status = "Refused";      break;
    	case Call::Error:        code="125"; status = "Error";        break;
    	case Call::Inactive:     code="125"; status = "Inactive";     break;
          }
        }
    
        // No Congestion
        // No Wrong Number
        // 116 <CSeq> <call-id> <acc> <destination> Busy
        destination = call->getPeerName();
        number = call->getPeerNumber();
        if (number!="") {
          destination.append(" <");
          destination.append(number);
          destination.append(">");
        }
        tk.push_back(iter->second);
        tk.push_back(destination);
        tk.push_back(status);
        tk.clear();
    
        iter++;
      }
    
      return true;
    }
    
    //THREAD=Main
      bool 
    ManagerImpl::getConfig(const std::string& section, const std::string& name, TokenList& arg)
    {
      return _config.getConfigTreeItemToken(section, name, arg);
    }
    
    //THREAD=Main
    // throw an Conf::ConfigTreeItemException if not found
      int 
    ManagerImpl::getConfigInt(const std::string& section, const std::string& name)
    {
      try {
        return _config.getConfigTreeItemIntValue(section, name);
      } catch (Conf::ConfigTreeItemException& e) {
        throw e;
      }
      return 0;
    }
    
    //THREAD=Main
    std::string 
    ManagerImpl::getConfigString(const std::string& section, const std::string&
        name)
    {
      try {
        return _config.getConfigTreeItemValue(section, name);
      } catch (Conf::ConfigTreeItemException& e) {
        throw e;
      }
      return "";
    }
    
    //THREAD=Main
      bool 
    ManagerImpl::setConfig(const std::string& section, const std::string& name, const std::string& value)
    {
      return _config.setConfigTreeItem(section, name, value);
    }
    
    //THREAD=Main
      bool 
    ManagerImpl::setConfig(const std::string& section, const std::string& name, int value)
    {
      std::ostringstream valueStream;
      valueStream << value;
      return _config.setConfigTreeItem(section, name, valueStream.str());
    }
    
      std::vector< std::string > 
    ManagerImpl::getAccountList() 
    {
      std::vector< std::string > v; 
    
      AccountMap::iterator iter = _accountMap.begin();
      while ( iter != _accountMap.end() ) {
        if ( iter->second != 0 ) {
          _debug("Account List: %s\n", iter->first.data()); 
          v.push_back(iter->first.data());
    
        }
        iter++;
      }
      _debug("Size: %d\n", v.size());
      return v;
    }
    
    std::map< std::string, std::string > ManagerImpl::getAccountDetails(const AccountID& accountID) 
    {
    
      std::map<std::string, std::string> a;
      std::string accountType;
      RegistrationState state;
      
      state = _accountMap[accountID]->getRegistrationState();
      accountType = getConfigString(accountID, CONFIG_ACCOUNT_TYPE);
    
      a.insert( std::pair<std::string, std::string>( CONFIG_ACCOUNT_ALIAS, getConfigString(accountID, CONFIG_ACCOUNT_ALIAS)) );
      a.insert( std::pair<std::string, std::string>( CONFIG_ACCOUNT_ENABLE, getConfigString(accountID, CONFIG_ACCOUNT_ENABLE) == "1" ? "TRUE": "FALSE"));
      a.insert( std::pair<std::string, std::string>(
    	"Status", 
    	(state == Registered ? "REGISTERED":
    	(state == Unregistered ? "UNREGISTERED":
    	(state == Trying ? "TRYING":
    	(state == ErrorAuth ? "ERROR_AUTH": 
    	(state == ErrorNetwork ? "ERROR_NETWORK": 
    	(state == ErrorHost ? "ERROR_HOST": 
    	(state == ErrorExistStun ? "ERROR_EXIST_STUN": 
    	(state == ErrorConfStun ? "ERROR_CONF_STUN": 
    	(state == Error ? "ERROR": "ERROR")))))))))
    	)
          );
     
      a.insert( std::pair<std::string, std::string>( CONFIG_ACCOUNT_TYPE, accountType ) );
      a.insert( std::pair<std::string, std::string>( USERNAME, getConfigString(accountID, USERNAME) ) );
      a.insert( std::pair<std::string, std::string>( PASSWORD, getConfigString(accountID, PASSWORD) ) );
      a.insert( std::pair<std::string, std::string>( HOSTNAME, getConfigString(accountID, HOSTNAME) ) );
      a.insert( std::pair<std::string, std::string>( CONFIG_ACCOUNT_MAILBOX, getConfigString(accountID, CONFIG_ACCOUNT_MAILBOX)) );
      
      return a;
    }
    
    void ManagerImpl::setAccountDetails( const std::string& accountID, const std::map< std::string, std::string >& details )
    {
    
        std::string accountType;
        Account *acc;
        VoIPLink *link;
      
        accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
    
        setConfig(accountID, CONFIG_ACCOUNT_ALIAS, (*details.find(CONFIG_ACCOUNT_ALIAS)).second);
        setConfig(accountID, CONFIG_ACCOUNT_ENABLE, (*details.find(CONFIG_ACCOUNT_ENABLE)).second == "TRUE" ? "1": "0" );
        setConfig(accountID, CONFIG_ACCOUNT_TYPE, accountType);
        setConfig(accountID, USERNAME, (*details.find(USERNAME)).second);
        setConfig(accountID, PASSWORD, (*details.find(PASSWORD)).second);
        setConfig(accountID, HOSTNAME, (*details.find(HOSTNAME)).second);
        setConfig(accountID, CONFIG_ACCOUNT_MAILBOX,(*details.find(CONFIG_ACCOUNT_MAILBOX)).second);
      
        saveConfig();
      
        acc = getAccount(accountID);
        acc->loadConfig();
        if (acc->isEnabled()){ 
            acc->unregisterVoIPLink();
            acc->registerVoIPLink();
        }
        else 
            acc->unregisterVoIPLink();
    
        // Update account details to the client side
        if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
    
    }
    
    void
    ManagerImpl::sendRegister( const std::string& accountID , const int32_t& expire )
    {
      // Update the active field
      setConfig( accountID, CONFIG_ACCOUNT_ENABLE, expire );
     
      Account* acc = getAccount(accountID);
      acc->loadConfig();
      // Test on the freshly updated value
      if ( acc->isEnabled() ) {
        // Verify we aren't already registered, then register
          _debug("Send register for account %s\n" , accountID.c_str());
          acc->registerVoIPLink();
      } else {
        // Verify we are already registered, then unregister
          _debug("Send unregister for account %s\n" , accountID.c_str());
          acc->unregisterVoIPLink();
      }
    }                   
    
      void
    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. */
    
        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);
    
        saveConfig();
    
        if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
    }
    
      void 
    ManagerImpl::removeAccount(const AccountID& accountID) 
    {
      // Get it down and dying
      Account* remAccount = getAccount(accountID);
    
      if (remAccount) {
        remAccount->unregisterVoIPLink();
        _accountMap.erase(accountID);
        delete remAccount;
      }
    
      _config.removeSection(accountID);
    
      saveConfig();
    
      _debug("REMOVE ACCOUNT\n");
      if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
    }
    
    // ACCOUNT handling
      bool
    ManagerImpl::associateCallToAccount(const CallID& callID, const AccountID& accountID)
    {
      if (getAccountFromCall(callID) == AccountNULL) { // nothing with the same ID
        if (  accountExists(accountID)  ) { // account id exist in AccountMap
          ost::MutexLock m(_callAccountMapMutex);
          _callAccountMap[callID] = accountID;
          _debug("Associate Call %s with Account %s\n", callID.data(), accountID.data());
          return true;
        } else {
          return false; 
        }
      } else {
        return false;
      }
    }
    
      AccountID
    ManagerImpl::getAccountFromCall(const CallID& callID)
    {
      ost::MutexLock m(_callAccountMapMutex);
      CallAccountMap::iterator iter = _callAccountMap.find(callID);
      if ( iter == _callAccountMap.end()) {
        return AccountNULL;
      } else {
        return iter->second;
      }
    }
    
      bool
    ManagerImpl::removeCallAccount(const CallID& callID)
    {
      ost::MutexLock m(_callAccountMapMutex);
      if ( _callAccountMap.erase(callID) ) {
        return true;
      }
      return false;
    }
    
      CallID 
    ManagerImpl::getNewCallID() 
    {
      std::ostringstream random_id("s");
      random_id << (unsigned)rand();
    
      // when it's not found, it return ""
      // generate, something like s10000s20000s4394040
      while (getAccountFromCall(random_id.str()) != AccountNULL) {
        random_id.clear();
        random_id << "s";
        random_id << (unsigned)rand();
      }
      return random_id.str();
    }
    
      short
    ManagerImpl::loadAccountMap()
    {
     
      short nbAccount = 0;
      TokenList sections = _config.getSections();
      std::string accountType;
      Account* tmpAccount;
    
    
      TokenList::iterator iter = sections.begin();
      while(iter != sections.end()) {
        // Check if it starts with "Account:" (SIP and IAX pour le moment)
        if ((int)(iter->find("Account:")) == -1) {
          iter++;
          continue;
        }
    
        accountType = getConfigString(*iter, CONFIG_ACCOUNT_TYPE);
        if (accountType == "SIP") {
          tmpAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, *iter);
        }
        else if (accountType == "IAX") {
          tmpAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, *iter);
        }
        else {
          _debug("Unknown %s param in config file (%s)\n", CONFIG_ACCOUNT_TYPE, accountType.c_str());
        }
     
        _debug("tmpAccount.getRegistrationState() %i \n ",tmpAccount->getRegistrationState());
        if (tmpAccount != NULL) {
        
          _debug(" %s \n", iter->c_str());
          _accountMap[iter->c_str()] = tmpAccount;
          nbAccount++;
        }
    
        iter++;
      }
      _debug("nbAccount loaded %i \n",nbAccount);
      return nbAccount;
    }
    
      void
    ManagerImpl::unloadAccountMap()
    {
    
      AccountMap::iterator iter = _accountMap.begin();
      while ( iter != _accountMap.end() ) {
    
        _debug("-> Deleting account %s\n", iter->first.c_str());
        delete iter->second; iter->second = 0;
    
        iter++;
      }
      _accountMap.clear();
    }
    
      bool
    ManagerImpl::accountExists(const AccountID& accountID)
    {
      AccountMap::iterator iter = _accountMap.find(accountID);
      if ( iter == _accountMap.end() ) {
        return false;
      }
      return true;
    }
    
      Account*
    ManagerImpl::getAccount(const AccountID& accountID)
    {
      AccountMap::iterator iter = _accountMap.find(accountID);
      if ( iter == _accountMap.end() ) {
        return 0;
      }
      return iter->second;
    }
    
    AccountID 
    ManagerImpl::getAccountIdFromNameAndServer(const std::string& userName, const std::string& server)
    {
      AccountMap::iterator iter;
      SIPAccount *account;
    
      // Try to find the account id from username and server name by full match
      for(iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) {
        account = dynamic_cast<SIPAccount *>(iter->second);
        if (account != NULL){
        	if(account->fullMatch(userName, server))
          		return iter->first;
        }
      }
    
      // We failed! Then only match the username
      for(iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) {
        account = dynamic_cast<SIPAccount *>(iter->second);
        if ( account != NULL ) {
        	if(account->userMatch(userName))
          		return iter->first;
        }
      }
    
      // Failed again! return AccountNULL
      return AccountNULL;
    }
    
    AccountMap ManagerImpl::getSipAccountMap( void )
    {
        
        AccountMap::iterator iter;
        AccountMap sipaccounts;
        AccountID id;
        Account *account;
    
        for(iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) {
            if( iter->second->getType() == "sip" ){
                //id = iter->first;
                //account = iter->second;
                //sipaccounts.insert( std::pair<id, account> );
            }
        }
        return sipaccounts;
    }
    
    void ManagerImpl::restartPJSIP (void)
    {
        SIPVoIPLink *siplink;
        siplink = dynamic_cast<SIPVoIPLink*> (getSIPAccountLink ());
        
        this->unregisterCurSIPAccounts();
        /* Terminate and initialize the PJSIP library */
        
        if (siplink) 
        {
            siplink->terminate ();
            siplink = SIPVoIPLink::instance("");
            siplink->init ();
        }
    
        /* Then register all enabled SIP accounts */
        this->registerCurSIPAccounts(siplink);
    }
    
    VoIPLink* ManagerImpl::getAccountLink(const AccountID& accountID)
    {
        if (accountID!=AccountNULL) {
            Account* acc = getAccount(accountID);
            if ( acc ) {
                return acc->getVoIPLink();
            }
            return 0;
        }
        else
            return SIPVoIPLink::instance("");
    }
    
    VoIPLink* ManagerImpl::getSIPAccountLink()
    {
        /* We are looking for the first SIP account we met because all the SIP accounts have the same voiplink */
        Account *account;
        AccountMap::iterator iter;
        for(iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) {
            account = iter->second;
            if( account->getType() == "sip" ){
                return account->getVoIPLink();
            }
        }
        return NULL;
    }
    
    
    
    
    pjsip_regc 
    *getSipRegcFromID(const AccountID& id UNUSED)
    {
      /*SIPAccount *tmp = dynamic_cast<SIPAccount *>getAccount(id);
      if(tmp != NULL)
        return tmp->getSipRegc();
      else*/
        return NULL;
    }
    
    void ManagerImpl::unregisterCurSIPAccounts()
    {
        Account *current;
    
        AccountMap::iterator iter = _accountMap.begin();
        while( iter != _accountMap.end() ) {
            current = iter->second;
            if (current) {
                if ( current->isEnabled() && current->getType() == "sip") {
    	            current->unregisterVoIPLink();
                }
            }
        iter++;
        }
    }
    
    void ManagerImpl::registerCurSIPAccounts(VoIPLink *link)
    {
        
        Account *current;
    
        AccountMap::iterator iter = _accountMap.begin();
    
        while( iter != _accountMap.end() ) {
            current = iter->second;
            
            if (current) {
                if (current->isEnabled() && current->getType() == "sip") {
                    //current->setVoIPLink(link);
    	            current->registerVoIPLink();
                }
            }
            current = NULL;
        iter++;
        }    
    }
    
    
    std::map<std::string, int32_t> ManagerImpl::getAddressbookSettings () {
    
        std::map<std::string, int32_t> settings;
    
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_MAX_RESULTS", getConfigInt (ADDRESSBOOK, ADDRESSBOOK_MAX_RESULTS)) );
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_CONTACT_PHOTO", getConfigInt (ADDRESSBOOK, ADDRESSBOOK_DISPLAY_CONTACT_PHOTO)));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_PHONE_BUSINESS", getConfigInt (ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_BUSINESS)));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_PHONE_HOME", getConfigInt (ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_HOME)));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_PHONE_MOBILE", getConfigInt (ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_MOBILE)));
    
        return settings;
    }
    
    void ManagerImpl::setAddressbookSettings (const std::map<std::string, int32_t>& settings){
    
        setConfig(ADDRESSBOOK, ADDRESSBOOK_MAX_RESULTS, (*settings.find("ADDRESSBOOK_MAX_RESULTS")).second);
        setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_CONTACT_PHOTO , (*settings.find("ADDRESSBOOK_DISPLAY_CONTACT_PHOTO")).second);
        setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_BUSINESS , (*settings.find("ADDRESSBOOK_DISPLAY_PHONE_BUSINESS")).second);
        setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_HOME , (*settings.find("ADDRESSBOOK_DISPLAY_PHONE_HOME")).second);
        setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_MOBILE , (*settings.find("ADDRESSBOOK_DISPLAY_PHONE_MOBILE")).second);
    
        // Write it to the configuration file
        saveConfig ();
    }
    
    
    std::map<std::string, std::string> ManagerImpl::getHookSettings () {
    
        std::map<std::string, std::string> settings;
    
        settings.insert (std::pair<std::string, std::string> ("URLHOOK_SIP_FIELD", getConfigString (HOOKS, URLHOOK_SIP_FIELD)) );
        settings.insert (std::pair<std::string, std::string> ("URLHOOK_COMMAND", getConfigString (HOOKS, URLHOOK_COMMAND)) );
        settings.insert (std::pair<std::string, std::string> ("URLHOOK_SIP_ENABLED", getConfigString (HOOKS, URLHOOK_SIP_ENABLED)) );
    
        return settings;
    }
    
    void ManagerImpl::setHookSettings (const std::map<std::string, std::string>& settings){
    
        setConfig(HOOKS, URLHOOK_SIP_FIELD, (*settings.find("URLHOOK_SIP_FIELD")).second);
        setConfig(HOOKS, URLHOOK_COMMAND, (*settings.find("URLHOOK_COMMAND")).second);
        setConfig(HOOKS, URLHOOK_SIP_ENABLED, (*settings.find("URLHOOK_SIP_ENABLED")).second);
    
        // Write it to the configuration file
        saveConfig ();
    }
    
    
    
    
    void ManagerImpl::check_call_configuration (const CallID& id, const std::string &to, Call::CallConfiguration *callConfig) {
        std::string pattern;
        Call::CallConfiguration config;
    
        /* Check if the call is an IP-to-IP call */
        /* For an IP-to-IP call, we don't need any account */
        /* Pattern looked for : ip:xxx.xxx.xxx.xxx */
        pattern = to.substr (0,3);
        if (pattern==IP_TO_IP_PATTERN) {
            config = Call::IPtoIP;
        } else {
            config = Call::Classic;
        }
        associateConfigToCall (id, config);
        *callConfig = config;
    }
    
    
    bool ManagerImpl::associateConfigToCall (const CallID& callID, Call::CallConfiguration config) {
    
        if (getConfigFromCall(callID) == CallConfigNULL) { // nothing with the same ID
            _callConfigMap[callID] = config;
            _debug("Associate Call %s with config %i\n", callID.data(), config);
            return true;
        } else {
            return false;
        }
    }
    
    Call::CallConfiguration ManagerImpl::getConfigFromCall(const CallID& callID) {
    
        CallConfigMap::iterator iter = _callConfigMap.find(callID);
        if ( iter == _callConfigMap.end()) {
            return (Call::CallConfiguration)CallConfigNULL;
        } else {
            return iter->second;
        }
    }
    
    bool ManagerImpl::removeCallConfig(const CallID& callID) {
    
        if ( _callConfigMap.erase(callID) ) {
            return true;
        }
        return false;
    }