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

sipaccount.cpp

Blame
    • Eden Abitbol's avatar
      60515d89
      upnp: support libupnp and libnatnatpmp simultaneously · 60515d89
      Eden Abitbol authored
      Update libupnp to version 1.8.4.
      
      For windows, the IPV6 preprocessor must be undefined. Or else
      libupnp won't initialize. Added visual studio 2017 support
      via one patch for windows that also combines previous windows
      patches.
      
      UPnPController: Class that the jami classes use to control the
      opening and closing of ports. Every  service has it's own upnp
      controller. The controller does it's actions by using the upnp
      context class. Also refactored the functions used to add
      mappings. Instead of using two different functions with
      different types of parameters, we now use one function with
      parameters that have default values. The logic stays the same
      but the function call is more clear.
      
      UPnPContext: Class that holds a (linked) list of discovered IGDs
      and their corresponding protocols (which discovered them).
      Whenever the controller wants to add or remove a mapping, the
      context picks a valid IGD in it's list and uses the correct
      protocol to complete the required action. This class also has
      the ability to swap protocols for an IGD that was discovered
      by more then one protocol.
      
      UPnPProtocol: Virtual base class that defines the functions
      needed by the context to use the corresponding protocol.
      
      PUPnP: UPnPProtocol derived class that represents a upnp client
      that uses the portable upnp library (libupnp). Every time the
      client discovers a new IGD it uses a callback to add it to the
      context's main IGD linked list. It also has an internal list of
      IGDs that it discovered. Added features to this class include:
      	- IGD event subscription.
      	- Use UpnpInit2 function instead of deprecated UpnpInit
      	  function. It's also supposed to support IPv6.
      
      NatPmp: UPnPProtocol derived class that represents a upnp client
      that uses the NAT-PMP library (libnatpmp). Unlike libupnp,
      libnatpmp only supports discovering one IGD. Also uses callbacks
      to add the IGD it finds to the context's main IGD class.
      
      Also inclided debug warning prints whenever a controller opens
      and closes the ports. That way we can keep track of whenever
      the application opens and closes ports on the internet
      gateway device.
      
      Gitlab: #96
      
      Change-Id: I199271edac2c6d93dc60c24e2e2aefe36de7950c
      60515d89
      History
      upnp: support libupnp and libnatnatpmp simultaneously
      Eden Abitbol authored
      Update libupnp to version 1.8.4.
      
      For windows, the IPV6 preprocessor must be undefined. Or else
      libupnp won't initialize. Added visual studio 2017 support
      via one patch for windows that also combines previous windows
      patches.
      
      UPnPController: Class that the jami classes use to control the
      opening and closing of ports. Every  service has it's own upnp
      controller. The controller does it's actions by using the upnp
      context class. Also refactored the functions used to add
      mappings. Instead of using two different functions with
      different types of parameters, we now use one function with
      parameters that have default values. The logic stays the same
      but the function call is more clear.
      
      UPnPContext: Class that holds a (linked) list of discovered IGDs
      and their corresponding protocols (which discovered them).
      Whenever the controller wants to add or remove a mapping, the
      context picks a valid IGD in it's list and uses the correct
      protocol to complete the required action. This class also has
      the ability to swap protocols for an IGD that was discovered
      by more then one protocol.
      
      UPnPProtocol: Virtual base class that defines the functions
      needed by the context to use the corresponding protocol.
      
      PUPnP: UPnPProtocol derived class that represents a upnp client
      that uses the portable upnp library (libupnp). Every time the
      client discovers a new IGD it uses a callback to add it to the
      context's main IGD linked list. It also has an internal list of
      IGDs that it discovered. Added features to this class include:
      	- IGD event subscription.
      	- Use UpnpInit2 function instead of deprecated UpnpInit
      	  function. It's also supposed to support IPv6.
      
      NatPmp: UPnPProtocol derived class that represents a upnp client
      that uses the NAT-PMP library (libnatpmp). Unlike libupnp,
      libnatpmp only supports discovering one IGD. Also uses callbacks
      to add the IGD it finds to the context's main IGD class.
      
      Also inclided debug warning prints whenever a controller opens
      and closes the ports. That way we can keep track of whenever
      the application opens and closes ports on the internet
      gateway device.
      
      Gitlab: #96
      
      Change-Id: I199271edac2c6d93dc60c24e2e2aefe36de7950c
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    managerimpl.cpp 117.77 KiB
    /*
     *  Copyright (C) 2004-2007 Savoir-Faire Linux inc.
     *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
     *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
     *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
     *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
     *  Author: 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.
     */
    
    #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 "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(), _codecBuilder(NULL), _audiodriver(NULL),
    			_dtmfKey(NULL), _codecDescriptorMap(), _toneMutex(),
    			_telephoneTone(NULL), _audiofile(), _spkr_volume(0),
    			_mic_volume(0), _mutex(), _dbus(NULL), _waitingCall(),
    			_waitingCallMutex(), _nbIncomingWaitingCall(0), _path(""),
    			_exist(0), _setupLoaded(false), _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();
    
    #ifdef TEST
    	testAccountMap();
    	loadAccountMap();
    	testCallAccountMap();
    	unloadAccountMap();
    #endif
    
    	// should be call before initConfigFile
    	// loadAccountMap();, called in init() now.
    }
    
    // never call if we use only the singleton...
    ManagerImpl::~ManagerImpl (void) {
    	// terminate();
    	delete _cleaner;
    	_cleaner = 0;
    	_debug ("%s stop correctly.", PROGNAME);
    }
    
    void ManagerImpl::init () {
    
    	// Load accounts, init map
    	loadAccountMap();
    
    	initVolume();
    
    	if (_exist == 0) {
    		_debug ("Cannot create config file in your home directory");
    	}
    
    	initAudioDriver();
    
    	selectAudioDriver();
    
    	// Initialize the list of supported audio codecs
    	initAudioCodec();
    
    	AudioLayer *audiolayer = getAudioDriver();
    
    	if (audiolayer != 0) {
    		unsigned int sampleRate = audiolayer->getSampleRate();
    
    		_debugInit ("Load Telephone Tone");
    		std::string country = getConfigString(PREFERENCES, ZONE_TONE);
    		_telephoneTone = new TelephoneTone(country, sampleRate);
    
    		_debugInit ("Loading DTMF key");
    		_dtmfKey = new DTMF(sampleRate);
    	}
    
    	if (audiolayer == 0)
    		audiolayer->stopStream();
    
    	// Load the history
    	_history->load_history(getConfigInt(PREFERENCES, CONFIG_HISTORY_LIMIT));
    }
    
    void ManagerImpl::terminate () {
    	_debug ("ManagerImpl::terminate ");
    	saveConfig();
    
    	unloadAccountMap();
    
    	_debug ("Unload DTMF Key ");
    	delete _dtmfKey;
    
    	_debug ("Unload Audio Driver ");
    	delete _audiodriver;
    	_audiodriver = NULL;
    
    	_debug ("Unload Telephone Tone ");
    	delete _telephoneTone;
    	_telephoneTone = NULL;
    
    	_debug ("Unload Audio Codecs ");
    	_codecDescriptorMap.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;
    
    	/*
    	 AudioLayer *al = getAudioDriver();
    
    	 if (id != "") {
    
    	 if(isConference(id)) {
    
    	 Conference *conf;
    
    	 ConferenceMap::iterator iter = _conferencemap.find(id);
    	 if(iter != _conferencemap.end())
    	 {
    	 _debug("    set call recordable in audio layer");
    	 conf = iter->second;
    	 al->setRecorderInstance((Recordable*)conf);
    	 }
    	 }
    	 else {
    
    	 // set the recordable instance in audiolayer
    	 AccountID account_id = getAccountFromCall(id);
    
    
    	 Call *call = NULL;
    	 call = getAccountLink (account_id)->getCall(id);
    
    	 _debug("    set call recordable in audio layer");
    	 al->setRecorderInstance((Recordable*)call);
    	 }
    	 }
    	 */
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    // Management of events' IP-phone user
    ///////////////////////////////////////////////////////////////////////////////
    /* Main Thread */
    
    bool ManagerImpl::outgoingCall (const std::string& account_id,
    		const CallID& call_id, const std::string& to) {
    	std::string pattern, to_cleaned;
    	Call::CallConfiguration callConfig;
    	SIPVoIPLink *siplink;
    
    	_debug ("ManagerImpl::outgoingCall(%s)", call_id.c_str());
    
    	CallID current_call_id = getCurrentCallId();
    
    	if (getConfigString(HOOKS, PHONE_NUMBER_HOOK_ENABLED) == "1")
    		_cleaner->set_phone_number_prefix(getConfigString(HOOKS,
    				PHONE_NUMBER_HOOK_ADD_PREFIX));
    	else
    		_cleaner->set_phone_number_prefix("");
    
    	to_cleaned = _cleaner->clean(to);
    
    	/* Check what kind of call we are dealing with */
    	check_call_configuration(call_id, to_cleaned, &callConfig);
    
    	// in any cases we have to detach from current communication
    	if (hasCurrentCall()) {
    
    		_debug ("    outgoingCall: 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)) {
    			_debug ("    outgoingCall: 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)) {
    			_debug ("    outgoingCall: detach main participant from conference");
    			detachParticipant(default_id, current_call_id);
    		}
    	}
    
    	if (callConfig == Call::IPtoIP) {
    		_debug ("    outgoingCall: Start IP to IP call");
    		/* We need to retrieve the sip voiplink instance */
    		siplink = SIPVoIPLink::instance("");
    
    		if (siplink->new_ip_to_ip_call(call_id, to_cleaned)) {
    			switchCall(call_id);
    			return true;
    		} else {
    			callFailure(call_id);
    		}
    
    		return false;
    	}
    
    	if (!accountExists(account_id)) {
    		_debug ("! Manager Error: Outgoing Call: account doesn't exist");
    		return false;
    	}
    
    	if (getAccountFromCall(call_id) != AccountNULL) {
    		_debug ("! Manager Error: Outgoing Call: call id already exists");
    		return false;
    	}
    
    	_debug ("- Manager Action: Adding Outgoing Call %s on account %s", call_id.data(), account_id.data());
    
    	associateCallToAccount(call_id, account_id);
    
    	if (getAccountLink(account_id)->newOutgoingCall(call_id, to_cleaned)) {
    		switchCall(call_id);
    		return true;
    	} else {
    		callFailure(call_id);
    		_debug ("! Manager Error: An error occur, the call was not created");
    	}
    
    	return false;
    }
    
    //THREAD=Main : for outgoing Call
    bool ManagerImpl::answerCall (const CallID& call_id) {
    
    	_debug ("ManagerImpl::answerCall(%s)", call_id.c_str());
    
    	stopTone();
    
    	// store the current call id
    	CallID current_call_id = getCurrentCallId();
    
    	AccountID account_id = getAccountFromCall(call_id);
    
    	if (account_id == AccountNULL) {
    		_debug ("    answerCall: AccountId is null");
    	}
    
    	Call* call = NULL;
    
    	call = getAccountLink(account_id)->getCall(call_id);
    
    	if (call == NULL) {
    		_debug ("    answerCall: Call is null");
    	}
    
    	// in any cases we have to detach from current communication
    	if (hasCurrentCall()) {
    
    		_debug ("    answerCall: Currently conversing with %s", current_call_id.c_str());
    		// if it is not a conference and is not a conference participant
    
    		if (!isConference(current_call_id) && !participToConference(
    				current_call_id)) {
    			_debug ("    answerCall: Put the current call (%s) on hold", current_call_id.c_str());
    			onHoldCall(current_call_id);
    		}
    
    		// if we are talking to a conference and we are answering an incoming call
    		else if (isConference(current_call_id)
    				&& !participToConference(call_id)) {
    			_debug ("    answerCall: Detach main participant from conference");
    			detachParticipant(default_id, current_call_id);
    		}
    
    	}
    
    	if (!getAccountLink(account_id)->answer(call_id)) {
    		// error when receiving...
    		removeCallAccount(call_id);
    		return false;
    	}
    
    	// if it was waiting, it's waiting no more
    	if (_dbus)
    		_dbus->getCallManager()->callStateChanged(call_id, "CURRENT");
    
    	// std::string codecName = Manager::instance().getCurrentCodecName (call_id);
    	// if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str());
    
    	removeWaitingCall(call_id);
    
    	// if we dragged this call into a conference already
    	if (participToConference(call_id)) {
    
    		// AccountID currentAccountId;
    		// Call* call = NULL;
    
    		// currentAccountId = getAccountFromCall (call_id);
    		// call = getAccountLink (currentAccountId)->getCall (call_id);
    
    		switchCall(call->getConfId());
    	} else {
    		switchCall(call_id);
    	}
    
    	return true;
    }
    
    //THREAD=Main
    bool ManagerImpl::hangupCall (const CallID& call_id) {
    
    	_info("Manager: Hangup call %s", call_id.c_str());
    
    	PulseLayer *pulselayer;
    	AccountID account_id;
    	bool returnValue = true;
    
    	// store the current call id
    	CallID current_call_id = getCurrentCallId();
    
    	stopTone();
    
    	/* Broadcast a signal over DBus */
    	_debug ("Manager: Send DBUS call state change (HUNGUP) for id %s", call_id.c_str());
    
    	if (_dbus)
    		_dbus->getCallManager()->callStateChanged(call_id, "HUNGUP");
    
    	if (participToConference(call_id)) {
    
    		Conference *conf = getConferenceFromCallID(call_id);
    
    		if (conf != NULL) {
    			// remove this participant
    			removeParticipant(call_id);
    
    			processRemainingParticipant(current_call_id, conf);
    		}
    
    	} else {
    		// we are not participating to a conference, current call switched to ""
    		if (!isConference(current_call_id))
    			switchCall("");
    	}
    
    	/* Direct IP to IP call */
    	if (getConfigFromCall(call_id) == Call::IPtoIP) {
    		returnValue = SIPVoIPLink::instance(AccountNULL)->hangup(call_id);
    	}
    	/* Classic call, attached to an account */
    	else {
    		account_id = getAccountFromCall(call_id);
    
    		if (account_id == AccountNULL) {
    
    			_error ("Manager: Error: account id is NULL in hangup");
    			returnValue = false;
    		} else {
    
    			returnValue = getAccountLink(account_id)->hangup(call_id);
    			removeCallAccount(call_id);
    		}
    	}
    
    	int nbCalls = getCallList().size();
    
    	AudioLayer *audiolayer = getAudioDriver();
    
    	// stop streams
    	if (audiolayer && (nbCalls <= 0)) {
    		_debug ("Manager: stop audio stream, ther is only %i call(s) remaining", nbCalls);
    		audiolayer->stopStream();
    	}
    
    	if (_audiodriver->getLayerType() == PULSEAUDIO) {
    		pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
    	}
    
    	return returnValue;
    }
    
    bool ManagerImpl::hangupConference (const ConfID& id) {
    
    	_debug ("Manager: Hangup conference %s", id.c_str());
    
    	Conference *conf;
    	ConferenceMap::iterator iter_conf = _conferencemap.find(id);
    
    	AccountID currentAccountId;
    
    	// Call* call = NULL;
    
    
    	if (iter_conf != _conferencemap.end()) {
    		conf = iter_conf->second;
    
    		ParticipantSet participants = conf->getParticipantList();
    		ParticipantSet::iterator iter_participant = participants.begin();
    
    		while (iter_participant != participants.end()) {
    			_debug ("Manager: Hangup onference participant %s", (*iter_participant).c_str());
    
    			hangupCall(*iter_participant);
    
    			iter_participant++;
    
    		}
    
    	}
    
    	switchCall("");
    
    	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);
    
    	switchCall("");
    
    	return returnValue;
    }
    
    //THREAD=Main
    bool ManagerImpl::onHoldCall (const CallID& call_id) {
    	AccountID account_id;
    	bool returnValue;
    
    	_debug ("Manager:  Put call %s on hold", call_id.c_str());
    
    	stopTone();
    
    	CallID current_call_id = getCurrentCallId();
    
    
    	/* Direct IP to IP call */
    
    	if (getConfigFromCall(call_id) == Call::IPtoIP) {
    		returnValue = SIPVoIPLink::instance(AccountNULL)-> onhold(call_id);
    	}
    
    	/* Classic call, attached to an account */
    	else {
    		account_id = getAccountFromCall(call_id);
    
    		if (account_id == AccountNULL) {
    			_debug ("Manager: Account ID %s or callid %s doesn't exists in call onHold", account_id.c_str(), call_id.c_str());
    			return false;
    		}
    
    		returnValue = getAccountLink(account_id)->onhold(call_id);
    	}
    
    	removeWaitingCall(call_id);
    
    	// keeps current call id if the action is not holding this call or a new outgoing call
    
    	if (current_call_id == call_id) {
    
    		switchCall("");
    	}
    
    	if (_dbus)
    		_dbus->getCallManager()->callStateChanged(call_id, "HOLD");
    
    	return returnValue;
    }
    
    //THREAD=Main
    bool ManagerImpl::offHoldCall (const CallID& call_id) {
    
    	AccountID account_id;
    	bool returnValue, is_rec;
    	std::string codecName;
    
    	is_rec = false;
    
    	_debug ("Manager: Put call %s off hold", call_id.c_str());
    
    	stopTone();
    
    	CallID current_call_id = getCurrentCallId();
    
    	//Place current call on hold if it isn't
    
    	if (hasCurrentCall()) {
    		// 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);
    		}
    	}
    
    	// switch current call id to id since sipvoip link need it to amke a call
    	// switchCall(id);
    
    	/* Direct IP to IP call */
    	if (getConfigFromCall(call_id) == Call::IPtoIP) {
    		// is_rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id);
    		returnValue = SIPVoIPLink::instance(AccountNULL)-> offhold(call_id);
    	}
    
    	/* Classic call, attached to an account */
    	else {
    		account_id = getAccountFromCall(call_id);
    
    		if (account_id == AccountNULL) {
    			_warn ("Manager: Error: Call doesn't exists in off hold");
    			return false;
    		}
    
    		_debug ("Manager: Setting offhold, Account %s, callid %s", account_id.c_str(), call_id.c_str());
    
    		is_rec = getAccountLink(account_id)->getCall(call_id)->isRecording();
    		returnValue = getAccountLink(account_id)->offhold(call_id);
    	}
    
    	if (_dbus) {
    		if (is_rec)
    			_dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_RECORD");
    		else
    			_dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_CURRENT");
    
    	}
    
    	if (participToConference(call_id)) {
    
    		AccountID currentAccountId;
    		Call* call = NULL;
    
    		currentAccountId = getAccountFromCall(call_id);
    		call = getAccountLink(currentAccountId)->getCall(call_id);
    
    		switchCall(call->getConfId());
    
    	} else {
    		switchCall(call_id);
    		_audiodriver->flushMain();
    	}
    
    	return returnValue;
    }
    
    //THREAD=Main
    bool ManagerImpl::transferCall (const CallID& call_id, const std::string& to) {
    	AccountID accountid;
    	bool returnValue;
    
    	_info("Manager: Transfer call %s\n", call_id.c_str());
    
    	CallID current_call_id = getCurrentCallId();
    
    	// Direct IP to IP call
    	if (getConfigFromCall(call_id) == Call::IPtoIP) {
    		returnValue = SIPVoIPLink::instance(AccountNULL)-> transfer(call_id, to);
    	}
    	// Classic call, attached to an account
    	else {
    
    	accountid = getAccountFromCall(call_id);
    
    		if (accountid == AccountNULL) {
    			_warn ("Manager: Call doesn't exists");
    			return false;
    		}
    
    		returnValue = getAccountLink(accountid)->transfer(call_id, to);
    
    	}
    
    	// remove waiting call in case we make transfer without even answer
    	removeWaitingCall(call_id);
    
    	return returnValue;
    }
    
    void ManagerImpl::transferFailed () {
    
    	_debug("UserAgent: Transfer failed");
    
    	if (_dbus)
    		_dbus->getCallManager()->transferFailed();
    }
    
    void ManagerImpl::transferSucceded () {
    
    	_debug("UserAgent: Transfer succeded");
    
    	if (_dbus)
    		_dbus->getCallManager()->transferSucceded();
    
    }
    
    //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();
    
    	// AudioLayer* audiolayer = getAudioDriver();
    
    	if (nbCalls <= 1) {
    		_debug ("    refuseCall: stop audio stream, there is only %i call(s) remaining", nbCalls);
    
    		AudioLayer* audiolayer = getAudioDriver();
    		audiolayer->stopStream();
    	}
    
    	/* 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");
    	}
    
    	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);
    
    	// broadcast a signal over 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;
    	}
    
    	// We now need to bind the audio to the remain participant
    
    	// Unbind main participant audio from conference
    	_audiodriver->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()) {
    
    		_audiodriver->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 succesfully", conference_id.c_str());
    	else
    		_error ("Manager: Error: Cannot remove conference: %s", conference_id.c_str());
    
    	// broadcast a signal over dbus
    	_dbus->getCallManager()->conferenceRemoved(conference_id);
    
    }
    
    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 ("ManagerImpl: holdConference()");
    
    	Conference *conf;
    	ConferenceMap::iterator iter_conf = _conferencemap.find(id);
    
    	AccountID currentAccountId;
    
    	Call* call = NULL;
    
    	if (iter_conf != _conferencemap.end()) {
    		conf = iter_conf->second;
    
    		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++;
    
    		}
    
    		conf->setState(Conference::Hold);
    
    		_dbus->getCallManager()->conferenceChanged(conf->getConfID(),
    				conf->getStateStr());
    
    	}
    
    }
    
    void ManagerImpl::unHoldConference (const CallID& id) {
    
    	_debug ("ManagerImpl::unHoldConference()");
    
    	Conference *conf;
    	ConferenceMap::iterator iter_conf = _conferencemap.find(id);
    
    	AccountID currentAccountId;
    
    	Call* call = NULL;
    
    	if (iter_conf != _conferencemap.end()) {
    		conf = iter_conf->second;
    
    		ParticipantSet participants = conf->getParticipantList();
    		ParticipantSet::iterator iter_participant = participants.begin();
    
    		while (iter_participant != participants.end()) {
    			_debug ("    unholdConference: participant %s", (*iter_participant).c_str());
    			currentAccountId = getAccountFromCall(*iter_participant);
    			call = getAccountLink(currentAccountId)->getCall(*iter_participant);
    
    			offHoldCall(*iter_participant);
    
    			iter_participant++;
    
    		}
    
    		conf->setState(Conference::Active_Atached);
    
    		_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;
    
    	Call* call = NULL;
    
    	accountId = getAccountFromCall(call_id);
    	call = getAccountLink(accountId)->getCall(call_id);
    
    	if (call == NULL) {
    		return false;
    
    	}
    
    	if (call->getConfId() == "") {
    		return false;
    	} else {
    
    		return true;
    	}
    }
    
    void ManagerImpl::addParticipant (const CallID& call_id,
    		const CallID& conference_id) {
    	_debug ("ManagerImpl::addParticipant(%s, %s)", call_id.c_str(), conference_id.c_str());
    
    	std::map<std::string, std::string> call_details = getCallDetails(call_id);
    
    	ConferenceMap::iterator iter = _conferencemap.find(conference_id);
    	std::map<std::string, std::string>::iterator iter_details;
    
    	// store the current call id (it will change in offHoldCall or in answerCall)
    	CallID current_call_id = getCurrentCallId();
    
    	// detach from the conference and switch to this conference
    
    	if (current_call_id != call_id) {
    		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("");
    
    	addMainParticipant(conference_id);
    
    	_debug ("    addParticipant: enter main process");
    
    	if (iter != _conferencemap.end()) {
    
    		Conference* conf = iter->second;
    		switchCall(conf->getConfID());
    
    		AccountID currentAccountId;
    		Call* call = NULL;
    
    		currentAccountId = getAccountFromCall(call_id);
    		call = getAccountLink(currentAccountId)->getCall(call_id);
    		call->setConfId(conf->getConfID());
    
    		conf->add(call_id);
    
    		iter_details = call_details.find("CALL_STATE");
    
    		_debug ("    addParticipant: call state: %s", iter_details->second.c_str());
    
    		if (iter_details->second == "HOLD") {
    			_debug ("    OFFHOLD %s", call_id.c_str());
    
    			// offHoldCall create a new rtp session which use addStream to bind participant
    			offHoldCall(call_id);
    		} else if (iter_details->second == "INCOMING") {
    			_debug ("    ANSWER %s", call_id.c_str());
    			// answerCall create a new rtp session which use addStream to bind participant
    			answerCall(call_id);
    		} else if (iter_details->second == "CURRENT") {
    			// Already a curent call, so we beed to reset audio stream bindings manually
    			_audiodriver->getMainBuffer()->unBindAll(call_id);
    			conf->bindParticipant(call_id);
    		}
    
    		// _dbus->getCallManager()->conferenceChanged(conference_id, conf->getStateStr());
    
    		ParticipantSet participants = conf->getParticipantList();
    
    		// reset ring buffer for all conference participant
    		ParticipantSet::iterator iter_p = participants.begin();
    
    		while (iter_p != participants.end()) {
    
    			// flush conference participants only
    			_audiodriver->getMainBuffer()->flush(*iter_p);
    
    			iter_p++;
    		}
    
    		_audiodriver->getMainBuffer()->flush(default_id);
    	} else {
    		_debug ("    addParticipant: Error, conference %s conference_id not found!", conference_id.c_str());
    	}
    
    }
    
    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;
    
    	if (iter != _conferencemap.end()) {
    		conf = iter->second;
    
    		ParticipantSet participants = conf->getParticipantList();
    
    		ParticipantSet::iterator iter_participant = participants.begin();
    
    		while (iter_participant != participants.end()) {
    			_audiodriver->getMainBuffer()->bindCallID(*iter_participant,
    					default_id);
    
    			iter_participant++;
    		}
    
    		// Reset ringbuffer's readpointers
    		iter_participant = participants.begin();
    
    		while (iter_participant != participants.end()) {
    			_audiodriver->getMainBuffer()->flush(*iter_participant);
    
    			iter_participant++;
    		}
    
    		_audiodriver->getMainBuffer()->flush(default_id);
    
    		conf->setState(Conference::Active_Atached);
    
    		_dbus->getCallManager()->conferenceChanged(conference_id,
    				conf->getStateStr());
    
    	}
    
    	switchCall(conference_id);
    }
    
    void ManagerImpl::joinParticipant (const CallID& call_id1, const CallID& call_id2) {
    
    	_debug ("Manager: Join participants %s, %s", call_id1.c_str(), call_id2.c_str());
    
    
    
    	std::map<std::string, std::string> call1_details = getCallDetails(call_id1);
    	std::map<std::string, std::string> call2_details = getCallDetails(call_id2);
    
    	std::map<std::string, std::string>::iterator iter_details;
    
    	// Test if we have valid call ids
    	iter_details = call1_details.find("PEER_NUMBER");
    	if(iter_details->second == "Unknown") {
    		_error("Manager: Error: Id %s is not a valid call", call_id1.c_str());
    		return;
    	}
    
    	iter_details = call2_details.find("PEER_NUMBER");
    	if(iter_details->second == "Unknown") {
    		_error("Manager: Error: Id %s is not a valid call", call_id2.c_str());
    		return;
    	}
    
    	AccountID currentAccountId;
    	Call* call = NULL;
    
    	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 != call_id1) && (current_call_id != call_id2)) {
    
    		// If currently in a conference
    		if (isConference(current_call_id))
    			detachParticipant(default_id, current_call_id);
    		// If currently in a call
    		else
    			onHoldCall(current_call_id);
    	}
    
    	_debug ("Manager: Create a conference");
    
    	Conference *conf = createConference(call_id1, call_id2);
    	switchCall(conf->getConfID());
    
    	currentAccountId = getAccountFromCall(call_id1);
    	call = getAccountLink(currentAccountId)->getCall(call_id1);
    	call->setConfId(conf->getConfID());
    
    	iter_details = call1_details.find("CALL_STATE");
    	_debug ("Manager: Process call %s state: %s", call_id1.c_str(), iter_details->second.c_str());
    
    	if (iter_details->second == "HOLD") {
    		offHoldCall(call_id1);
    	} else if (iter_details->second == "INCOMING") {
    		answerCall(call_id1);
    	} else if (iter_details->second == "CURRENT") {
    		_audiodriver->getMainBuffer()->unBindAll(call_id1);
    		conf->bindParticipant(call_id1);
    	} else if (iter_details->second == "INACTIVE") {
    		answerCall(call_id1);
    	} else {
    		_warn ("Manager: Call state not recognized");
    	}
    
    	currentAccountId = getAccountFromCall(call_id2);
    
    	call = getAccountLink(currentAccountId)->getCall(call_id2);
    	call->setConfId(conf->getConfID());
    
    	iter_details = call2_details.find("CALL_STATE");
    	_debug ("Manager: Process call %s state: %s", call_id2.c_str(), iter_details->second.c_str());
    
    	if (iter_details->second == "HOLD") {
    		offHoldCall(call_id2);
    	} else if (iter_details->second == "INCOMING") {
    		answerCall(call_id2);
    	} else if (iter_details->second == "CURRENT") {
    		_audiodriver->getMainBuffer()->unBindAll(call_id2);
    		conf->bindParticipant(call_id2);
    	} else if (iter_details->second == "INACTIVE") {
    		answerCall(call_id2);
    	} else {
    		_warn ("Manager: Call state not recognized");
    	}
    
    	if (_audiodriver)
    		_audiodriver->getMainBuffer()->stateInfo();
    
    }
    
    void ManagerImpl::detachParticipant (const CallID& call_id,
    		const CallID& current_id) {
    	_debug ("ManagerImpl::detachParticipant(%s)", call_id.c_str());
    
    	CallID current_call_id = current_id;
    
    	current_call_id = getCurrentCallId();
    
    	if (call_id != default_id) {
    		AccountID currentAccountId;
    		Call* call = NULL;
    
    		currentAccountId = getAccountFromCall(call_id);
    		call = getAccountLink(currentAccountId)->getCall(call_id);
    
    		// TODO: add conference_id as a second parameter
    		ConferenceMap::iterator iter = _conferencemap.find(call->getConfId());
    
    		Conference *conf = getConferenceFromCallID(call_id);
    
    		if (conf != NULL) {
    
    			_debug ("    detachParticipant: detaching participant %s", call_id.c_str());
    
    			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->second == "RINGING") {
    				removeParticipant(call_id);
    			} else {
    				_debug ("    ONHOLD %s", call_id.c_str());
    				onHoldCall(call_id);
    
    				removeParticipant(call_id);
    
    				processRemainingParticipant(current_call_id, conf);
    			}
    		} else {
    
    			_debug ("    detachParticipant: call is not conferencing, cannot detach");
    
    		}
    	} else {
    		_debug ("    detachParticipant: unbind main participant from all");
    		_audiodriver->getMainBuffer()->unBindAll(default_id);
    
    		if (isConference(current_call_id)) {
    
    			ConferenceMap::iterator iter = _conferencemap.find(current_call_id);
    			Conference *conf = iter->second;
    
    			conf->setState(Conference::Active_Detached);
    
    			_dbus->getCallManager()->conferenceChanged(conf->getConfID(),
    					conf->getStateStr());
    		}
    
    		switchCall("");
    
    	}
    
    }
    
    void ManagerImpl::removeParticipant (const CallID& call_id) {
    	_debug ("ManagerImpl::removeParticipant(%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()) {
    		_debug ("    no conference created, cannot remove participant ");
    	} else {
    
    		conf = iter->second;
    
    		_debug ("    removeParticipant %s", call_id.c_str());
    		conf->remove(call_id);
    		call->setConfId("");
    
    	}
    
    	if (_audiodriver)
    		_audiodriver->getMainBuffer()->stateInfo();
    
    }
    
    void ManagerImpl::processRemainingParticipant (CallID current_call_id,
    		Conference *conf) {
    
    	_debug ("ManagerImpl::processRemainingParticipant()");
    
    	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()) {
    			_audiodriver->getMainBuffer()->flush(*iter_participant);
    
    			iter_participant++;
    		}
    
    		_audiodriver->getMainBuffer()->flush(default_id);
    
    	} else if (conf->getNbParticipants() == 1) {
    		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 {
    		removeConference(conf->getConfID());
    
    		switchCall("");
    	}
    
    }
    
    void ManagerImpl::joinConference (const CallID& conf_id1,
    		const CallID& conf_id2) {
    	_debug ("ManagerImpl::joinConference(%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;
    
    	iter = _conferencemap.find(conf_id2);
    
    	if (iter != _conferencemap.end())
    		conf2 = iter->second;
    
    	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++;
    	}
    
    	// detachParticipant(default_id, "");
    
    }
    
    void ManagerImpl::addStream (const CallID& call_id) {
    	_debug ("ManagerImpl::addStream %s", call_id.c_str());
    
    	AccountID currentAccountId;
    	Call* call = NULL;
    
    	currentAccountId = getAccountFromCall(call_id);
    	call = getAccountLink(currentAccountId)->getCall(call_id);
    
    	if (participToConference(call_id)) {
    
    		// 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("");
    				_audiodriver->getMainBuffer()->flush(*iter_p);
    
    				iter_p++;
    			}
    
    			_audiodriver->getMainBuffer()->flush(default_id);
    		}
    
    	} else {
    
    		// bind to main
    		getAudioDriver()->getMainBuffer()->bindCallID(call_id);
    
    		// _audiodriver->getMainBuffer()->flush(default_id);
    		_audiodriver->flushUrgent();
    		_audiodriver->flushMain();
    
    	}
    
    	if (_audiodriver)
    		_audiodriver->getMainBuffer()->stateInfo();
    }
    
    void ManagerImpl::removeStream (const CallID& call_id) {
    	_debug ("ManagerImpl::removeStream %s", call_id.c_str());
    
    	getAudioDriver()->getMainBuffer()->unBindAll(call_id);
    
    	if (participToConference(call_id)) {
    		removeParticipant(call_id);
    	}
    
    	if (_audiodriver)
    		_audiodriver->getMainBuffer()->stateInfo();
    }
    
    //THREAD=Main
    bool ManagerImpl::saveConfig (void) {
    	_debug ("Saving Configuration to XDG directory %s ... ", _path.c_str());
    	setConfig(AUDIO, VOLUME_SPKR, getSpkrVolume());
    	setConfig(AUDIO, VOLUME_MICRO, getMicVolume());
    
    	_setupLoaded = _config.saveConfigTree(_path.data());
    	return _setupLoaded;
    }
    
    //THREAD=Main
    bool ManagerImpl::sendDtmf (const CallID& id, char code) {
    
    	AccountID accountid = getAccountFromCall(id);
    
    	bool returnValue = false;
    
    	playDtmf(code);
    
    	CallAccountMap::iterator iter = _callAccountMap.find(id);
    
    	// Make sure the call exist before sending DTMF, ths could be simply call dialing
    	if(iter != _callAccountMap.end())
    		returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
    
    	return returnValue;
    }
    
    //THREAD=Main | VoIPLink
    bool ManagerImpl::playDtmf (char code) {
    	int pulselen, layer, size;
    	bool ret = false;
    	AudioLayer *audiolayer;
    	SFLDataFormat *buf;
    
    	stopTone();
    
    	bool hasToPlayTone = getConfigBool(SIGNALISATION, PLAY_DTMF);
    
    	if (!hasToPlayTone) {
    		_debug ("    playDtmf: Do not have to play a tone...");
    		return false;
    	}
    
    	// length in milliseconds
    	pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
    
    	if (!pulselen) {
    		_debug ("    playDtmf: Pulse length is not set...");
    		return false;
    	}
    
    	// numbers of int = length in milliseconds / 1000 (number of seconds)
    	//                = number of seconds * SAMPLING_RATE by SECONDS
    	audiolayer = getAudioDriver();
    
    	layer = audiolayer->getLayerType();
    
    	// fast return, no sound, so no dtmf
    	if (audiolayer == 0 || _dtmfKey == 0) {
    		_debug ("    playDtmf: Error no audio layer...");
    		return false;
    	}
    
    	// number of data sampling in one pulselen depends on samplerate
    	// size (n sampling) = time_ms * sampling/s
    	//                     ---------------------
    	//                            ms/s
    	size = (int) ((pulselen * (float) audiolayer->getSampleRate()) / 1000);
    
    	// this buffer is for mono
    	// TODO <-- this should be global and hide if same size
    	buf = new SFLDataFormat[size];
    
    	// Handle dtmf
    	_dtmfKey->startTone(code);
    
    	// copy the sound
    	if (_dtmfKey->generateDTMF(buf, size)) {
    		// Put buffer to urgentRingBuffer
    		// put the size in bytes...
    		// so size * 1 channel (mono) * sizeof (bytes for the data)
    		// audiolayer->flushUrgent();
    		audiolayer->startStream();
    		audiolayer->putUrgent(buf, size * sizeof(SFLDataFormat));
    	}
    
    	ret = true;
    
    	// TODO Cache the DTMF
    
    	delete[] buf;
    	buf = 0;
    
    	return ret;
    }
    
    // Multi-thread
    bool ManagerImpl::incomingCallWaiting () {
    	return (_nbIncomingWaitingCall > 0) ? true : false;
    }
    
    void ManagerImpl::addWaitingCall (const CallID& id) {
    
    	ost::MutexLock m(_waitingCallMutex);
    	_waitingCall.insert(id);
    	_nbIncomingWaitingCall++;
    
    	_info("Manager: Add waiting call %s (%d calls)", id.c_str(), _nbIncomingWaitingCall);
    }
    
    void ManagerImpl::removeWaitingCall (const CallID& id) {
    
    	ost::MutexLock m(_waitingCallMutex);
    	// should return more than 1 if it erase a call
    
    	if (_waitingCall.erase(id)) {
    		_nbIncomingWaitingCall--;
    	}
    
    	_info("Manager: Remove waiting call %s (%d calls)", id.c_str(), _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) string::npos) {
    			std::string strippedPeerNumber = peerNumber.substr(startIndex + 4);
    			call->setPeerNumber(strippedPeerNumber);
    		}
    
    	}
    
    	if (!hasCurrentCall()) {
    		_debug ("Manager: Has no current call");
    
    		call->setConnectionState(Call::Ringing);
    		ringtone();
    
    	}
    	else {
    		_debug ("Manager: has current call");
    	}
    
    	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 AccountID& accountId,
    		const std::string& message) {
    	if (_dbus) {
    		_dbus->getCallManager()->incomingMessage(accountId, message);
    	}
    }
    
    //THREAD=VoIP CALL=Outgoing
    void ManagerImpl::peerAnsweredCall (const CallID& id) {
    	// The if statement is usefull only if we sent two calls at the same time.
    	if (isCurrentCall(id)) {
    		stopTone();
    	}
    
    	if (_dbus)
    		_dbus->getCallManager()->callStateChanged(id, "CURRENT");
    
    	// std::string codecName = getCurrentCodecName (id);
    
    	// _debug("ManagerImpl::hangupCall(): broadcast codec name %s ",codecName.c_str());
    	// if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
    
    	// Required if there have been no sip reinvite, in this case we must reinit buffers since the
    	_audiodriver->flushMain();
    
    	_audiodriver->flushUrgent();
    }
    
    //THREAD=VoIP Call=Outgoing
    void ManagerImpl::peerRingingCall (const CallID& id) {
    	if (isCurrentCall(id)) {
    		ringback();
    	}
    
    	if (_dbus)
    		_dbus->getCallManager()->callStateChanged(id, "RINGING");
    }
    
    //THREAD=VoIP Call=Outgoing/Ingoing
    void ManagerImpl::peerHungupCall (const CallID& call_id) {
    	PulseLayer *pulselayer;
    	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 ("    hangupCall: stop audio stream, ther is only %i call(s) remaining", nbCalls);
    
    		AudioLayer* audiolayer = getAudioDriver();
    		audiolayer->stopStream();
    	}
    
    	if (_audiodriver->getLayerType() == PULSEAUDIO) {
    		pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
    	}
    }
    
    //THREAD=VoIP
    void ManagerImpl::callBusy (const CallID& id) {
    	_debug ("Call busy");
    
    	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 ("Call %s participating to a conference failed\n", call_id.c_str());
    
    		Conference *conf = getConferenceFromCallID(call_id);
    
    		if (conf != NULL) {
    			// 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 () {
    	if (_dbus != NULL) {
    		_dbus->getConfigurationManager()->accountsChanged();
    	}
    }
    
    /**
     * Multi Thread
     */
    bool ManagerImpl::playATone (Tone::TONEID toneId) {
    	bool hasToPlayTone;
    	// AudioLoop *audioloop;
    	AudioLayer *audiolayer;
    	// unsigned int nbSamples;
    
    	_debug ("ManagerImpl::playATone");
    
    	hasToPlayTone = getConfigBool(SIGNALISATION, PLAY_TONES);
    
    	if (!hasToPlayTone)
    		return false;
    
    	audiolayer = getAudioDriver();
    
    	if (audiolayer) {
    
    		audiolayer->flushUrgent();
    		audiolayer->startStream();
    	}
    
    	if (_telephoneTone != 0) {
    		_toneMutex.enterMutex();
    		_telephoneTone->setCurrentTone(toneId);
    		_toneMutex.leaveMutex();
    		/*
    		 audioloop = getTelephoneTone();
    		 nbSamples = audioloop->getSize();
    		 SFLDataFormat buf[nbSamples];
    
    
    		 if (audiolayer) {
    		 audiolayer->putUrgent (buf, nbSamples);
    		 } else
    		 return false;
    		 */
    	}
    
    	return true;
    }
    
    /**
     * Multi Thread
     */
    void ManagerImpl::stopTone () {
    	bool hasToPlayTone;
    
    	hasToPlayTone = getConfigBool(SIGNALISATION, PLAY_TONES);
    
    	if (!hasToPlayTone)
    		return;
    
    	_toneMutex.enterMutex();
    
    	if (_telephoneTone != 0) {
    		_telephoneTone->setCurrentTone(Tone::TONE_NULL);
    	}
    
    	_toneMutex.leaveMutex();
    
    	// for ringing tone..
    	_toneMutex.enterMutex();
    	_audiofile.stop();
    	_toneMutex.leaveMutex();
    }
    
    /**
     * Multi Thread
     */
    bool ManagerImpl::playTone () {
    	playATone(Tone::TONE_DIALTONE);
    	return true;
    }
    
    /**
     * Multi Thread
     */
    bool ManagerImpl::playToneWithMessage () {
    	playATone(Tone::TONE_CONGESTION);
    	return true;
    }
    
    /**
     * Multi Thread
     */
    void ManagerImpl::congestion () {
    	playATone(Tone::TONE_CONGESTION);
    }
    
    /**
     * Multi Thread
     */
    void ManagerImpl::ringback () {
    	_debug ("ManagerImpl::ringback");
    
    	playATone(Tone::TONE_RINGTONE);
    }
    
    /**
     * Multi Thread
     */
    void ManagerImpl::ringtone () {
    
    	_debug ("Manager: Start ringtone");
    	std::string ringchoice;
    	AudioLayer *audiolayer;
    	AudioCodec *codecForTone;
    	int layer, samplerate;
    	bool loadFile;
    
    	if (isRingtoneEnabled()) {
    
    		_debug ("Manager: Tone is enabled");
    		//TODO Comment this because it makes the daemon crashes since the main thread
    		//synchronizes the ringtone thread.
    
    		ringchoice = getConfigString(AUDIO, RING_CHOICE);
    		//if there is no / inside the path
    
    		if (ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos) {
    			// check inside global share directory
    			ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR
    					+ RINGDIR + DIR_SEPARATOR_STR + ringchoice;
    		}
    
    		audiolayer = getAudioDriver();
    
    		if (!audiolayer) {
    			_error("Manager: Error: no audio layer in ringtone");
    			return;
    		}
    
    		layer = audiolayer->getLayerType();
    
    		samplerate = audiolayer->getSampleRate();
    
    		codecForTone = _codecDescriptorMap.getFirstCodecAvailable();
    
    		_toneMutex.enterMutex();
    
    		loadFile = _audiofile.loadFile(ringchoice, codecForTone, samplerate);
    
    		_toneMutex.leaveMutex();
    
    		if (loadFile) {
    
    			_toneMutex.enterMutex();
    			_audiofile.start();
    			_toneMutex.leaveMutex();
    
    			// start audio if not started AND flush all buffers (main and urgent)
    			audiolayer->startStream();
    
    		} else {
    			ringback();
    		}
    
    	} else {
    		ringback();
    	}
    }
    
    AudioLoop*
    ManagerImpl::getTelephoneTone () {
    	// _debug("ManagerImpl::getTelephoneTone()");
    	if (_telephoneTone != 0) {
    		ost::MutexLock m(_toneMutex);
    		return _telephoneTone->getCurrentTone();
    	} else {
    		return 0;
    	}
    }
    
    AudioLoop*
    ManagerImpl::getTelephoneFile () {
    	// _debug("ManagerImpl::getTelephoneFile()");
    	ost::MutexLock m(_toneMutex);
    
    	if (_audiofile.isStarted()) {
    		return &_audiofile;
    	} else {
    		return 0;
    	}
    }
    
    void ManagerImpl::notificationIncomingCall (void) {
    	AudioLayer *audiolayer;
    	std::ostringstream frequency;
    	unsigned int samplerate, nbSampling;
    
    	audiolayer = getAudioDriver();
    
    	_debug ("ManagerImpl::notificationIncomingCall");
    
    	if (audiolayer != 0) {
    		samplerate = audiolayer->getSampleRate();
    		frequency << "440/" << FRAME_PER_BUFFER;
    		Tone tone(frequency.str(), samplerate);
    		nbSampling = tone.getSize();
    		SFLDataFormat buf[nbSampling];
    		tone.getNext(buf, tone.getSize());
    		/* Put the data in the urgent ring buffer */
    		audiolayer->flushUrgent();
    		audiolayer->putUrgent(buf, sizeof(SFLDataFormat) * nbSampling);
    	}
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    // 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 + "rc";
    
    	return 1;
    }
    
    /**
     * Initialization: Main Thread
     */
    void ManagerImpl::initConfigFile (bool load_user_value, std::string alternate) {
    	_debug ("ManagerImpl::InitConfigFile");
    
    	// Default values, that will be overwritten by the call to
    	// 'populateFromFile' below.
    
    	// Peer to peer settings
    	_config.addDefaultValue(std::pair<std::string, std::string>(SRTP_ENABLE,
    			FALSE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			SRTP_RTP_FALLBACK, FALSE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			SRTP_KEY_EXCHANGE, "1"), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ZRTP_HELLO_HASH, TRUE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ZRTP_DISPLAY_SAS, TRUE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ZRTP_DISPLAY_SAS_ONCE, FALSE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ZRTP_NOT_SUPP_WARNING, TRUE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_LISTENER_PORT, DEFAULT_SIP_TLS_PORT), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(TLS_ENABLE,
    			FALSE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_CA_LIST_FILE, EMPTY_FIELD), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_CERTIFICATE_FILE, EMPTY_FIELD), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_PRIVATE_KEY_FILE, EMPTY_FIELD), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(TLS_PASSWORD,
    			EMPTY_FIELD), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(TLS_METHOD,
    			"TLSv1"), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(TLS_CIPHERS,
    			EMPTY_FIELD), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_SERVER_NAME, EMPTY_FIELD), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_VERIFY_SERVER, TRUE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_VERIFY_CLIENT, TRUE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_REQUIRE_CLIENT_CERTIFICATE, TRUE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_NEGOTIATION_TIMEOUT_SEC, "2"), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			TLS_NEGOTIATION_TIMEOUT_MSEC, "0"), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			LOCAL_INTERFACE, "default"), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			PUBLISHED_SAMEAS_LOCAL, TRUE_STR), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(LOCAL_PORT,
    			DEFAULT_SIP_PORT), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(PUBLISHED_PORT,
    			DEFAULT_SIP_PORT), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			PUBLISHED_ADDRESS, DEFAULT_ADDRESS), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(STUN_ENABLE,
    			DFT_STUN_ENABLE), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(STUN_SERVER,
    			DFT_STUN_SERVER), IP2IP_PROFILE);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_ALIAS, EMPTY_FIELD), IP2IP_PROFILE);
    
    	// Init display name to the username under which
    	// this sflphone instance is running.
    	std::string diplayName("");
    	uid_t uid = getuid();
    
    	struct passwd * user_info = NULL;
    	user_info = getpwuid(uid);
    
    	if (user_info != NULL) {
    		diplayName = user_info->pw_name;
    	}
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(DISPLAY_NAME,
    			diplayName), IP2IP_PROFILE);
    
    	// Signalisation settings
    	_config.addDefaultValue(std::pair<std::string, std::string>(SYMMETRIC,
    			TRUE_STR), SIGNALISATION);
    	_config.addDefaultValue(std::pair<std::string, std::string>(PLAY_DTMF,
    			TRUE_STR), SIGNALISATION);
    	_config.addDefaultValue(std::pair<std::string, std::string>(PLAY_TONES,
    			TRUE_STR), SIGNALISATION);
    	_config.addDefaultValue(std::pair<std::string, std::string>(PULSE_LENGTH,
    			DFT_PULSE_LENGTH_STR), SIGNALISATION);
    	_config.addDefaultValue(std::pair<std::string, std::string>(SEND_DTMF_AS,
    			SIP_INFO_STR), SIGNALISATION);
    	_config.addDefaultValue(std::pair<std::string, std::string>(ZRTP_ZIDFILE,
    			ZRTP_ZID_FILENAME), SIGNALISATION);
    
    	// Audio settings
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ALSA_CARD_ID_IN, ALSA_DFT_CARD), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ALSA_CARD_ID_OUT, ALSA_DFT_CARD), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			AUDIO_SAMPLE_RATE, DFT_SAMPLE_RATE), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ALSA_FRAME_SIZE, DFT_FRAME_SIZE), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(ALSA_PLUGIN,
    			PCM_DEFAULT), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(RING_CHOICE,
    			DFT_RINGTONE), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(VOLUME_SPKR,
    			DFT_VOL_SPKR_STR), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(VOLUME_MICRO,
    			DFT_VOL_MICRO_STR), AUDIO);
    	_config.addDefaultValue(std::pair<std::string, std::string>(RECORD_PATH,
    			DFT_RECORD_PATH), AUDIO);
    
    	// General settings
    	_config.addDefaultValue(std::pair<std::string, std::string>(ZONE_TONE,
    			DFT_ZONE), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_RINGTONE, TRUE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(CONFIG_DIALPAD,
    			TRUE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_SEARCHBAR, TRUE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(CONFIG_START,
    			FALSE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(CONFIG_POPUP,
    			TRUE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(CONFIG_NOTIFY,
    			TRUE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_MAIL_NOTIFY, FALSE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(CONFIG_VOLUME,
    			TRUE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_HISTORY_LIMIT, DFT_HISTORY_LIMIT), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_HISTORY_ENABLED, TRUE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(CONFIG_AUDIO,
    			DFT_AUDIO_MANAGER), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_SIP_PORT, DFT_SIP_PORT), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNTS_ORDER, EMPTY_FIELD), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(CONFIG_MD5HASH,
    			FALSE_STR), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(WINDOW_WIDTH,
    			DFT_WINDOW_WIDTH), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(WINDOW_HEIGHT,
    			DFT_WINDOW_HEIGHT), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			WINDOW_POSITION_X, "0"), PREFERENCES);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			WINDOW_POSITION_Y, "0"), PREFERENCES);
    
    	// Addressbook settings
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ADDRESSBOOK_ENABLE, TRUE_STR), ADDRESSBOOK);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ADDRESSBOOK_MAX_RESULTS, "25"), ADDRESSBOOK);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ADDRESSBOOK_DISPLAY_CONTACT_PHOTO, FALSE_STR), ADDRESSBOOK);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ADDRESSBOOK_DISPLAY_PHONE_BUSINESS, TRUE_STR), ADDRESSBOOK);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ADDRESSBOOK_DISPLAY_PHONE_HOME, FALSE_STR), ADDRESSBOOK);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			ADDRESSBOOK_DISPLAY_PHONE_MOBILE, FALSE_STR), ADDRESSBOOK);
    
    	// Hooks settings
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			URLHOOK_SIP_FIELD, HOOK_DEFAULT_SIP_FIELD), HOOKS);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			URLHOOK_COMMAND, HOOK_DEFAULT_URL_COMMAND), HOOKS);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			URLHOOK_SIP_ENABLED, FALSE_STR), HOOKS);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			URLHOOK_IAX2_ENABLED, FALSE_STR), HOOKS);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			PHONE_NUMBER_HOOK_ENABLED, FALSE_STR), HOOKS);
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			PHONE_NUMBER_HOOK_ADD_PREFIX, EMPTY_FIELD), HOOKS);
    
    	std::string path;
    	// Loads config from ~/.sflphone/sflphonedrc or so..
    
    	if (createSettingsPath() == 1 && load_user_value) {
    		(alternate == "") ? path = _path : path = alternate;
    		std::cout << path << std::endl;
    		_exist = _config.populateFromFile(path);
    	}
    
    	// Globally shared default values (not to be populated from file)
    	_config.addDefaultValue(std::pair<std::string, std::string>(HOSTNAME,
    			EMPTY_FIELD));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			AUTHENTICATION_USERNAME, EMPTY_FIELD));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(USERNAME,
    			EMPTY_FIELD));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(PASSWORD,
    			EMPTY_FIELD));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(REALM,
    			DEFAULT_REALM));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(USERAGENT,
    			DFT_USERAGENT));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_REGISTRATION_EXPIRE, DFT_EXPIRE_VALUE));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_RESOLVE_ONCE, FALSE_STR));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_ALIAS, EMPTY_FIELD));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_MAILBOX, EMPTY_FIELD));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_ENABLE, TRUE_STR));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_CREDENTIAL_NUMBER, "0"));
    
    	_config.addDefaultValue(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_TYPE, DEFAULT_ACCOUNT_TYPE));
    
    	_setupLoaded = (_exist == 2) ? false : true;
    }
    
    /**
     * 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.
    	 */
    	_codecDescriptorMap.init();
    }
    
    /*
     * TODO Retrieve the active codec list per account
     */
    std::vector<std::string> ManagerImpl::retrieveActiveCodecs () {
    
    	// This property is now set per account basis
    	std::string s = getConfigString(AUDIO, "ActiveCodecs");
    	_info("Manager: Retrieve active codecs: %s", s.c_str ());
    	return unserialize(s);
    }
    
    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);
    
    	if (!call)
    		return "";
    
    	if (call->getState() != Call::Active)
    		return "";
    	else
    		return link->getCurrentCodecName();
    }
    
    /**
     * Set input audio plugin
     */
    void ManagerImpl::setInputAudioPlugin (const std::string& audioPlugin) {
    	int layer = _audiodriver -> getLayerType();
    
    	if (CHECK_INTERFACE (layer , ALSA)) {
    		_debug ("Set input audio plugin");
    		_audiodriver -> setErrorMessage(-1);
    		_audiodriver -> openDevice(_audiodriver -> getIndexIn(),
    				_audiodriver -> getIndexOut(), _audiodriver -> getSampleRate(),
    				_audiodriver -> getFrameSize(), SFL_PCM_CAPTURE, audioPlugin);
    
    		if (_audiodriver -> getErrorMessage() != -1)
    			notifyErrClient(_audiodriver -> getErrorMessage());
    	} else {
    	}
    
    }
    
    /**
     * Set output audio plugin
     */
    void ManagerImpl::setOutputAudioPlugin (const std::string& audioPlugin) {
    
    	int res;
    
    	_debug ("Manager: Set output audio plugin");
    	_audiodriver -> setErrorMessage(-1);
    	res = _audiodriver -> openDevice(_audiodriver -> getIndexIn(),
    			_audiodriver -> getIndexOut(), _audiodriver -> getSampleRate(),
    			_audiodriver -> getFrameSize(), SFL_PCM_BOTH, audioPlugin);
    
    	if (_audiodriver -> getErrorMessage() != -1)
    		notifyErrClient(_audiodriver -> getErrorMessage());
    
    	// set config
    	if (res)
    		setConfig(AUDIO, ALSA_PLUGIN, audioPlugin);
    }
    
    /**
     * Get list of supported audio output device
     */
    std::vector<std::string> ManagerImpl::getAudioOutputDeviceList (void) {
    	_debug ("Manager: Get audio output device list");
    	AlsaLayer *layer;
    	std::vector<std::string> devices;
    
    	layer = dynamic_cast<AlsaLayer*> (getAudioDriver());
    
    	if (layer)
    		devices = layer -> getSoundCardsInfo(SFL_PCM_PLAYBACK);
    
    	return devices;
    }
    
    /**
     * Set audio output device
     */
    void ManagerImpl::setAudioOutputDevice (const int index) {
    	AlsaLayer *alsalayer;
    	std::string alsaplugin;
    	_debug ("Set audio output device: %i", index);
    
    	_audiodriver -> setErrorMessage(-1);
    
    	alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver());
    	alsaplugin = alsalayer->getAudioPlugin();
    
    	_debug ("  set output plugin: %s", alsaplugin.c_str());
    
    	_audiodriver->openDevice(_audiodriver->getIndexIn(), index,
    			_audiodriver->getSampleRate(), _audiodriver->getFrameSize(),
    			SFL_PCM_PLAYBACK, alsaplugin);
    
    	if (_audiodriver -> getErrorMessage() != -1)
    		notifyErrClient(_audiodriver -> getErrorMessage());
    
    	// set config
    	setConfig(AUDIO, ALSA_CARD_ID_OUT, index);
    }
    
    /**
     * Get list of supported audio input device
     */
    std::vector<std::string> ManagerImpl::getAudioInputDeviceList (void) {
    	AlsaLayer *audiolayer;
    	std::vector<std::string> devices;
    
    	audiolayer = dynamic_cast<AlsaLayer *> (getAudioDriver());
    
    	if (audiolayer)
    		devices = audiolayer->getSoundCardsInfo(SFL_PCM_CAPTURE);
    
    	return devices;
    }
    
    /**
     * Set audio input device
     */
    void ManagerImpl::setAudioInputDevice (const int index) {
    	AlsaLayer *alsalayer;
    	std::string alsaplugin;
    
    	_debug ("Set audio input device %i", index);
    
    	_audiodriver -> setErrorMessage(-1);
    
    	alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver());
    	alsaplugin = alsalayer->getAudioPlugin();
    
    	_debug ("  set input plugin: %s", alsaplugin.c_str());
    
    	_audiodriver->openDevice(index, _audiodriver->getIndexOut(),
    			_audiodriver->getSampleRate(), _audiodriver->getFrameSize(),
    			SFL_PCM_CAPTURE, alsaplugin);
    
    	if (_audiodriver -> getErrorMessage() != -1)
    		notifyErrClient(_audiodriver -> getErrorMessage());
    
    	// set config
    	setConfig(AUDIO, ALSA_CARD_ID_IN, index);
    }
    
    /**
     * Get string array representing integer indexes of output and input device
     */
    std::vector<std::string> ManagerImpl::getCurrentAudioDevicesIndex () {
    	_debug ("Get current audio devices index");
    	std::vector<std::string> v;
    	std::stringstream ssi, sso;
    	sso << _audiodriver->getIndexOut();
    	v.push_back(sso.str());
    	ssi << _audiodriver->getIndexIn();
    	v.push_back(ssi.str());
    	return v;
    }
    
    int ManagerImpl::isIax2Enabled (void) {
    #ifdef USE_IAX
    	return true;
    #else
    	return false;
    #endif
    }
    
    int ManagerImpl::isRingtoneEnabled (void) {
    	return (getConfigString(PREFERENCES, CONFIG_RINGTONE) == "true") ? 1 : 0;
    }
    
    void ManagerImpl::ringtoneEnabled (void) {
    	(getConfigString(PREFERENCES, CONFIG_RINGTONE) == RINGTONE_ENABLED) ? setConfig(
    			PREFERENCES, CONFIG_RINGTONE, FALSE_STR)
    			: setConfig(PREFERENCES, CONFIG_RINGTONE, TRUE_STR);
    }
    
    std::string ManagerImpl::getRingtoneChoice (void) {
    	// we need the absolute path
    	std::string tone_name = getConfigString(AUDIO, RING_CHOICE);
    	std::string tone_path;
    
    	if (tone_name.find(DIR_SEPARATOR_CH) == std::string::npos) {
    		// check in ringtone directory ($(PREFIX)/share/sflphone/ringtones)
    		tone_path = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR
    				+ DIR_SEPARATOR_STR + tone_name;
    	} else {
    		// the absolute has been saved; do nothing
    		tone_path = tone_name;
    	}
    
    	_debug ("%s", tone_path.c_str());
    
    	return tone_path;
    }
    
    void ManagerImpl::setRingtoneChoice (const std::string& tone) {
    	// we save the absolute path
    	setConfig(AUDIO, RING_CHOICE, tone);
    }
    
    std::string ManagerImpl::getRecordPath (void) {
    	return getConfigString(AUDIO, RECORD_PATH);
    }
    
    void ManagerImpl::setRecordPath (const std::string& recPath) {
    	_debug ("ManagerImpl::setRecordPath(%s)! ", recPath.c_str());
    	setConfig(AUDIO, RECORD_PATH, recPath);
    }
    
    bool ManagerImpl::getMd5CredentialHashing (void) {
    	return getConfigBool(PREFERENCES, CONFIG_MD5HASH);
    }
    
    int ManagerImpl::getDialpad (void) {
    	if (getConfigString(PREFERENCES, CONFIG_DIALPAD) == TRUE_STR) {
    		return 1;
    	} else {
    		return 0;
    	}
    }
    
    void ManagerImpl::setDialpad (bool display) {
    	std::string set;
    
    	display ? set = TRUE_STR : set = FALSE_STR;
    	// If the value we received is different from the one saved in the config file, save the new value
    	// Else do nothing
    
    	if ((display && (getConfigString(PREFERENCES, CONFIG_DIALPAD) != TRUE_STR))
    			|| (!display && (getConfigString(PREFERENCES, CONFIG_DIALPAD)
    					!= FALSE_STR)))
    		setConfig(PREFERENCES, CONFIG_DIALPAD, set);
    }
    
    int ManagerImpl::getVolumeControls (void) {
    	if (getConfigString(PREFERENCES, CONFIG_VOLUME) == TRUE_STR) {
    		return 1;
    	} else {
    		return 0;
    	}
    }
    
    void ManagerImpl::setVolumeControls (bool display) {
    	std::string set;
    
    	display ? set = TRUE_STR : set = FALSE_STR;
    	// If the value we received is different from the one saved in the config file, save the new value
    	// Else do nothing
    
    	if ((display && (getConfigString(PREFERENCES, CONFIG_VOLUME) != TRUE_STR))
    			|| (!display && (getConfigString(PREFERENCES, CONFIG_VOLUME)
    					!= FALSE_STR)))
    		setConfig(PREFERENCES, CONFIG_VOLUME, set);
    }
    
    void ManagerImpl::setRecordingCall (const CallID& id) {
    	/*
    	 _debug ("ManagerImpl::setRecording()! ");
    	 AccountID accountid = getAccountFromCall (id);
    
    	 getAccountLink (accountid)->setRecording (id);
    	 */
    	AccountID accountid = getAccountFromCall(id);
    	Recordable* rec = (Recordable*) getAccountLink(accountid)->getCall(id);
    
    	rec->setRecording();
    }
    
    bool ManagerImpl::isRecording (const CallID& id) {
    	/*
    	 _debug ("ManagerImpl::isRecording()! ");
    	 AccountID accountid = getAccountFromCall (id);
    
    	 return getAccountLink (accountid)->isRecording (id);
    	 */
    
    	AccountID accountid = getAccountFromCall(id);
    	Recordable* rec = (Recordable*) getAccountLink(accountid)->getCall(id);
    
    	return rec->isRecording();
    }
    
    void ManagerImpl::startHidden (void) {
    	(getConfigString(PREFERENCES, CONFIG_START) == START_HIDDEN) ? setConfig(
    			PREFERENCES, CONFIG_START, FALSE_STR) : setConfig(PREFERENCES,
    			CONFIG_START, TRUE_STR);
    }
    
    int ManagerImpl::isStartHidden (void) {
    	return (getConfigBool(PREFERENCES, CONFIG_START) == true) ? 1 : 0;
    }
    
    void ManagerImpl::switchPopupMode (void) {
    	(getConfigString(PREFERENCES, CONFIG_POPUP) == WINDOW_POPUP) ? setConfig(
    			PREFERENCES, CONFIG_POPUP, FALSE_STR) : setConfig(PREFERENCES,
    			CONFIG_POPUP, TRUE_STR);
    }
    
    void ManagerImpl::setHistoryLimit (const int& days) {
    	setConfig(PREFERENCES, CONFIG_HISTORY_LIMIT, days);
    }
    
    int ManagerImpl::getHistoryLimit (void) {
    	return getConfigInt(PREFERENCES, CONFIG_HISTORY_LIMIT);
    }
    
    std::string ManagerImpl::getHistoryEnabled (void) {
    	return getConfigString(PREFERENCES, CONFIG_HISTORY_ENABLED);
    }
    
    void ManagerImpl::setHistoryEnabled (void) {
    	(getConfigString(PREFERENCES, CONFIG_HISTORY_ENABLED) == TRUE_STR) ? setConfig(
    			PREFERENCES, CONFIG_HISTORY_ENABLED, FALSE_STR)
    			: setConfig(PREFERENCES, CONFIG_HISTORY_ENABLED, TRUE_STR);
    }
    
    int ManagerImpl::getSearchbar (void) {
    	return getConfigInt(PREFERENCES, CONFIG_SEARCHBAR);
    }
    
    void ManagerImpl::setSearchbar (void) {
    	(getConfigInt(PREFERENCES, CONFIG_SEARCHBAR) == 1) ? setConfig(PREFERENCES,
    			CONFIG_SEARCHBAR, FALSE_STR) : setConfig(PREFERENCES,
    			CONFIG_SEARCHBAR, TRUE_STR);
    }
    
    int ManagerImpl::popupMode (void) {
    	return (getConfigBool(PREFERENCES, CONFIG_POPUP) == true) ? 1 : 0;
    }
    
    int32_t ManagerImpl::getNotify (void) {
    	return (getConfigBool(PREFERENCES, CONFIG_NOTIFY) == true) ? 1 : 0;
    }
    
    void ManagerImpl::setNotify (void) {
    	(getConfigString(PREFERENCES, CONFIG_NOTIFY) == NOTIFY_ALL) ? setConfig(
    			PREFERENCES, CONFIG_NOTIFY, FALSE_STR) : setConfig(PREFERENCES,
    			CONFIG_NOTIFY, TRUE_STR);
    }
    
    int32_t ManagerImpl::getMailNotify (void) {
    	return getConfigInt(PREFERENCES, CONFIG_MAIL_NOTIFY);
    }
    
    void ManagerImpl::setAudioManager (const int32_t& api) {
    
    	int type;
    	std::string alsaPlugin;
    
    	_debug ("Setting audio manager ");
    
    	if (!_audiodriver)
    		return;
    
    	type = _audiodriver->getLayerType();
    
    	if (type == api) {
    		_debug ("Audio manager chosen already in use. No changes made. ");
    		return;
    	}
    
    	setConfig(PREFERENCES, CONFIG_AUDIO, api);
    
    	switchAudioManager();
    	return;
    
    }
    
    int32_t ManagerImpl::getAudioManager (void) {
    	return getConfigInt(PREFERENCES, CONFIG_AUDIO);
    }
    
    void ManagerImpl::setMailNotify (void) {
    	(getConfigString(PREFERENCES, CONFIG_MAIL_NOTIFY) == NOTIFY_ALL) ? setConfig(
    			PREFERENCES, CONFIG_MAIL_NOTIFY, FALSE_STR)
    			: setConfig(PREFERENCES, CONFIG_MAIL_NOTIFY, TRUE_STR);
    }
    
    void ManagerImpl::notifyErrClient (const int32_t& errCode) {
    	if (_dbus) {
    		_debug ("NOTIFY ERR NUMBER %i" , errCode);
    		_dbus -> getConfigurationManager() -> errorAlert(errCode);
    	}
    }
    
    int ManagerImpl::getAudioDeviceIndex (const std::string name) {
    	AlsaLayer *alsalayer;
    
    	_debug ("Get audio device index");
    
    	alsalayer = dynamic_cast<AlsaLayer *> (getAudioDriver());
    
    	if (alsalayer)
    		return alsalayer -> soundCardGetIndex(name);
    	else
    		return 0;
    }
    
    std::string ManagerImpl::getCurrentAudioOutputPlugin (void) {
    	AlsaLayer *alsalayer;
    
    	_debug ("Get alsa plugin");
    
    	alsalayer = dynamic_cast<AlsaLayer *> (getAudioDriver());
    
    	if (alsalayer)
    		return alsalayer -> getAudioPlugin();
    	else
    		return getConfigString(AUDIO, ALSA_PLUGIN);
    }
    
    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 ("AudioLayer Creation");
    
    	if (getConfigInt(PREFERENCES, CONFIG_AUDIO) == ALSA) {
    		_audiodriver = new AlsaLayer(this);
    		_audiodriver->setMainBuffer(&_mainBuffer);
    	} else if (getConfigInt(PREFERENCES, CONFIG_AUDIO) == PULSEAUDIO) {
    		if (app_is_running("pulseaudio") == 0) {
    			_audiodriver = new PulseLayer(this);
    			_audiodriver->setMainBuffer(&_mainBuffer);
    		} else {
    			_audiodriver = new AlsaLayer(this);
    			setConfig(PREFERENCES, CONFIG_AUDIO, ALSA);
    			_audiodriver->setMainBuffer(&_mainBuffer);
    		}
    	} else
    		_debug ("Error - Audio API unknown");
    
    	if (_audiodriver == 0) {
    		_debug ("Init audio driver error");
    		return false;
    	} else {
    		error = getAudioDriver()->getErrorMessage();
    
    		if (error == -1) {
    			_debug ("Init audio driver: %i", error);
    			return false;
    		}
    	}
    
    	return true;
    
    }
    
    /**
     * Initialization: Main Thread and gui
     */
    void ManagerImpl::selectAudioDriver (void) {
    	int layer, numCardIn, numCardOut, sampleRate, frameSize;
    	std::string alsaPlugin;
    	AlsaLayer *alsalayer;
    
    	layer = _audiodriver->getLayerType();
    	_debug ("Audio layer type: %i" , layer);
    
    	/* Retrieve the global devices info from the user config */
    	alsaPlugin = getConfigString(AUDIO, ALSA_PLUGIN);
    	numCardIn = getConfigInt(AUDIO, ALSA_CARD_ID_IN);
    	numCardOut = getConfigInt(AUDIO, ALSA_CARD_ID_OUT);
    	sampleRate = getConfigInt(AUDIO, AUDIO_SAMPLE_RATE);
    
    	if (sampleRate <= 0 || sampleRate > 48000) {
    		sampleRate = 44100;
    	}
    
    	frameSize = getConfigInt(AUDIO, ALSA_FRAME_SIZE);
    
    	/* Only for the ALSA layer, we check the sound card information */
    
    	if (layer == ALSA) {
    		alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver());
    
    		if (!alsalayer -> soundCardIndexExist(numCardIn, SFL_PCM_CAPTURE)) {
    			_debug (" Card with index %i doesn't exist or cannot capture. Switch to 0.", numCardIn);
    			numCardIn = ALSA_DFT_CARD_ID;
    			setConfig(AUDIO, ALSA_CARD_ID_IN, ALSA_DFT_CARD_ID);
    		}
    
    		if (!alsalayer -> soundCardIndexExist(numCardOut, SFL_PCM_PLAYBACK)) {
    			_debug (" Card with index %i doesn't exist or cannot playback . Switch to 0.", numCardOut);
    			numCardOut = ALSA_DFT_CARD_ID;
    			setConfig(AUDIO, ALSA_CARD_ID_OUT, ALSA_DFT_CARD_ID);
    		}
    	}
    
    	_audiodriver->setErrorMessage(-1);
    
    	/* Open the audio devices */
    	_audiodriver->openDevice(numCardIn, numCardOut, sampleRate, frameSize,
    			SFL_PCM_BOTH, alsaPlugin);
    	/* Notify the error if there is one */
    
    	if (_audiodriver -> getErrorMessage() != -1)
    		notifyErrClient(_audiodriver -> getErrorMessage());
    
    }
    
    void ManagerImpl::switchAudioManager (void) {
    	int type, samplerate, framesize, numCardIn, numCardOut;
    	std::string alsaPlugin;
    
    	_debug ("Switching audio manager ");
    
    	if (!_audiodriver)
    		return;
    
    	type = _audiodriver->getLayerType();
    
    	samplerate = getConfigInt(AUDIO, AUDIO_SAMPLE_RATE);
    
    	framesize = getConfigInt(AUDIO, ALSA_FRAME_SIZE);
    
    	_debug ("samplerate: %i, framesize %i\n", samplerate, framesize);
    
    	alsaPlugin = getConfigString(AUDIO, ALSA_PLUGIN);
    
    	numCardIn = getConfigInt(AUDIO, ALSA_CARD_ID_IN);
    
    	numCardOut = getConfigInt(AUDIO, ALSA_CARD_ID_OUT);
    
    	_debug ("Deleting current layer... ");
    
    	// ost::MutexLock lock (*getAudioLayerMutex());
    	getAudioLayerMutex()->enter();
    
    	// _audiodriver->closeLayer();
    	delete _audiodriver;
    
    	_audiodriver = NULL;
    
    	switch (type) {
    
    	case ALSA:
    		_debug ("Creating Pulseaudio layer...");
    		_audiodriver = new PulseLayer(this);
    		_audiodriver->setMainBuffer(&_mainBuffer);
    		break;
    
    	case PULSEAUDIO:
    		_debug ("Creating ALSA layer...");
    		_audiodriver = new AlsaLayer(this);
    		_audiodriver->setMainBuffer(&_mainBuffer);
    		break;
    
    	default:
    		_debug ("Error: audio layer unknown");
    		break;
    	}
    
    	_audiodriver->setErrorMessage(-1);
    
    	_audiodriver->openDevice(numCardIn, numCardOut, samplerate, framesize,
    			SFL_PCM_BOTH, alsaPlugin);
    
    	if (_audiodriver -> getErrorMessage() != -1)
    		notifyErrClient(_audiodriver -> getErrorMessage());
    
    	_debug ("Current device: %i ", type);
    
    	_debug ("has current call: %i ", hasCurrentCall());
    
    	if (hasCurrentCall())
    		_audiodriver->startStream();
    
    	// ost::MutexLock unlock (*getAudioLayerMutex());
    	getAudioLayerMutex()->leave();
    
    	// need to stop audio streams if there is currently no call
    	// if ( (type != PULSEAUDIO) && (!hasCurrentCall())) {
    	// _debug("There is currently a call!!");
    	// _audiodriver->stopStream();
    
    	// }
    }
    
    /**
     * Init the volume for speakers/micro from 0 to 100 value
     * Initialization: Main Thread
     */
    void ManagerImpl::initVolume () {
    	_debugInit ("Initiate Volume");
    	setSpkrVolume(getConfigInt(AUDIO, VOLUME_SPKR));
    	setMicVolume(getConfigInt(AUDIO, VOLUME_MICRO));
    }
    
    void ManagerImpl::setSpkrVolume (unsigned short spkr_vol) {
    	PulseLayer *pulselayer = NULL;
    
    	/* Set the manager sound volume */
    	_spkr_volume = spkr_vol;
    
    	/* Only for PulseAudio */
    	pulselayer = dynamic_cast<PulseLayer*> (getAudioDriver());
    
    	if (pulselayer) {
    		if (pulselayer->getLayerType() == PULSEAUDIO) {
    			if (pulselayer)
    				pulselayer->setPlaybackVolume(spkr_vol);
    		}
    	}
    }
    
    void ManagerImpl::setMicVolume (unsigned short mic_vol) {
    	_mic_volume = mic_vol;
    }
    
    int ManagerImpl::getLocalIp2IpPort (void) {
    	// The SIP port used for default account (IP to IP) calls=
    	return getConfigInt(IP2IP_PROFILE, LOCAL_PORT);
    
    }
    
    // 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) {
    	_debug ("ManagerImpl::setConfig %s %s %s", section.c_str(), name.c_str(), value.c_str());
    	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 ("Setcreate accounts order : %s", order.c_str());
    	// Set the new config
    	setConfig(PREFERENCES, CONFIG_ACCOUNTS_ORDER, order);
    }
    
    std::vector<std::string> ManagerImpl::getAccountList () {
    
    	std::vector<std::string> v;
    	std::vector<std::string> account_order;
    	unsigned int i;
    
    	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)
    		v.push_back(iter->first.data());
    
    	// If no order has been set, load the default one
    	// ie according to the creation date.
    
    	if (account_order.size() == 0) {
    		iter = _accountMap.begin();
    
    		while (iter != _accountMap.end()) {
    
    			if (iter->second != NULL && iter->first != IP2IP_PROFILE) {
    				//_debug("PUSHING BACK %s\n", iter->first.c_str());
    				v.push_back(iter->first.data());
    			}
    
    			iter++;
    		}
    	}
    
    	// Otherelse, load the custom one
    	// ie according to the saved order
    	else {
    
    		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) {
    					v.push_back(iter->first.data());
    				}
    			}
    		}
    	}
    
    	return v;
    }
    
    std::map<std::string, std::string> ManagerImpl::getAccountDetails (
    		const AccountID& accountID) {
    	std::map<std::string, std::string> a;
    
    	Account * account = _accountMap[accountID];
    
    	if (account == NULL) {
    		_debug ("Cannot getAccountDetails on a non-existing accountID %s. Defaults will be used.", accountID.c_str());
    	}
    
    	a.insert(std::pair<std::string, std::string>(ACCOUNT_ID, accountID));
    
    	// The IP profile does not allow to set an alias
    	(accountID == IP2IP_PROFILE) ? a.insert(
    			std::pair<std::string, std::string>(CONFIG_ACCOUNT_ALIAS,
    					DIRECT_IP_CALL)) : a.insert(std::pair<std::string,
    			std::string>(CONFIG_ACCOUNT_ALIAS, getConfigString(accountID,
    			CONFIG_ACCOUNT_ALIAS)));
    
    	a.insert(std::pair<std::string, std::string>(CONFIG_ACCOUNT_ENABLE,
    			getConfigString(accountID, CONFIG_ACCOUNT_ENABLE)));
    	a.insert(std::pair<std::string, std::string>(CONFIG_ACCOUNT_RESOLVE_ONCE,
    			getConfigString(accountID, CONFIG_ACCOUNT_RESOLVE_ONCE)));
    	a.insert(std::pair<std::string, std::string>(CONFIG_ACCOUNT_TYPE,
    			getConfigString(accountID, CONFIG_ACCOUNT_TYPE)));
    	a.insert(std::pair<std::string, std::string>(HOSTNAME, getConfigString(
    			accountID, HOSTNAME)));
    	a.insert(std::pair<std::string, std::string>(USERNAME, getConfigString(
    			accountID, USERNAME)));
    	a.insert(std::pair<std::string, std::string>(PASSWORD, getConfigString(
    			accountID, PASSWORD)));
    	a.insert(std::pair<std::string, std::string>(REALM, getConfigString(
    			accountID, REALM)));
    	a.insert(std::pair<std::string, std::string>(USERAGENT, getConfigString(
    			accountID, USERAGENT)));
    	a.insert(std::pair<std::string, std::string>(AUTHENTICATION_USERNAME,
    			getConfigString(accountID, AUTHENTICATION_USERNAME)));
    	a.insert(std::pair<std::string, std::string>(CONFIG_ACCOUNT_MAILBOX,
    			getConfigString(accountID, CONFIG_ACCOUNT_MAILBOX)));
    	a.insert(std::pair<std::string, std::string>(
    			CONFIG_ACCOUNT_REGISTRATION_EXPIRE, getConfigString(accountID,
    					CONFIG_ACCOUNT_REGISTRATION_EXPIRE)));
    	a.insert(std::pair<std::string, std::string>(LOCAL_INTERFACE,
    			getConfigString(accountID, LOCAL_INTERFACE)));
    	a.insert(std::pair<std::string, std::string>(PUBLISHED_SAMEAS_LOCAL,
    			getConfigString(accountID, PUBLISHED_SAMEAS_LOCAL)));
    	a.insert(std::pair<std::string, std::string>(PUBLISHED_ADDRESS,
    			getConfigString(accountID, PUBLISHED_ADDRESS)));
    	a.insert(std::pair<std::string, std::string>(LOCAL_PORT, getConfigString(
    			accountID, LOCAL_PORT)));
    	a.insert(std::pair<std::string, std::string>(PUBLISHED_PORT,
    			getConfigString(accountID, PUBLISHED_PORT)));
    	a.insert(std::pair<std::string, std::string>(DISPLAY_NAME, getConfigString(
    			accountID, DISPLAY_NAME)));
    	a.insert(std::pair<std::string, std::string>(STUN_ENABLE, getConfigString(
    			accountID, STUN_ENABLE)));
    	a.insert(std::pair<std::string, std::string>(STUN_SERVER, getConfigString(
    			accountID, STUN_SERVER)));
    	a.insert(std::pair<std::string, std::string>(ACCOUNT_DTMF_TYPE, getConfigString(
    				accountID, ACCOUNT_DTMF_TYPE)));
    
    	RegistrationState state;
    	std::string registrationStateCode;
    	std::string registrationStateDescription;
    
    	if (account != NULL) {
    		if (accountID == IP2IP_PROFILE) {
    			registrationStateCode = EMPTY_FIELD;
    			registrationStateDescription = "Direct IP call";
    		} else {
    			state = account->getRegistrationState();
    			int code = account->getRegistrationStateDetailed().first;
    			std::stringstream out;
    			out << code;
    			registrationStateCode = out.str();
    			registrationStateDescription
    					= account->getRegistrationStateDetailed().second;
    		}
    	} else {
    		state = Unregistered;
    	}
    
    	(accountID == IP2IP_PROFILE) ? a.insert(
    			std::pair<std::string, std::string>(REGISTRATION_STATUS, "READY"))
    			: a.insert(std::pair<std::string, std::string>(REGISTRATION_STATUS,
    					mapStateNumberToString(state)));
    
    	a.insert(std::pair<std::string, std::string>(REGISTRATION_STATE_CODE,
    			registrationStateCode));
    	a.insert(std::pair<std::string, std::string>(
    			REGISTRATION_STATE_DESCRIPTION, registrationStateDescription));
    	a.insert(std::pair<std::string, std::string>(SRTP_KEY_EXCHANGE,
    			getConfigString(accountID, SRTP_KEY_EXCHANGE)));
    	a.insert(std::pair<std::string, std::string>(SRTP_ENABLE, getConfigString(
    			accountID, SRTP_ENABLE)));
    	a.insert(std::pair<std::string, std::string>(SRTP_RTP_FALLBACK,
    			getConfigString(accountID, SRTP_RTP_FALLBACK)));
    	a.insert(std::pair<std::string, std::string>(ZRTP_DISPLAY_SAS,
    			getConfigString(accountID, ZRTP_DISPLAY_SAS)));
    	a.insert(std::pair<std::string, std::string>(ZRTP_DISPLAY_SAS_ONCE,
    			getConfigString(accountID, ZRTP_DISPLAY_SAS_ONCE)));
    	a.insert(std::pair<std::string, std::string>(ZRTP_HELLO_HASH,
    			getConfigString(accountID, ZRTP_HELLO_HASH)));
    	a.insert(std::pair<std::string, std::string>(ZRTP_NOT_SUPP_WARNING,
    			getConfigString(accountID, ZRTP_NOT_SUPP_WARNING)));
    
    	// TLS listener is unique and parameters are modified through IP2IP_PROFILE
    	a.insert(std::pair<std::string, std::string>(TLS_LISTENER_PORT,
    			Manager::instance().getConfigString(IP2IP_PROFILE,
    					TLS_LISTENER_PORT)));
    	a.insert(std::pair<std::string, std::string>(TLS_ENABLE,
    			Manager::instance().getConfigString(accountID, TLS_ENABLE)));
    	a.insert(std::pair<std::string, std::string>(TLS_CA_LIST_FILE,
    			Manager::instance().getConfigString(accountID, TLS_CA_LIST_FILE)));
    	a.insert(
    			std::pair<std::string, std::string>(TLS_CERTIFICATE_FILE,
    					Manager::instance().getConfigString(accountID,
    							TLS_CERTIFICATE_FILE)));
    	a.insert(
    			std::pair<std::string, std::string>(TLS_PRIVATE_KEY_FILE,
    					Manager::instance().getConfigString(accountID,
    							TLS_PRIVATE_KEY_FILE)));
    	a.insert(std::pair<std::string, std::string>(TLS_PASSWORD,
    			Manager::instance().getConfigString(accountID, TLS_PASSWORD)));
    	a.insert(std::pair<std::string, std::string>(TLS_METHOD,
    			Manager::instance().getConfigString(accountID, TLS_METHOD)));
    	a.insert(std::pair<std::string, std::string>(TLS_CIPHERS,
    			Manager::instance().getConfigString(accountID, TLS_CIPHERS)));
    	a.insert(std::pair<std::string, std::string>(TLS_SERVER_NAME,
    			Manager::instance().getConfigString(accountID, TLS_SERVER_NAME)));
    	a.insert(std::pair<std::string, std::string>(TLS_VERIFY_SERVER,
    			Manager::instance().getConfigString(accountID, TLS_VERIFY_SERVER)));
    	a.insert(std::pair<std::string, std::string>(TLS_VERIFY_CLIENT,
    			Manager::instance().getConfigString(accountID, TLS_VERIFY_CLIENT)));
    	a.insert(std::pair<std::string, std::string>(
    			TLS_REQUIRE_CLIENT_CERTIFICATE,
    			Manager::instance().getConfigString(accountID,
    					TLS_REQUIRE_CLIENT_CERTIFICATE)));
    	a.insert(std::pair<std::string, std::string>(TLS_NEGOTIATION_TIMEOUT_SEC,
    			Manager::instance().getConfigString(accountID,
    					TLS_NEGOTIATION_TIMEOUT_SEC)));
    	a.insert(std::pair<std::string, std::string>(TLS_NEGOTIATION_TIMEOUT_MSEC,
    			Manager::instance().getConfigString(accountID,
    					TLS_NEGOTIATION_TIMEOUT_MSEC)));
    
    	return a;
    }
    
    /* 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,
    		const int32_t& index, const std::map<std::string, std::string>& details) {
    	std::map<std::string, std::string>::iterator it;
    	std::map<std::string, std::string> credentialInformation = details;
    
    	std::string credentialIndex;
    	std::stringstream streamOut;
    	streamOut << index;
    	credentialIndex = streamOut.str();
    
    	std::string section = "Credential" + std::string(":") + accountID
    			+ std::string(":") + credentialIndex;
    
    	_debug ("Setting credential in section %s", section.c_str());
    
    	it = credentialInformation.find(USERNAME);
    	std::string username;
    
    	if (it == credentialInformation.end()) {
    		username = EMPTY_FIELD;
    	} else {
    		username = it->second;
    	}
    
    	Manager::instance().setConfig(section, USERNAME, username);
    
    	it = credentialInformation.find(REALM);
    	std::string realm;
    
    	if (it == credentialInformation.end()) {
    		realm = EMPTY_FIELD;
    	} else {
    		realm = it->second;
    	}
    
    	Manager::instance().setConfig(section, REALM, realm);
    
    	it = credentialInformation.find(PASSWORD);
    	std::string password;
    
    	if (it == credentialInformation.end()) {
    		password = EMPTY_FIELD;
    	} else {
    		password = it->second;
    	}
    
    	if (getMd5CredentialHashing()) {
    		// TODO: Fix this.
    		// This is an extremly weak test in order to check
    		// if the password is a hashed value. This is done
    		// because deleteCredential() is called before this
    		// method. Therefore, we cannot check if the value
    		// is different from the one previously stored in
    		// the configuration file. This is to avoid to
    		// re-hash a hashed password.
    
    		if (password.length() != 32) {
    			password = computeMd5HashFromCredential(username, password, realm);
    		}
    	}
    
    	Manager::instance().setConfig(section, PASSWORD, password);
    }
    
    //TODO: tidy this up. Make a macro or inline
    // 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) {
    
    	std::string accountType;
    	std::map<std::string, std::string> map_cpy;
    	std::map<std::string, std::string>::iterator iter;
    
    	// Work on a copy
    	map_cpy = details;
    
    	std::string username;
    	std::string authenticationName;
    	std::string password;
    	std::string realm;
    	std::string voicemail_count;
    	std::string ua_name;
    
    	if ((iter = map_cpy.find(AUTHENTICATION_USERNAME)) != map_cpy.end()) {
    		authenticationName = iter->second;
    	}
    
    	if ((iter = map_cpy.find(USERNAME)) != map_cpy.end()) {
    		username = iter->second;
    	}
    
    	if ((iter = map_cpy.find(PASSWORD)) != map_cpy.end()) {
    		password = iter->second;
    	}
    
    	if ((iter = map_cpy.find(REALM)) != map_cpy.end()) {
    		realm = iter->second;
    	}
    
    	if ((iter = map_cpy.find(USERAGENT)) != map_cpy.end()) {
    		ua_name = iter->second;
    	}
    
    	setConfig(accountID, REALM, realm);
    	setConfig(accountID, USERAGENT, ua_name);
    	setConfig(accountID, USERNAME, username);
    	setConfig(accountID, AUTHENTICATION_USERNAME, authenticationName);
    
    	if (!getMd5CredentialHashing()) {
    		setConfig(accountID, PASSWORD, password);
    	} else {
    		// Make sure not to re-hash the password field if
    		// it is already saved as a MD5 Hash.
    		// TODO: This test is weak. Fix this.
    		if ((password.compare(getConfigString(accountID, PASSWORD)) != 0)) {
    			_debug ("Password sent and password from config are different. Re-hashing");
    			std::string hash;
    
    			if (authenticationName.empty()) {
    				hash = computeMd5HashFromCredential(username, password, realm);
    			} else {
    				hash = computeMd5HashFromCredential(authenticationName,
    						password, realm);
    			}
    
    			setConfig(accountID, PASSWORD, hash);
    		}
    	}
    
    	std::string alias;
    
    	std::string mailbox;
    	std::string accountEnable;
    	std::string type;
    	std::string resolveOnce;
    	std::string registrationExpire;
    
    	std::string hostname;
    	std::string displayName;
    	std::string localInterface;
    	std::string publishedSameasLocal;
    	std::string localAddress;
    	std::string publishedAddress;
    	std::string localPort;
    	std::string publishedPort;
    	std::string stunEnable;
    	std::string stunServer;
    	std::string dtmfType;
    	std::string srtpEnable;
    	std::string srtpRtpFallback;
    	std::string zrtpDisplaySas;
    	std::string zrtpDisplaySasOnce;
    	std::string zrtpNotSuppWarning;
    	std::string zrtpHelloHash;
    	std::string srtpKeyExchange;
    
    	std::string tlsListenerPort;
    	std::string tlsEnable;
    	std::string tlsCaListFile;
    	std::string tlsCertificateFile;
    	std::string tlsPrivateKeyFile;
    	std::string tlsPassword;
    	std::string tlsMethod;
    	std::string tlsCiphers;
    	std::string tlsServerName;
    	std::string tlsVerifyServer;
    	std::string tlsVerifyClient;
    	std::string tlsRequireClientCertificate;
    	std::string tlsNegotiationTimeoutSec;
    	std::string tlsNegotiationTimeoutMsec;
    
    	if ((iter = map_cpy.find(HOSTNAME)) != map_cpy.end()) {
    		hostname = iter->second;
    	}
    
    	if ((iter = map_cpy.find(DISPLAY_NAME)) != map_cpy.end()) {
    		displayName = iter->second;
    	}
    
    	if ((iter = map_cpy.find(LOCAL_INTERFACE)) != map_cpy.end()) {
    		localInterface = iter->second;
    	}
    
    	if ((iter = map_cpy.find(PUBLISHED_SAMEAS_LOCAL)) != map_cpy.end()) {
    		publishedSameasLocal = iter->second;
    	}
    
    	if ((iter = map_cpy.find(PUBLISHED_ADDRESS)) != map_cpy.end()) {
    		publishedAddress = iter->second;
    	}
    
    	if ((iter = map_cpy.find(LOCAL_PORT)) != map_cpy.end()) {
    		localPort = iter->second;
    	}
    
    	if ((iter = map_cpy.find(PUBLISHED_PORT)) != map_cpy.end()) {
    		publishedPort = iter->second;
    	}
    
    	if ((iter = map_cpy.find(STUN_ENABLE)) != map_cpy.end()) {
    		stunEnable = iter->second;
    	}
    
    	if ((iter = map_cpy.find(STUN_SERVER)) != map_cpy.end()) {
    		stunServer = iter->second;
    	}
    
    	if((iter = map_cpy.find(ACCOUNT_DTMF_TYPE)) != map_cpy.end()) {
    		dtmfType = iter->second;
    	}
    
    	if ((iter = map_cpy.find(SRTP_ENABLE)) != map_cpy.end()) {
    		srtpEnable = iter->second;
    	}
    
    	if ((iter = map_cpy.find(SRTP_RTP_FALLBACK)) != map_cpy.end()) {
    		srtpRtpFallback = iter->second;
    	}
    
    	if ((iter = map_cpy.find(ZRTP_DISPLAY_SAS)) != map_cpy.end()) {
    		zrtpDisplaySas = iter->second;
    	}
    
    	if ((iter = map_cpy.find(ZRTP_DISPLAY_SAS_ONCE)) != map_cpy.end()) {
    		zrtpDisplaySasOnce = iter->second;
    	}
    
    	if ((iter = map_cpy.find(ZRTP_NOT_SUPP_WARNING)) != map_cpy.end()) {
    		zrtpNotSuppWarning = iter->second;
    	}
    
    	if ((iter = map_cpy.find(ZRTP_HELLO_HASH)) != map_cpy.end()) {
    		zrtpHelloHash = iter->second;
    	}
    
    	if ((iter = map_cpy.find(SRTP_KEY_EXCHANGE)) != map_cpy.end()) {
    		srtpKeyExchange = iter->second;
    	}
    
    	if ((iter = map_cpy.find(CONFIG_ACCOUNT_ALIAS)) != map_cpy.end()) {
    		alias = iter->second;
    	}
    
    	if ((iter = map_cpy.find(CONFIG_ACCOUNT_MAILBOX)) != map_cpy.end()) {
    		mailbox = iter->second;
    	}
    
    	if ((iter = map_cpy.find(CONFIG_ACCOUNT_ENABLE)) != map_cpy.end()) {
    		accountEnable = iter->second;
    	}
    
    	if ((iter = map_cpy.find(CONFIG_ACCOUNT_TYPE)) != map_cpy.end()) {
    		type = iter->second;
    	}
    
    	if ((iter = map_cpy.find(CONFIG_ACCOUNT_RESOLVE_ONCE)) != map_cpy.end()) {
    		resolveOnce = iter->second;
    	}
    
    	if ((iter = map_cpy.find(CONFIG_ACCOUNT_REGISTRATION_EXPIRE))
    			!= map_cpy.end()) {
    		registrationExpire = iter->second;
    	}
    
    	// The TLS listener is unique and globally defined through IP2IP_PROFILE
    	if ((accountID == IP2IP_PROFILE)
    			&& (iter = map_cpy.find(TLS_LISTENER_PORT)) != map_cpy.end()) {
    		tlsListenerPort = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_ENABLE)) != map_cpy.end()) {
    		tlsEnable = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_CA_LIST_FILE)) != map_cpy.end()) {
    		tlsCaListFile = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_CERTIFICATE_FILE)) != map_cpy.end()) {
    		tlsCertificateFile = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_PRIVATE_KEY_FILE)) != map_cpy.end()) {
    		tlsPrivateKeyFile = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_PASSWORD)) != map_cpy.end()) {
    		tlsPassword = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_METHOD)) != map_cpy.end()) {
    		tlsMethod = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_CIPHERS)) != map_cpy.end()) {
    		tlsCiphers = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_SERVER_NAME)) != map_cpy.end()) {
    		tlsServerName = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_VERIFY_SERVER)) != map_cpy.end()) {
    		tlsVerifyServer = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_VERIFY_CLIENT)) != map_cpy.end()) {
    		tlsVerifyClient = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_REQUIRE_CLIENT_CERTIFICATE)) != map_cpy.end()) {
    		tlsRequireClientCertificate = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_NEGOTIATION_TIMEOUT_SEC)) != map_cpy.end()) {
    		tlsNegotiationTimeoutSec = iter->second;
    	}
    
    	if ((iter = map_cpy.find(TLS_NEGOTIATION_TIMEOUT_MSEC)) != map_cpy.end()) {
    		tlsNegotiationTimeoutMsec = iter->second;
    	}
    
    	setConfig(accountID, HOSTNAME, hostname);
    
    	setConfig(accountID, LOCAL_INTERFACE, localInterface);
    	setConfig(accountID, PUBLISHED_SAMEAS_LOCAL, publishedSameasLocal);
    	setConfig(accountID, PUBLISHED_ADDRESS, publishedAddress);
    	setConfig(accountID, LOCAL_PORT, localPort);
    	setConfig(accountID, PUBLISHED_PORT, publishedPort);
    	setConfig(accountID, DISPLAY_NAME, displayName);
    	setConfig(accountID, SRTP_ENABLE, srtpEnable);
    	setConfig(accountID, SRTP_RTP_FALLBACK, srtpRtpFallback);
    	setConfig(accountID, ZRTP_DISPLAY_SAS, zrtpDisplaySas);
    	setConfig(accountID, ZRTP_DISPLAY_SAS_ONCE, zrtpDisplaySasOnce);
    	setConfig(accountID, ZRTP_NOT_SUPP_WARNING, zrtpNotSuppWarning);
    	setConfig(accountID, ZRTP_HELLO_HASH, zrtpHelloHash);
    	setConfig(accountID, SRTP_KEY_EXCHANGE, srtpKeyExchange);
    
    	setConfig(accountID, STUN_ENABLE, stunEnable);
    	setConfig(accountID, STUN_SERVER, stunServer);
    	setConfig(accountID, ACCOUNT_DTMF_TYPE, dtmfType);
    
    	// The TLS listener is unique and globally defined through IP2IP_PROFILE
    	if (accountID == IP2IP_PROFILE)
    		setConfig(accountID, TLS_LISTENER_PORT, tlsListenerPort);
    
    	setConfig(accountID, TLS_ENABLE, tlsEnable);
    	setConfig(accountID, TLS_CA_LIST_FILE, tlsCaListFile);
    	setConfig(accountID, TLS_CERTIFICATE_FILE, tlsCertificateFile);
    	setConfig(accountID, TLS_PRIVATE_KEY_FILE, tlsPrivateKeyFile);
    	setConfig(accountID, TLS_PASSWORD, tlsPassword);
    	setConfig(accountID, TLS_METHOD, tlsMethod);
    	setConfig(accountID, TLS_CIPHERS, tlsCiphers);
    	setConfig(accountID, TLS_SERVER_NAME, tlsServerName);
    	setConfig(accountID, TLS_VERIFY_SERVER, tlsVerifyServer);
    	setConfig(accountID, TLS_VERIFY_CLIENT, tlsVerifyClient);
    	setConfig(accountID, TLS_REQUIRE_CLIENT_CERTIFICATE,
    			tlsRequireClientCertificate);
    	setConfig(accountID, TLS_NEGOTIATION_TIMEOUT_SEC, tlsNegotiationTimeoutSec);
    	setConfig(accountID, TLS_NEGOTIATION_TIMEOUT_MSEC,
    			tlsNegotiationTimeoutMsec);
    
    	setConfig(accountID, CONFIG_ACCOUNT_ALIAS, alias);
    	setConfig(accountID, CONFIG_ACCOUNT_MAILBOX, mailbox);
    	setConfig(accountID, CONFIG_ACCOUNT_ENABLE, accountEnable);
    	setConfig(accountID, CONFIG_ACCOUNT_TYPE, type);
    	setConfig(accountID, CONFIG_ACCOUNT_RESOLVE_ONCE, resolveOnce);
    	setConfig(accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE, registrationExpire);
    
    	saveConfig();
    
    	Account * acc = NULL;
    	acc = getAccount(accountID);
    
    	if (acc != NULL) {
    		acc->loadConfig();
    
    		if (acc->isEnabled()) {
    			acc->registerVoIPLink();
    		} else {
    			acc->unregisterVoIPLink();
    		}
    	} else {
    		_debug ("ManagerImpl::setAccountDetails: account is NULL");
    	}
    
    	// Update account details to the client side
    	if (_dbus)
    		_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 ("%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 {
    		_debug ("Unknown %s param when calling addAccount(): %s", CONFIG_ACCOUNT_TYPE, accountType.c_str());
    		return "";
    	}
    
    	_accountMap[newAccountID] = newAccount;
    
    	setAccountDetails(accountID.str(), details);
    
    	// Add the newly created account in the account order list
    	account_list = getConfigString(PREFERENCES, CONFIG_ACCOUNTS_ORDER);
    
    	if (account_list != "") {
    		newAccountID += "/";
    		// Prepend the new account
    		account_list.insert(0, newAccountID);
    		setConfig(PREFERENCES, CONFIG_ACCOUNTS_ORDER, account_list);
    	}
    
    	saveConfig();
    
    	if (_dbus)
    		_dbus->getConfigurationManager()->accountsChanged();
    
    	return accountID.str();
    }
    
    void ManagerImpl::deleteAllCredential (const AccountID& accountID) {
    	int numberOfCredential = getConfigInt(accountID, CONFIG_CREDENTIAL_NUMBER);
    
    	int i;
    
    	for (i = 0; i < numberOfCredential; i++) {
    		std::string credentialIndex;
    		std::stringstream streamOut;
    		streamOut << i;
    		credentialIndex = streamOut.str();
    		std::string section = "Credential" + std::string(":") + accountID
    				+ std::string(":") + credentialIndex;
    
    		_config.removeSection(section);
    	}
    
    	if (accountID.empty() == false) {
    		setConfig(accountID, CONFIG_CREDENTIAL_NUMBER, 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 ("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;
    }
    
    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 = getConfigString(PREFERENCES, CONFIG_ACCOUNTS_ORDER);
    	return unserialize(account_list);
    }
    
    short ManagerImpl::loadAccountMap () {
    
    	_debug ("Loading account map");
    
    	short nbAccount = 0;
    	TokenList sections = _config.getSections();
    	std::string accountType;
    	Account *tmpAccount = 0;
    	std::vector<std::string> account_order;
    
    	TokenList::iterator iter = sections.begin();
    
    	// Those calls that are placed to an uri that cannot be
    	// associated to an account are using that special account.
    	// An account, that is not account, in the sense of
    	// registration. This is useful since the Account object
    	// provides a handful of method that simplifies URI creation
    	// and loading of various settings.
    	_directIpAccount = AccountCreator::createAccount(
    			AccountCreator::SIP_DIRECT_IP_ACCOUNT, "");
    
    	_debug ("Create default \"account\" (used as default UDP transport)");
    	if (_directIpAccount == NULL) {
    
    		_debug ("Failed to create default \"account\"");
    	} else {
    
    		_accountMap[IP2IP_PROFILE] = _directIpAccount;
    
    		// 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();
    
    	}
    
    	// initialize other accounts
    	while (iter != sections.end()) {
    		// Check if it starts with "Account:" (SIP and IAX pour le moment)
    		if ((int) (iter->find("Account:")) != 0) {
    			iter++;
    			continue;
    		}
    
    		accountType = getConfigString(*iter, CONFIG_ACCOUNT_TYPE);
    
    		if (accountType == "SIP") {
    			tmpAccount = AccountCreator::createAccount(
    					AccountCreator::SIP_ACCOUNT, *iter);
    		}
    
    		else if (accountType == "IAX") {
    			tmpAccount = AccountCreator::createAccount(
    					AccountCreator::IAX_ACCOUNT, *iter);
    		}
    
    		else {
    			_error ("Unknown %s param in config file (%s)", CONFIG_ACCOUNT_TYPE, accountType.c_str());
    		}
    
    		if (tmpAccount != NULL) {
    			_debug ("Loading account %s ", iter->c_str());
    			_accountMap[iter->c_str()] = tmpAccount;
    			// tmpAccount->setVoIPLink(SIPVoIPLink::instance (""));
    			tmpAccount->setVoIPLink();
    			nbAccount++;
    		}
    
    		iter++;
    	}
    
    	_debug ("nb account loaded %i \n", nbAccount);
    
    	return nbAccount;
    }
    
    void ManagerImpl::unloadAccountMap () {
    
    	AccountMap::iterator iter = _accountMap.begin();
    
    	while (iter != _accountMap.end()) {
    
    		_debug ("Unloading account %s\n", iter->first.c_str());
    
    		delete iter->second;
    		iter->second = 0;
    
    		iter++;
    	}
    
    	_accountMap.clear();
    }
    
    bool ManagerImpl::accountExists (const AccountID& accountID) {
    	AccountMap::iterator iter = _accountMap.find(accountID);
    
    	if (iter == _accountMap.end()) {
    		return false;
    	}
    
    	return true;
    }
    
    Account*
    ManagerImpl::getAccount (const AccountID& accountID) {
    	// In our definition,
    	// this is the "direct ip calls account"
    	if (accountID == AccountNULL) {
    		_debug ("Returns the direct IP account");
    		return _directIpAccount;
    	}
    
    	AccountMap::iterator iter = _accountMap.find(accountID);
    
    	if (iter == _accountMap.end()) {
    		return NULL;
    	}
    
    	return iter->second;
    }
    
    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",
    			getConfigInt(ADDRESSBOOK, ADDRESSBOOK_ENABLE)));
    	settings.insert(std::pair<std::string, int32_t>("ADDRESSBOOK_MAX_RESULTS",
    			getConfigInt(ADDRESSBOOK, ADDRESSBOOK_MAX_RESULTS)));
    	settings.insert(std::pair<std::string, int32_t>(
    			"ADDRESSBOOK_DISPLAY_CONTACT_PHOTO", getConfigInt(ADDRESSBOOK,
    					ADDRESSBOOK_DISPLAY_CONTACT_PHOTO)));
    	settings.insert(std::pair<std::string, int32_t>(
    			"ADDRESSBOOK_DISPLAY_PHONE_BUSINESS", getConfigInt(ADDRESSBOOK,
    					ADDRESSBOOK_DISPLAY_PHONE_BUSINESS)));
    	settings.insert(std::pair<std::string, int32_t>(
    			"ADDRESSBOOK_DISPLAY_PHONE_HOME", getConfigInt(ADDRESSBOOK,
    					ADDRESSBOOK_DISPLAY_PHONE_HOME)));
    	settings.insert(std::pair<std::string, int32_t>(
    			"ADDRESSBOOK_DISPLAY_PHONE_MOBILE", getConfigInt(ADDRESSBOOK,
    					ADDRESSBOOK_DISPLAY_PHONE_MOBILE)));
    
    	return settings;
    }
    
    void ManagerImpl::setAddressbookSettings (
    		const std::map<std::string, int32_t>& settings) {
    
    	setConfig(ADDRESSBOOK, ADDRESSBOOK_ENABLE, (*settings.find(
    			"ADDRESSBOOK_ENABLE")).second);
    	setConfig(ADDRESSBOOK, ADDRESSBOOK_MAX_RESULTS, (*settings.find(
    			"ADDRESSBOOK_MAX_RESULTS")).second);
    	setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_CONTACT_PHOTO, (*settings.find(
    			"ADDRESSBOOK_DISPLAY_CONTACT_PHOTO")).second);
    	setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_BUSINESS, (*settings.find(
    			"ADDRESSBOOK_DISPLAY_PHONE_BUSINESS")).second);
    	setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_HOME, (*settings.find(
    			"ADDRESSBOOK_DISPLAY_PHONE_HOME")).second);
    	setConfig(ADDRESSBOOK, ADDRESSBOOK_DISPLAY_PHONE_MOBILE, (*settings.find(
    			"ADDRESSBOOK_DISPLAY_PHONE_MOBILE")).second);
    
    	// Write it to the configuration file
    	saveConfig();
    }
    
    void ManagerImpl::setAddressbookList (const std::vector<std::string>& list) {
    
    	std::string s = serialize(list);
    	setConfig(ADDRESSBOOK, ADDRESSBOOK_LIST, s);
    }
    
    std::vector<std::string> ManagerImpl::getAddressbookList (void) {
    
    	std::string s = getConfigString(ADDRESSBOOK, ADDRESSBOOK_LIST);
    	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_SIP_FIELD",
    			getConfigString(HOOKS, URLHOOK_SIP_FIELD)));
    	settings.insert(std::pair<std::string, std::string>("URLHOOK_COMMAND",
    			getConfigString(HOOKS, URLHOOK_COMMAND)));
    	settings.insert(std::pair<std::string, std::string>("URLHOOK_SIP_ENABLED",
    			getConfigString(HOOKS, URLHOOK_SIP_ENABLED)));
    	settings.insert(std::pair<std::string, std::string>("URLHOOK_IAX2_ENABLED",
    			getConfigString(HOOKS, URLHOOK_IAX2_ENABLED)));
    	settings.insert(std::pair<std::string, std::string>(
    			"PHONE_NUMBER_HOOK_ENABLED", getConfigString(HOOKS,
    					PHONE_NUMBER_HOOK_ENABLED)));
    	settings.insert(std::pair<std::string, std::string>(
    			"PHONE_NUMBER_HOOK_ADD_PREFIX", getConfigString(HOOKS,
    					PHONE_NUMBER_HOOK_ADD_PREFIX)));
    
    	return settings;
    }
    
    void ManagerImpl::setHookSettings (
    		const std::map<std::string, std::string>& settings) {
    
    	setConfig(HOOKS, URLHOOK_SIP_FIELD,
    			(*settings.find("URLHOOK_SIP_FIELD")).second);
    	setConfig(HOOKS, URLHOOK_COMMAND,
    			(*settings.find("URLHOOK_COMMAND")).second);
    	setConfig(HOOKS, URLHOOK_SIP_ENABLED,
    			(*settings.find("URLHOOK_SIP_ENABLED")).second);
    	setConfig(HOOKS, URLHOOK_IAX2_ENABLED, (*settings.find(
    			"URLHOOK_IAX2_ENABLED")).second);
    	setConfig(HOOKS, PHONE_NUMBER_HOOK_ENABLED, (*settings.find(
    			"PHONE_NUMBER_HOOK_ENABLED")).second);
    	setConfig(HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX, (*settings.find(
    			"PHONE_NUMBER_HOOK_ADD_PREFIX")).second);
    
    	// Write it to the configuration file
    	saveConfig();
    }
    
    void ManagerImpl::check_call_configuration (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 ("Sending Sip 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 %i", 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)) != 0) {
    		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>("CALL_STATE", "UNKNOWN"));
    		call_details.insert(std::pair<std::string, std::string>("CALL_TYPE", "0"));
    	}
    
    	return call_details;
    }
    
    std::map<std::string, std::string> ManagerImpl::send_history_to_client (void) {
    	return _history->get_history_serialized();
    }
    
    void ManagerImpl::receive_history_from_client (std::map<std::string,
    		std::string> history) {
    	_history->set_serialized_history(history, Manager::instance().getConfigInt(
    			PREFERENCES, CONFIG_HISTORY_LIMIT));
    	_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::getParticipantList");
    	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++;
    		}
    	}
    
    	return v;
    }