Skip to content
Snippets Groups Projects
Select Git revision
  • 146fa009d2f082c959ffc63e3f9a0911eaba0afc
  • 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
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    managerimpl.cpp 44.12 KiB
    /*
     *  Copyright (C) 2004-2006 Savoir-Faire Linux inc.
     *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
     *  Author : Laurielle Lea <laurielle.lea@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 2 of the License, or
     *  (at your option) any later version.
     *                                                                              
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *                                                                              
     *  You should have received a copy of the GNU General Public License
     *  along with this program; if not, write to the Free Software
     *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    #include <errno.h>
    #include <time.h>
    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    
    #include <sys/types.h> // mkdir(2)
    #include <sys/stat.h>	// mkdir(2)
    
    #include <cc++/socket.h>   // why do I need this here?
    #include <ccrtp/channel.h> // why do I need this here?
    #include <ccrtp/rtp.h>     // why do I need this here?
    #include <cc++/file.h>
    
    #include "manager.h"
    #include "audio/audiolayer.h"
    #include "audio/audiocodec.h"
    #include "audio/tonelist.h"
    
    #include "accountcreator.h" // create new account
    #include "voIPLink.h"
    
    #include "user_cfg.h"
    #include "gui/guiframework.h"
    
    #ifdef USE_ZEROCONF
    #include "zeroconf/DNSService.h"
    #include "zeroconf/DNSServiceTXTRecord.h"
    #endif
    
    #define fill_config_str(name, value) \
      (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
    #define fill_config_int(name, value) \
      (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))
    
    ManagerImpl::ManagerImpl (void)
    {
      // Init private variables 
      _hasZeroconf = false;
    #ifdef USE_ZEROCONF
      _hasZeroconf = true;
      _DNSService = new DNSService();
    #endif
    
      // setup
      _path = ""; 
      _exist = 0;
      _setupLoaded = false;
      _gui = 0;
    
      // sound
      _audiodriver = 0;
      _dtmfKey = 0;
      _spkr_volume = 0;  // Initialize after by init() -> initVolume()
      _mic_volume  = 0;  // Initialize after by init() -> initVolume()
      _mic_volume_before_mute = 0; 
    
      // Call
      _nbIncomingWaitingCall=0;
      _hasTriedToRegister = false;
    
      // initialize random generator for call id
      srand (time(NULL));
    
    #ifdef TEST
      testAccountMap();
      loadAccountMap();
      testCallAccountMap();
      unloadAccountMap();
    #endif
    
      // should be call before initConfigFile
      loadAccountMap();
    }
    
    // never call if we use only the singleton...
    ManagerImpl::~ManagerImpl (void) 
    {
      terminate();
    
    #ifdef USE_ZEROCONF
      delete _DNSService; _DNSService = 0;
    #endif
    
      _debug("%s stop correctly.\n", PROGNAME);
    }
    
    void 
    ManagerImpl::init() 
    {
      initVolume();
    
      if (_exist == 0) {
        _debug("Cannot create config file in your home directory\n");
      }
    
      initAudioDriver();
      selectAudioDriver();
    
      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);
      }
    
      // initRegisterVoIP was here, but we doing it after the gui loaded... 
      // the stun detection is long, so it's a better idea to do it after getEvents
      initZeroconf();
    }
    
    void ManagerImpl::terminate()
    {
      saveConfig();
    
      unloadAccountMap();
    
      _debug("Unload DTMF Key\n");
      delete _dtmfKey;
    
      _debug("Unload Audio Driver\n");
      delete _audiodriver; _audiodriver = 0;
    
      _debug("Unload Telephone Tone\n");
      delete _telephoneTone; _telephoneTone = 0;
    }
    
    bool
    ManagerImpl::isCurrentCall(const CallID& callId) {
      ost::MutexLock m(_currentCallMutex);
      return (_currentCallId2 == callId ? true : false);
    }
    
    bool
    ManagerImpl::hasCurrentCall() {
      ost::MutexLock m(_currentCallMutex);
      if ( _currentCallId2 != "") {
        return true;
      }
      return false;
    }
    
    const CallID& 
    ManagerImpl::getCurrentCallId() {
      ost::MutexLock m(_currentCallMutex);
      return _currentCallId2;
    }
    
    void
    ManagerImpl::switchCall(const CallID& id ) {
      ost::MutexLock m(_currentCallMutex);
      _currentCallId2 = id;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // Management of events' IP-phone user
    ///////////////////////////////////////////////////////////////////////////////
    /* Main Thread */ 
    bool
    ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to)
    {
      if (!accountExists(accountid)) {
        _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
        return false;
      }
      if (getAccountFromCall(id) != AccountNULL) {
        _debug("! Manager Error: Outgoing Call: call id already exists\n");
        return false;
      }
      if (hasCurrentCall()) {
        _debug("* Manager Info: there is currently a call, try to hold it\n");
        onHoldCall(getCurrentCallId());
      }
      _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
      if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
        associateCallToAccount( id, accountid );
        switchCall(id);
        return true;
      } else {
        _debug("! Manager Error: An error occur, the call was not created\n");
      }
      return false;
    }
    
    //THREAD=Main : for outgoing Call
    bool
    ManagerImpl::answerCall(const CallID& id)
    {
      stopTone(false); 
    
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("Answering Call: Call doesn't exists\n");
        return false;
      }
    
      if (!getAccountLink(accountid)->answer(id)) {
        // error when receiving...
        removeCallAccount(id);
        return false;
      }
    
      // if it was waiting, it's waiting no more
      removeWaitingCall(id);
      switchCall(id);
      return true;
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message) 
    {
      if (accountExists(accountId)) {
        return getAccountLink(accountId)->sendMessage(to, message);
      }
      return false;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::hangupCall(const CallID& id)
    {
      stopTone(true);
    
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("! Manager Hangup Call: Call doesn't exists\n");
        return false;
      }
    
      bool returnValue = getAccountLink(accountid)->hangup(id);
      removeCallAccount(id);
      switchCall("");
    
      return returnValue;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::cancelCall (const CallID& id)
    {
      stopTone(true);
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("! Manager Cancel Call: Call doesn't exists\n");
        return false;
      }
    
      bool returnValue = getAccountLink(accountid)->cancel(id);
      // it could be a waiting call?
      removeWaitingCall(id);
      removeCallAccount(id);
      switchCall("");
      
      return returnValue;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::onHoldCall(const CallID& id)
    {
      stopTone(true);
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("5 Manager On Hold Call: Account ID %s or callid %s desn't exists\n", accountid.c_str(), id.c_str());
        return false;
      }
    
      bool returnValue = getAccountLink(accountid)->onhold(id);
      removeWaitingCall(id);
      switchCall("");
      
      return returnValue;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::offHoldCall(const CallID& id)
    {
      stopTone(false);
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("5 Manager OffHold Call: Call doesn't exists\n");
        return false;
      }
      bool returnValue = getAccountLink(accountid)->offhold(id);
      switchCall(id);
    
      if (returnValue) {
        try {
          getAudioDriver()->startStream();
        } catch(...) {
          _debugException("! Manager Off hold could not start audio stream");
        }
      }
      return returnValue;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::transferCall(const CallID& id, const std::string& to)
    {
      stopTone(true);
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("! Manager Transfer Call: Call doesn't exists\n");
        return false;
      }
      bool returnValue = getAccountLink(accountid)->transfer(id, to);
      removeWaitingCall(id);
      removeCallAccount(id);
      switchCall("");
    
      return returnValue;
    }
    
    //THREAD=Main
    void
    ManagerImpl::mute() {
      _mic_volume_before_mute = _mic_volume;
      setMicVolume(0);
    }
    
    //THREAD=Main
    void
    ManagerImpl::unmute() {
      if ( _mic_volume == 0 ) {
        setMicVolume(_mic_volume_before_mute);
      }
    }
    
    //THREAD=Main : Call:Incoming
    bool
    ManagerImpl::refuseCall (const CallID& id)
    {
      stopTone(true);
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("! Manager OffHold Call: Call doesn't exists\n");
        return false;
      }
      bool returnValue = getAccountLink(accountid)->refuse(id);
      // if the call was outgoing or established, we didn't refuse it
      // so the method did nothing
      if (returnValue) {
        removeWaitingCall(id);
        removeCallAccount(id);
        switchCall("");
      }
      return returnValue;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::saveConfig (void)
    {
      _debug("Saving Configuration...\n");
      setConfig(AUDIO, VOLUME_SPKR, getSpkrVolume());
      setConfig(AUDIO, VOLUME_MICRO, getMicVolume());
    
      _setupLoaded = _config.saveConfigTree(_path.data());
      return _setupLoaded;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::initRegisterVoIPLink() 
    {
      _debugInit("Initiate VoIP Links Registration");
      AccountMap::iterator iter = _accountMap.begin();
      while( iter != _accountMap.end() ) {
        if ( iter->second) {
          iter->second->loadConfig();
          if ( iter->second->shouldInitOnStart() ) {
            if ( iter->second->init() && iter->second->shouldRegisterOnStart()) {
                iter->second->registerAccount();
            }
            // init only the first account
            break;
          }
        }
        iter++;
      }
      return true;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::registerVoIPLink(const AccountID& accountId)
    {
      _debug("Register VoIP Link\n");
      int returnValue = false;
      // right now, we don't support two SIP account
      // so we close everything before registring a new account
      Account* account = getAccount(accountId);
      if (account != 0) {
        AccountMap::iterator iter = _accountMap.begin();
        while ( iter != _accountMap.end() ) {
          if ( iter->second ) {
            iter->second->unregisterAccount();
            iter->second->terminate();
          }
          iter++;
        }
        returnValue = account->registerAccount();
      }
      return returnValue;
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::unregisterVoIPLink(const AccountID& accountId)
    {
      _debug("Unregister VoIP Link\n");
      int returnValue = false;
      if (accountExists( accountId ) ) {
        returnValue = getAccount(accountId)->unregisterAccount();
      }
      return returnValue;
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::sendDtmf(const CallID& id, char code)
    {
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("Send DTMF: call doesn't exists\n");
        return false;
      }
    
      int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
      bool returnValue = false;
      switch (sendType) {
      case 0: // SIP INFO
        playDtmf(code);
        returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
        break;
    
      case 1: // Audio way
        break;
      case 2: // rfc 2833
        break;
      default: // unknown - error config?
        break;
      }
      return returnValue;
    }
    
    //THREAD=Main | VoIPLink
    bool
    ManagerImpl::playDtmf(char code)
    {
      // HERE are the variable:
      // - boolean variable to play or not (config)
      // - length in milliseconds to play
      // - sample of audiolayer
      stopTone(false);
      int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
      if (!hasToPlayTone) return false;
    
      // length in milliseconds
      int pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
      if (!pulselen) { return false; }
    
      // numbers of int = length in milliseconds / 1000 (number of seconds)
      //                = number of seconds * SAMPLING_RATE by SECONDS
      AudioLayer* audiolayer = getAudioDriver();
    
      // fast return, no sound, so no dtmf
      if (audiolayer==0 || _dtmfKey == 0) { return false; }
      // number of data sampling in one pulselen depends on samplerate
      // size (n sampling) = time_ms * sampling/s 
      //                     ---------------------
      //                            ms/s
      int size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));
    
      // this buffer is for mono
      // TODO <-- this should be global and hide if same size
      SFLDataFormat* _buf = new SFLDataFormat[size];
      bool returnValue = false;
    
      // 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->putUrgent(_buf, size * sizeof(SFLDataFormat));
    
        try {
          // We activate the stream if it's not active yet.
          if (!audiolayer->isStreamActive()) {
            audiolayer->startStream();
          } else {
            audiolayer->sleep(pulselen); // in milliseconds
          }
        } catch(...) {
          _debugException("Portaudio exception when playing a dtmf");
        }
        returnValue = true;
      }
    
      // TODO: add caching
      delete[] _buf; _buf = 0;
      return returnValue;
    }
    
    
    
    // Multi-thread 
    bool
    ManagerImpl::incomingCallWaiting() {
      ost::MutexLock m(_waitingCallMutex);
      return (_nbIncomingWaitingCall > 0) ? true : false;
    }
    
    void
    ManagerImpl::addWaitingCall(const CallID& id) {
      ost::MutexLock m(_waitingCallMutex);
      _waitingCall.insert(id);
      _nbIncomingWaitingCall++;
    }
    
    void
    ManagerImpl::removeWaitingCall(const CallID& id) {
      ost::MutexLock m(_waitingCallMutex);
      // should return more than 1 if it erase a call
      if (_waitingCall.erase(id)) {
        _nbIncomingWaitingCall--;
      }
    }
    
    bool
    ManagerImpl::isWaitingCall(const CallID& id) {
      ost::MutexLock m(_waitingCallMutex);
      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) 
    {
      _debug("Incoming call\n");
      associateCallToAccount(call->getCallId(), accountId);
      if ( !hasCurrentCall() ) {
        call->setConnectionState(Call::Ringing);
        ringtone();
        switchCall(call->getCallId());
      } else {
         addWaitingCall(call->getCallId());
      }
    
      std::string from = call->getPeerName();
      std::string number = call->getPeerNumber();
    
      if ( !number.empty() ) {
        from.append(" <");
        from.append(number);
        from.append(">");
      }
      _gui->incomingCall(accountId, call->getCallId(), from);
    
      return true;
    }
    
    //THREAD=VoIP
    void
    ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
      if (_gui) {
        _gui->incomingMessage(accountId, message);
      }
    }
    
    //THREAD=VoIP CALL=Outgoing
    void
    ManagerImpl::peerAnsweredCall(const CallID& id)
    {
      if (isCurrentCall(id)) {
        stopTone(false);
      }
      if (_gui) _gui->peerAnsweredCall(id);
    }
    
    //THREAD=VoIP Call=Outgoing
    void
    ManagerImpl::peerRingingCall(const CallID& id)
    {
      if (isCurrentCall(id)) {
        ringback();
      }
      if (_gui) _gui->peerRingingCall(id);
    }
    
    //THREAD=VoIP Call=Outgoing/Ingoing
    void
    ManagerImpl::peerHungupCall(const CallID& id)
    {
      AccountID accountid = getAccountFromCall( id );
      if (accountid == AccountNULL) {
        _debug("peerHungupCall: Call doesn't exists\n");
        return;
      }
      if (isCurrentCall(id)) {
        stopTone(true);
        switchCall("");
      }
      removeWaitingCall(id);
      removeCallAccount(id);
      if (_gui) _gui->peerHungupCall(id);
    }
    
    //THREAD=VoIP
    void
    ManagerImpl::callBusy(const CallID& id) {
      _debug("Call busy\n");
      if (isCurrentCall(id) ) {
        playATone(Tone::TONE_BUSY);
        switchCall("");
      }
      removeCallAccount(id);
      removeWaitingCall(id);
      if(_gui) _gui->displayErrorText( id, "Call is busy");
    }
    
    //THREAD=VoIP
    void
    ManagerImpl::callFailure(const CallID& id) 
    {
      _debug("Call failed\n");
      if (isCurrentCall(id) ) {
        playATone(Tone::TONE_BUSY);
        switchCall("");
      }
      if (_gui) {
        _gui->callFailure(id);
      }
      removeCallAccount(id);
      removeWaitingCall(id);
    }
    
    //THREAD=VoIP
    void 
    ManagerImpl::displayTextMessage(const CallID& id, const std::string& message)
    {
      if(_gui) {
       _gui->displayTextMessage(id, message);
      }
    }
    
    //THREAD=VoIP
    void 
    ManagerImpl::displayErrorText(const CallID& id, const std::string& message)
    {
      if(_gui) {
        _gui->displayErrorText(id, message);
      } else {
        std::cerr << message << std::endl;
      }
    }
    
    //THREAD=VoIP
    void 
    ManagerImpl::displayError (const std::string& error)
    {
      if(_gui) {
        _gui->displayError(error);
      }
    }
    
    //THREAD=VoIP
    void 
    ManagerImpl::displayStatus(const std::string& status)
    {
      if(_gui) {
        _gui->displayStatus(status);
      }
    }
    
    //THREAD=VoIP
    void 
    ManagerImpl::displayConfigError (const std::string& message)
    {
      if(_gui) {
        _gui->displayConfigError(message);
      }
    }
    
    //THREAD=VoIP
    void
    ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, const std::string& nb_msg)
    {
      if (_gui) _gui->sendVoiceNbMessage(accountId, nb_msg);
    }
    
    //THREAD=VoIP
    void
    ManagerImpl::stopVoiceMessageNotification(const AccountID& accountId)
    {
      if (_gui) _gui->sendVoiceNbMessage(accountId, std::string("0"));
    } 
    
    //THREAD=VoIP
    void 
    ManagerImpl::registrationSucceed(const AccountID& accountid)
    {
      Account* acc = getAccount(accountid);
      if ( acc ) { 
        acc->setState(true); 
        if (_gui) _gui->sendRegistrationState(accountid, true);
      }
    }
    
    //THREAD=VoIP
    void 
    ManagerImpl::registrationFailed(const AccountID& accountid)
    {
      Account* acc = getAccount(accountid);
      if ( acc ) { 
        acc->setState(false);
        if (_gui) _gui->sendRegistrationState(accountid, false);
      }
    }
    
    /**
     * Multi Thread
     */
    bool 
    ManagerImpl::playATone(Tone::TONEID toneId) {
      int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
      if (!hasToPlayTone) return false;
    
      if (_telephoneTone != 0) {
        _toneMutex.enterMutex();
        _telephoneTone->setCurrentTone(toneId);
        _toneMutex.leaveMutex();
    
        try {
          AudioLayer* audiolayer = getAudioDriver();
          if (audiolayer) { audiolayer->startStream(); }
        } catch(...) {
          _debugException("Off hold could not start audio stream");
          return false;
        }
      }
      return true;
    }
    
    /**
     * Multi Thread
     */
    void 
    ManagerImpl::stopTone(bool stopAudio=true) {
      int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
      if (!hasToPlayTone) return;
    
      if (stopAudio) {
        try {
          AudioLayer* audiolayer = getAudioDriver();
          if (audiolayer) { audiolayer->stopStream(); }
        } catch(...) {
          _debugException("Stop tone and stop stream");
        }
      }
    
      _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()
    {
      //return playATone(Tone::TONE_DIALTONE);
      playATone(Tone::TONE_DIALTONE);
    }
    
    /**
     * Multi Thread
     */
    void
    ManagerImpl::congestion () {
      playATone(Tone::TONE_CONGESTION);
    }
    
    /**
     * Multi Thread
     */
    void
    ManagerImpl::ringback () {
      playATone(Tone::TONE_RINGTONE);
    }
    
    /**
     * Multi Thread
     */
    void
    ManagerImpl::ringtone() 
    {
      int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
      if (!hasToPlayTone) { return; }
    
      std::string 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* audiolayer = getAudioDriver();
      if (audiolayer==0) { return; }
      int sampleRate  = audiolayer->getSampleRate();
    
      _toneMutex.enterMutex(); 
      bool loadFile = _audiofile.loadFile(ringchoice, sampleRate);
      _toneMutex.leaveMutex(); 
      if (loadFile) {
        _toneMutex.enterMutex(); 
        _audiofile.start();
        _toneMutex.leaveMutex(); 
        try {
          audiolayer->startStream();
        } catch(...) {
          _debugException("Audio file couldn't start audio stream");
        }
      } else {
        ringback();
      }
    }
    
    AudioLoop*
    ManagerImpl::getTelephoneTone()
    {
      if(_telephoneTone != 0) {
        ost::MutexLock m(_toneMutex);
        return _telephoneTone->getCurrentTone();
      }
      else {
        return 0;
      }
    }
    
    AudioLoop*
    ManagerImpl::getTelephoneFile()
    {
      ost::MutexLock m(_toneMutex);
      if(_audiofile.isStarted()) {
        return &_audiofile;
      } else {
        return 0;
      }
    }
    
    
    /**
     * Use Urgent Buffer
     * By AudioRTP thread
     */
    void
    ManagerImpl::notificationIncomingCall(void) {
    
      AudioLayer* audiolayer = getAudioDriver();
      if (audiolayer != 0) {
        unsigned int samplerate = audiolayer->getSampleRate();
        std::ostringstream frequency;
        frequency << "440/" << FRAME_PER_BUFFER;
    
        Tone tone(frequency.str(), samplerate);
        unsigned int nbSampling = tone.getSize();
        SFLDataFormat buf[nbSampling];
        tone.getNext(buf, tone.getSize());
        audiolayer->putUrgent(buf, sizeof(SFLDataFormat)*nbSampling);
      }
    }
    
    /**
     * Multi Thread
     */
    bool
    ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr, int port) 
    {
      StunAddress4 mappedAddr;
      struct in_addr in;
      char* addr;
    
      //int fd3, fd4;
      // bool ok = stunOpenSocketPair(stunSvrAddr, &mappedAddr, &fd3, &fd4, port);
      int fd1 = stunOpenSocket(stunSvrAddr, &mappedAddr, port);
      bool ok = (fd1 == -1 || fd1 == INVALID_SOCKET) ? false : true;
      if (ok) {
        closesocket(fd1);
        //closesocket(fd3);
        //closesocket(fd4);
        _firewallPort = mappedAddr.port;
        // Convert ipv4 address to host byte ordering
        in.s_addr = ntohl (mappedAddr.addr);
        addr = inet_ntoa(in);
        _firewallAddr = std::string(addr);
        _debug("STUN Firewall: [%s:%d]\n", _firewallAddr.data(), _firewallPort);
        return true;
      } else {
        _debug("Opening a stun socket pair failed\n");
      }
      return false;
    }
    
    bool
    ManagerImpl::behindNat(const std::string& svr, int port)
    {
      StunAddress4 stunSvrAddr;
      stunSvrAddr.addr = 0;
      
      // Convert char* to StunAddress4 structure
      bool ret = stunParseServerName ((char*)svr.data(), stunSvrAddr);
      if (!ret) {
        _debug("SIP: Stun server address (%s) is not valid\n", svr.data());
        return 0;
      }
      
      // Firewall address
      //_debug("STUN server: %s\n", svr.data());
      return getStunInfo(stunSvrAddr, port);
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // Private functions
    ///////////////////////////////////////////////////////////////////////////////
    /**
     * Initialization: Main Thread
     * @return 1: ok
              -1: error directory
               0: unable to load the setting
               2: file doesn't exist yet
     */
    int
    ManagerImpl::createSettingsPath (void) {
      _path = std::string(HOMEDIR) + DIR_SEPARATOR_STR + "." + PROGDIR;
    
      if (mkdir (_path.data(), 0755) != 0) {
        // If directory	creation failed
        if (errno != EEXIST) {
          _debug("Cannot create directory: %s\n", strerror(errno));
          return -1;
        }
      }
    
      // Load user's configuration
      _path = _path + DIR_SEPARATOR_STR + PROGNAME + "rc";
      return _config.populateFromFile(_path);
    }
    
    /**
     * Initialization: Main Thread
     */
    void
    ManagerImpl::initConfigFile (void) 
    {
      std::string type_str("string");
      std::string type_int("int");
    
      std::string section;
      section = SIGNALISATION;
      fill_config_int(SYMMETRIC, YES_STR);
      fill_config_int(PLAY_DTMF, YES_STR);
      fill_config_int(PLAY_TONES, YES_STR);
      fill_config_int(PULSE_LENGTH, DFT_PULSE_LENGTH_STR);
      fill_config_int(SEND_DTMF_AS, SIP_INFO_STR);
    
      section = AUDIO;
      fill_config_int(DRIVER_NAME, DFT_DRIVER_STR);
      fill_config_int(DRIVER_NAME_IN, DFT_DRIVER_STR);
      fill_config_int(DRIVER_NAME_OUT, DFT_DRIVER_STR);
      fill_config_int(DRIVER_SAMPLE_RATE, DRIVER_SAMPLE_RATE_DEFAULT);
      fill_config_str(CODEC1, DFT_CODEC);
      fill_config_str(CODEC2, DFT_CODEC);
      fill_config_str(CODEC3, DFT_CODEC);
      fill_config_str(RING_CHOICE, DFT_RINGTONE);
      fill_config_int(VOLUME_SPKR, DFT_VOL_SPKR_STR);
      fill_config_int(VOLUME_MICRO, DFT_VOL_MICRO_STR);
    
      section = PREFERENCES;
      fill_config_str(SKIN_CHOICE, DFT_SKIN);
      fill_config_int(CONFIRM_QUIT, YES_STR);
      fill_config_str(ZONE_TONE, DFT_ZONE);
      fill_config_int(CHECKED_TRAY, NO_STR);
      fill_config_str(VOICEMAIL_NUM, DFT_VOICEMAIL);
      fill_config_int(CONFIG_ZEROCONF, CONFIG_ZEROCONF_DEFAULT_STR);
    
      initConfigAccount();
      
      _exist = createSettingsPath();
      _setupLoaded = (_exist == 2 ) ? false : true;
    }
    
    /**
     * Initialization: Main Thread
     */
    void
    ManagerImpl::initAudioCodec (void)
    {
      _debugInit("Active Codecs");
      // TODO: need to be more dynamic...
      _codecDescriptorMap.setActive(getConfigString(AUDIO, CODEC1));
      _codecDescriptorMap.setActive(getConfigString(AUDIO, CODEC2));
      _codecDescriptorMap.setActive(getConfigString(AUDIO, CODEC3));
    }
    
    
    /**
     * Initialization: Main Thread
     */
    void
    ManagerImpl::initAudioDriver(void) 
    {
      _debugInit("AudioLayer Creation");
      _audiodriver = new AudioLayer(this);
      if (_audiodriver == 0) {
        _debug("Init audio driver error\n");
      } else {
        std::string error = getAudioDriver()->getErrorMessage();
        if (!error.empty()) {
          _debug("Init audio driver: %s\n", error.c_str());
        }
      } 
    }
    
    /**
     * Initialization: Main Thread and gui
     */
    void
    ManagerImpl::selectAudioDriver (void)
    {
      int noDevice  = getConfigInt(AUDIO, DRIVER_NAME);
      int noDeviceIn  = getConfigInt(AUDIO, DRIVER_NAME_IN);
      int noDeviceOut = getConfigInt(AUDIO, DRIVER_NAME_OUT);
      int sampleRate  = getConfigInt(AUDIO, DRIVER_SAMPLE_RATE);
      if (sampleRate <=0 || sampleRate > 48000) {
          sampleRate = 8000;
      }
    
      // this is when no audio device in/out are set
      // or the audio device in/out are set to 0
      // we take the nodevice instead
      if (noDeviceIn == 0 && noDeviceOut == 0) {
        noDeviceIn = noDeviceOut = noDevice;
      }
      _debugInit(" AudioLayer Opening Device");
      _audiodriver->setErrorMessage("");
      _audiodriver->openDevice(noDeviceIn, noDeviceOut, sampleRate);
    }
    
    /**
     * Initialize the Zeroconf scanning services loop
     * Informations will be store inside a map DNSService->_services
     * Initialization: Main Thread
     */
    void 
    ManagerImpl::initZeroconf(void) 
    {
    #ifdef USE_ZEROCONF
      _debugInit("Zeroconf Initialization");
      int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
    
      if (useZeroconf) {
        _DNSService->startScanServices();
      }
    #endif
    }
    
    /**
     * Init the volume for speakers/micro from 0 to 100 value
     * Initialization: Main Thread
     */
    void
    ManagerImpl::initVolume()
    {
      _debugInit("Initiate Volume");
      setSpkrVolume(getConfigInt(AUDIO, VOLUME_SPKR));
      setMicVolume(getConfigInt(AUDIO, VOLUME_MICRO));
    }
    
    /**
     * configuration function requests
     * Main Thread
     */
    bool 
    ManagerImpl::getZeroconf(const std::string& sequenceId)
    {
      bool returnValue = false;
    #ifdef USE_ZEROCONF
      int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
      if (useZeroconf && _gui != NULL) {
        TokenList arg;
        TokenList argTXT;
        std::string newService = "new service";
        std::string newTXT = "new txt record";
        if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
        DNSServiceMap services = _DNSService->getServices();
        DNSServiceMap::iterator iter = services.begin();
        arg.push_back(newService);
        while(iter!=services.end()) {
          arg.push_front(iter->first);
          _gui->sendMessage("100",sequenceId,arg);
          arg.pop_front(); // remove the first, the name
    
          TXTRecordMap record = iter->second.getTXTRecords();
          TXTRecordMap::iterator iterTXT = record.begin();
          while(iterTXT!=record.end()) {
            argTXT.clear();
            argTXT.push_back(iter->first);
            argTXT.push_back(iterTXT->first);
            argTXT.push_back(iterTXT->second);
            argTXT.push_back(newTXT);
            _gui->sendMessage("101",sequenceId,argTXT);
            iterTXT++;
          }
          iter++;
        }
        returnValue = true;
      }
    #else
      (void)sequenceId;
    #endif
      return returnValue;
    }
    
    /**
     * Main Thread
     */
    bool 
    ManagerImpl::attachZeroconfEvents(const std::string& sequenceId, Pattern::Observer& observer)
    {
      bool returnValue = false;
      // don't need the _gui like getZeroconf function
      // because Observer is here
    #ifdef USE_ZEROCONF
      int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
      if (useZeroconf) {
        if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
        _DNSService->attach(observer);
        returnValue = true;
      }
    #else
      (void)sequenceId;
      (void)observer;
    #endif
      return returnValue;
    }
    bool
    ManagerImpl::detachZeroconfEvents(Pattern::Observer& observer)
    {
      bool returnValue = false;
    #ifdef USE_ZEROCONF
      if (_DNSService) {
        _DNSService->detach(observer);
        returnValue = true;
      }
    #else
      (void)observer;
    #endif
      return returnValue;
    }
    
    /**
     * Main Thread
     */
    bool
    ManagerImpl::getEvents() {
      initRegisterVoIPLink();
      return true;
    }
    
    // TODO: rewrite this
    /**
     * Main Thread
     */
    bool 
    ManagerImpl::getCallStatus(const std::string& sequenceId)
    {
      if (!_gui) { return false; }
      ost::MutexLock m(_callAccountMapMutex);
      CallAccountMap::iterator iter = _callAccountMap.begin();
      TokenList tk;
      std::string code;
      std::string status;
      std::string destination;  
      std::string number;
    
      while (iter != _callAccountMap.end())
      {
        Call* call = getAccountLink(iter->second)->getCall(iter->first);
        Call::ConnectionState state = call->getConnectionState();
        if (state != Call::Connected) {
          switch(state) {
            case Call::Trying:       code="110"; status = "Trying";       break;
            case Call::Ringing:      code="111"; status = "Ringing";      break;
            case Call::Progressing:  code="125"; status = "Progressing";  break;
            case Call::Disconnected: code="125"; status = "Disconnected"; break;
            default: code=""; status= "";
          }
        } else {
          switch (call->getState()) {
            case Call::Active:       code="112"; status = "Established";  break;
            case Call::Hold:         code="114"; status = "Held";         break;
            case Call::Busy:         code="113"; status = "Busy";         break;
            case Call::Refused:      code="125"; status = "Refused";      break;
            case Call::Error:        code="125"; status = "Error";        break;
            case Call::Inactive:     code="125"; status = "Inactive";     break;
          }
        }
    
        // No Congestion
        // No Wrong Number
        // 116 <CSeq> <call-id> <acc> <destination> Busy
        destination = call->getPeerName();
        number = call->getPeerNumber();
        if (number!="") {
          destination.append(" <");
          destination.append(number);
          destination.append(">");
        }
        tk.push_back(iter->second);
        tk.push_back(destination);
        tk.push_back(status);
        _gui->sendCallMessage(code, sequenceId, iter->first, tk);
        tk.clear();
    
        iter++;
      }
      
      return true;
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::getConfigAll(const std::string& sequenceId)
    {
      bool returnValue = false;
      Conf::ConfigTreeIterator iter = _config.createIterator();
      TokenList tk = iter.begin();
      if (tk.size()) {
        returnValue = true;
      }
      while (tk.size()) {
        _gui->sendMessage("100", sequenceId, tk);
        tk = iter.next();
      }
      return returnValue;
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::getConfig(const std::string& section, const std::string& name, TokenList& arg)
    {
      return _config.getConfigTreeItemToken(section, name, arg);
    }
    
    //THREAD=Main
    // throw an Conf::ConfigTreeItemException if not found
    int 
    ManagerImpl::getConfigInt(const std::string& section, const std::string& name)
    {
      try {
        return _config.getConfigTreeItemIntValue(section, name);
      } catch (Conf::ConfigTreeItemException& e) {
        throw e;
      }
      return 0;
    }
    
    //THREAD=Main
    std::string 
    ManagerImpl::getConfigString(const std::string& section, const std::string&
    name)
    {
      try {
        return _config.getConfigTreeItemValue(section, name);
      } catch (Conf::ConfigTreeItemException& e) {
        throw e;
      }
      return "";
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::setConfig(const std::string& section, const std::string& name, const std::string& value)
    {
      return _config.setConfigTreeItem(section, name, value);
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::setConfig(const std::string& section, const std::string& name, int value)
    {
      std::ostringstream valueStream;
      valueStream << value;
      return _config.setConfigTreeItem(section, name, valueStream.str());
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::getConfigList(const std::string& sequenceId, const std::string& name)
    {
      bool returnValue = false;
      TokenList tk;
      if (name=="codecdescriptor") {
    
        CodecMap map = _codecDescriptorMap.getMap();
        CodecMap::iterator iter = map.begin();
        while( iter != map.end() ) {
          tk.clear();
          std::ostringstream strType;
          strType << iter->first;
          tk.push_back(strType.str());
          if (iter->second) {
            tk.push_back(iter->second->getOfficialName());
          } else {
            tk.push_back(strType.str());
          }
          _gui->sendMessage("100", sequenceId, tk);
          iter++;
        }
        returnValue = true;
      } else if (name=="ringtones") {
        // add empty line
        std::ostringstream str;
        str << 1;
        tk.push_back(str.str());
        tk.push_back(""); // filepath
        _gui->sendMessage("100", sequenceId, tk);
    
        // share directory
        std::string path = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR;
        int nbFile = 1;
        returnValue = getDirListing(sequenceId, path, &nbFile);
    
        // home directory
        path = std::string(HOMEDIR) + DIR_SEPARATOR_STR + "." + PROGDIR + DIR_SEPARATOR_STR + RINGDIR;
        getDirListing(sequenceId, path, &nbFile);
      } else if (name=="audiodevice") {
        returnValue = getAudioDeviceList(sequenceId, AudioLayer::InputDevice | AudioLayer::OutputDevice);
      } else if (name=="audiodevicein") {
        returnValue = getAudioDeviceList(sequenceId, AudioLayer::InputDevice);
      } else if (name=="audiodeviceout") {
        returnValue = getAudioDeviceList(sequenceId, AudioLayer::OutputDevice);
      } else if (name=="countrytones") {
        returnValue = getCountryTones(sequenceId);
      }
      return returnValue;
    }
    
    //THREAD=Main
    bool 
    ManagerImpl::getAudioDeviceList(const std::string& sequenceId, int ioDeviceMask) 
    {
      AudioLayer* audiolayer = getAudioDriver();
      if (audiolayer == 0) { return false; }
    
      bool returnValue = false;
      
      // TODO: test when there is an error on initializing...
      TokenList tk;
      AudioDevice* device = 0;
      int nbDevice = audiolayer->getDeviceCount();
      
      for (int index = 0; index < nbDevice; index++ ) {
        device = audiolayer->getAudioDeviceInfo(index, ioDeviceMask);
        if (device != 0) {
          tk.clear();
          std::ostringstream str; str << index; tk.push_back(str.str());
          tk.push_back(device->getName());
          tk.push_back(device->getApiName());
          std::ostringstream rate; rate << (int)(device->getRate()); tk.push_back(rate.str());
          _gui->sendMessage("100", sequenceId, tk);
    
          // don't forget to delete it after
          delete device; device = 0;
        }
      }
      returnValue = true;
      
      std::ostringstream rate; 
      rate << "VARIABLE";
      tk.clear();
      tk.push_back(rate.str());
      _gui->sendMessage("101", sequenceId, tk);
    
      return returnValue;
    }
    
    //THREAD=Main
    bool
    ManagerImpl::getCountryTones(const std::string& sequenceId)
    {
      // see ToneGenerator for the list...
      sendCountryTone(sequenceId, 1, "North America");
      sendCountryTone(sequenceId, 2, "France");
      sendCountryTone(sequenceId, 3, "Australia");
      sendCountryTone(sequenceId, 4, "United Kingdom");
      sendCountryTone(sequenceId, 5, "Spain");
      sendCountryTone(sequenceId, 6, "Italy");
      sendCountryTone(sequenceId, 7, "Japan");
    
      return true;
    }
    
    //THREAD=Main
    void 
    ManagerImpl::sendCountryTone(const std::string& sequenceId, int index, const std::string& name) {
      TokenList tk;
      std::ostringstream str; str << index; tk.push_back(str.str());
      tk.push_back(name);
      _gui->sendMessage("100", sequenceId, tk);
    }
    
    //THREAD=Main
    bool
    ManagerImpl::getDirListing(const std::string& sequenceId, const std::string& path, int *nbFile) {
      TokenList tk;
      try {
        ost::Dir dir(path.c_str());
        const char *cFileName = 0;
        std::string fileName;
        std::string filePathName;
        while ( (cFileName=dir++) != 0 ) {
          fileName = cFileName;
          filePathName = path + DIR_SEPARATOR_STR + cFileName;
          if (fileName.length() && fileName[0]!='.' && !ost::isDir(filePathName.c_str())) {
            tk.clear();
            std::ostringstream str;
            str << (*nbFile);
            tk.push_back(str.str());
            tk.push_back(filePathName);
            _gui->sendMessage("100", sequenceId, tk);
            (*nbFile)++;
          }
        }
        return true;
      } catch (...) {
        // error to open file dir
        return false;
      }
    }
    
    bool 
    ManagerImpl::getAccountList(const std::string& sequenceId) 
    {
      bool oneActive = false;
      TokenList tk;
    
      AccountMap::iterator iter = _accountMap.begin();
      while ( iter != _accountMap.end() ) {
        if ( iter->second != 0 ) {
          _debug("Account List: %s\n", iter->first.data()); 
          tk.push_back(iter->first);
          // we try to send one active account for default account on start
          // this is not the way it should be... 
          if ( iter->second->isEnabled() || iter->second->shouldInitOnStart()) {
            tk.push_back("Active");
            tk.push_back(getConfigString(iter->first,CONFIG_ACCOUNT_ALIAS));
             _gui->sendMessage("130", sequenceId, tk);
            oneActive = true;
          } else {
            tk.push_back("Inactive");
            tk.push_back(getConfigString(iter->first,CONFIG_ACCOUNT_ALIAS));
             _gui->sendMessage("131", sequenceId, tk);
          }
    
         tk.clear();
        }
        iter++;
      }
    
      return oneActive;
    }
    
    //THREAD=Main
    /*
     * Experimental...
     */
    bool
    ManagerImpl::setSwitch(const std::string& switchName, std::string& message) {
      AudioLayer* audiolayer = 0;
      if (switchName == "audiodriver" ) {
        // hangup all call here 
        audiolayer = getAudioDriver();
    
        int oldSampleRate = 0;
        if (audiolayer) { oldSampleRate = audiolayer->getSampleRate(); }
    
        selectAudioDriver();
        audiolayer = getAudioDriver();
    
        if (audiolayer) {
          std::string error = audiolayer->getErrorMessage();
          int newSampleRate = audiolayer->getSampleRate();
    
          if (!error.empty()) {
            message = error;
            return false;
          }
    
          if (newSampleRate != oldSampleRate) {
            _toneMutex.enterMutex();
    
            _debug("Unload Telephone Tone\n");
            delete _telephoneTone; _telephoneTone = 0;
            _debug("Unload DTMF Key\n");
            delete _dtmfKey; _dtmfKey = 0;
    
            _debug("Load Telephone Tone\n");
            std::string country = getConfigString(PREFERENCES, ZONE_TONE);
            _telephoneTone = new TelephoneTone(country, newSampleRate);
    
            _debugInit("Loading DTMF key");
            _dtmfKey = new DTMF(newSampleRate);
    
            _toneMutex.leaveMutex();
          }
    
          message = _("Change with success");
          playDtmf('9');
          getAudioDriver()->sleep(300); // in milliseconds
          playDtmf('1');
          getAudioDriver()->sleep(300); // in milliseconds
          playDtmf('1');
          return true;
        }
      } else if ( switchName == "echo" ) {
        audiolayer = getAudioDriver();
        if (audiolayer) {
          audiolayer->toggleEchoTesting();
          return true;
        }
      }
    
    
      return false;
    }
    
    // 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;
          return true;
        } else {
          return false; 
        }
      } else {
        return false;
      }
    }
    
    AccountID
    ManagerImpl::getAccountFromCall(const CallID& callID)
    {
      ost::MutexLock m(_callAccountMapMutex);
      CallAccountMap::iterator iter = _callAccountMap.find(callID);
      if ( iter == _callAccountMap.end()) {
        return AccountNULL;
      } else {
        return iter->second;
      }
    }
    
    bool
    ManagerImpl::removeCallAccount(const CallID& callID)
    {
      ost::MutexLock m(_callAccountMapMutex);
      if ( _callAccountMap.erase(callID) ) {
        return true;
      }
      return false;
    }
    
    CallID 
    ManagerImpl::getNewCallID() 
    {
      std::ostringstream random_id("s");
      random_id << (unsigned)rand();
      
      // when it's not found, it return ""
      // generate, something like s10000s20000s4394040
      while (getAccountFromCall(random_id.str()) != AccountNULL) {
        random_id.clear();
        random_id << "s";
        random_id << (unsigned)rand();
      }
      return random_id.str();
    }
    
    short
    ManagerImpl::loadAccountMap()
    {
      _debugStart("Load account:");
      short nbAccount = 0;
      Account* tmpAccount;
      
      // SIP Loading X account...
      short nbAccountSIP = ACCOUNT_SIP_COUNT_DEFAULT;
      for (short iAccountSIP = 0; iAccountSIP<nbAccountSIP; iAccountSIP++) {
        std::ostringstream accountName;
        accountName << "SIP" << iAccountSIP;
        
        tmpAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, accountName.str());
         if (tmpAccount!=0) {
           _debugMid(" %s", accountName.str().data());
           _accountMap[accountName.str()] = tmpAccount;
          nbAccount++;
        }
      }
    
      // IAX Loading X account...
      short nbAccountIAX = ACCOUNT_IAX_COUNT_DEFAULT;
      for (short iAccountIAX = 0; iAccountIAX<nbAccountIAX; iAccountIAX++) {
        std::ostringstream accountName;
        accountName << "IAX" << iAccountIAX;
        tmpAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, accountName.str());
        if (tmpAccount!=0) {
           _debugMid(" %s", accountName.str().data());
           _accountMap[accountName.str()] = tmpAccount;
          nbAccount++;
        }
      }
      _debugEnd("\n");
    
      return nbAccount;
    }
    
    void
    ManagerImpl::unloadAccountMap()
    {
      _debug("Unloading account map...\n");
      AccountMap::iterator iter = _accountMap.begin();
      while ( iter != _accountMap.end() ) {
        _debug("-> Deleting account %s\n", iter->first.c_str());
        delete iter->second; iter->second = 0;
        iter++;
      }
      _accountMap.clear();
    }
    
    bool
    ManagerImpl::accountExists(const AccountID& accountID)
    {
      AccountMap::iterator iter = _accountMap.find(accountID);
      if ( iter == _accountMap.end() ) {
        return false;
      }
      return true;
    }
    
    Account*
    ManagerImpl::getAccount(const AccountID& accountID)
    {
      AccountMap::iterator iter = _accountMap.find(accountID);
      if ( iter == _accountMap.end() ) {
        return 0;
      }
      return iter->second;
    }
    
    VoIPLink* 
    ManagerImpl::getAccountLink(const AccountID& accountID)
    {
      Account* acc = getAccount(accountID);
      if ( acc ) {
        return acc->getVoIPLink();
      }
      return 0;
    }
    
    void
    ManagerImpl::initConfigAccount() {
      AccountMap::iterator iter = _accountMap.begin();
      while ( iter != _accountMap.end() ) {
        if (iter->second!=0) {
          iter->second->initConfig(_config);
        }
        iter++;
      }
    }
    
    #ifdef TEST
    /** 
     * Test accountMap
     */
    bool ManagerImpl::testCallAccountMap()
    {
      if ( getAccountFromCall(1) != AccountNULL ) {
        _debug("TEST: getAccountFromCall with empty list failed\n");
      }
      if ( removeCallAccount(1) != false ) {
        _debug("TEST: removeCallAccount with empty list failed\n");
      }
      CallID newid = getNewCallID();
      if ( associateCallToAccount(newid, "acc0") == false ) {
        _debug("TEST: associateCallToAccount with new CallID empty list failed\n");
      }
      if ( associateCallToAccount(newid, "acc1") == true ) {
        _debug("TEST: associateCallToAccount with a known CallID failed\n");
      }
      if ( getAccountFromCall( newid ) != "acc0" ) {
        _debug("TEST: getAccountFromCall don't return the good account id\n");
      }
      CallID secondnewid = getNewCallID();
      if ( associateCallToAccount(secondnewid, "xxxx") == true ) {
        _debug("TEST: associateCallToAccount with unknown account id failed\n");
      }
      if ( removeCallAccount( newid ) != true ) {
        _debug("TEST: removeCallAccount don't remove the association\n");
      }
    
      return true;
    }
    
    /**
     * Test AccountMap
     */
    bool ManagerImpl::testAccountMap() 
    {
      if (loadAccountMap() != 2) {
        _debug("TEST: loadAccountMap didn't load 2 account\n");
      }
      if (accountExists("acc0") == false) {
        _debug("TEST: accountExists didn't find acc0\n");
      }
      if (accountExists("accZ") != false) {
        _debug("TEST: accountExists found an unknown account\n");
      }
      if (getAccount("acc0") == 0) {
        _debug("TEST: getAccount didn't find acc0\n");
      }
      if (getAccount("accZ") != 0) {
        _debug("TEST: getAccount found an unknown account\n");
      }
      unloadAccountMap();
      if ( accountExists("acc0") == true ) {
        _debug("TEST: accountExists found an account after unloadAccount\n");
      }
      return true;
    }
    #endif