Skip to content
Snippets Groups Projects
Select Git revision
  • 4ca867750560e3a129c5cdd2afca1eaf2ce12861
  • 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

CreationUsingNew.hpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    call.cpp 59.30 KiB
    /****************************************************************************
     *   Copyright (C) 2009-2014 by Savoir-Faire Linux                          *
     *   Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com>          *
     *            Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
     *                                                                          *
     *   This library is free software; you can redistribute it and/or          *
     *   modify it under the terms of the GNU Lesser General Public             *
     *   License as published by the Free Software Foundation; either           *
     *   version 2.1 of the License, or (at your option) any later version.     *
     *                                                                          *
     *   This library 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      *
     *   Lesser General Public License for more details.                        *
     *                                                                          *
     *   You should have received a copy of the GNU General Public License      *
     *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
     ***************************************************************************/
    
    //Parent
    #include "call.h"
    
    //C include
    #include <time.h>
    
    //Qt
    #include <QtCore/QFile>
    #include <QtCore/QTimer>
    
    
    //SFLPhone library
    #include "dbus/callmanager.h"
    #include "dbus/configurationmanager.h"
    #include "abstractitembackend.h"
    #include "contact.h"
    #include "account.h"
    #include "accountlistmodel.h"
    #include "videomodel.h"
    #include "historymodel.h"
    #include "instantmessagingmodel.h"
    #include "useractionmodel.h"
    #include "callmodel.h"
    #include "numbercategory.h"
    #include "phonedirectorymodel.h"
    #include "phonenumber.h"
    #include "videorenderer.h"
    #include "tlsmethodmodel.h"
    #include "audiosettingsmodel.h"
    #include "contactmodel.h"
    
    const TypedStateMachine< TypedStateMachine< Call::State , Call::Action> , Call::State> Call::actionPerformedStateMap =
    {{
    //                           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::TRANSFERRED  , 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::TRANSFERRED, Call::State::TRANSFERRED , Call::State::CURRENT      , Call::State::TRANSFERRED  ,  Call::State::TRANSFERRED  }},/**/
    /*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        }},/**/
    /*CONF         */  {{Call::State::ERROR      , Call::State::CURRENT     , Call::State::TRANSFERRED  , Call::State::CURRENT      ,  Call::State::CURRENT      }},/**/
    /*CONF_HOLD    */  {{Call::State::ERROR      , Call::State::HOLD        , Call::State::TRANSF_HOLD  , Call::State::HOLD         ,  Call::State::HOLD         }},/**/
    }};//                                                                                                                                                    
    
    
    const TypedStateMachine< TypedStateMachine< function , Call::Action > , Call::State > Call::actionPerformedFunctionMap =
    {{
    //                        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::transfer       , &Call::hold        ,  &Call::setRecord     }},/**/
    /*TRANSFERT_HOLD */  {{&Call::transfer   , &Call::hangUp   , &Call::transfer       , &Call::unhold      ,  &Call::setRecord     }},/**/
    /*OVER           */  {{&Call::nothing    , &Call::nothing  , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
    /*ERROR          */  {{&Call::nothing    , &Call::remove   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
    /*CONF           */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::hold        ,  &Call::setRecord     }},/**/
    /*CONF_HOLD      */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::unhold      ,  &Call::setRecord     }},/**/
    }};//                                                                                                                                 
    
    
    const TypedStateMachine< TypedStateMachine< Call::State , Call::DaemonState> , Call::State> Call::stateChangedStateMap =
    {{
    //                        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::TRANSFERRED , Call::State::TRANSFERRED, Call::State::BUSY   , Call::State::TRANSF_HOLD  ,  Call::State::OVER  ,  Call::State::FAILURE  }},/**/
    /*TRANSF_HOLD  */ {{Call::State::TRANSF_HOLD , Call::State::TRANSFERRED, 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    }},/**/
    /*CONF         */ {{Call::State::CURRENT     , Call::State::CURRENT    , Call::State::BUSY   , Call::State::HOLD         ,  Call::State::OVER  ,  Call::State::FAILURE  }},/**/
    /*CONF_HOLD    */ {{Call::State::HOLD        , Call::State::CURRENT    , Call::State::BUSY   , Call::State::HOLD         ,  Call::State::OVER  ,  Call::State::FAILURE  }},/**/
    }};//                                                                                                                                                             
    
    const TypedStateMachine< TypedStateMachine< function , Call::DaemonState > , Call::State > Call::stateChangedFunctionMap =
    {{ 
    //                      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::error      , &Call::error     , &Call::error          , &Call::error        ,  &Call::stop         , &Call::error   }},/**/
    /*CONF           */  {{&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing }},/**/
    /*CONF_HOLD      */  {{&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing }},/**/
    }};//                                                                                                                                                   
    
    QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::State& c)
    {
       dbg.nospace() << QString(Call::toHumanStateName(c));
       return dbg.space();
    }
    
    QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::DaemonState& c)
    {
       dbg.nospace() << static_cast<int>(c);
       return dbg.space();
    }
    
    QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::Action& c)
    {
       dbg.nospace() << static_cast<int>(c);
       return dbg.space();
    }
    
    ///Constructor
    Call::Call(Call::State startState, const QString& callId, const QString& peerName, PhoneNumber* number, Account* account)
       :  QObject(CallModel::instance()), m_isConference(false),m_pStopTimeStamp(0),
       m_pImModel(nullptr),m_pTimer(nullptr),m_Recording(false),m_Account(nullptr),
       m_PeerName(peerName),m_pPeerPhoneNumber(number),m_HistoryConst(HistoryTimeCategoryModel::HistoryConst::Never),
       m_CallId(callId),m_CurrentState(startState),m_pStartTimeStamp(0),m_pDialNumber(nullptr),m_pTransferNumber(nullptr),
       m_History(false),m_Missed(false),m_Direction(Call::Direction::OUTGOING),m_pBackend(nullptr)
    {
       m_Account = account;
       Q_ASSERT(!callId.isEmpty());
       setObjectName("Call:"+callId);
       changeCurrentState(startState);
       m_pUserActionModel = new UserActionModel(this);
    
       emit changed();
       emit changed(this);
    }
    
    ///Destructor
    Call::~Call()
    {
       if (m_pTimer) delete m_pTimer;
       this->disconnect();
       if ( m_pTransferNumber ) delete m_pTransferNumber;
       if ( m_pDialNumber     ) delete m_pDialNumber;
    }
    
    ///Constructor
    Call::Call(const QString& confId, const QString& account): QObject(CallModel::instance()),
       m_pStopTimeStamp(0),m_pStartTimeStamp(0),m_pImModel(nullptr),m_ConfId(confId),
       m_Account(AccountListModel::instance()->getAccountById(account)),m_CurrentState(Call::State::CONFERENCE),
       m_pTimer(nullptr), m_isConference(false),m_pPeerPhoneNumber(nullptr),m_pDialNumber(nullptr),m_pTransferNumber(nullptr),
       m_HistoryConst(HistoryTimeCategoryModel::HistoryConst::Never),m_History(false),m_Missed(false),
       m_Direction(Call::Direction::OUTGOING),m_pBackend(nullptr)
    {
       setObjectName("Conf:"+confId);
       m_isConference  = !m_ConfId.isEmpty();
       m_pUserActionModel = new UserActionModel(this);
    
       if (m_isConference) {
          time_t curTime;
          ::time(&curTime);
          setStartTimeStamp(curTime);
          m_pTimer = new QTimer(this);
          m_pTimer->setInterval(1000);
          connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated()));
          m_pTimer->start();
          CallManagerInterface& callManager = DBus::CallManager::instance();
          MapStringString        details    = callManager.getConferenceDetails(m_ConfId)  ;
          m_CurrentState = confStatetoCallState(details["CONF_STATE"]);
          emit stateChanged();
       }
    }
    
    /*****************************************************************************
     *                                                                           *
     *                               Call builder                                *
     *                                                                           *
     ****************************************************************************/
    
    ///Build a call from its ID
    Call* Call::buildExistingCall(const QString& callId)
    {
       CallManagerInterface& callManager = DBus::CallManager::instance();
       MapStringString       details     = callManager.getCallDetails(callId).value();
    
       //Too noisy
       //qDebug() << "Constructing existing call with details : " << details;
    
       const QString peerNumber  = details[ Call::DetailsMapFields::PEER_NUMBER ];
       const QString peerName    = details[ Call::DetailsMapFields::PEER_NAME   ];
       const QString account     = details[ Call::DetailsMapFields::ACCOUNT_ID  ];
       Call::State   startState  = startStateFromDaemonCallState(details[Call::DetailsMapFields::STATE], details[Call::DetailsMapFields::TYPE]);
       Account*      acc         = AccountListModel::instance()->getAccountById(account);
       PhoneNumber*  nb          = PhoneDirectoryModel::instance()->getNumber(peerNumber,acc);
       Call*         call        = new Call(startState, callId, peerName, nb, acc);
       call->m_Recording      = callManager.getIsRecording(callId);
       call->m_HistoryState   = historyStateFromType(details[Call::HistoryMapFields::STATE]);
    
       if (!details[ Call::DetailsMapFields::TIMESTAMP_START ].isEmpty())
          call->setStartTimeStamp(details[ Call::DetailsMapFields::TIMESTAMP_START ].toInt());
       else {
          time_t curTime;
          ::time(&curTime);
          call->setStartTimeStamp(curTime);
       }
    
    
       call->m_pTimer = new QTimer(CallModel::instance());
       call->m_pTimer->setInterval(1000);
       connect(call->m_pTimer,SIGNAL(timeout()),call,SLOT(updated()));
       call->m_pTimer->start();
    
       if (call->peerPhoneNumber()) {
          call->peerPhoneNumber()->addCall(call);
       }
    
       return call;
    } //buildExistingCall
    
    ///Build a call from a dialing call (a call that is about to exist)
    Call* Call::buildDialingCall(const QString& callId, const QString & peerName, Account* account)
    {
       Call* call = new Call(Call::State::DIALING, callId, peerName, nullptr, account);
       call->m_HistoryState = Call::LegacyHistoryState::NONE;
       call->m_Direction = Call::Direction::OUTGOING;
       if (AudioSettingsModel::instance()->isRoomToneEnabled()) {
          AudioSettingsModel::instance()->playRoomTone();
       }
       return call;
    }
    
    ///Build a call from a dbus event
    Call* Call::buildIncomingCall(const QString& callId)
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       MapStringString details = callManager.getCallDetails(callId).value();
    
       const QString from     = details[ Call::DetailsMapFields::PEER_NUMBER ];
       const QString account  = details[ Call::DetailsMapFields::ACCOUNT_ID  ];
       const QString peerName = details[ Call::DetailsMapFields::PEER_NAME   ];
       Account*      acc      = AccountListModel::instance()->getAccountById(account);
       PhoneNumber*  nb       = PhoneDirectoryModel::instance()->getNumber(from,acc);
       Call* call = new Call(Call::State::INCOMING, callId, peerName, nb, acc);
       call->m_HistoryState   = Call::LegacyHistoryState::MISSED;
       call->m_Direction      = Call::Direction::INCOMING;
       if (call->peerPhoneNumber()) {
          call->peerPhoneNumber()->addCall(call);
       }
       return call;
    } //buildIncomingCall
    
    ///Build a ringing call (from dbus)
    Call* Call::buildRingingCall(const QString & callId)
    {
       CallManagerInterface& callManager = DBus::CallManager::instance();
       MapStringString details = callManager.getCallDetails(callId).value();
    
       const QString from     = details[ Call::DetailsMapFields::PEER_NUMBER ];
       const QString account  = details[ Call::DetailsMapFields::ACCOUNT_ID  ];
       const QString peerName = details[ Call::DetailsMapFields::PEER_NAME   ];
       Account*      acc      = AccountListModel::instance()->getAccountById(account);
       PhoneNumber*  nb       = PhoneDirectoryModel::instance()->getNumber(from,acc);
    
       Call* call = new Call(Call::State::RINGING, callId, peerName, nb, acc);
       call->m_HistoryState = LegacyHistoryState::OUTGOING;
       call->m_Direction    = Call::Direction::OUTGOING;
    
       if (call->peerPhoneNumber()) {
          call->peerPhoneNumber()->addCall(call);
       }
       return call;
    } //buildRingingCall
    
    
    /*****************************************************************************
     *                                                                           *
     *                                  History                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Build a call that is already over
    Call* Call::buildHistoryCall(const QMap<QString,QString>& hc)
    {
       const QString& callId          = hc[ Call::HistoryMapFields::CALLID          ]          ;
       time_t         startTimeStamp  = hc[ Call::HistoryMapFields::TIMESTAMP_START ].toUInt() ;
       time_t         stopTimeStamp   = hc[ Call::HistoryMapFields::TIMESTAMP_STOP  ].toUInt() ;
       const QString& accId           = hc[ Call::HistoryMapFields::ACCOUNT_ID      ]          ;
       const QString& name            = hc[ Call::HistoryMapFields::DISPLAY_NAME    ]          ;
       const QString& number          = hc[ Call::HistoryMapFields::PEER_NUMBER     ]          ;
       const QString& type            = hc[ Call::HistoryMapFields::STATE           ]          ;
       const QString& direction       = hc[ Call::HistoryMapFields::DIRECTION       ]          ;
       const bool     missed          = hc[ Call::HistoryMapFields::MISSED          ] == "true";
    
       Account*      acc       = AccountListModel::instance()->getAccountById(accId);
       PhoneNumber*  nb        = PhoneDirectoryModel::instance()->getNumber(number,acc);
       Call*         call      = new Call(Call::State::OVER, callId, (name == "empty")?QString():name, nb, acc );
    
       call->m_pStopTimeStamp  = stopTimeStamp ;
       call->m_History         = true;
       call->setStartTimeStamp(startTimeStamp);
    
       call->m_HistoryState    = historyStateFromType(type);
       call->m_Account         = AccountListModel::instance()->getAccountById(accId);
    
       //BEGIN In ~2015, remove the old logic and clean this
       if (missed || call->m_HistoryState == Call::LegacyHistoryState::MISSED) {
          call->m_Missed = true;
          call->m_HistoryState = Call::LegacyHistoryState::MISSED;
       }
       if (!direction.isEmpty()) {
          if (direction == HistoryStateName::INCOMING) {
             call->m_Direction    = Call::Direction::INCOMING         ;
             call->m_HistoryState = Call::LegacyHistoryState::INCOMING;
          }
          else if (direction == HistoryStateName::OUTGOING) {
             call->m_Direction    = Call::Direction::OUTGOING         ;
             call->m_HistoryState = Call::LegacyHistoryState::OUTGOING;
          }
       }
       else if (call->m_HistoryState == Call::LegacyHistoryState::INCOMING)
          call->m_Direction    = Call::Direction::INCOMING            ;
       else if (call->m_HistoryState == Call::LegacyHistoryState::OUTGOING)
          call->m_Direction    = Call::Direction::OUTGOING            ;
       else //BUG Pick one, even if it is the wrong one
          call->m_Direction    = Call::Direction::OUTGOING            ;
       if (missed)
          call->m_HistoryState = Call::LegacyHistoryState::MISSED;
       //END
    
       call->setObjectName("History:"+call->m_CallId);
    
       if (call->peerPhoneNumber()) {
          call->peerPhoneNumber()->addCall(call);
          connect(call->peerPhoneNumber(),SIGNAL(presentChanged(bool)),call,SLOT(updated()));
       }
    
       return call;
    }
    
    ///Get the history state from the type (see Call.cpp header)
    Call::LegacyHistoryState Call::historyStateFromType(const QString& type)
    {
       if(type == Call::HistoryStateName::MISSED        )
          return Call::LegacyHistoryState::MISSED   ;
       else if(type == Call::HistoryStateName::OUTGOING )
          return Call::LegacyHistoryState::OUTGOING ;
       else if(type == Call::HistoryStateName::INCOMING )
          return Call::LegacyHistoryState::INCOMING ;
       return  Call::LegacyHistoryState::NONE       ;
    }
    
    ///Get the start sate from the daemon state
    Call::State Call::startStateFromDaemonCallState(const QString& daemonCallState, const QString& daemonCallType)
    {
       if(daemonCallState      == Call::DaemonStateInit::CURRENT  )
          return Call::State::CURRENT  ;
       else if(daemonCallState == Call::DaemonStateInit::HOLD     )
          return Call::State::HOLD     ;
       else if(daemonCallState == Call::DaemonStateInit::BUSY     )
          return Call::State::BUSY     ;
       else if(daemonCallState == Call::DaemonStateInit::INACTIVE && daemonCallType == Call::CallType::INCOMING )
          return Call::State::INCOMING ;
       else if(daemonCallState == Call::DaemonStateInit::INACTIVE && daemonCallType == Call::CallType::OUTGOING )
          return Call::State::RINGING  ;
       else if(daemonCallState == Call::DaemonStateInit::INCOMING )
          return Call::State::INCOMING ;
       else if(daemonCallState == Call::DaemonStateInit::RINGING  )
          return Call::State::RINGING  ;
       else
          return Call::State::FAILURE  ;
    } //getStartStateFromDaemonCallState
    
    
    /*****************************************************************************
     *                                                                           *
     *                                  Getters                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Transfer state from internal to daemon internal syntaz
    Call::DaemonState Call::toDaemonCallState(const QString& stateName)
    {
       if(stateName == Call::StateChange::HUNG_UP        )
          return Call::DaemonState::HUNG_UP ;
       if(stateName == Call::StateChange::RINGING        )
          return Call::DaemonState::RINGING ;
       if(stateName == Call::StateChange::CURRENT        )
          return Call::DaemonState::CURRENT ;
       if(stateName == Call::StateChange::UNHOLD_CURRENT )
          return Call::DaemonState::CURRENT ;
       if(stateName == Call::StateChange::HOLD           )
          return Call::DaemonState::HOLD    ;
       if(stateName == Call::StateChange::BUSY           )
          return Call::DaemonState::BUSY    ;
       if(stateName == Call::StateChange::FAILURE        )
          return Call::DaemonState::FAILURE ;
    
       qDebug() << "stateChanged signal received with unknown state.";
       return Call::DaemonState::FAILURE    ;
    } //toDaemonCallState
    
    ///Transform a conference call state to a proper call state
    Call::State Call::confStatetoCallState(const QString& stateName)
    {
       if      ( stateName == Call::ConferenceStateChange::HOLD   )
          return Call::State::CONFERENCE_HOLD;
       else if ( stateName == Call::ConferenceStateChange::ACTIVE )
          return Call::State::CONFERENCE;
       else
          return Call::State::ERROR; //Well, this may bug a little
    }
    
    ///Transform a backend state into a translated string
    const QString Call::toHumanStateName(const Call::State cur)
    {
       switch (cur) {
          case Call::State::INCOMING:
             return tr( "Ringing (in)"      );
             break;
          case Call::State::RINGING:
             return tr( "Ringing (out)"     );
             break;
          case Call::State::CURRENT:
             return tr( "Talking"           );
             break;
          case Call::State::DIALING:
             return tr( "Dialing"           );
             break;
          case Call::State::HOLD:
             return tr( "Hold"              );
             break;
          case Call::State::FAILURE:
             return tr( "Failed"            );
             break;
          case Call::State::BUSY:
             return tr( "Busy"              );
             break;
          case Call::State::TRANSFERRED:
             return tr( "Transfer"          );
             break;
          case Call::State::TRANSF_HOLD:
             return tr( "Transfer hold"     );
             break;
          case Call::State::OVER:
             return tr( "Over"              );
             break;
          case Call::State::ERROR:
             return tr( "Error"             );
             break;
          case Call::State::CONFERENCE:
             return tr( "Conference"        );
             break;
          case Call::State::CONFERENCE_HOLD:
             return tr( "Conference (hold)" );
          case Call::State::COUNT:
             return tr( "ERROR"             );
          default:
             return QString::number(static_cast<int>(cur));
       }
    }
    
    QString Call::toHumanStateName() const
    {
       return toHumanStateName(state());
    }
    
    ///Get the time (second from 1 jan 1970) when the call ended
    time_t Call::stopTimeStamp() const
    {
       return m_pStopTimeStamp;
    }
    
    ///Get the time (second from 1 jan 1970) when the call started
    time_t Call::startTimeStamp() const
    {
       return m_pStartTimeStamp;
    }
    
    ///Get the number where the call have been transferred
    const QString Call::transferNumber() const
    {
       return m_pTransferNumber?m_pTransferNumber->uri():QString();
    }
    
    ///Get the call / peer number
    const QString Call::dialNumber() const
    {
       if (m_CurrentState != Call::State::DIALING) return QString();
       if (!m_pDialNumber) {
          const_cast<Call*>(this)->m_pDialNumber = new TemporaryPhoneNumber();
       }
       return m_pDialNumber->uri();
    }
    
    ///Return the call id
    const QString Call::id() const
    {
       return m_CallId;
    }
    
    PhoneNumber* Call::peerPhoneNumber() const
    {
       if (m_CurrentState == Call::State::DIALING) {
          if (!m_pTransferNumber) {
             const_cast<Call*>(this)->m_pTransferNumber = new TemporaryPhoneNumber(m_pPeerPhoneNumber);
          }
          if (!m_pDialNumber)
             const_cast<Call*>(this)->m_pDialNumber = new TemporaryPhoneNumber(m_pPeerPhoneNumber);
          return m_pDialNumber;
       }
       return m_pPeerPhoneNumber?m_pPeerPhoneNumber:const_cast<PhoneNumber*>(PhoneNumber::BLANK());
    }
    
    ///Get the peer name
    const QString Call::peerName() const
    {
       return m_PeerName;
    }
    
    ///Generate the best possible peer name
    const QString Call::formattedName() const
    {
       if (isConference())
          return tr("Conference");
       else if (!peerPhoneNumber())
          return "Error";
       else if (peerPhoneNumber()->contact() && !peerPhoneNumber()->contact()->formattedName().isEmpty())
          return peerPhoneNumber()->contact()->formattedName();
       else if (!peerName().isEmpty())
          return m_PeerName;
       else if (peerPhoneNumber())
          return peerPhoneNumber()->uri();
       else
          return tr("Unknown");
    }
    
    ///If the call have a valid record
    bool Call::hasRecording() const
    {
       return !recordingPath().isEmpty() && QFile::exists(recordingPath());
    }
    
    ///Generate an human readable string from the difference between StartTimeStamp and StopTimeStamp (or 'now')
    QString Call::length() const
    {
       if (m_pStartTimeStamp == m_pStopTimeStamp) return QString(); //Invalid
       int nsec =0;
       if (m_pStopTimeStamp)
          nsec = stopTimeStamp() - startTimeStamp();//If the call is over
       else { //Time to now
          time_t curTime;
          ::time(&curTime);
          nsec = curTime - m_pStartTimeStamp;
       }
       if (nsec/3600)
          return QString("%1:%2:%3 ").arg((nsec%(3600*24))/3600).arg(((nsec%(3600*24))%3600)/60,2,10,QChar('0')).arg(((nsec%(3600*24))%3600)%60,2,10,QChar('0'));
       else
          return QString("%1:%2 ").arg(nsec/60,2,10,QChar('0')).arg(nsec%60,2,10,QChar('0'));
    }
    
    ///Is this call part of history
    bool Call::isHistory()
    {
       if (m_CurrentState == Call::State::OVER && !m_History)
          m_History = true;
       return m_History;
    }
    
    ///Is this call missed
    bool Call::isMissed() const
    {
       return m_Missed;
    }
    
    ///Is the call incoming or outgoing
    Call::Direction Call::direction() const
    {
       return m_Direction;
    }
    
    ///Return the backend used to serialize this call
    AbstractHistoryBackend* Call::backend() const
    {
       return m_pBackend;
    }
    
    
    ///Does this call currently has video
    bool Call::hasVideo() const
    {
       #ifdef ENABLE_VIDEO
       return VideoModel::instance()->getRenderer(this) != nullptr;
       #else
       return false;
       #endif
    }
    
    
    ///Get the current state
    Call::State Call::state() const
    {
       return m_CurrentState;
    }
    
    ///Get the call recording
    bool Call::isRecording() const
    {
       return m_Recording;
    }
    
    ///Get the call account id
    Account* Call::account() const
    {
       return m_Account;
    }
    
    ///Is this call a conference
    bool Call::isConference() const
    {
       return m_isConference;
    }
    
    ///Get the conference ID
    const QString Call::confId() const
    {
       return m_ConfId;
    }
    
    ///Get the recording path
    const QString Call::recordingPath() const
    {
       return m_RecordingPath;
    }
    
    ///Get the history state
    Call::LegacyHistoryState Call::historyState() const
    {
       return m_HistoryState;
    }
    
    ///This function could also be called mayBeSecure or haveChancesToBeEncryptedButWeCantTell.
    bool Call::isSecure() const
    {
    
       if (!m_Account) {
          qDebug() << "Account not set, can't check security";
          return false;
       }
       //BUG this doesn't work
       return m_Account && ((m_Account->isTlsEnable()) || (m_Account->tlsMethod() != TlsMethodModel::Type::DEFAULT));
    } //isSecure
    
    ///Return the renderer associated with this call or nullptr
    VideoRenderer* Call::videoRenderer() const
    {
       #ifdef ENABLE_VIDEO
       return VideoModel::instance()->getRenderer(this);
       #else
       return nullptr;
       #endif
    }
    
    
    /*****************************************************************************
     *                                                                           *
     *                                  Setters                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Set the transfer number
    void Call::setTransferNumber(const QString& number)
    {
       if (!m_pTransferNumber) {
          m_pTransferNumber = new TemporaryPhoneNumber();
       }
       m_pTransferNumber->setUri(number);
    }
    
    ///This call is a conference
    void Call::setConference(bool value)
    {
       m_isConference = value;
    }
    
    ///Set the call number
    void Call::setDialNumber(const QString& number)
    {
       //This is not supposed to happen, but this is not a serious issue if it does
       if (m_CurrentState != Call::State::DIALING) {
          qDebug() << "Trying to set a dial number to a non-dialing call, doing nothing";
          return;
       }
    
       if (!m_pDialNumber) {
          m_pDialNumber = new TemporaryPhoneNumber();
       }
    
       m_pDialNumber->setUri(number);
       emit dialNumberChanged(m_pDialNumber->uri());
       emit changed();
       emit changed(this);
    }
    
    ///Set the dial number from a full phone number
    void Call::setDialNumber(const PhoneNumber* number)
    {
       if (m_CurrentState == Call::State::DIALING && !m_pDialNumber) {
          m_pDialNumber = new TemporaryPhoneNumber(number);
       }
       if (m_pDialNumber)
          m_pDialNumber->setUri(number->uri());
       emit dialNumberChanged(m_pDialNumber->uri());
       emit changed();
       emit changed(this);
    }
    
    ///Set the conference ID
    void Call::setConfId(const QString& value)
    {
       m_ConfId = value;
    }
    
    ///Set the recording path
    void Call::setRecordingPath(const QString& path)
    {
       m_RecordingPath = path;
       if (!m_RecordingPath.isEmpty()) {
          CallManagerInterface & callManager = DBus::CallManager::instance();
          connect(&callManager,SIGNAL(recordPlaybackStopped(QString)), this, SLOT(stopPlayback(QString))  );
          connect(&callManager,SIGNAL(updatePlaybackScale(QString,int,int))  , this, SLOT(updatePlayback(QString,int,int)));
       }
    }
    
    ///Set peer name
    void Call::setPeerName(const QString& name)
    {
       m_PeerName = name;
    }
    
    ///Set the account (DIALING only, may be ignored)
    void Call::setAccount( Account* account)
    {
       if (state() == Call::State::DIALING)
          m_Account = account;
    }
    
    /// Set the backend to save this call to. It is currently impossible to migrate.
    void Call::setBackend(AbstractHistoryBackend* backend)
    {
       m_pBackend = backend;
    }
    
    /*****************************************************************************
     *                                                                           *
     *                                  Mutator                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///The call state just changed
    Call::State Call::stateChanged(const QString& newStateName)
    {
       Call::State previousState = m_CurrentState;
       if (!m_isConference) {
          Call::DaemonState dcs = toDaemonCallState(newStateName);
          if (dcs == Call::DaemonState::COUNT || m_CurrentState == Call::State::COUNT) {
             qDebug() << "Error: Invalid state change";
             return Call::State::FAILURE;
          }
    
          try {
             changeCurrentState(stateChangedStateMap[m_CurrentState][dcs]);
          }
          catch(Call::State& state) {
             qDebug() << "State change failed (stateChangedStateMap)" << state;
             m_CurrentState = Call::State::ERROR;
             emit stateChanged();
             emit changed();
             return m_CurrentState;
          }
          catch(Call::DaemonState& state) {
             qDebug() << "State change failed (stateChangedStateMap)" << state;
             m_CurrentState = Call::State::ERROR;
             emit stateChanged();
             emit changed();
             return m_CurrentState;
          }
          catch (...) {
             qDebug() << "State change failed (stateChangedStateMap) other";;
             m_CurrentState = Call::State::ERROR;
             emit stateChanged();
             emit changed();
             return m_CurrentState;
          }
    
          CallManagerInterface & callManager = DBus::CallManager::instance();
          MapStringString details = callManager.getCallDetails(m_CallId).value();
          if (details[Call::DetailsMapFields::PEER_NAME] != m_PeerName)
             m_PeerName = details[Call::DetailsMapFields::PEER_NAME];
    
          try {
             (this->*(stateChangedFunctionMap[previousState][dcs]))();
          }
          catch(Call::State& state) {
             qDebug() << "State change failed (stateChangedFunctionMap)" << state;
             m_CurrentState = Call::State::ERROR;
             emit stateChanged();
             emit changed();
             return m_CurrentState;
          }
          catch(Call::DaemonState& state) {
             qDebug() << "State change failed (stateChangedFunctionMap)" << state;
             m_CurrentState = Call::State::ERROR;
             emit stateChanged();
             emit changed();
             return m_CurrentState;
          }
          catch (...) {
             qDebug() << "State change failed (stateChangedFunctionMap) other";;
             m_CurrentState = Call::State::ERROR;
             emit stateChanged();
             emit changed();
             return m_CurrentState;
          }
       }
       else {
          //Until now, it does not worth using stateChangedStateMap, conferences are quite simple
          m_CurrentState = confStatetoCallState(newStateName);
          emit stateChanged();
       }
       if ((m_CurrentState == Call::State::HOLD || m_CurrentState == Call::State::CURRENT) && !m_pTimer) {
          m_pTimer = new QTimer(this);
          m_pTimer->setInterval(1000);
          connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated()));
          m_pTimer->start();
       }
       if (m_CurrentState != Call::State::DIALING && m_pDialNumber) {
          if (!m_pPeerPhoneNumber)
             m_pPeerPhoneNumber = PhoneDirectoryModel::instance()->fromTemporary(m_pDialNumber);
          delete m_pDialNumber;
          m_pDialNumber = nullptr;
       }
       emit changed();
       emit changed(this);
       qDebug() << "Calling stateChanged " << newStateName << " -> " << toDaemonCallState(newStateName) << " on call with state " << previousState << ". Become " << m_CurrentState;
       return m_CurrentState;
    } //stateChanged
    
    ///An account have been performed
    Call::State Call::performAction(Call::Action action)
    {
       const Call::State previousState = m_CurrentState;
       //update the state
       try {
          changeCurrentState(actionPerformedStateMap[previousState][action]);
       }
       catch(Call::State& state) {
          qDebug() << "State change failed (actionPerformedStateMap)" << state;
          m_CurrentState = Call::State::ERROR;
          emit stateChanged();
          emit changed();
          return Call::State::ERROR;
       }
       catch (...) {
          qDebug() << "State change failed (actionPerformedStateMap) other";;
          m_CurrentState = Call::State::ERROR;
          emit stateChanged();
          emit changed();
          return m_CurrentState;
       }
    
       //execute the action associated with this transition
       try {
          (this->*(actionPerformedFunctionMap[previousState][action]))();
       }
       catch(Call::State& state) {
          qDebug() << "State change failed (actionPerformedFunctionMap)" << state;
          m_CurrentState = Call::State::ERROR;
          emit stateChanged();
          emit changed();
          return Call::State::ERROR;
       }
       catch(Call::Action& action) {
          qDebug() << "State change failed (actionPerformedFunctionMap)" << action;
          m_CurrentState = Call::State::ERROR;
          emit stateChanged();
          emit changed();
          return Call::State::ERROR;
       }
       catch (...) {
          qDebug() << "State change failed (actionPerformedFunctionMap) other";;
          m_CurrentState = Call::State::ERROR;
          emit stateChanged();
          emit changed();
          return m_CurrentState;
       }
       qDebug() << "Calling action " << action << " on call with state " << previousState << ". Become " << m_CurrentState;
       return m_CurrentState;
    } //actionPerformed
    
    ///Change the state
    void Call::changeCurrentState(Call::State newState)
    {
       if (newState == Call::State::COUNT) {
          qDebug() << "Error: Call reach invalid state";
          m_CurrentState = Call::State::ERROR;
          throw newState;
       }
    
       m_CurrentState = newState;
    
       emit stateChanged();
       emit changed();
       emit changed(this);
    
       if (m_CurrentState == Call::State::OVER)
          emit isOver(this);
    }
    
    ///Set the start timestamp and update the cache
    void Call::setStartTimeStamp(time_t stamp)
    {
       m_pStartTimeStamp = stamp;
       //While the HistoryConst is not directly related to the call concept,
       //It is called to often to ignore
       m_HistoryConst = HistoryTimeCategoryModel::timeToHistoryConst(m_pStartTimeStamp);
    }
    
    ///Send a text message
    void Call::sendTextMessage(const QString& message)
    {
       CallManagerInterface& callManager = DBus::CallManager::instance();
       Q_NOREPLY callManager.sendTextMessage(isConference()?m_ConfId:m_CallId,message);
       if (!m_pImModel) {
          m_pImModel = InstantMessagingModelManager::instance()->getModel(this);
       }
       m_pImModel->addOutgoingMessage(message);
    }
    
    
    /*****************************************************************************
     *                                                                           *
     *                              Automate function                            *
     *                                                                           *
     ****************************************************************************/
    ///@warning DO NOT TOUCH THAT, THEY ARE CALLED FROM AN ARRAY, HIGH FRAGILITY
    
    ///Do nothing (literally)
    void Call::nothing()
    {
       //nop
    }
    
    void Call::error()
    {
       if (videoRenderer()) {
          //Well, in this case we have no choice, it still doesn't belong here
          videoRenderer()->stopRendering();
       }
       throw QString("There was an error handling your call, please restart SFLPhone.Is you encounter this problem often, \
       please open SFLPhone-KDE in a terminal and send this last 100 lines before this message in a bug report at \
       https://projects.savoirfairelinux.com/projects/sflphone/issues");
    }
    
    ///Accept the call
    void Call::accept()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Accepting call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       Q_NOREPLY callManager.accept(m_CallId);
       time_t curTime;
       ::time(&curTime);
       setStartTimeStamp(curTime);
       this->m_HistoryState = LegacyHistoryState::INCOMING;
       m_Direction = Call::Direction::INCOMING;
       if (!m_pTimer) {
          m_pTimer = new QTimer(this);
          m_pTimer->setInterval(1000);
          connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated()));
          m_pTimer->start();
       }
    }
    
    ///Refuse the call
    void Call::refuse()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Refusing call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       Q_NOREPLY callManager.refuse(m_CallId);
       time_t curTime;
       ::time(&curTime);
       setStartTimeStamp(curTime);
       this->m_HistoryState = Call::LegacyHistoryState::MISSED;
       m_Missed = true;
    }
    
    ///Accept the transfer
    void Call::acceptTransf()
    {
       if (!m_pTransferNumber) {
          qDebug() << "Trying to transfer to no one";
          return;
       }
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Accepting call and transferring it to number : " << m_pTransferNumber->uri() << ". callId : " << m_CallId  << "ConfId:" << m_ConfId;
       callManager.accept(m_CallId);
       Q_NOREPLY callManager.transfer(m_CallId, m_pTransferNumber->uri());
    }
    
    ///Put the call on hold
    void Call::acceptHold()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Accepting call and holding it. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       callManager.accept(m_CallId);
       Q_NOREPLY callManager.hold(m_CallId);
       this->m_HistoryState = LegacyHistoryState::INCOMING;
       m_Direction = Call::Direction::INCOMING;
    }
    
    ///Hang up
    void Call::hangUp()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       time_t curTime;
       ::time(&curTime);
       m_pStopTimeStamp = curTime;
       qDebug() << "Hanging up call. callId : " << m_CallId << "ConfId:" << m_ConfId;
       bool ret;
       if (videoRenderer()) { //TODO remove, cheap hack
          videoRenderer()->stopRendering();
       }
       if (!isConference())
          ret = callManager.hangUp(m_CallId);
       else
          ret = callManager.hangUpConference(m_ConfId);
       if (!ret) { //Can happen if the daemon crash and open again
          qDebug() << "Error: Invalid call, the daemon may have crashed";
          m_CurrentState = Call::State::OVER;
          emit stateChanged();
          emit changed();
          emit changed(this);
       }
       if (m_pTimer)
          m_pTimer->stop();
    }
    
    ///Remove the call without contacting the daemon
    void Call::remove()
    {
       m_CurrentState = Call::State::OVER;
       emit stateChanged();
       emit changed();
       emit changed(this);
    }
    
    ///Cancel this call
    void Call::cancel()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Canceling call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       emit dialNumberChanged(QString());
       Q_NOREPLY callManager.hangUp(m_CallId);
    }
    
    ///Put on hold
    void Call::hold()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Holding call. callId : " << m_CallId << "ConfId:" << m_ConfId;
       if (!isConference())
          Q_NOREPLY callManager.hold(m_CallId);
       else
          Q_NOREPLY callManager.holdConference(m_ConfId);
    }
    
    ///Start the call
    void Call::call()
    {
       CallManagerInterface& callManager = DBus::CallManager::instance();
       qDebug() << "account = " << m_Account;
       if(!m_Account) {
          qDebug() << "Account is not set, taking the first registered.";
          this->m_Account = AccountListModel::currentAccount();
       }
       //Calls to empty URI should not be allowed, sflphoned will go crazy
       if (m_pDialNumber->uri().isEmpty()) {
          qDebug() << "Trying to call an empty URI";
          m_CurrentState = Call::State::FAILURE;
          if (m_pDialNumber)
             emit dialNumberChanged(QString());
          setPeerName(tr("Failure"));
          emit stateChanged();
          emit changed();
          delete m_pDialNumber;
          m_pDialNumber = nullptr;
       }
       //Normal case
       else if(m_Account) {
          qDebug() << "Calling " << peerPhoneNumber()->uri() << " with account " << m_Account << ". callId : " << m_CallId  << "ConfId:" << m_ConfId;
          callManager.placeCall(m_Account->id(), m_CallId, m_pDialNumber->uri());
          this->m_pPeerPhoneNumber = PhoneDirectoryModel::instance()->getNumber(m_pDialNumber->uri(),account());
          if (ContactModel::instance()->hasBackends()) {
             if (peerPhoneNumber()->contact())
                m_PeerName = peerPhoneNumber()->contact()->formattedName();
          }
          connect(peerPhoneNumber(),SIGNAL(presentChanged(bool)),this,SLOT(updated()));
          time_t curTime;
          ::time(&curTime);
          setStartTimeStamp(curTime);
          this->m_HistoryState = LegacyHistoryState::OUTGOING;
          m_Direction = Call::Direction::OUTGOING;
          if (peerPhoneNumber()) {
             peerPhoneNumber()->addCall(this);
          }
          if (m_pDialNumber)
             emit dialNumberChanged(QString());
          delete m_pDialNumber;
          m_pDialNumber = nullptr;
       }
       else {
          qDebug() << "Trying to call " << (m_pTransferNumber?m_pTransferNumber->uri():"ERROR") 
             << " with no account registered . callId : " << m_CallId  << "ConfId:" << m_ConfId;
          this->m_HistoryState = LegacyHistoryState::NONE;
          throw tr("No account registered!");
       }
    }
    
    ///Trnasfer the call
    void Call::transfer()
    {
       if (m_pTransferNumber) {
          CallManagerInterface & callManager = DBus::CallManager::instance();
          qDebug() << "Transferring call to number : " << m_pTransferNumber->uri() << ". callId : " << m_CallId;
          Q_NOREPLY callManager.transfer(m_CallId, m_pTransferNumber->uri());
          time_t curTime;
          ::time(&curTime);
          m_pStopTimeStamp = curTime;
       }
    }
    
    ///Unhold the call
    void Call::unhold()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Unholding call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       if (!isConference())
          Q_NOREPLY callManager.unhold(m_CallId);
       else
          Q_NOREPLY callManager.unholdConference(m_ConfId);
    }
    
    ///Record the call
    void Call::setRecord()
    {
       CallManagerInterface & callManager = DBus::CallManager::instance();
       qDebug() << "Setting record " << !m_Recording << " for call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       callManager.toggleRecording((!m_isConference)?m_CallId:m_ConfId);
    }
    
    ///Start the timer
    void Call::start()
    {
       qDebug() << "Starting call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       time_t curTime;
       ::time(&curTime);
       emit changed();
       emit changed(this);
       if (m_pDialNumber) {
          if (!m_pPeerPhoneNumber)
             m_pPeerPhoneNumber = PhoneDirectoryModel::instance()->fromTemporary(m_pDialNumber);
          delete m_pDialNumber;
          m_pDialNumber = nullptr;
       }
       setStartTimeStamp(curTime);
    }
    
    ///Toggle the timer
    void Call::startStop()
    {
       qDebug() << "Starting and stoping call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       time_t curTime;
       ::time(&curTime);
       setStartTimeStamp(curTime);
       m_pStopTimeStamp  = curTime;
    }
    
    ///Stop the timer
    void Call::stop()
    {
       qDebug() << "Stoping call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       if (videoRenderer()) { //TODO remove, cheap hack
          videoRenderer()->stopRendering();
       }
       time_t curTime;
       ::time(&curTime);
       m_pStopTimeStamp = curTime;
    }
    
    ///Handle error instead of crashing
    void Call::startWeird()
    {
       qDebug() << "Starting call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
       time_t curTime;
       ::time(&curTime);
       setStartTimeStamp(curTime);
       qDebug() << "Warning : call " << m_CallId << " had an unexpected transition of state at its start.";
    }
    
    ///Print a warning
    void Call::warning()
    {
       qWarning() << "Warning : call " << m_CallId << " had an unexpected transition of state.(" << m_CurrentState << ")";
       switch (m_CurrentState) {
          case Call::State::FAILURE        :
          case Call::State::ERROR          :
          case Call::State::COUNT          :
             //If not stopped, then the counter will keep going
             //Getting here indicate something wrong happened
             //It can be normal, aka, an invalid URI such as '><'
             // or an SFLPhone-KDE bug
             stop();
             break;
          case Call::State::TRANSFERRED    :
          case Call::State::TRANSF_HOLD    :
          case Call::State::DIALING        :
          case Call::State::INCOMING       :
          case Call::State::RINGING        :
          case Call::State::CURRENT        :
          case Call::State::HOLD           :
          case Call::State::BUSY           :
          case Call::State::OVER           :
          case Call::State::CONFERENCE     :
          case Call::State::CONFERENCE_HOLD:
          default:
             break;
       }
    }
    
    /*****************************************************************************
     *                                                                           *
     *                             Keyboard handling                             *
     *                                                                           *
     ****************************************************************************/
    
    ///Input text on the call item
    void Call::appendText(const QString& str)
    {
       TemporaryPhoneNumber* editNumber = nullptr;
    
       switch (m_CurrentState) {
       case Call::State::TRANSFERRED :
       case Call::State::TRANSF_HOLD :
          editNumber = m_pTransferNumber;
          break;
       case Call::State::DIALING     :
          editNumber = m_pDialNumber;
          break;
       case Call::State::INCOMING:
       case Call::State::RINGING:
       case Call::State::CURRENT:
       case Call::State::HOLD:
       case Call::State::FAILURE:
       case Call::State::BUSY:
       case Call::State::OVER:
       case Call::State::ERROR:
       case Call::State::CONFERENCE:
       case Call::State::CONFERENCE_HOLD:
       case Call::State::COUNT:
       default:
          qDebug() << "Backspace on call not editable. Doing nothing.";
          return;
       }
    
       if (editNumber) {
          editNumber->setUri(editNumber->uri()+str);
          if (state() == Call::State::DIALING)
             emit dialNumberChanged(editNumber->uri());
       }
       else
          qDebug() << "TemporaryPhoneNumber not defined";
    
    
       emit changed();
       emit changed(this);
    }
    
    ///Remove the last character
    void Call::backspaceItemText()
    {
       TemporaryPhoneNumber* editNumber = nullptr;
    
       switch (m_CurrentState) {
          case Call::State::TRANSFERRED      :
          case Call::State::TRANSF_HOLD      :
             editNumber = m_pTransferNumber;
             break;
          case Call::State::DIALING          :
             editNumber = m_pDialNumber;
             break;
          case Call::State::INCOMING:
          case Call::State::RINGING:
          case Call::State::CURRENT:
          case Call::State::HOLD:
          case Call::State::FAILURE:
          case Call::State::BUSY:
          case Call::State::OVER:
          case Call::State::ERROR:
          case Call::State::CONFERENCE:
          case Call::State::CONFERENCE_HOLD:
          case Call::State::COUNT:
          default                          :
             qDebug() << "Backspace on call not editable. Doing nothing.";
             return;
       }
       if (editNumber) {
          QString text = editNumber->uri();
          const int textSize = text.size();
          if(textSize > 0) {
             editNumber->setUri(text.remove(textSize-1, 1));
             emit changed();
             emit changed(this);
          }
          else {
             changeCurrentState(Call::State::OVER);
          }
       }
       else
          qDebug() << "TemporaryPhoneNumber not defined";
    }
    
    ///Reset the string a dialing or transfer call
    void Call::reset()
    {
       TemporaryPhoneNumber* editNumber = nullptr;
    
       switch (m_CurrentState) {
          case Call::State::TRANSFERRED      :
          case Call::State::TRANSF_HOLD      :
             editNumber = m_pTransferNumber;
             break;
          case Call::State::DIALING          :
             editNumber = m_pDialNumber;
             break;
          case Call::State::INCOMING         :
          case Call::State::RINGING          :
          case Call::State::CURRENT          :
          case Call::State::HOLD             :
          case Call::State::FAILURE          :
          case Call::State::BUSY             :
          case Call::State::OVER             :
          case Call::State::ERROR            :
          case Call::State::CONFERENCE       :
          case Call::State::CONFERENCE_HOLD  :
          case Call::State::COUNT:
          default                            :
             qDebug() << "Cannot reset" << m_CurrentState << "calls";
             return;
       }
       if (editNumber) {
          editNumber->setUri(QString());
       }
    }
    
    /*****************************************************************************
     *                                                                           *
     *                                   SLOTS                                   *
     *                                                                           *
     ****************************************************************************/
    
    void Call::updated()
    {
       emit changed();
       emit changed(this);
    }
    
    ///Play the record, if any
    void Call::playRecording()
    {
       CallManagerInterface& callManager = DBus::CallManager::instance();
       const bool retval = callManager.startRecordedFilePlayback(recordingPath());
       if (retval)
          emit playbackStarted();
    }
    
    ///Stop the record, if any
    void Call::stopRecording()
    {
       CallManagerInterface& callManager = DBus::CallManager::instance();
       Q_NOREPLY callManager.stopRecordedFilePlayback(recordingPath());
       emit playbackStopped(); //TODO remove this, it is a workaround for bug #11942
    }
    
    ///seek the record, if any
    void Call::seekRecording(double position)
    {
       CallManagerInterface& callManager = DBus::CallManager::instance();
       Q_NOREPLY callManager.recordPlaybackSeek(position);
    }
    
    ///Daemon record playback stopped
    void Call::stopPlayback(const QString& filePath)
    {
       if (filePath == recordingPath()) {
          emit playbackStopped();
       }
    }
    
    ///Daemon playback position chnaged
    void Call::updatePlayback(const QString& path, int position,int size)
    {
       if (path == m_RecordingPath) {
          emit playbackPositionChanged(position,size);
       }
    }
    
    UserActionModel* Call::userActionModel() const
    {
       return m_pUserActionModel;
    }
    
    ///Common source for model data roles
    QVariant Call::roleData(int role) const
    {
       const Contact* ct = peerPhoneNumber()?peerPhoneNumber()->contact():nullptr;
       switch (role) {
          case Call::Role::Name:
          case Qt::DisplayRole:
             if (isConference())
                return tr("Conference");
             else if (state() == Call::State::DIALING)
                return dialNumber();
             else if (m_PeerName.isEmpty())
                return ct?ct->formattedName():peerPhoneNumber()?peerPhoneNumber()->uri():dialNumber();
             else
                return formattedName();
             break;
          case Qt::EditRole:
             return dialNumber();
          case Call::Role::Number:
             return peerPhoneNumber()->uri();
             break;
          case Call::Role::Direction2:
             return static_cast<int>(m_Direction);
             break;
          case Call::Role::Date:
             return (int)startTimeStamp();
             break;
          case Call::Role::Length:
             return length();
             break;
          case Call::Role::FormattedDate:
             return QDateTime::fromTime_t(startTimeStamp()).toString();
             break;
          case Call::Role::HasRecording:
             return hasRecording();
             break;
          case Call::Role::Historystate:
             return static_cast<int>(historyState());
             break;
          case Call::Role::Filter: {
             QString normStripppedC;
             foreach(QChar char2,QString(static_cast<int>(historyState())+'\n'+roleData(Call::Role::Name).toString()+'\n'+
                roleData(Call::Role::Number).toString()).toLower().normalized(QString::NormalizationForm_KD) ) {
                if (!char2.combiningClass())
                   normStripppedC += char2;
             }
             return normStripppedC;
             }
             break;
          case Call::Role::FuzzyDate:
             return (int)m_HistoryConst;
             break;
          case Call::Role::IsBookmark:
             return false;
             break;
          case Call::Role::Security:
             return isSecure();
             break;
          case Call::Role::Department:
             return ct?ct->department():QVariant();
             break;
          case Call::Role::Email:
             return ct?ct->preferredEmail():QVariant();
             break;
          case Call::Role::Organisation:
             return ct?ct->organization():QVariant();
             break;
          case Call::Role::IsConference:
             return isConference();
             break;
          case Call::Role::Object:
             return QVariant::fromValue(const_cast<Call*>(this));
             break;
          case Call::Role::PhoneNu:
             return QVariant::fromValue(const_cast<PhoneNumber*>(peerPhoneNumber()));
             break;
          case Call::Role::PhotoPtr:
             return QVariant::fromValue((void*)(ct?ct->photo():nullptr));
             break;
          case Call::Role::CallState:
             return static_cast<int>(state());
             break;
          case Call::Role::Id:
             return ((m_isConference)?confId():id());
             break;
          case Call::Role::StartTime:
             return (int) m_pStartTimeStamp;
          case Call::Role::StopTime:
             return (int) m_pStopTimeStamp;
          case Call::Role::IsRecording:
             return isRecording();
          case Call::Role::IsPresent:
             return peerPhoneNumber()->isPresent();
          case Call::Role::IsTracked:
             return peerPhoneNumber()->isTracked();
          case Call::Role::SupportPresence:
             return peerPhoneNumber()->supportPresence();
          case Call::Role::CategoryIcon:
             return peerPhoneNumber()->category()->icon(peerPhoneNumber()->isTracked(),peerPhoneNumber()->isPresent());
          case Call::Role::CallCount:
             return peerPhoneNumber()->callCount();
          case Call::Role::TotalSpentTime:
             return peerPhoneNumber()->totalSpentTime();
          case Call::Role::DropState:
             return property("dropState");
             break;
          case Call::Role::Missed:
             return m_Missed;
          case Call::Role::DTMFAnimState:
             return property("DTMFAnimState");
             break;
          case Call::Role::LastDTMFidx:
             return property("latestDtmfIdx");
             break;
          case Call::Role::DropPosition:
             return property("dropPosition");
             break;
          default:
             break;
       };
       return QVariant();
    }
    
    
    void Call::playDTMF(const QString& str)
    {
       Q_NOREPLY DBus::CallManager::instance().playDTMF(str);
       emit dtmfPlayed(str);
    }