Skip to content
Snippets Groups Projects
Select Git revision
  • 325b12cc3da4f2ee2ccc4b48b6d34ef3d30a73fe
  • master default protected
  • release/201811
  • release/201812
  • release/201901
  • release/201902
  • release/201903
  • release/201904
  • release/201905
  • release/201906
  • release/201908
  • release/201912
  • release/202001
  • release/202005
  • release/windows-test/201910
  • release/201808
  • wip/smartlist_refacto
  • wip/patches_poly_2017/JimmyHamel/MathieuGirouxHuppe
18 results

ring-client-uwp.sln

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    managerimpl.cpp 127.83 KiB
    /*
     *  Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010, 2011 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: Alexandre Savard <alexandre.savard@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.
     *
     *  Additional permission under GNU GPL version 3 section 7:
     *
     *  If you modify this program, or any covered work, by linking or
     *  combining it with the OpenSSL project's OpenSSL library (or a
     *  modified version of that library), containing parts covered by the
     *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
     *  grants you additional permission to convey the resulting work.
     *  Corresponding Source for a non-source form of such a combination
     *  shall include the source code for the parts of OpenSSL used as well
     *  as that of the covered work.
     */
    
    #include "managerimpl.h"
    
    #include "account.h"
    #include "dbus/callmanager.h"
    #include "user_cfg.h"
    #include "global.h"
    #include "sip/sipaccount.h"
    
    //#include "audio/audiolayer.h"
    #include "audio/alsa/alsalayer.h"
    #include "audio/pulseaudio/pulselayer.h"
    #include "audio/sound/tonelist.h"
    #include "history/historymanager.h"
    #include "accountcreator.h" // create new account
    #include "sip/sipvoiplink.h"
    #include "iax/iaxvoiplink.h"
    #include "manager.h"
    #include "dbus/configurationmanager.h"
    
    #include "conference.h"
    
    #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 <pwd.h>       // getpwuid
    
    #define DIRECT_IP_CALL	"IP CALL"
    
    #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)))
    
    #define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len)
    
    ManagerImpl::ManagerImpl (void) :
        _hasTriedToRegister (false), _config(), _currentCallId2(),
        _currentCallMutex(), _audiodriver (NULL),
        _dtmfKey (NULL), _audioCodecFactory(), _toneMutex(),
        _telephoneTone (NULL), _audiofile (NULL), _spkr_volume (0),
        _mic_volume (0), _mutex(), _dbus (NULL), _waitingCall(),
        _waitingCallMutex(), _nbIncomingWaitingCall (0), _path (""),
        _setupLoaded (false), _callAccountMap(),
        _callAccountMapMutex(), _callConfigMap(), _accountMap(),
        _directIpAccount (NULL), _cleaner (NULL), _history (NULL)
    {
    
        // initialize random generator for call id
        srand (time (NULL));
    
        _cleaner = new NumberCleaner();
        _history = new HistoryManager();
        _imModule = new sfl::InstantMessaging();
    
    #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)
    {
        if (_audiofile) {
            delete _audiofile;
            _audiofile = NULL;
        }
    
        delete _cleaner;
        _cleaner = NULL;
        delete _history;
        _history = NULL;
        delete _imModule;
        _imModule = NULL;
    
        _debug ("Manager: %s stop correctly.", PROGNAME);
    }
    
    void ManagerImpl::init ()
    {
    
        _debug ("Manager: Init");
    
        // Load accounts, init map
        buildConfiguration();
    
        _debug ("Manager: account map loaded");
    
        initVolume();
        initAudioDriver();
        selectAudioDriver();
    
        // Initialize the list of supported audio codecs
        initAudioCodec();
    
        audioLayerMutexLock();
    
        if (_audiodriver != NULL) {
            unsigned int sampleRate = _audiodriver->getSampleRate();
    
            _debugInit ("Manager: Load telephone tone");
            std::string country = preferences.getZoneToneChoice();
            _telephoneTone = new TelephoneTone (country, sampleRate);
    
            _debugInit ("Manager: Loading DTMF key (%d)", sampleRate);
            // if(sampleRate > 44100)
    
            sampleRate = 8000;
    
            _dtmfKey = new DTMF (sampleRate);
        }
    
        audioLayerMutexUnlock();
    
        // Load the history
        _history->load_history (preferences.getHistoryLimit());
    
        // Init the instant messaging module
        _imModule->init();
    
    
    }
    
    void ManagerImpl::terminate ()
    {
    
        _debug ("Manager: Terminate ");
    
        std::vector<std::string> callList = getCallList();
        _debug ("Manager: Hangup %d remaining call", callList.size());
        std::vector<std::string>::iterator iter = callList.begin();
    
        while (iter != callList.end()) {
            hangupCall (*iter);
            iter++;
        }
    
        unloadAccountMap();
    
        _debug ("Manager: Unload DTMF key");
        delete _dtmfKey;
    
        _debug ("Manager: Unload telephone tone");
        delete _telephoneTone;
        _telephoneTone = NULL;
    
        audioLayerMutexLock();
    
        _debug ("Manager: Unload audio driver");
        delete _audiodriver;
        _audiodriver = NULL;
    
        _debug ("Manager: Unload audio codecs ");
        _audioCodecFactory.deleteHandlePointer();
    
    }
    
    bool ManagerImpl::isCurrentCall (const CallID& callId)
    {
        return (_currentCallId2 == callId ? true : false);
    }
    
    bool ManagerImpl::hasCurrentCall ()
    {
        // _debug ("ManagerImpl::hasCurrentCall current call ID = %s", _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);
        _debug ("----- Switch current call id to %s -----", id.c_str());
        _currentCallId2 = id;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    // Management of events' IP-phone user
    ///////////////////////////////////////////////////////////////////////////////
    /* Main Thread */
    
    bool ManagerImpl::outgoingCall (const std::string& account_id,
                                    const CallID& call_id, const std::string& to, const std::string& conf_id)
    {
    
        std::string pattern, to_cleaned;
        Call::CallConfiguration callConfig;
        SIPVoIPLink *siplink;
    
        if (call_id.empty()) {
            _debug ("Manager: New outgoing call abbort, missing callid");
            return false;
        }
    
        // Call ID must be unique
        if (getAccountFromCall (call_id) != AccountNULL) {
            _error ("Manager: Error: Call id already exists in outgoing call");
            return false;
        }
    
    
        _debug ("Manager: New outgoing call %s to %s", call_id.c_str(), to.c_str());
    
        stopTone();
    
        CallID current_call_id = getCurrentCallId();
    
        if (hookPreference.getNumberEnabled()) {
            _cleaner->set_phone_number_prefix (hookPreference.getNumberAddPrefix());
        }
        else {
            _cleaner->set_phone_number_prefix ("");
        }
        to_cleaned = _cleaner->clean (to);
    
        /* Check what kind of call we are dealing with */
        checkCallConfiguration (call_id, to_cleaned, &callConfig);
    
        // in any cases we have to detach from current communication
        if (hasCurrentCall()) {
            _debug ("Manager: Has current call (%s) put it onhold", current_call_id.c_str());
    
            // if this is not a conferenceand this and is not a conference participant
            if (!isConference (current_call_id) && !participToConference (current_call_id)) {
           	    onHoldCall (current_call_id);
            } else if (isConference (current_call_id) && !participToConference (call_id)) {
                detachParticipant (default_id, current_call_id);
            }
        }
    
        if (callConfig == Call::IPtoIP) {
            _debug ("Manager: Start IP2IP call");
            /* We need to retrieve the sip voiplink instance */
            siplink = SIPVoIPLink::instance ("");
    
            if (siplink->SIPNewIpToIpCall(call_id, to_cleaned)) {
                switchCall (call_id);
                return true;
            } else {
                callFailure (call_id);
            }
    
            return false;
        }
    
        _debug ("Manager: Selecting account %s", account_id.c_str());
    
        // Is this accout exist
        if (!accountExists (account_id)) {
            _error ("Manager: Error: Account doesn't exist in new outgoing call");
            return false;
        }
    
        if(!associateCallToAccount (call_id, account_id)) {
        	_warn("Manager: Warning: Could not associate call id %s to account id %s", call_id.c_str(), account_id.c_str());
        }
    
        Call *call = NULL;
        try {
            call = getAccountLink(account_id)->newOutgoingCall (call_id, to_cleaned);
            
            switchCall (call_id);
            
            call->setConfId(conf_id);
        } catch (VoipLinkException &e) {
            callFailure (call_id);
            _error ("Manager: %s", e.what());
    	return false;
        }
    
        getMainBuffer()->stateInfo();
    
        return true;
    }
    
    //THREAD=Main : for outgoing Call
    bool ManagerImpl::answerCall (const CallID& call_id)
    {
    
        _debug ("Manager: Answer call %s", call_id.c_str());
    
        // If sflphone is ringing
        stopTone();
    
        // store the current call id
        CallID current_call_id = getCurrentCallId();
    
        // Retreive call coresponding to this id
        AccountID account_id = getAccountFromCall (call_id);
        Call *call = getAccountLink (account_id)->getCall (call_id);
        if (call == NULL) {
            _error("Manager: Error: Call is null");
        }
    
        // in any cases we have to detach from current communication
        if (hasCurrentCall()) {
    
            _debug ("Manager: Currently conversing with %s", current_call_id.c_str());
    
            if (!isConference(current_call_id) && !participToConference (current_call_id)) {
                // if it is not a conference and is not a conference participant
                _debug ("Manager: Answer call: Put the current call (%s) on hold", current_call_id.c_str());
                onHoldCall (current_call_id);
            } else if (isConference (current_call_id) && !participToConference (call_id)) {
                // if we are talking to a conference and we are answering an incoming call
                _debug ("Manager: Detach main participant from conference");
                detachParticipant (default_id, current_call_id);
            }
        }
    
        try {
            if (!getAccountLink (account_id)->answer (call_id)) {
                removeCallAccount (call_id);
                return false;
            }
        }
        catch(VoipLinkException &e) {
        	_error("Manager: Error: %s", e.what());
        }
    
    
        // if it was waiting, it's waiting no more
        removeWaitingCall (call_id);
    
        // if we dragged this call into a conference already
        if (participToConference (call_id)) {
            switchCall (call->getConfId());
        } else {
            switchCall (call_id);
        }
    
        // Connect streams
        addStream (call_id);
    
        getMainBuffer()->stateInfo();
    
        // Start recording if set in preference
        if(audioPreference.getIsAlwaysRecording()) {
        	setRecordingCall(call_id);
        }
    
        // update call state on client side
        if (_dbus == NULL) {
        	_error("Manager: Error: DBUS was not initialized");
        	return false;
        }
    
        if(audioPreference.getIsAlwaysRecording()) {
            _dbus->getCallManager()->callStateChanged (call_id, "RECORD");
        }
        else {
        	_dbus->getCallManager()->callStateChanged(call_id, "CURRENT");
        }
    
        return true;
    }
    
    //THREAD=Main
    bool ManagerImpl::hangupCall (const CallID& callId)
    {
        bool returnValue = true;
    
        _info ("Manager: Hangup call %s", callId.c_str());
    
    
        // First stop audio layer if there is no call anymore
        int nbCalls = getCallList().size();
        if(nbCalls <= 0) {
    
        	audioLayerMutexLock();
    
            if(_audiodriver == NULL) {
            	audioLayerMutexUnlock();
            	_error("Manager: Error: Audio layer was not instantiated");
            	return returnValue;
            }
    
            _debug ("Manager: stop audio stream, there is no call remaining", nbCalls);
            _audiodriver->stopStream();
            audioLayerMutexUnlock();
        }
    
    
        if (_dbus == NULL) {
        	_error("Manager: Error: Dbus layer have not been instantiated");
        	return false;
        }
    
        // store the current call id
        CallID currentCallId = getCurrentCallId();
    
        stopTone();
    
        /* Broadcast a signal over DBus */
        _debug ("Manager: Send DBUS call state change (HUNGUP) for id %s", callId.c_str());
        _dbus->getCallManager()->callStateChanged (callId, "HUNGUP");
    
        if(!isValidCall(callId)) {
        	_error("Manager: Error: Could not hang up call, call not valid");
        	return false;
        }
    
        // Disconnect streams
        removeStream(callId);
    
        if (participToConference (callId)) {
        	Conference *conf = getConferenceFromCallID (callId);
            if (conf != NULL) {
                // remove this participant
                removeParticipant (callId);
                processRemainingParticipant (currentCallId, conf);
            }
        } else {
            // we are not participating to a conference, current call switched to ""
            if (!isConference (currentCallId)) {
                switchCall ("");
            }
        }
    
        if (getConfigFromCall (callId) == Call::IPtoIP) {
            /* Direct IP to IP call */
            returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (callId);
        }
        else {
        	AccountID accountId = getAccountFromCall (callId);
            returnValue = getAccountLink (accountId)->hangup (callId);
            removeCallAccount (callId);
        }
    
        getMainBuffer()->stateInfo();
    
        return returnValue;
    }
    
    bool ManagerImpl::hangupConference (const ConfID& id)
    {
        _debug ("Manager: Hangup conference %s", id.c_str());
    
        ConferenceMap::iterator iter_conf = _conferencemap.find (id);
    
        AccountID currentAccountId;
    
        if (iter_conf != _conferencemap.end()) {
            Conference *conf = iter_conf->second;
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
                _debug ("Manager: Hangup conference participant %s", (*iter_participant).c_str());
    
                hangupCall (*iter_participant);
    
                iter_participant++;
            }
        }
    
        switchCall ("");
    
        getMainBuffer()->stateInfo();
    
        return true;
    }
    
    //THREAD=Main
    bool ManagerImpl::cancelCall (const CallID& id)
    {
        AccountID accountid;
        bool returnValue;
    
        _debug ("Manager: Cancel call");
    
        stopTone();
    
        /* 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");
                return false;
            }
    
            returnValue = getAccountLink (accountid)->cancel (id);
    
            removeCallAccount (id);
        }
    
        // it could be a waiting call?
        removeWaitingCall (id);
    
        removeStream(id);
    
        switchCall ("");
    
        getMainBuffer()->stateInfo();
    
        return returnValue;
    }
    
    //THREAD=Main
    bool ManagerImpl::onHoldCall (const CallID& callId)
    {
        AccountID account_id;
        bool returnValue = false;
    
        _debug ("Manager: Put call %s on hold", callId.c_str());
    
        stopTone();
    
        CallID current_call_id = getCurrentCallId();
    
        try {
    
        	if (getConfigFromCall (callId) == Call::IPtoIP) {
        		/* Direct IP to IP call */
        		returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (callId);
        	}
        	else {
        		/* Classic call, attached to an account */
        		account_id = getAccountFromCall (callId);
    
        		if (account_id == AccountNULL) {
        			_debug ("Manager: Account ID %s or callid %s doesn't exists in call onHold", account_id.c_str(), callId.c_str());
        			return false;
        		}
        		returnValue = getAccountLink (account_id)->onhold (callId);
        	}
        }
        catch (VoipLinkException &e){
        	_error("Manager: Error: %s", e.what());
        }
    
        // Unbind calls in main buffer
        removeStream(callId);
    
        // Remove call from teh queue if it was still there
        removeWaitingCall (callId);
    
        // keeps current call id if the action is not holding this call or a new outgoing call
        // this could happen in case of a conference
        if (current_call_id == callId) {
            switchCall ("");
        }
    
        if (_dbus == NULL) {
        	_error("Manager: Error: DBUS not initialized");
        	return false;
        }
    
        _dbus->getCallManager()->callStateChanged (callId, "HOLD");
    
        getMainBuffer()->stateInfo();
    
        return returnValue;
    }
    
    //THREAD=Main
    bool ManagerImpl::offHoldCall (const CallID& callId)
    {
    
        AccountID accountId;
        bool returnValue, isRec;
        std::string codecName;
    
        isRec = false;
    
        _debug ("Manager: Put call %s off hold", callId.c_str());
    
        stopTone();
    
        CallID currentCallId = getCurrentCallId();
    
        //Place current call on hold if it isn't
    
        if (hasCurrentCall()) {
    
            // if this is not a conference and this and is not a conference participant
            if (!isConference (currentCallId) && !participToConference (currentCallId)) {
            	_debug ("Manager: Has current call (%s), put on hold", currentCallId.c_str());
                onHoldCall (currentCallId);
            } else if (isConference (currentCallId) && !participToConference (callId)) {
                detachParticipant (default_id, currentCallId);
            }
        }
    
        /* Direct IP to IP call */
        if (getConfigFromCall (callId) == Call::IPtoIP) {
            // is_rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id);
            returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (callId);
        }
        /* Classic call, attached to an account */
        else {
            accountId = getAccountFromCall (callId);
    
            _debug ("Manager: Setting offhold, Account %s, callid %s", accountId.c_str(), callId.c_str());
    
            isRec = getAccountLink (accountId)->getCall (callId)->isRecording();
            returnValue = getAccountLink (accountId)->offhold (callId);
        }
    
        if (_dbus == NULL) {
         	_error("Manager: Error: DBUS not initialized");   
        }
    
        if (isRec) {
        	_dbus->getCallManager()->callStateChanged (callId, "UNHOLD_RECORD");
        }
        else {
            _dbus->getCallManager()->callStateChanged (callId, "UNHOLD_CURRENT");
        }
    
        if (participToConference (callId)) {
            AccountID currentAccountId;
            Call* call = NULL;
    
            currentAccountId = getAccountFromCall (callId);
            call = getAccountLink (currentAccountId)->getCall (callId);
    
            switchCall (call->getConfId());
    
        } else {
            switchCall (callId);
        }
    
        addStream(callId);
    
        getMainBuffer()->stateInfo();
    
        return returnValue;
    }
    
    //THREAD=Main
    bool ManagerImpl::transferCall (const CallID& callId, const std::string& to)
    {
        bool returnValue = false;;
    
        _info ("Manager: Transfer call %s", callId.c_str());
    
        CallID currentCallId = getCurrentCallId();
    
        if(participToConference(callId)) {
    	Conference *conf = getConferenceFromCallID(callId);
    	if(conf == NULL) {
    	    _error("Manager: Error: Could not find conference from call id");
            }
    
    	removeParticipant (callId);
    	processRemainingParticipant (callId, conf);
        }
        else {
    	if(!isConference(currentCallId)) {
    	    switchCall("");
    	}
        }
    
        // Direct IP to IP call
        if (getConfigFromCall (callId) == Call::IPtoIP) {
            returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (callId, to);
        }
        // Classic call, attached to an account
        else {
    
            AccountID accountid = getAccountFromCall (callId);
    
            if (accountid == AccountNULL) {
                _warn ("Manager: Call doesn't exists");
                return false;
            }
    
            returnValue = getAccountLink (accountid)->transfer (callId, to);
    
        }
    
        // remove waiting call in case we make transfer without even answer
        removeWaitingCall (callId);
    
        getMainBuffer()->stateInfo();
    
        return returnValue;
    }
    
    void ManagerImpl::transferFailed ()
    {
    
        _debug ("Manager: Transfer failed");
    
        if (_dbus)
            _dbus->getCallManager()->transferFailed();
    }
    
    void ManagerImpl::transferSucceded ()
    {
    
        _debug ("Manager: Transfer succeded");
    
        if (_dbus)
            _dbus->getCallManager()->transferSucceded();
    
    }
    
    bool ManagerImpl::attendedTransfer(const CallID& transferID, const CallID& targetID)
    {
        bool returnValue = false;
    
        _debug("Manager: Attended transfer");
    
        // Direct IP to IP call
        if (getConfigFromCall (transferID) == Call::IPtoIP) {
            returnValue = SIPVoIPLink::instance (AccountNULL)-> attendedTransfer(transferID, targetID);
        }
        else {	// Classic call, attached to an account
    
            AccountID accountid = getAccountFromCall (transferID);
    
            if (accountid == AccountNULL) {
                _warn ("Manager: Call doesn't exists");
    	    return false;
            }
    
            returnValue = getAccountLink (accountid)->attendedTransfer (transferID, targetID);
    
        }
    
        getMainBuffer()->stateInfo();
    
        return returnValue;
    }
    
    //THREAD=Main : Call:Incoming
    bool ManagerImpl::refuseCall (const CallID& id)
    {
        AccountID accountid;
        bool returnValue;
    
        _debug ("Manager: Refuse call %s", id.c_str());
    
        CallID current_call_id = getCurrentCallId();
    
        stopTone();
    
        int nbCalls = getCallList().size();
    
        if (nbCalls <= 1) {
            _debug ("    refuseCall: stop audio stream, there is only %d call(s) remaining", nbCalls);
    
            audioLayerMutexLock();
            _audiodriver->stopStream();
            audioLayerMutexUnlock();
        }
    
        /* 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) {
                _warn ("Manager: Call doesn't exists");
                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");
        }
    
        // Disconnect streams
        removeStream(id);
    
        getMainBuffer()->stateInfo();
    
        return returnValue;
    }
    
    Conference*
    ManagerImpl::createConference (const CallID& id1, const CallID& id2)
    {
        _debug ("Manager: Create conference with call %s and %s", id1.c_str(), id2.c_str());
    
        Conference* conf = new Conference();
    
        conf->add (id1);
        conf->add (id2);
    
        // Add conference to map
        _conferencemap.insert (std::pair<CallID, Conference*> (conf->getConfID(), conf));
    
        // broadcast a signal over dbus
        if (_dbus) {
            _dbus->getCallManager()->conferenceCreated (conf->getConfID());
        }
    
        return conf;
    }
    
    void ManagerImpl::removeConference (const ConfID& conference_id)
    {
    
        _debug ("Manager: Remove conference %s", conference_id.c_str());
    
        Conference* conf = NULL;
    
        _debug ("Manager: number of participant: %d", (int) _conferencemap.size());
        ConferenceMap::iterator iter = _conferencemap.find (conference_id);
    
    
        if (iter != _conferencemap.end()) {
            conf = iter->second;
        }
    
        if (conf == NULL) {
            _error ("Manager: Error: Conference not found");
            return;
        }
    
        // broadcast a signal over dbus
        if (_dbus) {
            _dbus->getCallManager()->conferenceRemoved (conference_id);
        }
    
        // We now need to bind the audio to the remain participant
    
        // Unbind main participant audio from conference
        getMainBuffer()->unBindAll (default_id);
    
        ParticipantSet participants = conf->getParticipantList();
    
        // bind main participant audio to remaining conference call
        ParticipantSet::iterator iter_p = participants.begin();
    
        if (iter_p != participants.end()) {
    
            getMainBuffer()->bindCallID (*iter_p, default_id);
        }
    
        // Then remove the conference from the conference map
        if (_conferencemap.erase (conference_id) == 1) {
            _debug ("Manager: Conference %s removed successfully", conference_id.c_str());
        }
        else {
            _error ("Manager: Error: Cannot remove conference: %s", conference_id.c_str());
        }
    
        delete conf;
    }
    
    Conference*
    ManagerImpl::getConferenceFromCallID (const CallID& call_id)
    {
        AccountID account_id;
        Call* call = NULL;
    
        account_id = getAccountFromCall (call_id);
        call = getAccountLink (account_id)->getCall (call_id);
    
        ConferenceMap::iterator iter = _conferencemap.find (call->getConfId());
    
        if (iter != _conferencemap.end()) {
            return iter->second;
        } else {
            return NULL;
        }
    }
    
    void ManagerImpl::holdConference (const CallID& id)
    {
        _debug ("Manager: Hold conference()");
    
        Conference *conf;
        ConferenceMap::iterator iter_conf = _conferencemap.find (id);
        bool isRec = false;
    
        AccountID currentAccountId;
    
        Call* call = NULL;
    
        if (iter_conf != _conferencemap.end()) {
            conf = iter_conf->second;
    
            if(conf->getState() == Conference::ACTIVE_ATTACHED_REC) {
            	isRec = true;
            } else if (conf->getState() == Conference::ACTIVE_DETACHED_REC) {
            	isRec = true;
            } else if (conf->getState() == Conference::HOLD_REC) {
            	isRec = true;
            }
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
                _debug ("    holdConference: participant %s", (*iter_participant).c_str());
                currentAccountId = getAccountFromCall (*iter_participant);
                call = getAccountLink (currentAccountId)->getCall (*iter_participant);
    
                switchCall (*iter_participant);
                onHoldCall (*iter_participant);
    
                iter_participant++;
    
            }
    
            if(isRec) {
            	conf->setState(Conference::HOLD_REC);
            }
            else {
                conf->setState (Conference::HOLD);
            }
    
            if (_dbus) {
                _dbus->getCallManager()->conferenceChanged (conf->getConfID(), conf->getStateStr());
            }
    
        }
    
    }
    
    void ManagerImpl::unHoldConference (const CallID& id)
    {
        _debug ("Manager: Unhold conference()");
    
        Conference *conf;
        ConferenceMap::iterator iter_conf = _conferencemap.find (id);
        bool isRec = false;
    
        AccountID currentAccountId;
    
        Call* call = NULL;
    
        if (iter_conf != _conferencemap.end()) {
            conf = iter_conf->second;
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            if((conf->getState() == Conference::ACTIVE_ATTACHED_REC) ||
               (conf->getState() == Conference::ACTIVE_DETACHED_REC) ||
               (conf->getState() == Conference::HOLD_REC)) {
            	isRec = true;
            }
    
            while (iter_participant != participants.end()) {
                _debug ("    unholdConference: participant %s", (*iter_participant).c_str());
                currentAccountId = getAccountFromCall (*iter_participant);
                call = getAccountLink (currentAccountId)->getCall (*iter_participant);
    
                // if one call is currently recording, the conference is in state recording
                if(call->isRecording()) {
                	isRec = true;
                }
    
                offHoldCall (*iter_participant);
    
                iter_participant++;
    
            }
    
            if(isRec) {
                conf->setState (Conference::ACTIVE_ATTACHED_REC);
            }
            else {
            	conf->setState (Conference::ACTIVE_ATTACHED);
            }
    
            if (_dbus) {
                _dbus->getCallManager()->conferenceChanged (conf->getConfID(), conf->getStateStr());
            }
        }
    
    }
    
    bool ManagerImpl::isConference (const CallID& id)
    {
        ConferenceMap::iterator iter = _conferencemap.find (id);
    
        if (iter == _conferencemap.end()) {
            return false;
        } else {
            return true;
        }
    }
    
    bool ManagerImpl::participToConference (const CallID& call_id)
    {
        AccountID accountId = getAccountFromCall (call_id);
        Call *call = getAccountLink (accountId)->getCall (call_id);
    
        if (call == NULL) {
        	_error("Manager: Error call is NULL in particip to conference");
            return false;
        }
    
        if (call->getConfId() == "") {
            return false;
        }
    
        return true;
    }
    
    void ManagerImpl::addParticipant (const CallID& callId, const CallID& conferenceId)
    {
        _debug ("Manager: Add participant %s to %s", callId.c_str(), conferenceId.c_str());
    
        ConferenceMap::iterator iter = _conferencemap.find (conferenceId);
        if (iter == _conferencemap.end()) {
        	_error("Manager: Error: Conference id is not valid");
        	return;
        }
    
        AccountID currentAccountId = getAccountFromCall (callId);
        Call *call = getAccountLink (currentAccountId)->getCall (callId);
        if(call == NULL) {
        	_error("Manager: Error: Call id is not valid");
        	return;
        }
    
        // store the current call id (it will change in offHoldCall or in answerCall)
        CallID current_call_id = getCurrentCallId();
    
        // detach from prior communication and switch to this conference
        if (current_call_id != callId) {
            if (isConference (current_call_id)) {
                detachParticipant (default_id, current_call_id);
            } else {
                onHoldCall (current_call_id);
            }
        }
        // TODO: remove this ugly hack => There should be different calls when double clicking
        // a conference to add main participant to it, or (in this case) adding a participant
        // toconference
        switchCall ("");
    
        // Add main participant
        addMainParticipant (conferenceId);
    
        Conference* conf = iter->second;
        switchCall (conf->getConfID());
    
        // Add coresponding IDs in conf and call
        call->setConfId (conf->getConfID());
        conf->add (callId);
    
        // Connect new audio streams together
        getMainBuffer()->unBindAll (callId);
    
        std::map<std::string, std::string> callDetails = getCallDetails (callId);
        std::string callState = callDetails.find("CALL_STATE")->second;
        if (callState == "HOLD") {
        	conf->bindParticipant (callId);
        	offHoldCall (callId);
        } else if (callState == "INCOMING") {
        	conf->bindParticipant (callId);
        	answerCall (callId);
        } else if (callState == "CURRENT") {
        	conf->bindParticipant (callId);
        }
    
        ParticipantSet participants = conf->getParticipantList();
        if(participants.empty()) {
        	_error("Manager: Error: Participant list is empty for this conference");
        }
    
        // reset ring buffer for all conference participant
        ParticipantSet::iterator iter_p = participants.begin();
        while (iter_p != participants.end()) {
        	// flush conference participants only
        	getMainBuffer()->flush (*iter_p);
        	iter_p++;
        }
    
        getMainBuffer()->flush (default_id);
    
        // Connect stream
        addStream(callId);
    }
    
    void ManagerImpl::addMainParticipant (const CallID& conference_id)
    {
        if (hasCurrentCall()) {
            CallID current_call_id = getCurrentCallId();
    
            if (isConference (current_call_id)) {
                detachParticipant (default_id, current_call_id);
            } else {
                onHoldCall (current_call_id);
            }
        }
    
        ConferenceMap::iterator iter = _conferencemap.find (conference_id);
    
        Conference *conf = NULL;
    
        audioLayerMutexLock();
    
        _debug("Manager: Add Main Participant");
    
        if (iter != _conferencemap.end()) {
            conf = iter->second;
    
            ParticipantSet participants = conf->getParticipantList();
    
            ParticipantSet::iterator iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
                getMainBuffer()->bindCallID (*iter_participant, default_id);
                iter_participant++;
            }
    
            // Reset ringbuffer's readpointers
            iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
                getMainBuffer()->flush (*iter_participant);
                iter_participant++;
            }
    
            getMainBuffer()->flush (default_id);
    
            if(conf->getState() == Conference::ACTIVE_DETACHED) {
                conf->setState (Conference::ACTIVE_ATTACHED);
            }
            else if(conf->getState() == Conference::ACTIVE_DETACHED_REC) {
            	conf->setState(Conference::ACTIVE_ATTACHED_REC);
            }
            else {
            	_warn("Manager: Warning: Invalid conference state while adding main participant");
            }
    
            if (_dbus)
                _dbus->getCallManager()->conferenceChanged (conference_id, conf->getStateStr());
    
        }
    
        audioLayerMutexUnlock();
    
        switchCall (conference_id);
    }
    
    void ManagerImpl::joinParticipant (const CallID& callId1, const CallID& callId2)
    {
    	bool isRec = false;
    
        _debug ("Manager: Join participants %s, %s", callId1.c_str(), callId2.c_str());
    
        std::map<std::string, std::string> call1Details = getCallDetails (callId1);
        std::map<std::string, std::string> call2Details = getCallDetails (callId2);
    
        CallID current_call_id = getCurrentCallId();
        _debug ("Manager: Current Call ID %s", current_call_id.c_str());
    
        // detach from the conference and switch to this conference
        if ( (current_call_id != callId1) && (current_call_id != callId2)) {
    
            if (isConference (current_call_id)) {
            	// If currently in a conference
                detachParticipant (default_id, current_call_id);
            }
            else {
                // If currently in a call
                onHoldCall (current_call_id);
            }
        }
    
        Conference *conf = createConference (callId1, callId2);
    
        // Set corresponding conference ids for call 1
        AccountID currentAccountId1 = getAccountFromCall (callId1);
        Call *call1 = getAccountLink (currentAccountId1)->getCall (callId1);
        if(call1 == NULL) {
        	_error("Manager: Could not find call %s", callId1.c_str());
        }
        call1->setConfId (conf->getConfID());
        getMainBuffer()->unBindAll(callId1);
    
        // Set corresponding conderence details
        AccountID currentAccountId2 = getAccountFromCall (callId2);
        Call *call2 = getAccountLink (currentAccountId2)->getCall (callId2);
        if(call2 == NULL) {
        	_error("Manager: Could not find call %s", callId2.c_str());
        }
        call2->setConfId (conf->getConfID());
        getMainBuffer()->unBindAll(callId2);
    
    
        // Process call1 according to its state
        std::string call1_state_str = call1Details.find ("CALL_STATE")->second;
        _debug ("Manager: Process call %s state: %s", callId1.c_str(), call1_state_str.c_str());
    
        if (call1_state_str == "HOLD") {
        	conf->bindParticipant (callId1);
            offHoldCall (callId1);
        } else if (call1_state_str == "INCOMING") {
        	conf->bindParticipant (callId1);
            answerCall (callId1);
        } else if (call1_state_str == "CURRENT") {
            conf->bindParticipant (callId1);
        } else if (call1_state_str == "RECORD") {
        	conf->bindParticipant(callId1);
        	isRec = true;
        } else if (call1_state_str == "INACTIVE") {
            conf->bindParticipant (callId1);
            answerCall (callId1);
        } else {
            _warn ("Manager: Call state not recognized");
        }
    
        // Process call2 according to its state
        std::string call2_state_str = call2Details.find ("CALL_STATE")->second;
        _debug ("Manager: Process call %s state: %s", callId2.c_str(), call2_state_str.c_str());
    
        if (call2_state_str == "HOLD") {
        	conf->bindParticipant (callId2);
            offHoldCall (callId2);
        } else if (call2_state_str == "INCOMING") {
        	conf->bindParticipant (callId2);
            answerCall (callId2);
        } else if (call2_state_str == "CURRENT") {
            conf->bindParticipant (callId2);
        } else if (call2_state_str == "RECORD") {
        	conf->bindParticipant (callId2);
        	isRec = true;
        } else if (call2_state_str == "INACTIVE") {
        	conf->bindParticipant (callId2);
            answerCall (callId2);
        } else {
            _warn ("Manager: Call state not recognized");
        }
    
        // Switch current call id to this conference
        switchCall (conf->getConfID());
        conf->setState(Conference::ACTIVE_ATTACHED);
    
        // set recording sampling rate
        audioLayerMutexLock();
        if (_audiodriver) {
        	conf->setRecordingSmplRate(_audiodriver->getSampleRate());
        }
        audioLayerMutexUnlock();
    
        getMainBuffer()->stateInfo();
    }
    
    void ManagerImpl::createConfFromParticipantList(const std::vector< std::string > &participantList)
    {
        bool callSuccess;
        int successCounter = 0;
    
        _debug("Manager: Create conference from participant list");
    
        // we must at least have 2 participant for a conference
        if(participantList.size() <= 1) {
            _error("Manager: Error: Participant number must be higher or equal to 2");
    	return;
        }
    
        Conference *conf = new Conference();
    
        for(unsigned int i = 0; i < participantList.size(); i++) {
    	std::string numberaccount = participantList[i];
    	std::string tostr = numberaccount.substr(0, numberaccount.find(","));
            std::string account = numberaccount.substr(numberaccount.find(",")+1, numberaccount.size());
    		
    	std::string generatedCallID = getNewCallID();
    
    	// Manager methods may behave differently if the call id particip to a conference
    	conf->add(generatedCallID);
    
    	switchCall("");
    
    	// Create call
    	callSuccess = outgoingCall(account, generatedCallID, tostr, conf->getConfID());
    
            // If not able to create call remove this participant from the conference
    	if(!callSuccess)
    	    conf->remove(generatedCallID);
    
    	if(_dbus && callSuccess) {
    	    _dbus->getCallManager()->newCallCreated(account, generatedCallID, tostr);
    	    successCounter++;
    	}	
        }
    
        // Create the conference if and only if at least 2 calls have been successfully created
        if(successCounter >= 2 ) {
            _conferencemap.insert(std::pair<CallID, Conference *> (conf->getConfID(), conf));
    
            if (_dbus) {
                _dbus->getCallManager()->conferenceCreated (conf->getConfID());
            }
    
    	audioLayerMutexLock();
    	if(_audiodriver) {
    	    conf->setRecordingSmplRate(_audiodriver->getSampleRate());
            }
    	audioLayerMutexUnlock();
    
    	getMainBuffer()->stateInfo();
        }
        else {
    	delete conf;
    	conf = NULL;
        }
        
    }
    
    void ManagerImpl::detachParticipant (const CallID& call_id,
                                         const CallID& current_id)
    {
    
        _debug ("Manager: Detach participant %s (current id: %s)", call_id.c_str(), current_id.c_str());
    
    
        CallID current_call_id = getCurrentCallId();
    
        if (call_id != default_id) {
    
            AccountID currentAccountId = getAccountFromCall (call_id);
            Call *call = getAccountLink (currentAccountId)->getCall (call_id);
    
            if(call == NULL) {
            	_error("Manager: Error: Could not find call %s", call_id.c_str());
            	return;
            }
    
            // TODO: add conference_id as a second parameter
            ConferenceMap::iterator iter = _conferencemap.find (call->getConfId());
    
            Conference *conf = getConferenceFromCallID (call_id);
            if (conf == NULL) {
                _error ("Manager: Error: Call is not conferencing, cannot detach");
                return;
            }
    
            std::map<std::string, std::string> call_details = getCallDetails (call_id);
            std::map<std::string, std::string>::iterator iter_details;
    
            iter_details = call_details.find ("CALL_STATE");
            if(iter_details == call_details.end()) {
            	_error ("Manager: Error: Could not find CALL_STATE");
            	return;
            }
    
            if (iter_details->second == "RINGING") {
            	removeParticipant (call_id);
            } else {
            	onHoldCall (call_id);
            	removeParticipant (call_id);
            	processRemainingParticipant (current_call_id, conf);
            }
        } else {
    
            _debug ("Manager: Unbind main participant from conference %d");
            getMainBuffer()->unBindAll (default_id);
    
            if(!isConference(current_call_id)) {
            	_error("Manager: Warning: Current call id (%s) is not a conference", current_call_id.c_str());
            	return;
            }
    
            ConferenceMap::iterator iter = _conferencemap.find (current_call_id);
            Conference *conf = iter->second;
    
            if(conf == NULL) {
            	_debug("Manager: Error: Conference is NULL");
            	return;
            }
    
            if(conf->getState() == Conference::ACTIVE_ATTACHED) {
            	conf->setState(Conference::ACTIVE_DETACHED);
            }
            else if(conf->getState() == Conference::ACTIVE_ATTACHED_REC) {
            	conf->setState(Conference::ACTIVE_DETACHED_REC);
            }
            else {
            	_warn("Manager: Warning: Undefined behavior, invalid conference state in detach participant");
            }
    
            if (_dbus) {
            	_dbus->getCallManager()->conferenceChanged (conf->getConfID(), conf->getStateStr());
            }
    
            switchCall ("");
    
        }
    }
    
    void ManagerImpl::removeParticipant (const CallID& call_id)
    {
        _debug ("Manager: Remove participant %s", call_id.c_str());
    
        // TODO: add conference_id as a second parameter
        Conference* conf;
    
        AccountID currentAccountId;
        Call* call = NULL;
    
        // this call is no more a conference participant
        currentAccountId = getAccountFromCall (call_id);
        call = getAccountLink (currentAccountId)->getCall (call_id);
    
        ConferenceMap conf_map = _conferencemap;
        ConferenceMap::iterator iter = conf_map.find (call->getConfId());
    
        if (iter == conf_map.end()) {
            _error ("Manager: Error: No conference with id %s, cannot remove participant", call->getConfId().c_str());
            return;
        }
    
        conf = iter->second;
    
        _debug ("Manager: Remove participant %s", call_id.c_str());
        conf->remove (call_id);
        call->setConfId ("");
    
        removeStream(call_id);
    
        getMainBuffer()->stateInfo();
    }
    
    void ManagerImpl::processRemainingParticipant (CallID current_call_id, Conference *conf)
    {
    
        _debug ("Manager: Process remaining %d participant(s) from conference %s",
                conf->getNbParticipants(), conf->getConfID().c_str());
    
        if (conf->getNbParticipants() > 1) {
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            // Reset ringbuffer's readpointers
            iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
                getMainBuffer()->flush (*iter_participant);
    
                iter_participant++;
            }
    
            getMainBuffer()->flush (default_id);
    
        } else if (conf->getNbParticipants() == 1) {
    
            _debug ("Manager: Only one remaining participant");
    
            AccountID currentAccountId;
            Call* call = NULL;
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            // bind main participant to remaining conference call
            if (iter_participant != participants.end()) {
    
                // this call is no more a conference participant
                currentAccountId = getAccountFromCall (*iter_participant);
                call = getAccountLink (currentAccountId)->getCall (*iter_participant);
                call->setConfId ("");
    
                // if we are not listening to this conference
    
                if (current_call_id != conf->getConfID()) {
                    onHoldCall (call->getCallId());
                } else {
                    switchCall (*iter_participant);
                }
            }
    
            removeConference (conf->getConfID());
    
        } else {
    
            _debug ("Manager: No remaining participant, remove conference");
    
            removeConference (conf->getConfID());
    
            switchCall ("");
        }
    
    }
    
    void ManagerImpl::joinConference (const CallID& conf_id1,
                                      const CallID& conf_id2)
    {
        _debug ("Manager: Join conference %s, %s", conf_id1.c_str(), conf_id2.c_str());
    
        ConferenceMap::iterator iter;
    
        Conference *conf1 = NULL;
        Conference *conf2 = NULL;
    
        iter = _conferencemap.find (conf_id1);
    
        if (iter != _conferencemap.end()) {
            conf1 = iter->second;
        } else {
            _error ("Manager: Error: Not a valid conference ID");
            return;
        }
    
        iter = _conferencemap.find (conf_id2);
    
        if (iter != _conferencemap.end()) {
            conf2 = iter->second;
        } else {
            _error ("Manager: Error: Not a valid conference ID");
            return;
        }
    
        ParticipantSet participants = conf1->getParticipantList();
    
        ParticipantSet::iterator iter_participant = participants.begin();
    
        while (iter_participant != participants.end()) {
            detachParticipant (*iter_participant, "");
            addParticipant (*iter_participant, conf_id2);
    
            iter_participant++;
        }
    
    }
    
    void ManagerImpl::addStream (const CallID& call_id)
    {
    
        _debug ("Manager: Add audio stream %s", call_id.c_str());
    
        AccountID currentAccountId;
        Call* call = NULL;
    
        currentAccountId = getAccountFromCall (call_id);
        call = getAccountLink (currentAccountId)->getCall (call_id);
    
        if (participToConference (call_id)) {
    
            _debug ("Manager: Add stream to conference");
    
            // bind to conference participant
            ConferenceMap::iterator iter = _conferencemap.find (call->getConfId());
    
            if (iter != _conferencemap.end()) {
                Conference* conf = iter->second;
    
                conf->bindParticipant (call_id);
    
                ParticipantSet participants = conf->getParticipantList();
    
                // reset ring buffer for all conference participant
                ParticipantSet::iterator iter_p = participants.begin();
    
                while (iter_p != participants.end()) {
    
                    // to avoid puting onhold the call
                    // switchCall("");
                    getMainBuffer()->flush (*iter_p);
    
                    iter_p++;
                }
    
                getMainBuffer()->flush (default_id);
            }
    
        } else {
            _debug ("Manager: Add stream to call");
    
            // bind to main
            getMainBuffer()->bindCallID (call_id);
    
            audioLayerMutexLock();
            _audiodriver->flushUrgent();
            _audiodriver->flushMain();
            audioLayerMutexUnlock();
        }
    
        getMainBuffer()->stateInfo();
    }
    
    void ManagerImpl::removeStream (const CallID& call_id)
    {
        _debug ("Manager: Remove audio stream %s", call_id.c_str());
    
        getMainBuffer()->unBindAll (call_id);
    
        getMainBuffer()->stateInfo();
    }
    
    //THREAD=Main
    bool ManagerImpl::saveConfig (void)
    {
        _debug ("Manager: Saving Configuration to XDG directory %s", _path.c_str());
        audioPreference.setVolumemic (getMicVolume());
        audioPreference.setVolumespkr (getSpkrVolume());
    
        AccountMap::iterator iter = _accountMap.begin();
    
        try {
            // emitter = new Conf::YamlEmitter("sequenceEmitter.yml");
            emitter = new Conf::YamlEmitter (_path.c_str());
    
            while (iter != _accountMap.end()) {
    
            	// Skip the "" account ID (which refer to the IP2IP account)
                if (iter->first == "") {
                    iter++;
                    continue;
                }
    
                iter->second->serialize (emitter);
                iter++;
            }
    
            preferences.serialize (emitter);
            voipPreferences.serialize (emitter);
            addressbookPreference.serialize (emitter);
            hookPreference.serialize (emitter);
            audioPreference.serialize (emitter);
            shortcutPreferences.serialize (emitter);
    
            emitter->serializeData();
    
            delete emitter;
        } catch (Conf::YamlEmitterException &e) {
            _error ("ConfigTree: %s", e.what());
        }
    
        return _setupLoaded;
    }
    
    //THREAD=Main
    bool ManagerImpl::sendDtmf (const CallID& id, char code)
    {
        _debug ("Manager: Send DTMF for call %s", id.c_str());
    
        AccountID accountid = getAccountFromCall (id);
    
        playDtmf (code);
    
        CallAccountMap::iterator iter = _callAccountMap.find (id);
    
        bool returnValue = getAccountLink (accountid)->carryingDTMFdigits (id, code);
    
        return returnValue;
    }
    
    //THREAD=Main | VoIPLink
    bool ManagerImpl::playDtmf (char code)
    {
        int pulselen, layerType, size;
        bool ret = false;
        SFLDataFormat *buf;
    
        stopTone();
    
        bool hasToPlayTone = voipPreferences.getPlayDtmf();
    
        if (!hasToPlayTone) {
            _debug ("Manager: playDtmf: Do not have to play a tone...");
            return false;
        }
    
        // length in milliseconds
        pulselen = voipPreferences.getPulseLength();
    
        if (!pulselen) {
            _debug ("Manager: playDtmf: Pulse length is not set...");
            return false;
        }
    
        audioLayerMutexLock();
    
        // numbers of int = length in milliseconds / 1000 (number of seconds)
        //                = number of seconds * SAMPLING_RATE by SECONDS
    
        layerType = _audiodriver->getLayerType();
    
        // fast return, no sound, so no dtmf
        if (_audiodriver == NULL || _dtmfKey == NULL) {
            _debug ("Manager: playDtmf: Error no audio layer...");
            audioLayerMutexUnlock();
            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) _audiodriver->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->flushUrgent();
            _audiodriver->startStream();
            _audiodriver->putUrgent (buf, size * sizeof (SFLDataFormat));
        }
    
        audioLayerMutexUnlock();
    
        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)
    {
    
        _info ("Manager: Add waiting call %s (%d calls)", id.c_str(), _nbIncomingWaitingCall);
    
        ost::MutexLock m (_waitingCallMutex);
        _waitingCall.insert (id);
        _nbIncomingWaitingCall++;
    }
    
    void ManagerImpl::removeWaitingCall (const CallID& id)
    {
    
        _info ("Manager: Remove waiting call %s (%d calls)", id.c_str(), _nbIncomingWaitingCall);
    
        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)
    {
    
        std::string from, number, display_name, display;
    
        if (!call)
            _error ("Manager: Error: no call at this point");
    
        stopTone();
    
        _debug ("Manager: Incoming call %s for account %s", call->getCallId().data(), accountId.c_str());
    
        associateCallToAccount (call->getCallId(), accountId);
    
        // If account is null it is an ip to ip call
        if (accountId == AccountNULL) {
            associateConfigToCall (call->getCallId(), Call::IPtoIP);
        } else {
            // strip sip: which is not required and bring confusion with ip to ip calls
            // when placing new call from history (if call is IAX, do nothing)
            std::string peerNumber = call->getPeerNumber();
    
            int startIndex = peerNumber.find ("sip:");
    
            if (startIndex != (int) std::string::npos) {
                std::string strippedPeerNumber = peerNumber.substr (startIndex + 4);
                call->setPeerNumber (strippedPeerNumber);
            }
    
        }
    
        if (!hasCurrentCall()) {
            _debug ("Manager: Has no current call start ringing");
    
            call->setConnectionState (Call::Ringing);
            ringtone (accountId);
    
        } else {
            _debug ("Manager: has current call, beep in current audio stream");
        }
    
        addWaitingCall (call->getCallId());
    
        from = call->getPeerName();
        number = call->getPeerNumber();
        display_name = call->getDisplayName();
    
        if (from != "" && number != "") {
            from.append (" <");
            from.append (number);
            from.append (">");
        } else if (from.empty()) {
            from.append ("<");
            from.append (number);
            from.append (">");
        }
    
        /* Broadcast a signal over DBus */
        _debug ("Manager: From: %s, Number: %s, Display Name: %s", from.c_str(), number.c_str(), display_name.c_str());
    
        display = display_name;
        display.append (" ");
        display.append (from);
    
        if (_dbus) {
            _dbus->getCallManager()->incomingCall (accountId, call->getCallId(), display.c_str());
        }
    
        return true;
    }
    
    
    //THREAD=VoIP
    void ManagerImpl::incomingMessage (const CallID& callID,
                                       const std::string& from,
                                       const std::string& message)
    {
    
        if (participToConference (callID)) {
            _debug ("Manager: Particip to a conference, send message to everyone");
    
            Conference *conf = getConferenceFromCallID (callID);
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
    
                if (*iter_participant == callID)
                    continue;
    
                AccountID accountId = getAccountFromCall (*iter_participant);
    
                _debug ("Manager: Send message to %s, (%s)", (*iter_participant).c_str(), accountId.c_str());
    
                Account *account = getAccount (accountId);
    
                if (!account) {
                    _debug ("Manager: Failed to get account while sending instant message");
                    return;
                }
    
                if (account->getType() == "SIP")
                    // link = dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId));
                    dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId))->sendTextMessage (_imModule, callID, message, from);
                else if (account->getType() == "IAX")
                    // link = dynamic_cast<IAXVoIPLink *> (account->getVoIPLink());
                    dynamic_cast<IAXVoIPLink *> (account->getVoIPLink())->sendTextMessage (_imModule, callID, message, from);
                else {
                    _debug ("Manager: Failed to get voip link while sending instant message");
                    return;
                }
    
                iter_participant++;
            }
    
            // in case of a conference we must notify client using conference id
            if (_dbus) {
                _dbus->getCallManager()->incomingMessage (conf->getConfID(), from, message);
            }
    
        } else {
    
            if (_dbus) {
                _dbus->getCallManager()->incomingMessage (callID, from, message);
            }
        }
    }
    
    
    //THREAD=VoIP
    bool ManagerImpl::sendTextMessage (const CallID& callID, const std::string& message, const std::string& from)
    {
    
        if (isConference (callID)) {
            _debug ("Manager: Is a conference, send instant message to everyone");
    
            ConferenceMap::iterator it = _conferencemap.find (callID);
    
            if (it == _conferencemap.end())
                return false;
    
            Conference *conf = it->second;
    
            if (!conf)
                return false;
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
    
                AccountID accountId = getAccountFromCall (*iter_participant);
    
                Account *account = getAccount (accountId);
    
                if (!account) {
                    _debug ("Manager: Failed to get account while sending instant message");
                    return false;
                }
    
                if (account->getType() == "SIP")
                    // link = dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId));
                    dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId))->sendTextMessage (_imModule, *iter_participant, message, from);
                else if (account->getType() == "IAX")
                    // link = dynamic_cast<IAXVoIPLink *> (account->getVoIPLink());
                    dynamic_cast<IAXVoIPLink *> (account->getVoIPLink())->sendTextMessage (_imModule, *iter_participant, message, from);
                else {
                    _debug ("Manager: Failed to get voip link while sending instant message");
                    return false;
                }
    
                iter_participant++;
            }
    
            return true;
        }
    
        if (participToConference (callID)) {
            _debug ("Manager: Particip to a conference, send instant message to everyone");
    
            Conference *conf = getConferenceFromCallID (callID);
    
            if (!conf)
                return false;
    
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
    
                AccountID accountId = getAccountFromCall (*iter_participant);
    
                Account *account = getAccount (accountId);
    
                if (!account) {
                    _debug ("Manager: Failed to get account while sending instant message");
                    return false;
                }
    
                if (account->getType() == "SIP")
                    // link = dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId));
                    dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId))->sendTextMessage (_imModule, *iter_participant, message, from);
                else if (account->getType() == "IAX")
                    // link = dynamic_cast<IAXVoIPLink *> (account->getVoIPLink());
                    dynamic_cast<IAXVoIPLink *> (account->getVoIPLink())->sendTextMessage (_imModule, *iter_participant, message, from);
                else {
                    _debug ("Manager: Failed to get voip link while sending instant message");
                    return false;
                }
    
                iter_participant++;
            }
    
        } else {
    
            AccountID accountId = getAccountFromCall (callID);
    
            Account *account = getAccount (accountId);
    
            if (!account) {
                _debug ("Manager: Failed to get account while sending instant message");
                return false;
            }
    
            if (account->getType() == "SIP")
                // link = dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId));
                dynamic_cast<SIPVoIPLink *> (getAccountLink (accountId))->sendTextMessage (_imModule, callID, message, from);
            else if (account->getType() == "IAX")
                // link = dynamic_cast<IAXVoIPLink *> (account->getVoIPLink());
                dynamic_cast<IAXVoIPLink *> (account->getVoIPLink())->sendTextMessage (_imModule, callID, message, from);
            else {
                _debug ("Manager: Failed to get voip link while sending instant message");
                return false;
            }
        }
    
        return true;
    }
    
    //THREAD=VoIP CALL=Outgoing
    void ManagerImpl::peerAnsweredCall (const CallID& id)
    {
    
        _debug ("Manager: Peer answered call %s", id.c_str());
    
        // The if statement is usefull only if we sent two calls at the same time.
        if (isCurrentCall (id)) {
            stopTone();
        }
    
    
        // Connect audio streams
        addStream(id);
    
        audioLayerMutexLock();
        _audiodriver->flushMain();
        _audiodriver->flushUrgent();
        audioLayerMutexUnlock();
    
        if(audioPreference.getIsAlwaysRecording()) {
        	setRecordingCall(id);
        }
    
        if(_dbus == NULL) {
        	_error("Manager: Error: DBUS not initialized");
        	return;
        }
    
        if(audioPreference.getIsAlwaysRecording()) {
        	_dbus->getCallManager()->callStateChanged (id, "RECORD");
        }
        else {
        	_dbus->getCallManager()->callStateChanged(id, "CURRENT");
        }
    }
    
    //THREAD=VoIP Call=Outgoing
    void ManagerImpl::peerRingingCall (const CallID& id)
    {
    
        _debug ("Manager: Peer call %s ringing", id.c_str());
    
        if (isCurrentCall (id)) {
            ringback();
        }
    
        if (_dbus == NULL) {
        	_error("Manager: Error: DBUS not initialized");
        }
    
        _dbus->getCallManager()->callStateChanged (id, "RINGING");
    }
    
    //THREAD=VoIP Call=Outgoing/Ingoing
    void ManagerImpl::peerHungupCall (const CallID& call_id)
    {
        AccountID account_id;
        bool returnValue;
    
        _debug ("Manager: Peer hungup call %s", call_id.c_str());
    
        // store the current call id
        CallID current_call_id = getCurrentCallId();
    
        if (participToConference (call_id)) {
    
            Conference *conf = getConferenceFromCallID (call_id);
    
            if (conf != NULL) {
                removeParticipant (call_id);
                processRemainingParticipant (current_call_id, conf);
            }
        } else {
            if (isCurrentCall (call_id)) {
                stopTone();
                switchCall("");
            }
        }
    
        /* Direct IP to IP call */
        if (getConfigFromCall (call_id) == Call::IPtoIP) {
            SIPVoIPLink::instance (AccountNULL)->hangup (call_id);
        }
        else {
            account_id = getAccountFromCall (call_id);
            returnValue = getAccountLink (account_id)->peerHungup (call_id);
        }
    
        /* Broadcast a signal over DBus */
        if (_dbus) {
            _dbus->getCallManager()->callStateChanged (call_id, "HUNGUP");
        }
    
        removeWaitingCall (call_id);
    
        removeCallAccount (call_id);
    
        int nbCalls = getCallList().size();
    
        // stop streams
    
        if (nbCalls <= 0) {
            _debug ("Manager: Stop audio stream, ther is only %d call(s) remaining", nbCalls);
    
            audioLayerMutexLock();
            _audiodriver->stopStream();
            audioLayerMutexUnlock();
        }
    }
    
    //THREAD=VoIP
    void ManagerImpl::callBusy (const CallID& id)
    {
        _debug ("Manager: Call %s busy", id.c_str());
    
        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& call_id)
    {
        if (_dbus) {
            _dbus->getCallManager()->callStateChanged (call_id, "FAILURE");
        }
    
        if (isCurrentCall (call_id)) {
            playATone (Tone::TONE_BUSY);
            switchCall ("");
        }
    
        CallID current_call_id = getCurrentCallId();
    
        if (participToConference (call_id)) {
    
            _debug ("Manager: Call %s participating to a conference failed", call_id.c_str());
    
            Conference *conf = getConferenceFromCallID (call_id);
    
            if (conf == NULL) {
            	_error("Manager: Could not retreive conference from call id %s", call_id.c_str());
            	return;
            }
    
            // remove this participant
            removeParticipant (call_id);
    
            processRemainingParticipant (current_call_id, conf);
    
        }
    
        removeCallAccount (call_id);
    
        removeWaitingCall (call_id);
    
    }
    
    //THREAD=VoIP
    void ManagerImpl::startVoiceMessageNotification (const AccountID& accountId,
            int nb_msg)
    {
        if (_dbus) {
            _dbus->getCallManager()->voiceMailNotify (accountId, nb_msg);
        }
    }
    
    void ManagerImpl::connectionStatusNotification ()
    {
    
        _debug ("Manager: connectionStatusNotification");
    
        if (_dbus != NULL) {
            _dbus->getConfigurationManager()->accountsChanged();
        }
    }
    
    /**
     * Multi Thread
     */
    bool ManagerImpl::playATone (Tone::TONEID toneId)
    {
    
        bool hasToPlayTone;
    
        // _debug ("Manager: Play tone %d", toneId);
    
        hasToPlayTone = voipPreferences.getPlayTones();
    
        if (!hasToPlayTone) {
            return false;
        }
    
        audioLayerMutexLock();
    
        if (_audiodriver == NULL) {
        	_error("Manager: Error: Audio layer not initialized");
        	audioLayerMutexUnlock();
        	return false;
        }
        _audiodriver->flushUrgent();
        _audiodriver->startStream();
        audioLayerMutexUnlock();
    
        if (_telephoneTone != 0) {
            _toneMutex.enterMutex();
            _telephoneTone->setCurrentTone (toneId);
            _toneMutex.leaveMutex();
        }
    
        return true;
    }
    
    /**
     * Multi Thread
     */
    void ManagerImpl::stopTone ()
    {
        bool hasToPlayTone = voipPreferences.getPlayTones();
    
        if (hasToPlayTone == false) {
            return;
        }
    
        _toneMutex.enterMutex();
    
        if (_telephoneTone != NULL) {
            _telephoneTone->setCurrentTone (Tone::TONE_NULL);
        }
    
        if (_audiofile) {
            _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 (const AccountID& accountID)
    {
        std::string ringchoice;
        sfl::AudioCodec *codecForTone;
        int samplerate;
    
        _debug ("Manager: Ringtone");
    
        Account *account = getAccount (accountID);
    
        if (!account) {
            _warn ("Manager: Warning: invalid account in ringtone");
            return;
        }
    
        if (account->getRingtoneEnabled()) {
    
            _debug ("Manager: Tone is enabled");
            //TODO Comment this because it makes the daemon crashes since the main thread
            //synchronizes the ringtone thread.
    
            ringchoice = account->getRingtonePath();
            //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;
            }
    
            audioLayerMutexLock();
    
    
            if (!_audiodriver) {
                _error ("Manager: Error: no audio layer in ringtone");
                audioLayerMutexUnlock();
                return;
            }
    
            samplerate = _audiodriver->getSampleRate();
            codecForTone = static_cast<sfl::AudioCodec *>(_audioCodecFactory.getFirstCodecAvailable());
    
            audioLayerMutexUnlock();
    
            _toneMutex.enterMutex();
    
            if (_audiofile) {
    	    if(_dbus) {
    		std::string filepath = _audiofile->getFilePath();
    		_dbus->getCallManager()->recordPlaybackStoped(filepath);
    	    }
                delete _audiofile;
                _audiofile = NULL;
            }
    
            std::string wave (".wav");
            size_t found = ringchoice.find (wave);
    
            try {
    
                if (found != std::string::npos) {
                    _audiofile = static_cast<AudioFile *> (new WaveFile());
                }
                else {
                    _audiofile = static_cast<AudioFile *> (new RawFile());
                }
    
                _debug ("Manager: ringChoice: %s, codecForTone: %d, samplerate %d", ringchoice.c_str(), codecForTone->getPayloadType(), samplerate);
    
                _audiofile->loadFile (ringchoice, codecForTone, samplerate);
            }
            catch (AudioFileException &e) {
    	    _error("Manager: Exception: %s", e.what());
            }
        
            _audiofile->start();
            _toneMutex.leaveMutex();
    
            audioLayerMutexLock();
            // start audio if not started AND flush all buffers (main and urgent)
            _audiodriver->startStream();
            audioLayerMutexUnlock();
    
        } else {
            ringback();
        }
    }
    
    AudioLoop*
    ManagerImpl::getTelephoneTone ()
    {
        if (_telephoneTone != NULL) {
            ost::MutexLock m (_toneMutex);
            return _telephoneTone->getCurrentTone();
        } else {
            return NULL;
        }
    }
    
    AudioLoop*
    ManagerImpl::getTelephoneFile ()
    {
        ost::MutexLock m (_toneMutex);
    
        if (!_audiofile) {
            return NULL;
        }
    
        if (_audiofile->isStarted()) {
            return _audiofile;
        } else {
            return NULL;
        }
    }
    
    void ManagerImpl::notificationIncomingCall (void)
    {
        std::ostringstream frequency;
        unsigned int sampleRate, nbSample;
    
        audioLayerMutexLock();
    
        if(_audiodriver == NULL) {
        	_error("Manager: Error: Audio layer not initialized");
        	audioLayerMutexUnlock();
        	return;
        }
    
        _debug ("ManagerImpl: Notification incoming call");
    
        // Enable notification only if more than one call
        if (hasCurrentCall()) {
            sampleRate = _audiodriver->getSampleRate();
            frequency << "440/" << 160;
            Tone tone (frequency.str(), sampleRate);
            nbSample = tone.getSize();
            SFLDataFormat buf[nbSample];
            tone.getNext (buf, nbSample);
            /* Put the data in the urgent ring buffer */
            _audiodriver->flushUrgent();
            _audiodriver->putUrgent (buf, sizeof (SFLDataFormat) * nbSample);
        }
    
        audioLayerMutexUnlock();
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    // Private functions
    ///////////////////////////////////////////////////////////////////////////////
    /**
     * Initialization: Main Thread
     * @return 1: ok
     -1: error directory
     */
    int ManagerImpl::createSettingsPath (void)
    {
    
        std::string xdg_config, xdg_env;
    
        _debug ("XDG_CONFIG_HOME: %s", XDG_CONFIG_HOME);
    
        xdg_config = std::string (HOMEDIR) + DIR_SEPARATOR_STR + ".config"
                     + DIR_SEPARATOR_STR + PROGDIR;
    
        if (XDG_CONFIG_HOME != NULL) {
            xdg_env = std::string (XDG_CONFIG_HOME);
            (xdg_env.length() > 0) ? _path = xdg_env : _path = xdg_config;
        } else
            _path = xdg_config;
    
        if (mkdir (_path.data(), 0700) != 0) {
            // If directory	creation failed
            if (errno != EEXIST) {
                _debug ("Cannot create directory: %s", strerror (errno));
                return -1;
            }
        }
    
        // Load user's configuration
        _path = _path + DIR_SEPARATOR_STR + PROGNAME + ".yml";
    
        return 1;
    }
    
    /**
     * Initialization: Main Thread
     */
    void ManagerImpl::initConfigFile (bool load_user_value, std::string alternate)
    {
    
        _debug ("Manager: Init config file");
    
        // Init display name to the username under which
        // this sflphone instance is running.
        uid_t uid = getuid();
    
        struct passwd * user_info = NULL;
        user_info = getpwuid (uid);
    
        std::string path;
        // Loads config from ~/.sflphone/sflphoned.yml or so..
    
        if (createSettingsPath() == 1 && load_user_value) {
    
            (alternate == "") ? path = _path : path = alternate;
            std::cout << path << std::endl;
    
            _path = path;
        }
    
        _debug ("Manager: configuration file path: %s", path.c_str());
    
    
        bool fileExist = true;
        bool out = false;
    
        if (path.empty()) {
            _error ("Manager: Error: XDG config file path is empty!");
            fileExist = false;
        }
    
        std::fstream file;
    
        file.open (path.data(), std::fstream::in);
    
        if (!file.is_open()) {
    
            _debug ("Manager: File %s not opened, create new one", path.c_str());
            file.open (path.data(), std::fstream::out);
            out = true;
    
            if (!file.is_open()) {
                _error ("Manager: Error: could not create empty configurationfile!");
                fileExist = false;
            }
    
            file.close();
    
            fileExist = false;
        }
    
        // get length of file:
        file.seekg (0, std::ios::end);
        int length = file.tellg();
    
        file.seekg (0, std::ios::beg);
    
        if (length <= 0) {
            _debug ("Manager: Configuration file length is empty", length);
            file.close();
            fileExist = false; // should load config
        }
    
        if (fileExist) {
            try {
    
                // parser = new Conf::YamlParser("sequenceParser.yml");
                parser = new Conf::YamlParser (_path.c_str());
    
                parser->serializeEvents();
    
                parser->composeEvents();
    
                parser->constructNativeData();
    
                _setupLoaded = true;
    
                _debug ("Manager: Configuration file parsed successfully");
            } catch (Conf::YamlParserException &e) {
                _error ("Manager: %s", e.what());
            }
        }
    }
    
    /**
     * Initialization: Main Thread
     */
    void ManagerImpl::initAudioCodec (void)
    {
        _info ("Manager: Init audio codecs");
    
        /* Init list of all supported codecs by the application.
         * This is a global list. Every account will inherit it.
         */
        _audioCodecFactory.init();
    }
    
    std::vector<std::string> ManagerImpl::unserialize (std::string s)
    {
    
        std::vector<std::string> list;
        std::string temp;
    
        while (s.find ("/", 0) != std::string::npos) {
            size_t pos = s.find ("/", 0);
            temp = s.substr (0, pos);
            s.erase (0, pos + 1);
            list.push_back (temp);
        }
    
        return list;
    }
    
    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::string ManagerImpl::getCurrentCodecName (const CallID& id)
    {
    
        AccountID accountid = getAccountFromCall (id);
        VoIPLink* link = getAccountLink (accountid);
        Call* call = link->getCall (id);
        std::string codecName = "";
    
        _debug("Manager: Get current codec name");
    
        
        if (!call) {
    	// return an empty codec name
            return codecName;
        }
    
        Call::CallState state = call->getState();
        if (state == Call::Active || state == Call::Conferencing) {
            codecName = link->getCurrentCodecName(id);
        }
    
        return codecName;	
    }
    
    /**
     * Set input audio plugin
     */
    void ManagerImpl::setAudioPlugin (const std::string& audioPlugin)
    {
    
    	audioLayerMutexLock();
        int layerType = _audiodriver -> getLayerType();
    
        audioPreference.setPlugin (audioPlugin);
    
        if (CHECK_INTERFACE (layerType , ALSA)) {
            _debug ("Set input audio plugin");
            _audiodriver -> setErrorMessage (-1);
            _audiodriver -> openDevice (_audiodriver->getIndexIn(), _audiodriver->getIndexOut(),
                                        _audiodriver->getIndexRing(), _audiodriver -> getSampleRate(),
                                        _audiodriver -> getFrameSize(), SFL_PCM_BOTH, audioPlugin);
    
            if (_audiodriver -> getErrorMessage() != -1)
                notifyErrClient (_audiodriver -> getErrorMessage());
        }
        audioLayerMutexUnlock();
    
    }
    
    /**
     * Set audio output device
     */
    void ManagerImpl::setAudioDevice (const int index, int streamType)
    {
    
        AlsaLayer *alsalayer = NULL;
        std::string alsaplugin;
        _debug ("Manager: Set audio device: %d", index);
    
        audioLayerMutexLock();
    
        if(_audiodriver == NULL) {
        	_warn ("Manager: Error: No audio driver");
        	audioLayerMutexUnlock();
        	return;
        }
    
        _audiodriver -> setErrorMessage (-1);
    
        alsalayer = dynamic_cast<AlsaLayer*> (_audiodriver);
        alsaplugin = alsalayer->getAudioPlugin();
    
        _debug ("Manager: Set ALSA plugin: %s", alsaplugin.c_str());
    
    
        switch (streamType) {
            case SFL_PCM_PLAYBACK:
                _debug ("Manager: Set output device");
                _audiodriver->openDevice (_audiodriver->getIndexIn(), index, _audiodriver->getIndexRing(),
                                          _audiodriver->getSampleRate(), _audiodriver->getFrameSize(),
                                          SFL_PCM_PLAYBACK, alsaplugin);
                audioPreference.setCardout (index);
                break;
            case SFL_PCM_CAPTURE:
                _debug ("Manager: Set input device");
                _audiodriver->openDevice (index, _audiodriver->getIndexOut(), _audiodriver->getIndexRing(),
                                          _audiodriver->getSampleRate(), _audiodriver->getFrameSize(),
                                          SFL_PCM_CAPTURE, alsaplugin);
                audioPreference.setCardin (index);
                break;
            case SFL_PCM_RINGTONE:
                _debug ("Manager: Set ringtone device");
                _audiodriver->openDevice (_audiodriver->getIndexOut(), _audiodriver->getIndexOut(), index,
                                          _audiodriver->getSampleRate(), _audiodriver->getFrameSize(),
                                          SFL_PCM_RINGTONE, alsaplugin);
                audioPreference.setCardring (index);
                break;
            default:
                _warn ("Unknown stream type");
        }
    
        if (_audiodriver -> getErrorMessage() != -1) {
            notifyErrClient (_audiodriver -> getErrorMessage());
        }
    
        audioLayerMutexUnlock();
    
    }
    
    /**
     * Get list of supported audio output device
     */
    std::vector<std::string> ManagerImpl::getAudioOutputDeviceList (void)
    {
        _debug ("Manager: Get audio output device list");
        AlsaLayer *alsalayer;
        std::vector<std::string> devices;
    
        audioLayerMutexLock();
    
        alsalayer = dynamic_cast<AlsaLayer*> (_audiodriver);
    
        if (alsalayer) {
            devices = alsalayer -> getSoundCardsInfo (SFL_PCM_PLAYBACK);
        }
        audioLayerMutexUnlock();
    
        return devices;
    }
    
    
    /**
     * Get list of supported audio input device
     */
    std::vector<std::string> ManagerImpl::getAudioInputDeviceList (void)
    {
        AlsaLayer *alsalayer;
        std::vector<std::string> devices;
    
        audioLayerMutexLock();
    
        alsalayer = dynamic_cast<AlsaLayer *> (_audiodriver);
    
        if (alsalayer == NULL) {
        	_error("Manager: Error: Audio layer not initialized");
        	audioLayerMutexUnlock();
        	return devices;
        }
    
        devices = alsalayer->getSoundCardsInfo (SFL_PCM_CAPTURE);
    
        audioLayerMutexUnlock();
    
        return devices;
    }
    
    /**
     * Get string array representing integer indexes of output and input device
     */
    std::vector<std::string> ManagerImpl::getCurrentAudioDevicesIndex ()
    {
        _debug ("Get current audio devices index");
    
        audioLayerMutexLock();
    
        std::vector<std::string> v;
    
        if(_audiodriver == NULL) {
        	_error("Manager: Error: Audio layer not initialized");
        	audioLayerMutexUnlock();
        	return v;
        }
    
        std::stringstream ssi, sso, ssr;
        sso << _audiodriver->getIndexOut();
        v.push_back (sso.str());
        ssi << _audiodriver->getIndexIn();
        v.push_back (ssi.str());
        ssr << _audiodriver->getIndexRing();
        v.push_back (ssr.str());
    
        audioLayerMutexUnlock();
    
        return v;
    }
    
    int ManagerImpl::isIax2Enabled (void)
    {
    #ifdef USE_IAX
        return true;
    #else
        return false;
    #endif
    }
    
    int ManagerImpl::isRingtoneEnabled (const AccountID& id)
    {
        Account *account = getAccount (id);
    
        if (!account) {
            _warn ("Manager: Warning: invalid account in ringtone enabled");
            return 0;
        }
    
        return account->getRingtoneEnabled() ? 1 : 0;
    }
    
    void ManagerImpl::ringtoneEnabled (const AccountID& id)
    {
    
        Account *account = getAccount (id);
    
        if (!account) {
            _warn ("Manager: Warning: invalid account in ringtone enabled");
            return;
        }
    
        account->getRingtoneEnabled() ? account->setRingtoneEnabled (false) : account->setRingtoneEnabled (true);
    
    }
    
    std::string ManagerImpl::getRingtoneChoice (const AccountID& id)
    {
    
        // retreive specified account id
        Account *account = getAccount (id);
    
        if (!account) {
            _warn ("Manager: Warning: Not a valid account ID for ringone choice");
            return std::string ("");
        }
    
        // we need the absolute path
        std::string tone_name = account->getRingtonePath();
        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 ("Manager: get ringtone path %s", tone_path.c_str());
    
        return tone_path;
    }
    
    void ManagerImpl::setRingtoneChoice (const std::string& tone, const AccountID& id)
    {
    
        _debug ("Manager: Set ringtone path %s to account", tone.c_str());
    
        // retreive specified account id
        Account *account = getAccount (id);
    
        if (!account) {
            _warn ("Manager: Warning: Not a valid account ID for ringtone choice");
            return;
        }
    
        // we save the absolute path
        account->setRingtonePath (tone);
    }
    
    std::string ManagerImpl::getRecordPath (void)
    {
        return audioPreference.getRecordpath();
    }
    
    void ManagerImpl::setRecordPath (const std::string& recPath)
    {
        _debug ("Manager: Set record path %s", recPath.c_str());
        audioPreference.setRecordpath (recPath);
    }
    
    bool ManagerImpl::getIsAlwaysRecording(void)
    {
    	return audioPreference.getIsAlwaysRecording();
    }
    
    void ManagerImpl::setIsAlwaysRecording(bool isAlwaysRec)
    {
    	return audioPreference.setIsAlwaysRecording(isAlwaysRec);
    }
    
    bool ManagerImpl::getMd5CredentialHashing (void)
    {
        return preferences.getMd5Hash();
    }
    
    
    
    void ManagerImpl::setRecordingCall (const CallID& id)
    {
        Call *call = NULL;
        Conference *conf = NULL;
        Recordable* rec = NULL;
    
        if (!isConference (id)) {
            _debug ("Manager: Set recording for call %s", id.c_str());
            AccountID accountid = getAccountFromCall (id);
            call = getAccountLink (accountid)->getCall (id);
            rec = static_cast<Recordable *>(call);
        } else {
            _debug ("Manager: Set recording for conference %s", id.c_str());
            ConferenceMap::iterator it = _conferencemap.find (id);
            conf = it->second;
            if(conf->isRecording()) {
            	conf->setState(Conference::ACTIVE_ATTACHED);
            }
            else {
            	conf->setState(Conference::ACTIVE_ATTACHED_REC);
            }
            rec = static_cast<Recordable *>(conf);
        }
    
        if (rec == NULL) {
    	_error("Manager: Error: Could not find recordable instance %s", id.c_str());
    	return;
        }
    
        rec->setRecording();
    
        if(_dbus)
    	_dbus->getCallManager()->recordPlaybackFilepath(id, rec->getFileName());  
    }
    
    bool ManagerImpl::isRecording (const CallID& id)
    {
    
        AccountID accountid = getAccountFromCall (id);
        Recordable* rec = (Recordable*) getAccountLink (accountid)->getCall (id);
    
        bool ret = false;
    
        if (rec)
            ret = rec->isRecording();
    
        return ret;
    }
    
    bool ManagerImpl::startRecordedFilePlayback(const std::string& filepath) 
    {
        int sampleRate;
     
        _debug("Manager: Start recorded file playback %s", filepath.c_str());
    
        audioLayerMutexLock();
    
        if(!_audiodriver) {
    	_error("Manager: Error: No audio layer in start recorded file playback");
        }
    
        sampleRate = _audiodriver->getSampleRate();
    
        audioLayerMutexUnlock();
    
        _toneMutex.enterMutex();
    
        if(_audiofile) {
    	 if(_dbus) {
    	     std::string file = _audiofile->getFilePath();
    	     _dbus->getCallManager()->recordPlaybackStoped(file);
             }
    	 delete _audiofile;
    	_audiofile = NULL;
        }
    
        try {
            _audiofile = static_cast<AudioFile *>(new WaveFile());
    
            _audiofile->loadFile(filepath, NULL, sampleRate);
        }
        catch(AudioFileException &e) {
            _error("Manager: Exception: %s", e.what());
        }
    
        _audiofile->start();
    
        _toneMutex.leaveMutex();
    
        audioLayerMutexLock();
        _audiodriver->startStream();
        audioLayerMutexUnlock(); 
    
        return true;
    }
    
    
    void ManagerImpl::stopRecordedFilePlayback(const std::string& filepath)
    {
        _debug("Manager: Stop recorded file playback %s", filepath.c_str());
    
        audioLayerMutexLock();
        _audiodriver->stopStream();
        audioLayerMutexUnlock();
    
        _toneMutex.enterMutex();
        if(_audiofile != NULL) {
            _audiofile->stop();
    	delete _audiofile;
    	_audiofile = NULL;
        }
        _toneMutex.leaveMutex();
    }
    
    void ManagerImpl::setHistoryLimit (const int& days)
    {
        _debug ("Manager: Set history limit");
    
        preferences.setHistoryLimit (days);
    
        saveConfig();
    }
    
    int ManagerImpl::getHistoryLimit (void)
    {
        return preferences.getHistoryLimit();
    }
    
    int32_t ManagerImpl::getMailNotify (void)
    {
        return preferences.getNotifyMails();
    }
    
    void ManagerImpl::setMailNotify (void)
    {
        _debug ("Manager: Set mail notify");
    
        preferences.getNotifyMails() ? preferences.setNotifyMails (true) : preferences.setNotifyMails (false);
    
        saveConfig();
    }
    
    void ManagerImpl::setAudioManager (const int32_t& api)
    {
    
        int layerType;
    
        _debug ("Manager: Setting audio manager ");
    
        audioLayerMutexLock();
    
        if (!_audiodriver) {
        	audioLayerMutexUnlock();
            return;
        }
    
        layerType = _audiodriver->getLayerType();
    
        if (layerType == api) {
            _debug ("Manager: Audio manager chosen already in use. No changes made. ");
            audioLayerMutexUnlock();
            return;
        }
    
        audioLayerMutexUnlock();
    
        preferences.setAudioApi (api);
    
        switchAudioManager();
    
        saveConfig();
    
    }
    
    int32_t ManagerImpl::getAudioManager (void)
    {
        return preferences.getAudioApi();
    }
    
    
    void ManagerImpl::notifyErrClient (const int32_t& errCode)
    {
        if (_dbus) {
            _debug ("Manager: NOTIFY ERR NUMBER %d" , errCode);
            _dbus -> getConfigurationManager() -> errorAlert (errCode);
        }
    }
    
    int ManagerImpl::getAudioDeviceIndex (const std::string name)
    {
        AlsaLayer *alsalayer;
        int soundCardIndex = 0;
    
        _debug ("Manager: Get audio device index");
    
        audioLayerMutexLock();
    
        if(_audiodriver == NULL) {
        	_error("Manager: Error: Audio layer not initialized");
        	audioLayerMutexUnlock();
        	return soundCardIndex;
        }
    
        alsalayer = dynamic_cast<AlsaLayer *> (_audiodriver);
    
        if (alsalayer) {
            soundCardIndex = alsalayer -> soundCardGetIndex (name);
        }
    
        audioLayerMutexUnlock();
    
        return soundCardIndex;
    }
    
    std::string ManagerImpl::getCurrentAudioOutputPlugin (void)
    {
        _debug ("Manager: Get alsa plugin");
    
        return audioPreference.getPlugin();
    }
    
    
    std::string ManagerImpl::getNoiseSuppressState (void)
    {
    
        // noise suppress disabled by default
        std::string state;
    
        state = audioPreference.getNoiseReduce() ? "enabled" : "disabled";
    
        return state;
    }
    
    void ManagerImpl::setNoiseSuppressState (std::string state)
    {
        _debug ("Manager: Set noise suppress state: %s", state.c_str());
    
        bool isEnabled = (state == "enabled");
    
        audioPreference.setNoiseReduce (isEnabled);
    
        audioLayerMutexLock();
    
        if (_audiodriver) {
            _audiodriver->setNoiseSuppressState (isEnabled);
        }
    
        audioLayerMutexUnlock();
    }
    
    std::string ManagerImpl::getEchoCancelState(void)
    {
    	// echo canceller disabled by default
    	std::string state;
    
    	state = audioPreference.getEchoCancel() ? "enabled" : "disabled";
    
    	return state;
    }
    
    void ManagerImpl::setEchoCancelState(std::string state)
    {
    
    	bool isEnabled = (state == "enabled");
    
    	audioPreference.setEchoCancel(isEnabled);
    }
    
    int ManagerImpl::getEchoCancelTailLength(void)
    {
    	return audioPreference.getEchoCancelTailLength();
    }
    
    void ManagerImpl::setEchoCancelTailLength(int length)
    {
    	audioPreference.setEchoCancelTailLength(length);
    }
    
    int ManagerImpl::getEchoCancelDelay(void)
    {
    	return audioPreference.getEchoCancelDelay();
    }
    
    void ManagerImpl::setEchoCancelDelay(int delay)
    {
    	audioPreference.setEchoCancelDelay(delay);
    }
    
    int ManagerImpl::app_is_running (std::string process)
    {
        std::ostringstream cmd;
    
        cmd << "ps -C " << process;
        return system (cmd.str().c_str());
    }
    
    /**
     * Initialization: Main Thread
     */
    bool ManagerImpl::initAudioDriver (void)
    {
    
        int error;
    
        _debugInit ("Manager: AudioLayer Creation");
    
        audioLayerMutexLock();
    
        if (preferences.getAudioApi() == ALSA) {
            _audiodriver = new AlsaLayer (this);
            _audiodriver->setMainBuffer (&_mainBuffer);
        } else if (preferences.getAudioApi() == PULSEAUDIO) {
            if (app_is_running ("pulseaudio") == 0) {
                _audiodriver = new PulseLayer (this);
                _audiodriver->setMainBuffer (&_mainBuffer);
            } else {
                _audiodriver = new AlsaLayer (this);
                preferences.setAudioApi (ALSA);
                _audiodriver->setMainBuffer (&_mainBuffer);
            }
        } else {
            _debug ("Error - Audio API unknown");
        }
    
        if (_audiodriver == NULL) {
            _debug ("Manager: Init audio driver error");
            audioLayerMutexUnlock();
            return false;
        } else {
            error = _audiodriver->getErrorMessage();
    
            if (error == -1) {
                _debug ("Manager: Init audio driver: %d", error);
                audioLayerMutexUnlock();
                return false;
            }
        }
    
        audioLayerMutexUnlock();
    
        return true;
    
    }
    
    /**
     * Initialization: Main Thread and gui
     */
    void ManagerImpl::selectAudioDriver (void)
    {
        int layerType, numCardIn, numCardOut, numCardRing, sampleRate, frameSize;
        std::string alsaPlugin;
        AlsaLayer *alsalayer;
    
        audioLayerMutexLock();
    
        if(_audiodriver == NULL) {
        	_debug("Manager: Audio layer not initialized");
        	audioLayerMutexUnlock();
        	return;
        }
    
        layerType = _audiodriver->getLayerType();
        _debug ("Manager: Audio layer type: %d" , layerType);
    
        /* Retrieve the global devices info from the user config */
        alsaPlugin = audioPreference.getPlugin();
        numCardIn = audioPreference.getCardin();
        numCardOut = audioPreference.getCardout();
        numCardRing = audioPreference.getCardring();
    
        sampleRate = getMainBuffer()->getInternalSamplingRate();
        frameSize = audioPreference.getFramesize();
    
        /* Only for the ALSA layer, we check the sound card information */
    
        if (layerType == ALSA) {
            alsalayer = dynamic_cast<AlsaLayer*> (_audiodriver);
    
            if (!alsalayer -> soundCardIndexExist (numCardIn, SFL_PCM_CAPTURE)) {
                _debug (" Card with index %d doesn't exist or cannot capture. Switch to 0.", numCardIn);
                numCardIn = ALSA_DFT_CARD_ID;
                audioPreference.setCardin (ALSA_DFT_CARD_ID);
            }
    
            if (!alsalayer -> soundCardIndexExist (numCardOut, SFL_PCM_PLAYBACK)) {
                _debug (" Card with index %d doesn't exist or cannot playback. Switch to 0.", numCardOut);
                numCardOut = ALSA_DFT_CARD_ID;
                audioPreference.setCardout (ALSA_DFT_CARD_ID);
            }
    
            if (!alsalayer->soundCardIndexExist (numCardRing, SFL_PCM_RINGTONE)) {
                _debug (" Card with index %d doesn't exist or cannot ringtone. Switch to 0.", numCardRing);
                numCardRing = ALSA_DFT_CARD_ID;
                audioPreference.setCardring (ALSA_DFT_CARD_ID);
            }
        }
    
        _audiodriver->setErrorMessage (-1);
    
        /* Open the audio devices */
        _audiodriver->openDevice (numCardIn, numCardOut, numCardRing, sampleRate, frameSize,
                                  SFL_PCM_BOTH, alsaPlugin);
    
        /* Notify the error if there is one */
    
        if (_audiodriver -> getErrorMessage() != -1) {
            notifyErrClient (_audiodriver -> getErrorMessage());
        }
    
        audioLayerMutexUnlock();
    
    }
    
    void ManagerImpl::switchAudioManager (void)
    {
        int type, samplerate, framesize, numCardIn, numCardOut, numCardRing;
        std::string alsaPlugin;
    
        _debug ("Manager: Switching audio manager ");
    
        audioLayerMutexLock();
    
        if (_audiodriver == NULL) {
        	audioLayerMutexUnlock();
            return;
        }
    
        bool wasStarted = _audiodriver->isStarted();
    
        type = _audiodriver->getLayerType();
    
        samplerate = _mainBuffer.getInternalSamplingRate();
        framesize = audioPreference.getFramesize();
    
        _debug ("Manager: samplerate: %d, framesize %d", samplerate, framesize);
    
        alsaPlugin = audioPreference.getPlugin();
    
        numCardIn = audioPreference.getCardin();
        numCardOut = audioPreference.getCardout();
        numCardRing = audioPreference.getCardring();
    
        _debug ("Manager: Deleting current layer... ");
    
        delete _audiodriver;
        _audiodriver = NULL;
    
        switch (type) {
    
            case ALSA:
                _debug ("Manager: Creating Pulseaudio layer...");
                _audiodriver = new PulseLayer (this);
                _audiodriver->setMainBuffer (&_mainBuffer);
                break;
    
            case PULSEAUDIO:
                _debug ("Manager: Creating ALSA layer...");
                _audiodriver = new AlsaLayer (this);
                _audiodriver->setMainBuffer (&_mainBuffer);
                break;
    
            default:
                _warn ("Manager: Error: audio layer unknown");
                break;
        }
    
        _audiodriver->setErrorMessage (-1);
    
        _audiodriver->openDevice (numCardIn, numCardOut, numCardRing, samplerate, framesize,
                                  SFL_PCM_BOTH, alsaPlugin);
    
        if (_audiodriver -> getErrorMessage() != -1)
            notifyErrClient (_audiodriver -> getErrorMessage());
    
        _debug ("Manager: Current device: %d ", type);
    
        if (wasStarted) {
            _audiodriver->startStream();
        }
    
        audioLayerMutexUnlock();
    }
    
    void ManagerImpl::audioSamplingRateChanged (int samplerate)
    {
    
        int type, currentSamplerate, framesize, numCardIn, numCardOut, numCardRing;
        std::string alsaPlugin;
        bool wasActive;
    
        audioLayerMutexLock();
    
        if (!_audiodriver) {
        	_debug("Manager: No Audio driver initialized");
        	audioLayerMutexUnlock();
            return;
        }
    
    
        // Only modify internal sampling rate if new sampling rate is higher
        currentSamplerate = _mainBuffer.getInternalSamplingRate();
        if(currentSamplerate >= samplerate) {
        	_debug("Manager: No need to update audio layer sampling rate");
        	audioLayerMutexUnlock();
        	return;
        }
        else {
            _debug ("Manager: Audio sampling rate changed");
        }
    
        type = _audiodriver->getLayerType();
        framesize = audioPreference.getFramesize();
    
        _debug ("Manager: New samplerate: %d, New framesize %d", samplerate, framesize);
    
        alsaPlugin = audioPreference.getPlugin();
    
        numCardIn = audioPreference.getCardin();
        numCardOut = audioPreference.getCardout();
        numCardRing = audioPreference.getCardring();
    
        _debug ("Manager: Deleting current layer...");
    
        wasActive = _audiodriver->isStarted();
    
        delete _audiodriver;
        _audiodriver = NULL;
    
        switch (type) {
    
            case PULSEAUDIO:
                _debug ("Manager: Creating Pulseaudio layer...");
                _audiodriver = new PulseLayer (this);
                _audiodriver->setMainBuffer (&_mainBuffer);
                break;
    
            case ALSA:
                _debug ("Manager: Creating ALSA layer...");
                _audiodriver = new AlsaLayer (this);
                _audiodriver->setMainBuffer (&_mainBuffer);
                break;
    
            default:
                _warn ("Manager: Error: audio layer unknown");
                break;
        }
    
        if(_audiodriver == NULL) {
        	_debug("Manager: Error: Audio driver could not be initialized");
        	audioLayerMutexUnlock();
        	return;
        }
    
        _audiodriver->setErrorMessage (-1);
    
        _audiodriver->openDevice (numCardIn, numCardOut, numCardRing, samplerate, framesize,
                                  SFL_PCM_BOTH, alsaPlugin);
    
        if (_audiodriver -> getErrorMessage() != -1) {
            notifyErrClient (_audiodriver -> getErrorMessage());
        }
    
        _debug ("Manager: Current device: %d ", type);
    
        _mainBuffer.setInternalSamplingRate(samplerate);
    
        unsigned int sampleRate = _audiodriver->getSampleRate();
    
        delete _telephoneTone;
        _telephoneTone = NULL;
    
        _debugInit ("Manager: Load telephone tone");
        std::string country = preferences.getZoneToneChoice();
        _telephoneTone = new TelephoneTone (country, sampleRate);
    
        if(_telephoneTone == NULL) {
            _debug("Manager: Error: Telephone tone is NULL");
        }
         
        delete _dtmfKey;
        _dtmfKey = NULL;
    
        _debugInit ("Manager: Loading DTMF key with sample rate %d", sampleRate);
        _dtmfKey = new DTMF (sampleRate);
    
        if(_dtmfKey == NULL) {
            _debug("Manager: Error: DtmfKey is NULL");
        }
    
        // Restart audio layer if it was active
        if (wasActive) {
            _audiodriver->startStream();
        }
    
        audioLayerMutexUnlock();
    }
    
    /**
     * Init the volume for speakers/micro from 0 to 100 value
     * Initialization: Main Thread
     */
    void ManagerImpl::initVolume ()
    {
        _debugInit ("Initiate Volume");
        setSpkrVolume (audioPreference.getVolumespkr());
        setMicVolume (audioPreference.getVolumemic());
    }
    
    void ManagerImpl::setSpkrVolume (unsigned short spkr_vol)
    {
        PulseLayer *pulselayer = NULL;
    
        /* Set the manager sound volume */
        _spkr_volume = spkr_vol;
    
        audioLayerMutexLock();
    
        /* Only for PulseAudio */
        pulselayer = dynamic_cast<PulseLayer*> (_audiodriver);
    
        if (pulselayer) {
            if (pulselayer->getLayerType() == PULSEAUDIO) {
                if (pulselayer)
                    pulselayer->setPlaybackVolume (spkr_vol);
            }
        }
    
        audioLayerMutexUnlock();
    }
    
    void ManagerImpl::setMicVolume (unsigned short mic_vol)
    {
        _mic_volume = mic_vol;
    }
    
    int ManagerImpl::getLocalIp2IpPort (void)
    {
        // The SIP port used for default account (IP to IP) calls=
        return preferences.getPortNum();
    
    }
    
    // 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:
    
                    case Call::Conferencing:
                        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;
    }
    
    bool ManagerImpl::getConfigBool (const std::string& section,
                                     const std::string& name)
    {
        try {
            return (_config.getConfigTreeItemValue (section, name) == TRUE_STR) ? true
                   : false;
        } catch (Conf::ConfigTreeItemException& e) {
            throw e;
        }
    
        return false;
    }
    
    //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());
    }
    
    void ManagerImpl::setAccountsOrder (const std::string& order)
    {
        _debug ("Manager: Set accounts order : %s", order.c_str());
        // Set the new config
    
        preferences.setAccountOrder (order);
    
        saveConfig();
    }
    
    std::vector<std::string> ManagerImpl::getAccountList ()
    {
    
        std::vector<std::string> v;
        std::vector<std::string> account_order;
        unsigned int i;
    
        _debug ("Manager: Get account list");
    
        account_order = loadAccountOrder();
        AccountMap::iterator iter;
    
        // The IP2IP profile is always available, and first in the list
        iter = _accountMap.find (IP2IP_PROFILE);
    
        if (iter->second != NULL) {
            // _debug("PUSHING BACK %s", iter->first.c_str());
            // v.push_back(iter->first.data());
            v.push_back (iter->second->getAccountID());
        } else {
            _error ("Manager: could not find IP2IP profile in getAccount list");
        }
    
        // If no order has been set, load the default one
        // ie according to the creation date.
    
        if (account_order.size() == 0) {
            _debug ("Manager: account order is empty");
            iter = _accountMap.begin();
    
            while (iter != _accountMap.end()) {
    
                if (iter->second != NULL && iter->first != IP2IP_PROFILE && iter->first != "") {
                    _debug ("PUSHING BACK %s", iter->first.c_str());
                    // v.push_back(iter->first.data());
                    v.push_back (iter->second->getAccountID());
                }
    
                iter++;
            }
        }
    
        // Otherelse, load the custom one
        // ie according to the saved order
        else {
            _debug ("Manager: Load account list according to preferences");
    
            for (i = 0; i < account_order.size(); i++) {
                // This account has not been loaded, so we ignore it
                if ( (iter = _accountMap.find (account_order[i]))
                        != _accountMap.end()) {
                    // If the account is valid
                    if (iter->second != NULL && iter->first != IP2IP_PROFILE && iter->first != "") {
                        //_debug("PUSHING BACK %s", iter->first.c_str());
                        // v.push_back(iter->first.data());
                        v.push_back (iter->second->getAccountID());
                    }
                }
            }
        }
    
        return v;
    }
    
    std::map<std::string, std::string> ManagerImpl::getAccountDetails (
        const AccountID& accountID)
    {
        // Default account used to get default parameters if requested by client (to build new account)
        static const SIPAccount DEFAULT_ACCOUNT("default");
    
        Account * account = _accountMap[accountID];
    
        if (accountID.empty()) {
            _debug ("Manager: Returning default account settings");
            // return a default map
            return DEFAULT_ACCOUNT.getAccountDetails();
        } else if (account) {
            return account->getAccountDetails();
        } else {
            _debug ("Manager: Get account details on a non-existing accountID %s. Returning default", accountID.c_str());
            return DEFAULT_ACCOUNT.getAccountDetails();
        }
    
    }
    
    /* Transform digest to string.
     * output must be at least PJSIP_MD5STRLEN+1 bytes.
     * Helper function taken from sip_auth_client.c in
     * pjproject-1.0.3.
     *
     * NOTE: THE OUTPUT STRING IS NOT NULL TERMINATED!
     */
    
    void ManagerImpl::digest2str (const unsigned char digest[], char *output)
    {
        int i;
    
        for (i = 0; i < 16; ++i) {
            pj_val_to_hex_digit (digest[i], output);
            output += 2;
        }
    }
    
    std::string ManagerImpl::computeMd5HashFromCredential (
        const std::string& username, const std::string& password,
        const std::string& realm)
    {
        pj_md5_context pms;
        unsigned char digest[16];
        char ha1[PJSIP_MD5STRLEN];
    
        pj_str_t usernamePjFormat = pj_str (strdup (username.c_str()));
        pj_str_t passwordPjFormat = pj_str (strdup (password.c_str()));
        pj_str_t realmPjFormat = pj_str (strdup (realm.c_str()));
    
        /* Compute md5 hash = MD5(username ":" realm ":" password) */
        pj_md5_init (&pms);
        MD5_APPEND (&pms, usernamePjFormat.ptr, usernamePjFormat.slen);
        MD5_APPEND (&pms, ":", 1);
        MD5_APPEND (&pms, realmPjFormat.ptr, realmPjFormat.slen);
        MD5_APPEND (&pms, ":", 1);
        MD5_APPEND (&pms, passwordPjFormat.ptr, passwordPjFormat.slen);
        pj_md5_final (&pms, digest);
    
        digest2str (digest, ha1);
    
        char ha1_null_terminated[PJSIP_MD5STRLEN + 1];
        memcpy (ha1_null_terminated, ha1, sizeof (char) * PJSIP_MD5STRLEN);
        ha1_null_terminated[PJSIP_MD5STRLEN] = '\0';
    
        std::string hashedDigest = ha1_null_terminated;
        return hashedDigest;
    }
    
    void ManagerImpl::setCredential (const std::string& accountID UNUSED,
                                     const int32_t& index UNUSED, const std::map<std::string, std::string>& details UNUSED)
    {
    
        _debug ("Manager: set credential");
    }
    
    // method to reduce the if/else mess.
    // Even better, switch to XML !
    
    void ManagerImpl::setAccountDetails (const std::string& accountID,
                                         const std::map<std::string, std::string>& details)
    {
    
        _debug ("Manager: Set account details for %s", accountID.c_str());
    
        Account* account = getAccount(accountID);
        if (account == NULL) {
            _error ("Manager: Error: Could not find account %s", accountID.c_str());
            return;
        }
    
        account->setAccountDetails (details);
    
        // Serialize configuration to disk once it is done
        saveConfig();
    
        if (account->isEnabled()) {
            account->registerVoIPLink();
        }
        else {
            account->unregisterVoIPLink();
        }
    
        // Update account details to the client side
        if (_dbus) {
            _error("Manager: Error: Dbus not initialized");
            return;
        }
    
        _dbus->getConfigurationManager()->accountsChanged();
    
    }
    
    std::string ManagerImpl::addAccount (
        const std::map<std::string, std::string>& details)
    {
    
        /** @todo Deal with both the _accountMap and the Configuration */
        std::string accountType, account_list;
        Account* newAccount;
        std::stringstream accountID;
        AccountID newAccountID;
    
        accountID << "Account:" << time (NULL);
        newAccountID = accountID.str();
    
        // Get the type
        accountType = (*details.find (CONFIG_ACCOUNT_TYPE)).second;
    
        _debug ("Manager: Adding account %s", newAccountID.c_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);
            newAccount->setVoIPLink();
        } else if (accountType == "IAX") {
            newAccount = AccountCreator::createAccount (AccountCreator::IAX_ACCOUNT,
                         newAccountID);
        } else {
            _error ("Unknown %s param when calling addAccount(): %s", CONFIG_ACCOUNT_TYPE, accountType.c_str());
            return "";
        }
    
        _accountMap[newAccountID] = newAccount;
    
        newAccount->setAccountDetails (details);
    
        // Add the newly created account in the account order list
        account_list = preferences.getAccountOrder();
    
        if (account_list != "") {
            newAccountID += "/";
            // Prepend the new account
            account_list.insert (0, newAccountID);
    
            preferences.setAccountOrder (account_list);
        } else {
            newAccountID += "/";
            account_list = newAccountID;
            preferences.setAccountOrder (account_list);
        }
    
        _debug ("AccountMap: %s", account_list.c_str());
    
        newAccount->setVoIPLink();
    
        newAccount->registerVoIPLink();
    
        saveConfig();
    
        if (_dbus)
            _dbus->getConfigurationManager()->accountsChanged();
    
        return accountID.str();
    }
    
    void ManagerImpl::deleteAllCredential (const AccountID& accountID)
    {
    
        _debug ("Manager: delete all credential");
    
        Account *account = getAccount (accountID);
    
        if (!account)
            return;
    
        if (account->getType() != "SIP")
            return;
    
        SIPAccount *sipaccount = (SIPAccount *) account;
    
        if (accountID.empty() == false) {
            sipaccount->setCredentialCount (0);
        }
    }
    
    void ManagerImpl::removeAccount (const AccountID& accountID)
    {
        // Get it down and dying
        Account* remAccount = NULL;
        remAccount = getAccount (accountID);
    
        if (remAccount != NULL) {
            remAccount->unregisterVoIPLink();
            _accountMap.erase (accountID);
            // http://projects.savoirfairelinux.net/issues/show/2355
            // delete remAccount;
        }
    
        _config.removeSection (accountID);
    
        saveConfig();
    
        _debug ("REMOVE ACCOUNT");
    
        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 ("Manager: Associate Call %s with Account %s", 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;
    }
    
    bool ManagerImpl::isValidCall(const CallID& callID)
    {
    	ost::MutexLock m(_callAccountMapMutex);
    	CallAccountMap::iterator iter = _callAccountMap.find (callID);
    
    	if(iter != _callAccountMap.end()) {
    		return true;
    	}
    	else {
    		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();
    }
    
    std::vector<std::string> ManagerImpl::loadAccountOrder (void)
    {
    
        std::string account_list;
        std::vector<std::string> account_vect;
    
        account_list = preferences.getAccountOrder();
    
        _debug ("Manager: Load sccount order %s", account_list.c_str());
    
        return unserialize (account_list);
    }
    
    short ManagerImpl::buildConfiguration ()
    {
    
        _debug ("Manager: Loading account map");
    
        loadIptoipProfile();
    
        int nbAccount = loadAccountMap();
    
        return nbAccount;
    }
    
    void ManagerImpl::loadIptoipProfile()
    {
    
        _debug ("Manager: Create default \"account\" (used as default UDP transport)");
    
        // build a default IP2IP account with default parameters
        _directIpAccount = AccountCreator::createAccount (AccountCreator::SIP_DIRECT_IP_ACCOUNT, "");
        _accountMap[IP2IP_PROFILE] = _directIpAccount;
        _accountMap[""] = _directIpAccount;
    
        if (_directIpAccount == NULL) {
            _error ("Manager: Failed to create default \"account\"");
            return;
        }
    
        // If configuration file parsed, load saved preferences
        if (_setupLoaded) {
    
            _debug ("Manager: Loading IP2IP profile preferences from config");
    
            Conf::SequenceNode *seq = parser->getAccountSequence();
    
            Conf::Sequence::iterator iterIP2IP = seq->getSequence()->begin();
            Conf::Key accID ("id");
    
            // Iterate over every account maps
            while (iterIP2IP != seq->getSequence()->end()) {
    
                Conf::MappingNode *map = (Conf::MappingNode *) (*iterIP2IP);
    
                // Get the account id
                Conf::ScalarNode * val = (Conf::ScalarNode *) (map->getValue (accID));
                Conf::Value accountid = val->getValue();
    
                // if ID is IP2IP, unserialize
                if (accountid == "IP2IP") {
    
                    try {
                        _directIpAccount->unserialize (map);
                    } catch (SipAccountException &e) {
                        _error ("Manager: %s", e.what());
                    }
    
                    break;
                }
    
                iterIP2IP++;
            }
        }
    
        // Force IP2IP settings to be loaded to be loaded
        // No registration in the sense of the REGISTER method is performed.
        _directIpAccount->registerVoIPLink();
    
        // SIPVoIPlink is used as a singleton, it is the first call to instance here
        // The SIP library initialization is done in the SIPVoIPLink constructor
        // We need the IP2IP settings to be loaded at this time as they are used
        // for default sip transport
    
        // _directIpAccount->setVoIPLink(SIPVoIPLink::instance (""));
        _directIpAccount->setVoIPLink();
    
    }
    
    short ManagerImpl::loadAccountMap()
    {
    
        _debug ("Manager: Load account map");
    
        // Conf::YamlParser *parser;
        int nbAccount = 0;
    
        if (!_setupLoaded) {
        	_error("Manager: Error: Configuration file not loaded yet, could not load config");
        	return 0;
        }
    
        // build preferences
        preferences.unserialize ( (Conf::MappingNode *) (parser->getPreferenceSequence()));
        voipPreferences.unserialize ( (Conf::MappingNode *) (parser->getVoipPreferenceSequence()));
        addressbookPreference.unserialize ( (Conf::MappingNode *) (parser->getAddressbookSequence()));
        hookPreference.unserialize ( (Conf::MappingNode *) (parser->getHookSequence()));
        audioPreference.unserialize ( (Conf::MappingNode *) (parser->getAudioSequence()));
        shortcutPreferences.unserialize ( (Conf::MappingNode *) (parser->getShortcutSequence()));
    
        Conf::SequenceNode *seq = parser->getAccountSequence();
    
        // Each element in sequence is a new account to create
        Conf::Sequence::iterator iterSeq = seq->getSequence()->begin();
    
        Conf::Key accTypeKey ("type");
        Conf::Key accID ("id");
        Conf::Key alias ("alias");
    
        while (iterSeq != seq->getSequence()->end()) {
    
            // Pointer to the account and account preferences map
            Account *tmpAccount = NULL;
            Conf::MappingNode *map = (Conf::MappingNode *) (*iterSeq);
    
            // Scalar node from yaml configuration
            Conf::ScalarNode * val = NULL;
    
            // Search for account types (IAX/IP2IP)
            val = (Conf::ScalarNode *) (map->getValue (accTypeKey));
            Conf::Value accountType;
    
            if (val)
                accountType = val->getValue();
            else
                accountType = "SIP"; // Assume type is SIP if not specified
    
            // search for account id
            val = NULL;
            val = (Conf::ScalarNode *) (map->getValue (accID));
            Conf::Value accountid;
    
            if (val)
                accountid = val->getValue();
    
            // search for alias (to get rid of the "ghost" account)
            val = NULL;
            val = (Conf::ScalarNode *) (map->getValue (alias));
            Conf::Value accountAlias;
    
            if (val)
                accountAlias = val->getValue();
    
            // do not insert in account map if id or alias is empty
            if (accountid.empty() || accountAlias.empty()) {
                iterSeq++;
                continue;
            }
    
            // Create a default account for specific type
            if (accountType == "SIP" && accountid != "IP2IP") {
                tmpAccount = AccountCreator::createAccount (AccountCreator::SIP_ACCOUNT, accountid);
            } else if (accountType == "IAX" && accountid != "IP2IP") {
                tmpAccount = AccountCreator::createAccount (AccountCreator::IAX_ACCOUNT, accountid);
            }
    
            // Fill account with configuration preferences
            if (tmpAccount != NULL) {
    
                try {
    
                    tmpAccount->unserialize (map);
                } catch (SipAccountException &e) {
                    _error ("Manager: %s", e.what());
                }
    
                _accountMap[accountid] = tmpAccount;
    
                tmpAccount->setVoIPLink();
                nbAccount++;
            }
    
            iterSeq++;
        }
    
        try {
            delete parser;
        } catch (Conf::YamlParserException &e) {
            _error ("Manager: %s", e.what());
        }
    
        parser = NULL;
    
        return nbAccount;
    
    }
    
    void ManagerImpl::unloadAccountMap ()
    {
        _debug ("Manager: Unload account map");
    
        AccountMap::iterator iter = _accountMap.begin();
    
        while (iter != _accountMap.end()) {
            // Avoid removing the IP2IP account twice
            if (iter->first != "") {
                delete iter->second;
                iter->second = NULL;
            }
    
            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 iter->second;
        }
    
        _debug ("Manager: Did not found account %s, returning IP2IP account", accountID.c_str());
        return _directIpAccount;
    }
    
    AccountID ManagerImpl::getAccountIdFromNameAndServer (
        const std::string& userName, const std::string& server)
    {
    
        AccountMap::iterator iter;
        SIPAccount *account;
    
        _info ("Manager : username = %s , server = %s", userName.c_str(), server.c_str());
        // 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)) {
                    _debug ("Manager: Matching account id in request is a fullmatch %s@%s", userName.c_str(), server.c_str());
                    return iter->first;
                }
            }
        }
    
        // We failed! Then only match the hostname
        for (iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) {
            account = dynamic_cast<SIPAccount *> (iter->second);
    
            if (account != NULL) {
                if (account->hostnameMatch (server)) {
                    _debug ("Manager: Matching account id in request with hostname %s", server.c_str());
                    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)) {
                    _debug ("Manager: Matching account id in request with username %s", userName.c_str());
                    return iter->first;
                }
            }
        }
    
        _debug ("Manager: Username %s or server %s doesn't match any account, using IP2IP", userName.c_str(), server.c_str());
    
        // Failed again! return AccountNULL
        return AccountNULL;
    }
    
    std::map<std::string, int32_t> ManagerImpl::getAddressbookSettings ()
    {
    
        std::map<std::string, int32_t> settings;
    
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_ENABLE", addressbookPreference.getEnabled() ? 1 : 0));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_MAX_RESULTS", addressbookPreference.getMaxResults()));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_CONTACT_PHOTO", addressbookPreference.getPhoto() ? 1 : 0));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_PHONE_BUSINESS", addressbookPreference.getBusiness() ? 1 : 0));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_PHONE_HOME", addressbookPreference.getHome() ? 1 : 0));
        settings.insert (std::pair<std::string, int32_t> ("ADDRESSBOOK_DISPLAY_PHONE_MOBILE", addressbookPreference.getMobile() ? 1 : 0));
    
        return settings;
    }
    
    void ManagerImpl::setAddressbookSettings (
        const std::map<std::string, int32_t>& settings)
    {
        _debug ("Manager: Update addressbook settings");
    
        addressbookPreference.setEnabled ( (settings.find ("ADDRESSBOOK_ENABLE")->second == 1) ? true : false);
        addressbookPreference.setMaxResults (settings.find ("ADDRESSBOOK_MAX_RESULTS")->second);
        addressbookPreference.setPhoto ( (settings.find ("ADDRESSBOOK_DISPLAY_CONTACT_PHOTO")->second == 1) ? true : false);
        addressbookPreference.setBusiness ( (settings.find ("ADDRESSBOOK_DISPLAY_PHONE_BUSINESS")->second == 1) ? true : false);
        addressbookPreference.setHone ( (settings.find ("ADDRESSBOOK_DISPLAY_PHONE_HOME")->second == 1) ? true : false);
        addressbookPreference.setMobile ( (settings.find ("ADDRESSBOOK_DISPLAY_PHONE_MOBILE")->second == 1) ? true : false);
    
        // Write it to the configuration file
        // TODO save config is called for updateAddressbookSettings, updateHookSettings, setHistoryLimit each called
        // when closing preference window (in this order)
        // saveConfig();
    }
    
    void ManagerImpl::setAddressbookList (const std::vector<std::string>& list)
    {
        _debug ("Manager: Set addressbook list");
    
        std::string s = serialize (list);
        _debug("Manager: New addressbook list: %s", s.c_str());
        addressbookPreference.setList (s);
    
        saveConfig();
    }
    
    std::vector<std::string> ManagerImpl::getAddressbookList (void)
    {
    
        std::string s = addressbookPreference.getList();
        return unserialize (s);
    }
    
    std::map<std::string, std::string> ManagerImpl::getHookSettings ()
    {
    
        std::map<std::string, std::string> settings;
    
    
        settings.insert (std::pair<std::string, std::string> ("URLHOOK_IAX2_ENABLED", hookPreference.getIax2Enabled() ? "true" : "false"));
        settings.insert (std::pair<std::string, std::string> ("PHONE_NUMBER_HOOK_ADD_PREFIX", hookPreference.getNumberAddPrefix()));
        settings.insert (std::pair<std::string, std::string> ("PHONE_NUMBER_HOOK_ENABLED", hookPreference.getNumberEnabled() ? "true" : "false"));
        settings.insert (std::pair<std::string, std::string> ("URLHOOK_SIP_ENABLED", hookPreference.getSipEnabled() ? "true" : "false"));
        settings.insert (std::pair<std::string, std::string> ("URLHOOK_COMMAND", hookPreference.getUrlCommand()));
        settings.insert (std::pair<std::string, std::string> ("URLHOOK_SIP_FIELD", hookPreference.getUrlSipField()));
    
        return settings;
    }
    
    void ManagerImpl::setHookSettings (const std::map<std::string, std::string>& settings)
    {
    
        hookPreference.setIax2Enabled ( (settings.find ("URLHOOK_IAX2_ENABLED")->second == "true") ? true : false);
        hookPreference.setNumberAddPrefix (settings.find ("PHONE_NUMBER_HOOK_ADD_PREFIX")->second);
        hookPreference.setNumberEnabled ( (settings.find ("PHONE_NUMBER_HOOK_ENABLED")->second == "true") ? true : false);
        hookPreference.setSipEnabled ( (settings.find ("URLHOOK_SIP_ENABLED")->second == "true") ? true : false);
        hookPreference.setUrlCommand (settings.find ("URLHOOK_COMMAND")->second);
        hookPreference.setUrlSipField (settings.find ("URLHOOK_SIP_FIELD")->second);
    
        // Write it to the configuration file
        // TODO save config is called for updateAddressbookSettings, updateHookSettings, setHistoryLimit each called
        // when closing preference window (in this order)
        // saveConfig();
    }
    
    void ManagerImpl::checkCallConfiguration (const CallID& id,
            const std::string &to, Call::CallConfiguration *callConfig)
    {
        Call::CallConfiguration config;
    
        if (to.find (SIP_SCHEME) == 0 || to.find (SIPS_SCHEME) == 0) {
            _debug ("Manager: Sip scheme detected (sip: or sips:), sending IP2IP Call");
            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 ("Manager: Associate call %s with config %d", callID.c_str(), 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;
    }
    
    std::map<std::string, std::string> ManagerImpl::getCallDetails (const CallID& callID)
    {
    
        std::map<std::string, std::string> call_details;
        AccountID accountid;
        Account *account;
        VoIPLink *link;
        Call *call = NULL;
        std::stringstream type;
    
        // We need here to retrieve the call information attached to the call ID
        // To achieve that, we need to get the voip link attached to the call
        // But to achieve that, we need to get the account the call was made with
    
        // So first we fetch the account
        accountid = getAccountFromCall (callID);
    
        // Then the VoIP link this account is linked with (IAX2 or SIP)
        if ( (account = getAccount (accountid)) != NULL) {
            link = account->getVoIPLink();
    
            if (link) {
                call = link->getCall (callID);
            }
        }
    
        if (call) {
            type << call->getCallType();
            call_details.insert (std::pair<std::string, std::string> ("ACCOUNTID", accountid));
            call_details.insert (std::pair<std::string, std::string> ("PEER_NUMBER", call->getPeerNumber()));
            call_details.insert (std::pair<std::string, std::string> ("PEER_NAME", call->getPeerName()));
            call_details.insert (std::pair<std::string, std::string> ("DISPLAY_NAME", call->getDisplayName()));
            call_details.insert (std::pair<std::string, std::string> ("CALL_STATE", call->getStateStr()));
            call_details.insert (std::pair<std::string, std::string> ("CALL_TYPE", type.str()));
        } else {
            _error ("Manager: Error: getCallDetails()");
            call_details.insert (std::pair<std::string, std::string> ("ACCOUNTID", AccountNULL));
            call_details.insert (std::pair<std::string, std::string> ("PEER_NUMBER", "Unknown"));
            call_details.insert (std::pair<std::string, std::string> ("PEER_NAME", "Unknown"));
            call_details.insert (std::pair<std::string, std::string> ("DISPLAY_NAME", "Unknown"));
            call_details.insert (std::pair<std::string, std::string> ("CALL_STATE", "UNKNOWN"));
            call_details.insert (std::pair<std::string, std::string> ("CALL_TYPE", "0"));
        }
    
        return call_details;
    }
    
    std::vector<std::string> ManagerImpl::getHistorySerialized(void)
    {
        _debug("Manager: Get history serialized"); 
    
        return _history->get_history_serialized();
    }
    
    void ManagerImpl::setHistorySerialized(std::vector<std::string> history)
    {
    
        _debug("Manager: Set history serialized");
    
        _history->set_serialized_history (history, preferences.getHistoryLimit());;
        _history->save_history();
    }
    
    std::vector<std::string> ManagerImpl::getCallList (void)
    {
        std::vector<std::string> v;
    
        CallAccountMap::iterator iter = _callAccountMap.begin();
    
        while (iter != _callAccountMap.end()) {
            v.push_back (iter->first.data());
            iter++;
        }
    
        return v;
    }
    
    std::map<std::string, std::string> ManagerImpl::getConferenceDetails (
        const ConfID& confID)
    {
    
        std::map<std::string, std::string> conf_details;
        ConferenceMap::iterator iter_conf;
    
        iter_conf = _conferencemap.find (confID);
    
        Conference* conf = NULL;
    
        if (iter_conf != _conferencemap.end()) {
    
            conf = iter_conf->second;
            conf_details.insert (std::pair<std::string, std::string> ("CONFID",
                                 confID));
            conf_details.insert (std::pair<std::string, std::string> ("CONF_STATE",
                                 conf->getStateStr()));
        }
    
        return conf_details;
    }
    
    std::vector<std::string> ManagerImpl::getConferenceList (void)
    {
        _debug ("ManagerImpl::getConferenceList");
        std::vector<std::string> v;
    
        ConferenceMap::iterator iter = _conferencemap.begin();
    
        while (iter != _conferencemap.end()) {
            v.push_back (iter->first);
            iter++;
        }
    
        return v;
    }
    
    std::vector<std::string> ManagerImpl::getParticipantList (
        const std::string& confID)
    {
    
        _debug ("ManagerImpl: Get participant list %s", confID.c_str());
        std::vector<std::string> v;
    
        ConferenceMap::iterator iter_conf = _conferencemap.find (confID);
        Conference *conf = NULL;
    
        if (iter_conf != _conferencemap.end())
            conf = iter_conf->second;
    
        if (conf != NULL) {
            ParticipantSet participants = conf->getParticipantList();
            ParticipantSet::iterator iter_participant = participants.begin();
    
            while (iter_participant != participants.end()) {
    
                v.push_back (*iter_participant);
    
                iter_participant++;
            }
        } else {
            _warn ("Manager: Warning: Did not found conference %s", confID.c_str());
        }
    
        return v;
    }