Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/releaseWindowsTestOne
  • release/releaseTest
  • release/releaseWindowsTest
  • release/windowsReleaseTest
  • 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
  • 1.0.0
  • 0.3.0
  • 0.2.1
  • 0.2.0
  • 0.1.0
25 results

Call.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Call.cpp 31.87 KiB
    /***************************************************************************
     *   Copyright (C) 2009-2012 by Savoir-Faire Linux                         *
     *   Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com>         *
     *            Emmanuel Lepage Valle <emmanuel.lepage@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.,                                       *
     *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
     **************************************************************************/
    
    //Parent
    #include "Call.h"
    
    //SFLPhone library
    #include "CallModel.h"
    #include "callmanager_interface_singleton.h"
    #include "configurationmanager_interface_singleton.h"
    #include "ContactBackend.h"
    #include "Contact.h"
    
    
    const call_state Call::actionPerformedStateMap [11][5] = 
    {
    //                      ACCEPT                  REFUSE                  TRANSFER                   HOLD                           RECORD            /**/
    /*INCOMING     */  {CALL_STATE_INCOMING   , CALL_STATE_INCOMING    , CALL_STATE_ERROR        , CALL_STATE_INCOMING     ,  CALL_STATE_INCOMING     },/**/
    /*RINGING      */  {CALL_STATE_ERROR      , CALL_STATE_RINGING     , CALL_STATE_ERROR        , CALL_STATE_ERROR        ,  CALL_STATE_RINGING      },/**/
    /*CURRENT      */  {CALL_STATE_ERROR      , CALL_STATE_CURRENT     , CALL_STATE_TRANSFER     , CALL_STATE_CURRENT      ,  CALL_STATE_CURRENT      },/**/
    /*DIALING      */  {CALL_STATE_DIALING    , CALL_STATE_OVER        , CALL_STATE_ERROR        , CALL_STATE_ERROR        ,  CALL_STATE_ERROR        },/**/
    /*HOLD         */  {CALL_STATE_ERROR      , CALL_STATE_HOLD        , CALL_STATE_TRANSF_HOLD  , CALL_STATE_HOLD         ,  CALL_STATE_HOLD         },/**/
    /*FAILURE      */  {CALL_STATE_ERROR      , CALL_STATE_FAILURE     , CALL_STATE_ERROR        , CALL_STATE_ERROR        ,  CALL_STATE_ERROR        },/**/
    /*BUSY         */  {CALL_STATE_ERROR      , CALL_STATE_BUSY        , CALL_STATE_ERROR        , CALL_STATE_ERROR        ,  CALL_STATE_ERROR        },/**/
    /*TRANSFER     */  {CALL_STATE_TRANSFER   , CALL_STATE_TRANSFER    , CALL_STATE_CURRENT      , CALL_STATE_TRANSFER     ,  CALL_STATE_TRANSFER     },/**/
    /*TRANSF_HOLD  */  {CALL_STATE_TRANSF_HOLD, CALL_STATE_TRANSF_HOLD , CALL_STATE_HOLD         , CALL_STATE_TRANSF_HOLD  ,  CALL_STATE_TRANSF_HOLD  },/**/
    /*OVER         */  {CALL_STATE_ERROR      , CALL_STATE_ERROR       , CALL_STATE_ERROR        , CALL_STATE_ERROR        ,  CALL_STATE_ERROR        },/**/
    /*ERROR        */  {CALL_STATE_ERROR      , CALL_STATE_ERROR       , CALL_STATE_ERROR        , CALL_STATE_ERROR        ,  CALL_STATE_ERROR        } /**/
    };//                                                                                                                                                    
    
    
    const function Call::actionPerformedFunctionMap[11][5] = 
    { 
    //                      ACCEPT               REFUSE            TRANSFER                 HOLD                  RECORD             /**/
    /*INCOMING       */  {&Call::accept     , &Call::refuse   , &Call::acceptTransf   , &Call::acceptHold  ,  &Call::setRecord     },/**/
    /*RINGING        */  {&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::nothing     ,  &Call::setRecord     },/**/
    /*CURRENT        */  {&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::hold        ,  &Call::setRecord     },/**/
    /*DIALING        */  {&Call::call       , &Call::cancel   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       },/**/
    /*HOLD           */  {&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::unhold      ,  &Call::setRecord     },/**/
    /*FAILURE        */  {&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       },/**/
    /*BUSY           */  {&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       },/**/
    /*TRANSFERT      */  {&Call::transfer   , &Call::hangUp   , &Call::nothing        , &Call::hold        ,  &Call::setRecord     },/**/
    /*TRANSFERT_HOLD */  {&Call::transfer   , &Call::hangUp   , &Call::nothing        , &Call::unhold      ,  &Call::setRecord     },/**/
    /*OVER           */  {&Call::nothing    , &Call::nothing  , &Call::nothing        , &Call::nothing     ,  &Call::nothing       },/**/
    /*ERROR          */  {&Call::nothing    , &Call::nothing  , &Call::nothing        , &Call::nothing     ,  &Call::nothing       } /**/
    };//                                                                                                                                 
    
    
    const call_state Call::stateChangedStateMap [11][6] = 
    {
    //                      RINGING                  CURRENT             BUSY              HOLD                           HUNGUP           FAILURE             /**/
    /*INCOMING     */ {CALL_STATE_INCOMING    , CALL_STATE_CURRENT  , CALL_STATE_BUSY   , CALL_STATE_HOLD         ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*RINGING      */ {CALL_STATE_RINGING     , CALL_STATE_CURRENT  , CALL_STATE_BUSY   , CALL_STATE_HOLD         ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*CURRENT      */ {CALL_STATE_CURRENT     , CALL_STATE_CURRENT  , CALL_STATE_BUSY   , CALL_STATE_HOLD         ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*DIALING      */ {CALL_STATE_RINGING     , CALL_STATE_CURRENT  , CALL_STATE_BUSY   , CALL_STATE_HOLD         ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*HOLD         */ {CALL_STATE_HOLD        , CALL_STATE_CURRENT  , CALL_STATE_BUSY   , CALL_STATE_HOLD         ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*FAILURE      */ {CALL_STATE_FAILURE     , CALL_STATE_FAILURE  , CALL_STATE_BUSY   , CALL_STATE_FAILURE      ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*BUSY         */ {CALL_STATE_BUSY        , CALL_STATE_CURRENT  , CALL_STATE_BUSY   , CALL_STATE_BUSY         ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*TRANSFER     */ {CALL_STATE_TRANSFER    , CALL_STATE_TRANSFER , CALL_STATE_BUSY   , CALL_STATE_TRANSF_HOLD  ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*TRANSF_HOLD  */ {CALL_STATE_TRANSF_HOLD , CALL_STATE_TRANSFER , CALL_STATE_BUSY   , CALL_STATE_TRANSF_HOLD  ,  CALL_STATE_OVER  ,  CALL_STATE_FAILURE  },/**/
    /*OVER         */ {CALL_STATE_OVER        , CALL_STATE_OVER     , CALL_STATE_OVER   , CALL_STATE_OVER         ,  CALL_STATE_OVER  ,  CALL_STATE_OVER     },/**/
    /*ERROR        */ {CALL_STATE_ERROR       , CALL_STATE_ERROR    , CALL_STATE_ERROR  , CALL_STATE_ERROR        ,  CALL_STATE_ERROR ,  CALL_STATE_ERROR    } /**/
    };//                                                                                                                                                           
    
    const function Call::stateChangedFunctionMap[11][6] = 
    { 
    //                      RINGING                  CURRENT             BUSY              HOLD                    HUNGUP           FAILURE            /**/
    /*INCOMING       */  {&Call::nothing    , &Call::start     , &Call::startWeird     , &Call::startWeird   ,  &Call::startStop    , &Call::start   },/**/
    /*RINGING        */  {&Call::nothing    , &Call::start     , &Call::start          , &Call::start        ,  &Call::startStop    , &Call::start   },/**/
    /*CURRENT        */  {&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing },/**/
    /*DIALING        */  {&Call::nothing    , &Call::warning   , &Call::warning        , &Call::warning      ,  &Call::stop         , &Call::warning },/**/
    /*HOLD           */  {&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing },/**/
    /*FAILURE        */  {&Call::nothing    , &Call::warning   , &Call::warning        , &Call::warning      ,  &Call::stop         , &Call::nothing },/**/
    /*BUSY           */  {&Call::nothing    , &Call::nothing   , &Call::nothing        , &Call::warning      ,  &Call::stop         , &Call::nothing },/**/
    /*TRANSFERT      */  {&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing },/**/
    /*TRANSFERT_HOLD */  {&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing },/**/
    /*OVER           */  {&Call::nothing    , &Call::warning   , &Call::warning        , &Call::warning      ,  &Call::stop         , &Call::warning },/**/
    /*ERROR          */  {&Call::nothing    , &Call::nothing   , &Call::nothing        , &Call::nothing      ,  &Call::stop         , &Call::nothing } /**/
    };//                                                                                                                                                   
    
    const char * Call::historyIcons[3] = {ICON_HISTORY_INCOMING, ICON_HISTORY_OUTGOING, ICON_HISTORY_MISSED};
    
    ContactBackend* Call::m_pContactBackend = 0;
    
    void Call::setContactBackend(ContactBackend* be)
    {
       m_pContactBackend = be;
    }
    
    ///Constructor
    Call::Call(call_state startState, QString callId, QString peerName, QString peerNumber, QString account)
       : m_isConference(false)
    {
       this->m_CallId          = callId     ;
       this->m_PeerPhoneNumber = peerNumber ;
       this->m_PeerName        = peerName   ;
       changeCurrentState(startState)       ;
       this->m_Account         = account    ;
       this->m_Recording       = false      ;
       this->m_pStartTime      = NULL       ;
       this->m_pStopTime       = NULL       ;
       emit changed();
    }
    
    ///Destructor
    Call::~Call()
    {
       delete m_pStartTime ;
       delete m_pStopTime  ;
    }
    
    ///Constructor
    Call::Call(QString confId, QString account) 
       : m_isConference(true)
    {
       this->m_ConfId  = confId  ;
       this->m_Account = account ;
    }
    
    /*****************************************************************************
     *                                                                           *
     *                               Call builder                                *
     *                                                                           *
     ****************************************************************************/
    
    ///Build a call from its ID
    Call* Call::buildExistingCall(QString callId)
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       MapStringString details = callManager.getCallDetails(callId).value();
       
       qDebug() << "Constructing existing call with details : " << details;
       
       QString    peerNumber = details[ CALL_PEER_NUMBER ];
       QString    peerName   = details[ CALL_PEER_NAME   ];
       QString    account    = details[ CALL_ACCOUNTID   ];
       call_state startState = getStartStateFromDaemonCallState(details[CALL_STATE], details[CALL_TYPE]);
       
       Call* call            = new Call(startState, callId, peerName, peerNumber, account)                 ;
       call->m_pStartTime    = new QDateTime(QDateTime::currentDateTime())                                 ;
       call->m_Recording     = callManager.getIsRecording(callId)                                          ;
       call->m_HistoryState  = getHistoryStateFromDaemonCallState(details[CALL_STATE], details[CALL_TYPE]) ;
       
       return call;
    }
    
    ///Build a call from a dialing call (a call that is about to exist)
    Call* Call::buildDialingCall(QString callId, const QString & peerName, QString account)
    {
       Call* call = new Call(CALL_STATE_DIALING, callId, peerName, "", account);
       call->m_HistoryState = NONE;
       return call;
    }
    
    ///Build a call from a dbus event
    Call* Call::buildIncomingCall(const QString & callId)
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       MapStringString details = callManager.getCallDetails(callId).value();
       
       QString from     = details[ CALL_PEER_NUMBER ];
       QString account  = details[ CALL_ACCOUNTID   ];
       QString peerName = details[ CALL_PEER_NAME   ];
       
       Call* call = new Call(CALL_STATE_INCOMING, callId, peerName, from, account);
       call->m_HistoryState = MISSED;
       return call;
    }
    
    ///Build a rigging call (from dbus)
    Call* Call::buildRingingCall(const QString & callId)
    {
       CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
       MapStringString details = callManager.getCallDetails(callId).value();
       
       QString from     = details[ CALL_PEER_NUMBER ];
       QString account  = details[ CALL_ACCOUNTID   ];
       QString peerName = details[ CALL_PEER_NAME   ];
       
       Call* call = new Call(CALL_STATE_RINGING, callId, peerName, from, account);
       call->m_HistoryState = OUTGOING;
       return call;
    }
    
    /*****************************************************************************
     *                                                                           *
     *                                  History                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Build a call that is already over
    Call* Call::buildHistoryCall(const QString & callId, uint startTimeStamp, uint stopTimeStamp, QString account, QString name, QString number, QString type)
    {
       if(name == "empty") name = "";
       Call* call            = new Call(CALL_STATE_OVER, callId, name, number, account );
       call->m_pStartTime    = new QDateTime(QDateTime::fromTime_t(startTimeStamp)     );
       call->m_pStopTime     = new QDateTime(QDateTime::fromTime_t(stopTimeStamp)      );
       call->m_HistoryState  = getHistoryStateFromType(type                            );
       return call;
    }
    
    ///Get the history state from the type (see Call.cpp header)
    history_state Call::getHistoryStateFromType(QString type)
    {
       if(type == DAEMON_HISTORY_TYPE_MISSED        )
          return MISSED   ;
       else if(type == DAEMON_HISTORY_TYPE_OUTGOING )
          return OUTGOING ;
       else if(type == DAEMON_HISTORY_TYPE_INCOMING )
          return INCOMING ;
       return NONE        ;
    }
    
    ///Get the type from an history state (see Call.cpp header)
    QString Call::getTypeFromHistoryState(history_state historyState)
    {
       if(historyState == MISSED        )
          return DAEMON_HISTORY_TYPE_MISSED   ;
       else if(historyState == OUTGOING )
          return DAEMON_HISTORY_TYPE_OUTGOING ;
       else if(historyState == INCOMING )
          return DAEMON_HISTORY_TYPE_INCOMING ;
       return QString()                       ;
    }
    
    ///Get history state from daemon
    history_state Call::getHistoryStateFromDaemonCallState(QString daemonCallState, QString daemonCallType)
    {
       if((daemonCallState      == DAEMON_CALL_STATE_INIT_CURRENT  || daemonCallState == DAEMON_CALL_STATE_INIT_HOLD) && daemonCallType == DAEMON_CALL_TYPE_INCOMING )
          return INCOMING ;
       else if((daemonCallState == DAEMON_CALL_STATE_INIT_CURRENT  || daemonCallState == DAEMON_CALL_STATE_INIT_HOLD) && daemonCallType == DAEMON_CALL_TYPE_OUTGOING )
          return OUTGOING ;
       else if(daemonCallState  == DAEMON_CALL_STATE_INIT_BUSY                                                                                                       )
          return OUTGOING ;
       else if(daemonCallState  == DAEMON_CALL_STATE_INIT_INACTIVE && daemonCallType == DAEMON_CALL_TYPE_INCOMING                                                    )
          return INCOMING ;
       else if(daemonCallState  == DAEMON_CALL_STATE_INIT_INACTIVE && daemonCallType == DAEMON_CALL_TYPE_OUTGOING                                                    )
          return MISSED   ;
       else
          return NONE     ;
    }
    
    ///Get the start sate from the daemon state
    call_state Call::getStartStateFromDaemonCallState(QString daemonCallState, QString daemonCallType)
    {
       if(daemonCallState      == DAEMON_CALL_STATE_INIT_CURRENT  )
          return CALL_STATE_CURRENT  ;
       else if(daemonCallState == DAEMON_CALL_STATE_INIT_HOLD     )
          return CALL_STATE_HOLD     ;
       else if(daemonCallState == DAEMON_CALL_STATE_INIT_BUSY     )
          return CALL_STATE_BUSY     ;
       else if(daemonCallState == DAEMON_CALL_STATE_INIT_INACTIVE && daemonCallType == DAEMON_CALL_TYPE_INCOMING )
          return CALL_STATE_INCOMING ;
       else if(daemonCallState == DAEMON_CALL_STATE_INIT_INACTIVE && daemonCallType == DAEMON_CALL_TYPE_OUTGOING )
          return CALL_STATE_RINGING  ;
       else if(daemonCallState == DAEMON_CALL_STATE_INIT_INCOMING )
          return CALL_STATE_INCOMING ;
       else if(daemonCallState == DAEMON_CALL_STATE_INIT_RINGING  )
          return CALL_STATE_RINGING  ;
       else
          return CALL_STATE_FAILURE  ;
    }
    
    /*****************************************************************************
     *                                                                           *
     *                                  Getters                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Transfer state from internal to daemon internal syntaz
    daemon_call_state Call::toDaemonCallState(const QString & stateName)
    {
       if(stateName == QString(CALL_STATE_CHANGE_HUNG_UP)        )
          return DAEMON_CALL_STATE_HUNG_UP ;
       if(stateName == QString(CALL_STATE_CHANGE_RINGING)        )
          return DAEMON_CALL_STATE_RINGING ;
       if(stateName == QString(CALL_STATE_CHANGE_CURRENT)        )
          return DAEMON_CALL_STATE_CURRENT ;
       if(stateName == QString(CALL_STATE_CHANGE_UNHOLD_CURRENT) )
          return DAEMON_CALL_STATE_CURRENT ;
       if(stateName == QString(CALL_STATE_CHANGE_UNHOLD_RECORD)  )
          return DAEMON_CALL_STATE_CURRENT ;
       if(stateName == QString(CALL_STATE_CHANGE_HOLD)           )
          return DAEMON_CALL_STATE_HOLD    ;
       if(stateName == QString(CALL_STATE_CHANGE_BUSY)           )
          return DAEMON_CALL_STATE_BUSY    ;
       if(stateName == QString(CALL_STATE_CHANGE_FAILURE)        )
          return DAEMON_CALL_STATE_FAILURE ;
       
       qDebug() << "stateChanged signal received with unknown state.";
       return DAEMON_CALL_STATE_FAILURE    ;
    }
    
    ///Get the time (second from 1 jan 1970) when the call ended
    QString Call::getStopTimeStamp()     const
    {
       if (m_pStopTime == NULL)
          return QString("0");
       return QString::number(m_pStopTime->toTime_t());
    }
    
    ///Get the time (second from 1 jan 1970) when the call started
    QString Call::getStartTimeStamp()    const
    {
       if (m_pStartTime == NULL)
          return QString("0");
       return QString::number(m_pStartTime->toTime_t());
    }
    
    ///Get the number where the call have been transferred
    const QString& Call::getTransferNumber()    const
    {
       return m_TransferNumber;
    }
    
    ///Get the call / peer number
    const QString& Call::getCallNumber()        const
    {
       return m_CallNumber;
    }
    
    ///Return the call id
    const QString& Call::getCallId()            const
    {
       return m_CallId;
    }
    
    ///Return the peer phone number
    const QString& Call::getPeerPhoneNumber()   const
    {
       return m_PeerPhoneNumber;
    }
    
    ///Get the peer name
    const QString& Call::getPeerName()          const
    {
       return m_PeerName;
    }
    
    ///Get the current state
    call_state Call::getCurrentState()          const
    {
       return m_CurrentState;
    }
    
    ///Get the call recording
    bool Call::getRecording()                   const
    {
       return m_Recording;
    }
    
    ///Get the call account id
    const QString& Call::getAccountId()         const
    {
       return m_Account;
    }
    
    ///Is this call a conference
    bool Call::isConference()                   const
    {
       return m_isConference;
    }
    
    ///Get the conference ID
    const QString& Call::getConfId()            const
    {
       return m_ConfId;
    }
    
    ///Get the recording path
    const QString& Call::getRecordingPath()      const
    {
       return m_RecordingPath;
    }
    
    ///Get the current codec
    QString Call::getCurrentCodecName()  const
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       return callManager.getCurrentAudioCodecName(m_CallId);
    }
    
    ///Get the state
    call_state Call::getState()                 const
    {
       return m_CurrentState;
    }
    
    ///Get the history state
    history_state Call::getHistoryState()       const
    {
       return m_HistoryState;
    }
    
    ///Is this call over?
    bool Call::isHistory()                      const
    {
       return (getState() == CALL_STATE_OVER);
    }
    
    ///This function could also be called mayBeSecure or haveChancesToBeEncryptedButWeCantTell.
    bool Call::isSecure() const {
    
       if (m_Account.isEmpty()) {
          qDebug() << "Account not set, can't check security";
          return false;
       }
    
       AccountList accountList(true);
       Account* currentAccount = accountList.getAccountById(m_Account);
    
       if ((currentAccount->getAccountDetail(TLS_ENABLE ) == "true") || (currentAccount->getAccountDetail(TLS_METHOD).toInt())) {
          return true;
       }
       return false;
    }
    
    
    /*****************************************************************************
     *                                                                           *
     *                                  Setters                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Set the transfer number
    void Call::setTransferNumber(const QString& number)
    {
       m_TransferNumber = number;
    }
    
    ///This call is a conference
    void Call::setConference(bool value)
    {
       m_isConference = value;
    }
    
    ///Set the call number
    void Call::setCallNumber(const QString& number)
    {
       m_CallNumber = number;
       emit changed();
    }
    
    ///Set the conference ID
    void Call::setConfId(QString value)
    {
       m_ConfId = value;
    }
    
    ///Set the recording path
    void Call::setRecordingPath(const QString& path)
    {
       m_RecordingPath = path;
    }
    
    ///Set peer name
    void Call::setPeerName(const QString& name)
    {
       m_PeerName = name;
    }
    
    /*****************************************************************************
     *                                                                           *
     *                                  Mutator                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///The call state just changed
    call_state Call::stateChanged(const QString& newStateName)
    {
       if (!m_isConference) {
          call_state previousState = m_CurrentState;
          daemon_call_state dcs = toDaemonCallState(newStateName);
          changeCurrentState(stateChangedStateMap[m_CurrentState][dcs]);
          (this->*(stateChangedFunctionMap[previousState][dcs]))();
          qDebug() << "Calling stateChanged " << newStateName << " -> " << toDaemonCallState(newStateName) << " on call with state " << previousState << ". Become " << m_CurrentState;
          return m_CurrentState;
       }
       else {
          qDebug() << "A conference have no call state";
          return CALL_STATE_ERROR;
       }
    }
    
    ///An acount have been performed
    call_state Call::actionPerformed(call_action action)
    {
       call_state previousState = m_CurrentState;
       Q_ASSERT_X((previousState>10) || (previousState<0),"perform action","Invalid previous state ("+QString::number(previousState)+")");
       Q_ASSERT_X((state>4) || (state < 0),"perform action","Invalid action ("+QString::number(action)+")");
       Q_ASSERT_X((action>5) || (action < 0),"perform action","Invalid action ("+QString::number(action)+")");
       //update the state
       if (previousState < 11 && action < 5) {
          changeCurrentState(actionPerformedStateMap[previousState][action]);
          //execute the action associated with this transition
          (this->*(actionPerformedFunctionMap[previousState][action]))();
          qDebug() << "Calling action " << action << " on call with state " << previousState << ". Become " << m_CurrentState;
          //return the new state
       }
       return m_CurrentState;
    }
    
    /*
    void Call::putRecording()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       bool daemonRecording = callManager.getIsRecording(this -> m_CallId);
       if(daemonRecording != m_Recording)
       {
          callManager.setRecording(this->m_CallId);
       }
    }
    */
    ///Change the state
    void Call::changeCurrentState(call_state newState)
    {
       //qDebug() << "Call state changed to: " << newState;
       m_CurrentState = newState;
    
       emit changed();
    
       if (m_CurrentState == CALL_STATE_OVER)
          emit isOver(this);
    }
    
    void Call::sendTextMessage(QString message)
    {
       CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
       callManager.sendTextMessage(m_CallId,message);
    }
    
    /*****************************************************************************
     *                                                                           *
     *                              Automate function                            *
     *                                                                           *
     ****************************************************************************/
    ///@warning DO NOT TOUCH THAT, THEY ARE CALLED FROM AN ARRAY, HIGH FRAGILITY
    
    ///Do nothing (literally)
    void Call::nothing()
    {
    }
    
    ///Accept the call
    void Call::accept()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Accepting call. callId : " << m_CallId;
       callManager.accept(m_CallId);
       this->m_pStartTime = new QDateTime(QDateTime::currentDateTime());
       this->m_HistoryState = INCOMING;
    }
    
    ///Refuse the call
    void Call::refuse()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Refusing call. callId : " << m_CallId;
       callManager.refuse(m_CallId);
       this->m_pStartTime = new QDateTime(QDateTime::currentDateTime());
       this->m_HistoryState = MISSED;
    }
    
    ///Accept the transfer
    void Call::acceptTransf()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Accepting call and transferring it to number : " << m_TransferNumber << ". callId : " << m_CallId;
       callManager.accept(m_CallId);
       callManager.transfer(m_CallId, m_TransferNumber);
    //   m_HistoryState = TRANSFERED;
    }
    
    ///Put the call on hold
    void Call::acceptHold()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Accepting call and holding it. callId : " << m_CallId;
       callManager.accept(m_CallId);
       callManager.hold(m_CallId);
       this->m_HistoryState = INCOMING;
    }
    
    ///Hang up
    void Call::hangUp()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       this->m_pStopTime = new QDateTime(QDateTime::currentDateTime());
       qDebug() << "Hanging up call. callId : " << m_CallId;
       callManager.hangUp(m_CallId);
    }
    
    ///Cancel this call
    void Call::cancel()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Canceling call. callId : " << m_CallId;
       callManager.hangUp(m_CallId);
    }
    
    ///Put on hold
    void Call::hold()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Holding call. callId : " << m_CallId;
       callManager.hold(m_CallId);
    }
    
    ///Start the call
    void Call::call()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "account = " << m_Account;
       if(m_Account.isEmpty()) {
          qDebug() << "Account is not set, taking the first registered.";
          this->m_Account = CallModel<>::getCurrentAccountId();
       }
       if(!m_Account.isEmpty()) {
          qDebug() << "Calling " << m_CallNumber << " with account " << m_Account << ". callId : " << m_CallId;
          callManager.placeCall(m_Account, m_CallId, m_CallNumber);
          this->m_Account = m_Account;
          this->m_PeerPhoneNumber = m_CallNumber;
          if (m_pContactBackend) {
             Contact* contact = m_pContactBackend->getContactByPhone(m_PeerPhoneNumber);
             if (contact)
                m_PeerName = contact->getFormattedName();
          }
          this->m_pStartTime = new QDateTime(QDateTime::currentDateTime());
          this->m_HistoryState = OUTGOING;
       }
       else {
          qDebug() << "Trying to call " << m_TransferNumber << " with no account registered . callId : " << m_CallId;
          this->m_HistoryState = NONE;
          throw "No account registered!";
       }
    }
    
    ///Trnasfer the call
    void Call::transfer()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Transferring call to number : " << m_TransferNumber << ". callId : " << m_CallId;
       callManager.transfer(m_CallId, m_TransferNumber);
       this->m_pStopTime = new QDateTime(QDateTime::currentDateTime());
    }
    
    void Call::unhold()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Unholding call. callId : " << m_CallId;
       callManager.unhold(m_CallId);
    }
    
    /*
    void Call::switchRecord()
    {
       qDebug() << "Switching record state for call automate. callId : " << callId;
       m_Recording = !m_Recording;
    }
    */
    
    ///Record the call
    void Call::setRecord()
    {
       CallManagerInterface & callManager = CallManagerInterfaceSingleton::getInstance();
       qDebug() << "Setting record " << !m_Recording << " for call. callId : " << m_CallId;
       callManager.setRecording(m_CallId);
       m_Recording = !m_Recording;
    }
    
    ///Start the timer
    void Call::start()
    {
       qDebug() << "Starting call. callId : " << m_CallId;
       this->m_pStartTime = new QDateTime(QDateTime::currentDateTime());
    }
    
    ///Toggle the timer
    void Call::startStop()
    {
       qDebug() << "Starting and stoping call. callId : " << m_CallId;
       this->m_pStartTime = new QDateTime(QDateTime::currentDateTime());
       this->m_pStopTime = new QDateTime(QDateTime::currentDateTime());
    }
    
    ///Stop the timer
    void Call::stop()
    {
       qDebug() << "Stoping call. callId : " << m_CallId;
       this->m_pStopTime = new QDateTime(QDateTime::currentDateTime());
    }
    
    ///Handle error instead of crashing
    void Call::startWeird()
    {
       qDebug() << "Starting call. callId : " << m_CallId;
       this->m_pStartTime = new QDateTime(QDateTime::currentDateTime());
       qDebug() << "Warning : call " << m_CallId << " had an unexpected transition of state at its start.";
    }
    
    ///Print a warning
    void Call::warning()
    {
       qDebug() << "Warning : call " << m_CallId << " had an unexpected transition of state.";
    }
    
    /*****************************************************************************
     *                                                                           *
     *                             Keyboard handling                             *
     *                                                                           *
     ****************************************************************************/
    
    ///Input text on the call item
    void Call::appendText(const QString& str)
    {
       QString * editNumber;
       
       switch (m_CurrentState) {
       case CALL_STATE_TRANSFER    :
       case CALL_STATE_TRANSF_HOLD :
          editNumber = &m_TransferNumber;
          break;
       case CALL_STATE_DIALING     :
          editNumber = &m_CallNumber;
          break;
       default                     :
          qDebug() << "Backspace on call not editable. Doing nothing.";
          return;
       }
    
       editNumber->append(str);
    
       emit changed();
    }
    
    ///Remove the last character
    void Call::backspaceItemText()
    {
       QString * editNumber;
    
       switch (m_CurrentState) {
          case CALL_STATE_TRANSFER         :
          case CALL_STATE_TRANSF_HOLD      :
             editNumber = &m_TransferNumber;
             break;
          case CALL_STATE_DIALING          :
             editNumber = &m_CallNumber;
             break;
          default                          :
             qDebug() << "Backspace on call not editable. Doing nothing.";
             return;
       }
       QString text = *editNumber;
       int textSize = text.size();
       if(textSize > 0) {
          *editNumber = text.remove(textSize-1, 1);
    
          emit changed();
       }
       else {
          changeCurrentState(CALL_STATE_OVER);
       }
    }