~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to kde/src/lib/call.cpp

  • Committer: Package Import Robot
  • Author(s): Francois Marier, Francois Marier, Mark Purcell
  • Date: 2014-10-18 15:08:50 UTC
  • mfrom: (1.1.12)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20141018150850-2exfk34ckb15pcwi
Tags: 1.4.1-0.1
[ Francois Marier ]
* Non-maintainer upload
* New upstream release (closes: #759576, #741130)
  - debian/rules +PJPROJECT_VERSION := 2.2.1
  - add upstream patch to fix broken TLS support
  - add patch to fix pjproject regression

[ Mark Purcell ]
* Build-Depends:
  - sflphone-daemon + libavformat-dev, libavcodec-dev, libswscale-dev,
  libavdevice-dev, libavutil-dev
  - sflphone-gnome + libclutter-gtk-1.0-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
//SFLPhone library
32
32
#include "dbus/callmanager.h"
33
33
#include "dbus/configurationmanager.h"
34
 
#include "abstractcontactbackend.h"
 
34
#include "abstractitembackend.h"
35
35
#include "contact.h"
 
36
#include "uri.h"
36
37
#include "account.h"
37
38
#include "accountlistmodel.h"
38
 
#include "videomodel.h"
 
39
#include "video/videomodel.h"
39
40
#include "historymodel.h"
40
41
#include "instantmessagingmodel.h"
41
42
#include "useractionmodel.h"
43
44
#include "numbercategory.h"
44
45
#include "phonedirectorymodel.h"
45
46
#include "phonenumber.h"
46
 
#include "videorenderer.h"
 
47
#include "video/videorenderer.h"
47
48
#include "tlsmethodmodel.h"
48
49
#include "audiosettingsmodel.h"
 
50
#include "contactmodel.h"
 
51
 
 
52
//Track where state changes are performed on finished (over, error, failed) calls
 
53
//while not really problematic, it is technically wrong
 
54
#define Q_ASSERT_IS_IN_PROGRESS Q_ASSERT(state() != Call::State::OVER);
 
55
#define FORCE_ERROR_STATE() {qDebug() << "Fatal error on " << this << __FILE__ << __LINE__;\
 
56
   changeCurrentState(Call::State::ERROR);}
49
57
 
50
58
const TypedStateMachine< TypedStateMachine< Call::State , Call::Action> , Call::State> Call::actionPerformedStateMap =
51
59
{{
52
 
//                           ACCEPT                   REFUSE                  TRANSFER                       HOLD                           RECORD              /**/
53
 
/*INCOMING     */  {{Call::State::INCOMING   , Call::State::INCOMING    , Call::State::ERROR        , Call::State::INCOMING     ,  Call::State::INCOMING     }},/**/
54
 
/*RINGING      */  {{Call::State::ERROR      , Call::State::RINGING     , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::RINGING      }},/**/
55
 
/*CURRENT      */  {{Call::State::ERROR      , Call::State::CURRENT     , Call::State::TRANSFERRED  , Call::State::CURRENT      ,  Call::State::CURRENT      }},/**/
56
 
/*DIALING      */  {{Call::State::DIALING    , Call::State::OVER        , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
57
 
/*HOLD         */  {{Call::State::ERROR      , Call::State::HOLD        , Call::State::TRANSF_HOLD  , Call::State::HOLD         ,  Call::State::HOLD         }},/**/
58
 
/*FAILURE      */  {{Call::State::ERROR      , Call::State::FAILURE     , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
59
 
/*BUSY         */  {{Call::State::ERROR      , Call::State::BUSY        , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
60
 
/*TRANSFER     */  {{Call::State::TRANSFERRED, Call::State::TRANSFERRED , Call::State::CURRENT      , Call::State::TRANSFERRED  ,  Call::State::TRANSFERRED  }},/**/
61
 
/*TRANSF_HOLD  */  {{Call::State::TRANSF_HOLD, Call::State::TRANSF_HOLD , Call::State::HOLD         , Call::State::TRANSF_HOLD  ,  Call::State::TRANSF_HOLD  }},/**/
62
 
/*OVER         */  {{Call::State::ERROR      , Call::State::ERROR       , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
63
 
/*ERROR        */  {{Call::State::ERROR      , Call::State::ERROR       , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
64
 
/*CONF         */  {{Call::State::ERROR      , Call::State::CURRENT     , Call::State::TRANSFERRED  , Call::State::CURRENT      ,  Call::State::CURRENT      }},/**/
65
 
/*CONF_HOLD    */  {{Call::State::ERROR      , Call::State::HOLD        , Call::State::TRANSF_HOLD  , Call::State::HOLD         ,  Call::State::HOLD         }},/**/
 
60
//                           ACCEPT                      REFUSE                  TRANSFER                       HOLD                           RECORD              /**/
 
61
/*INCOMING     */  {{Call::State::INCOMING      , Call::State::INCOMING    , Call::State::ERROR        , Call::State::INCOMING     ,  Call::State::INCOMING     }},/**/
 
62
/*RINGING      */  {{Call::State::ERROR         , Call::State::RINGING     , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::RINGING      }},/**/
 
63
/*CURRENT      */  {{Call::State::ERROR         , Call::State::CURRENT     , Call::State::TRANSFERRED  , Call::State::CURRENT      ,  Call::State::CURRENT      }},/**/
 
64
/*DIALING      */  {{Call::State::INITIALIZATION, Call::State::OVER        , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
 
65
/*HOLD         */  {{Call::State::ERROR         , Call::State::HOLD        , Call::State::TRANSF_HOLD  , Call::State::HOLD         ,  Call::State::HOLD         }},/**/
 
66
/*FAILURE      */  {{Call::State::ERROR         , Call::State::OVER        , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
 
67
/*BUSY         */  {{Call::State::ERROR         , Call::State::BUSY        , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
 
68
/*TRANSFER     */  {{Call::State::TRANSFERRED   , Call::State::TRANSFERRED , Call::State::CURRENT      , Call::State::TRANSFERRED  ,  Call::State::TRANSFERRED  }},/**/
 
69
/*TRANSF_HOLD  */  {{Call::State::TRANSF_HOLD   , Call::State::TRANSF_HOLD , Call::State::HOLD         , Call::State::TRANSF_HOLD  ,  Call::State::TRANSF_HOLD  }},/**/
 
70
/*OVER         */  {{Call::State::ERROR         , Call::State::ERROR       , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
 
71
/*ERROR        */  {{Call::State::ERROR         , Call::State::ERROR       , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
 
72
/*CONF         */  {{Call::State::ERROR         , Call::State::CURRENT     , Call::State::TRANSFERRED  , Call::State::CURRENT      ,  Call::State::CURRENT      }},/**/
 
73
/*CONF_HOLD    */  {{Call::State::ERROR         , Call::State::HOLD        , Call::State::TRANSF_HOLD  , Call::State::HOLD         ,  Call::State::HOLD         }},/**/
 
74
/*INIT         */  {{Call::State::INITIALIZATION, Call::State::OVER        , Call::State::ERROR        , Call::State::ERROR        ,  Call::State::ERROR        }},/**/
66
75
}};//                                                                                                                                                    
67
76
 
68
77
 
74
83
/*CURRENT        */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::hold        ,  &Call::setRecord     }},/**/
75
84
/*DIALING        */  {{&Call::call       , &Call::cancel   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
76
85
/*HOLD           */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::unhold      ,  &Call::setRecord     }},/**/
77
 
/*FAILURE        */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
 
86
/*FAILURE        */  {{&Call::nothing    , &Call::remove   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
78
87
/*BUSY           */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
79
88
/*TRANSFERT      */  {{&Call::transfer   , &Call::hangUp   , &Call::transfer       , &Call::hold        ,  &Call::setRecord     }},/**/
80
89
/*TRANSFERT_HOLD */  {{&Call::transfer   , &Call::hangUp   , &Call::transfer       , &Call::unhold      ,  &Call::setRecord     }},/**/
82
91
/*ERROR          */  {{&Call::nothing    , &Call::remove   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
83
92
/*CONF           */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::hold        ,  &Call::setRecord     }},/**/
84
93
/*CONF_HOLD      */  {{&Call::nothing    , &Call::hangUp   , &Call::nothing        , &Call::unhold      ,  &Call::setRecord     }},/**/
 
94
/*INITIALIZATION */  {{&Call::call       , &Call::cancel   , &Call::nothing        , &Call::nothing     ,  &Call::nothing       }},/**/
85
95
}};//                                                                                                                                 
86
96
 
87
97
 
101
111
/*ERROR        */ {{Call::State::ERROR       , Call::State::ERROR      , Call::State::ERROR  , Call::State::ERROR        ,  Call::State::ERROR ,  Call::State::ERROR    }},/**/
102
112
/*CONF         */ {{Call::State::CURRENT     , Call::State::CURRENT    , Call::State::BUSY   , Call::State::HOLD         ,  Call::State::OVER  ,  Call::State::FAILURE  }},/**/
103
113
/*CONF_HOLD    */ {{Call::State::HOLD        , Call::State::CURRENT    , Call::State::BUSY   , Call::State::HOLD         ,  Call::State::OVER  ,  Call::State::FAILURE  }},/**/
 
114
/*INIT         */ {{Call::State::RINGING     , Call::State::CURRENT    , Call::State::BUSY   , Call::State::HOLD         ,  Call::State::OVER  ,  Call::State::FAILURE  }},/**/
104
115
}};//                                                                                                                                                             
105
116
 
106
117
const TypedStateMachine< TypedStateMachine< function , Call::DaemonState > , Call::State > Call::stateChangedFunctionMap =
107
 
{{ 
 
118
{{
108
119
//                      RINGING                  CURRENT             BUSY              HOLD                    HUNGUP           FAILURE            /**/
109
 
/*INCOMING       */  {{&Call::nothing    , &Call::start     , &Call::startWeird     , &Call::startWeird   ,  &Call::startStop    , &Call::start   }},/**/
110
 
/*RINGING        */  {{&Call::nothing    , &Call::start     , &Call::start          , &Call::start        ,  &Call::startStop    , &Call::start   }},/**/
 
120
/*INCOMING       */  {{&Call::nothing    , &Call::start     , &Call::startWeird     , &Call::startWeird   ,  &Call::startStop    , &Call::failure }},/**/
 
121
/*RINGING        */  {{&Call::nothing    , &Call::start     , &Call::start          , &Call::start        ,  &Call::startStop    , &Call::failure }},/**/
111
122
/*CURRENT        */  {{&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing }},/**/
112
123
/*DIALING        */  {{&Call::nothing    , &Call::warning   , &Call::warning        , &Call::warning      ,  &Call::stop         , &Call::warning }},/**/
113
124
/*HOLD           */  {{&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing }},/**/
119
130
/*ERROR          */  {{&Call::error      , &Call::error     , &Call::error          , &Call::error        ,  &Call::stop         , &Call::error   }},/**/
120
131
/*CONF           */  {{&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing }},/**/
121
132
/*CONF_HOLD      */  {{&Call::nothing    , &Call::nothing   , &Call::warning        , &Call::nothing      ,  &Call::stop         , &Call::nothing }},/**/
 
133
/*INIT           */  {{&Call::nothing    , &Call::warning   , &Call::warning        , &Call::warning      ,  &Call::stop         , &Call::warning }},/**/
122
134
}};//                                                                                                                                                   
123
135
 
 
136
const TypedStateMachine< Call::LifeCycleState , Call::State > Call::metaStateMap =
 
137
{{
 
138
/*               *        Life cycle meta-state              **/
 
139
/*INCOMING       */   Call::LifeCycleState::INITIALIZATION ,/**/
 
140
/*RINGING        */   Call::LifeCycleState::INITIALIZATION ,/**/
 
141
/*CURRENT        */   Call::LifeCycleState::PROGRESS       ,/**/
 
142
/*DIALING        */   Call::LifeCycleState::INITIALIZATION ,/**/
 
143
/*HOLD           */   Call::LifeCycleState::PROGRESS       ,/**/
 
144
/*FAILURE        */   Call::LifeCycleState::FINISHED       ,/**/
 
145
/*BUSY           */   Call::LifeCycleState::FINISHED       ,/**/
 
146
/*TRANSFERT      */   Call::LifeCycleState::PROGRESS       ,/**/
 
147
/*TRANSFERT_HOLD */   Call::LifeCycleState::PROGRESS       ,/**/
 
148
/*OVER           */   Call::LifeCycleState::FINISHED       ,/**/
 
149
/*ERROR          */   Call::LifeCycleState::FINISHED       ,/**/
 
150
/*CONF           */   Call::LifeCycleState::PROGRESS       ,/**/
 
151
/*CONF_HOLD      */   Call::LifeCycleState::PROGRESS       ,/**/
 
152
/*INIT           */   Call::LifeCycleState::INITIALIZATION ,/**/
 
153
}};/*                                                        **/
 
154
 
 
155
const TypedStateMachine< TypedStateMachine< bool , Call::LifeCycleState > , Call::State > Call::metaStateTransitionValidationMap =
 
156
{{
 
157
/*               *     INITIALIZATION    PROGRESS      FINISHED   **/
 
158
/*INCOMING       */  {{     true     ,    false    ,    false }},/**/
 
159
/*RINGING        */  {{     true     ,    false    ,    false }},/**/
 
160
/*CURRENT        */  {{     true     ,    true     ,    false }},/**/
 
161
/*DIALING        */  {{     true     ,    false    ,    false }},/**/
 
162
/*HOLD           */  {{     true     ,    true     ,    false }},/**/
 
163
/*FAILURE        */  {{     true     ,    true     ,    false }},/**/
 
164
/*BUSY           */  {{     true     ,    false    ,    false }},/**/
 
165
/*TRANSFERT      */  {{     false    ,    true     ,    false }},/**/
 
166
/*TRANSFERT_HOLD */  {{     false    ,    true     ,    false }},/**/
 
167
/*OVER           */  {{     true     ,    true     ,    true  }},/**/
 
168
/*ERROR          */  {{     true     ,    true     ,    false }},/**/
 
169
/*CONF           */  {{     true     ,    false    ,    false }},/**/
 
170
/*CONF_HOLD      */  {{     true     ,    false    ,    false }},/**/
 
171
/*INIT           */  {{     true     ,    false    ,    false }},/**/
 
172
}};/*                                                             **/
 
173
/*^^ A call _can_ be created on hold (conference) and as over (peer hang up before pickup)
 
174
 the progress->failure one is an implementation bug*/
 
175
 
 
176
 
124
177
QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::State& c)
125
178
{
126
179
   dbg.nospace() << QString(Call::toHumanStateName(c));
135
188
 
136
189
QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::Action& c)
137
190
{
138
 
   dbg.nospace() << static_cast<int>(c);
 
191
   switch (c) {
 
192
      case Call::Action::ACCEPT:
 
193
         dbg.nospace() << "ACCEPT";
 
194
      case Call::Action::REFUSE:
 
195
         dbg.nospace() << "REFUSE";
 
196
      case Call::Action::TRANSFER:
 
197
         dbg.nospace() << "TRANSFER";
 
198
      case Call::Action::HOLD:
 
199
         dbg.nospace() << "HOLD";
 
200
      case Call::Action::RECORD:
 
201
         dbg.nospace() << "RECORD";
 
202
      case Call::Action::__COUNT:
 
203
         dbg.nospace() << "COUNT";
 
204
   };
 
205
   dbg.space();
 
206
   dbg.nospace() << '(' << static_cast<int>(c) << ')';
139
207
   return dbg.space();
140
208
}
141
209
 
142
 
AbstractContactBackend* Call::m_pContactBackend = nullptr;
143
 
Call*                   Call::m_sSelectedCall   = nullptr;
144
 
 
145
 
void Call::setContactBackend(AbstractContactBackend* be)
146
 
{
147
 
   m_pContactBackend = be;
148
 
}
149
 
 
150
 
AbstractContactBackend* Call::contactBackend ()
151
 
{
152
 
   return m_pContactBackend;
153
 
}
154
 
 
155
210
///Constructor
156
211
Call::Call(Call::State startState, const QString& callId, const QString& peerName, PhoneNumber* number, Account* account)
157
 
   :  QObject(CallModel::instance()), m_isConference(false),m_pStopTimeStamp(0),
 
212
   :  QObject(CallModel::instance()),m_pStopTimeStamp(0),
158
213
   m_pImModel(nullptr),m_pTimer(nullptr),m_Recording(false),m_Account(nullptr),
159
214
   m_PeerName(peerName),m_pPeerPhoneNumber(number),m_HistoryConst(HistoryTimeCategoryModel::HistoryConst::Never),
160
215
   m_CallId(callId),m_CurrentState(startState),m_pStartTimeStamp(0),m_pDialNumber(nullptr),m_pTransferNumber(nullptr),
161
 
   m_History(false),m_Missed(false),m_Direction(Call::Direction::OUTGOING)
 
216
   m_History(false),m_Missed(false),m_Direction(Call::Direction::OUTGOING),m_pBackend(nullptr),m_Type(Call::Type::CALL)
162
217
{
163
218
   m_Account = account;
164
219
   Q_ASSERT(!callId.isEmpty());
181
236
 
182
237
///Constructor
183
238
Call::Call(const QString& confId, const QString& account): QObject(CallModel::instance()),
184
 
   m_pStopTimeStamp(0),m_pStartTimeStamp(0),m_pImModel(nullptr),m_ConfId(confId),
 
239
   m_pStopTimeStamp(0),m_pStartTimeStamp(0),m_pImModel(nullptr),
185
240
   m_Account(AccountListModel::instance()->getAccountById(account)),m_CurrentState(Call::State::CONFERENCE),
186
 
   m_pTimer(nullptr), m_isConference(false),m_pPeerPhoneNumber(nullptr),m_pDialNumber(nullptr),m_pTransferNumber(nullptr),
 
241
   m_pTimer(nullptr),m_pPeerPhoneNumber(nullptr),m_pDialNumber(nullptr),m_pTransferNumber(nullptr),
187
242
   m_HistoryConst(HistoryTimeCategoryModel::HistoryConst::Never),m_History(false),m_Missed(false),
188
 
   m_Direction(Call::Direction::OUTGOING)
 
243
   m_Direction(Call::Direction::OUTGOING),m_pBackend(nullptr), m_CallId(confId),
 
244
   m_Type((!confId.isEmpty())?Call::Type::CONFERENCE:Call::Type::CALL)
189
245
{
190
246
   setObjectName("Conf:"+confId);
191
 
   m_isConference  = !m_ConfId.isEmpty();
192
247
   m_pUserActionModel = new UserActionModel(this);
193
248
 
194
 
   if (m_isConference) {
 
249
   if (type() == Call::Type::CONFERENCE) {
195
250
      time_t curTime;
196
251
      ::time(&curTime);
197
252
      setStartTimeStamp(curTime);
198
 
      m_pTimer = new QTimer(this);
199
 
      m_pTimer->setInterval(1000);
200
 
      connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated()));
201
 
      m_pTimer->start();
 
253
      initTimer();
202
254
      CallManagerInterface& callManager = DBus::CallManager::instance();
203
 
      MapStringString        details    = callManager.getConferenceDetails(m_ConfId)  ;
204
 
      m_CurrentState = confStatetoCallState(details["CONF_STATE"]);
 
255
      MapStringString        details    = callManager.getConferenceDetails(id())  ;
 
256
      m_CurrentState = confStatetoCallState(details[ConfDetailsMapFields::CONF_STATE]);
205
257
      emit stateChanged();
206
258
   }
207
259
}
213
265
 ****************************************************************************/
214
266
 
215
267
///Build a call from its ID
216
 
Call* Call::buildExistingCall(QString callId)
 
268
Call* Call::buildExistingCall(const QString& callId)
217
269
{
218
270
   CallManagerInterface& callManager = DBus::CallManager::instance();
219
271
   MapStringString       details     = callManager.getCallDetails(callId).value();
239
291
      call->setStartTimeStamp(curTime);
240
292
   }
241
293
 
242
 
 
243
 
   call->m_pTimer = new QTimer(CallModel::instance());
244
 
   call->m_pTimer->setInterval(1000);
245
 
   connect(call->m_pTimer,SIGNAL(timeout()),call,SLOT(updated()));
246
 
   call->m_pTimer->start();
 
294
   call->initTimer();
247
295
 
248
296
   if (call->peerPhoneNumber()) {
249
297
      call->peerPhoneNumber()->addCall(call);
261
309
   if (AudioSettingsModel::instance()->isRoomToneEnabled()) {
262
310
      AudioSettingsModel::instance()->playRoomTone();
263
311
   }
 
312
   qDebug() << "Created dialing call" << call;
264
313
   return call;
265
314
}
266
315
 
317
366
Call* Call::buildHistoryCall(const QMap<QString,QString>& hc)
318
367
{
319
368
   const QString& callId          = hc[ Call::HistoryMapFields::CALLID          ]          ;
320
 
   time_t         startTimeStamp  = hc[ Call::HistoryMapFields::TIMESTAMP_START ].toUInt() ;
321
 
   time_t         stopTimeStamp   = hc[ Call::HistoryMapFields::TIMESTAMP_STOP  ].toUInt() ;
322
 
   const QString& accId           = hc[ Call::HistoryMapFields::ACCOUNT_ID      ]          ;
323
369
   const QString& name            = hc[ Call::HistoryMapFields::DISPLAY_NAME    ]          ;
324
370
   const QString& number          = hc[ Call::HistoryMapFields::PEER_NUMBER     ]          ;
325
371
   const QString& type            = hc[ Call::HistoryMapFields::STATE           ]          ;
326
372
   const QString& direction       = hc[ Call::HistoryMapFields::DIRECTION       ]          ;
327
 
   const bool     missed          = hc[ Call::HistoryMapFields::MISSED          ] == "true";
 
373
   const bool     missed          = hc[ Call::HistoryMapFields::MISSED          ] == "1";
 
374
   time_t         startTimeStamp  = hc[ Call::HistoryMapFields::TIMESTAMP_START ].toUInt() ;
 
375
   time_t         stopTimeStamp   = hc[ Call::HistoryMapFields::TIMESTAMP_STOP  ].toUInt() ;
 
376
   QString accId                  = hc[ Call::HistoryMapFields::ACCOUNT_ID      ]          ;
 
377
 
 
378
   if (accId.isEmpty()) {
 
379
      qWarning() << "An history call has an invalid account identifier";
 
380
      accId = QString(Account::ProtocolName::IP2IP);
 
381
   }
 
382
 
 
383
   //Try to assiciate a contact now, the real contact object is probably not
 
384
   //loaded yet, but we can get a placeholder for now
 
385
//    const QString& contactUsed    = hc[ Call::HistoryMapFields::CONTACT_USED ]; //TODO
 
386
   const QString& contactUid     = hc[ Call::HistoryMapFields::CONTACT_UID  ];
 
387
 
 
388
   Contact* ct = nullptr;
 
389
   if (!hc[ Call::HistoryMapFields::CONTACT_UID].isEmpty())
 
390
      ct = ContactModel::instance()->getPlaceHolder(contactUid.toAscii());
328
391
 
329
392
   Account*      acc       = AccountListModel::instance()->getAccountById(accId);
330
 
   PhoneNumber*  nb        = PhoneDirectoryModel::instance()->getNumber(number,acc);
 
393
   PhoneNumber*  nb        = PhoneDirectoryModel::instance()->getNumber(number,ct,acc);
 
394
 
331
395
   Call*         call      = new Call(Call::State::OVER, callId, (name == "empty")?QString():name, nb, acc );
332
396
 
333
397
   call->m_pStopTimeStamp  = stopTimeStamp ;
334
398
   call->m_History         = true;
335
399
   call->setStartTimeStamp(startTimeStamp);
336
 
 
337
400
   call->m_HistoryState    = historyStateFromType(type);
338
401
   call->m_Account         = AccountListModel::instance()->getAccountById(accId);
339
402
 
356
419
      call->m_Direction    = Call::Direction::INCOMING            ;
357
420
   else if (call->m_HistoryState == Call::LegacyHistoryState::OUTGOING)
358
421
      call->m_Direction    = Call::Direction::OUTGOING            ;
359
 
   else //BUG Pick one, even if it is the wrong one
 
422
   else //Getting there is a bug. Pick one, even if it is the wrong one
360
423
      call->m_Direction    = Call::Direction::OUTGOING            ;
361
424
   if (missed)
362
425
      call->m_HistoryState = Call::LegacyHistoryState::MISSED;
366
429
 
367
430
   if (call->peerPhoneNumber()) {
368
431
      call->peerPhoneNumber()->addCall(call);
 
432
 
 
433
      //Reload the glow and number colors
369
434
      connect(call->peerPhoneNumber(),SIGNAL(presentChanged(bool)),call,SLOT(updated()));
 
435
 
 
436
      //Change the display name and picture
 
437
      connect(call->peerPhoneNumber(),SIGNAL(rebased(PhoneNumber*)),call,SLOT(updated()));
370
438
   }
371
439
 
372
440
   return call;
373
441
}
374
442
 
 
443
/// aCall << Call::Action::HOLD
 
444
Call* Call::operator<<( Call::Action& c)
 
445
{
 
446
   performAction(c);
 
447
   return this;
 
448
}
 
449
 
375
450
///Get the history state from the type (see Call.cpp header)
376
451
Call::LegacyHistoryState Call::historyStateFromType(const QString& type)
377
452
{
393
468
      return Call::State::HOLD     ;
394
469
   else if(daemonCallState == Call::DaemonStateInit::BUSY     )
395
470
      return Call::State::BUSY     ;
396
 
   else if(daemonCallState == Call::DaemonStateInit::INACTIVE && daemonCallType == Call::CallType::INCOMING )
 
471
   else if(daemonCallState == Call::DaemonStateInit::INACTIVE && daemonCallType == Call::CallDirection::INCOMING )
397
472
      return Call::State::INCOMING ;
398
 
   else if(daemonCallState == Call::DaemonStateInit::INACTIVE && daemonCallType == Call::CallType::OUTGOING )
 
473
   else if(daemonCallState == Call::DaemonStateInit::INACTIVE && daemonCallType == Call::CallDirection::OUTGOING )
399
474
      return Call::State::RINGING  ;
400
475
   else if(daemonCallState == Call::DaemonStateInit::INCOMING )
401
476
      return Call::State::INCOMING ;
487
562
         break;
488
563
      case Call::State::CONFERENCE_HOLD:
489
564
         return tr( "Conference (hold)" );
490
 
      case Call::State::COUNT:
 
565
      case Call::State::__COUNT:
491
566
         return tr( "ERROR"             );
 
567
      case Call::State::INITIALIZATION:
 
568
         return tr( "Initialization"    );
492
569
      default:
493
570
         return QString::number(static_cast<int>(cur));
494
571
   }
555
632
///Generate the best possible peer name
556
633
const QString Call::formattedName() const
557
634
{
558
 
   if (isConference())
 
635
   if (type() == Call::Type::CONFERENCE)
559
636
      return tr("Conference");
560
637
   else if (!peerPhoneNumber())
561
638
      return "Error";
596
673
///Is this call part of history
597
674
bool Call::isHistory()
598
675
{
599
 
   if (m_CurrentState == Call::State::OVER && !m_History)
 
676
   if (lifeCycleState() == Call::LifeCycleState::FINISHED && !m_History)
600
677
      m_History = true;
601
678
   return m_History;
602
679
}
604
681
///Is this call missed
605
682
bool Call::isMissed() const
606
683
{
607
 
   return m_Missed;
 
684
   return m_Missed || m_HistoryState == Call::LegacyHistoryState::MISSED;
608
685
}
609
686
 
610
687
///Is the call incoming or outgoing
613
690
   return m_Direction;
614
691
}
615
692
 
 
693
///Is the call a conference or something else
 
694
Call::Type Call::type() const
 
695
{
 
696
   return m_Type;
 
697
}
 
698
 
 
699
///Return the backend used to serialize this call
 
700
AbstractHistoryBackend* Call::backend() const
 
701
{
 
702
   return m_pBackend;
 
703
}
 
704
 
 
705
 
 
706
///Does this call currently has video
 
707
bool Call::hasVideo() const
 
708
{
 
709
   #ifdef ENABLE_VIDEO
 
710
   return VideoModel::instance()->getRenderer(this) != nullptr;
 
711
   #else
 
712
   return false;
 
713
   #endif
 
714
}
 
715
 
 
716
 
616
717
///Get the current state
617
718
Call::State Call::state() const
618
719
{
619
720
   return m_CurrentState;
620
721
}
621
722
 
 
723
///Translate the state into its life cycle equivalent
 
724
Call::LifeCycleState Call::lifeCycleState() const
 
725
{
 
726
   return metaStateMap[m_CurrentState];
 
727
}
 
728
 
622
729
///Get the call recording
623
730
bool Call::isRecording() const
624
731
{
631
738
   return m_Account;
632
739
}
633
740
 
634
 
///Is this call a conference
635
 
bool Call::isConference() const
636
 
{
637
 
   return m_isConference;
638
 
}
639
 
 
640
 
///Get the conference ID
641
 
const QString Call::confId() const
642
 
{
643
 
   return m_ConfId;
644
 
}
645
 
 
646
741
///Get the recording path
647
742
const QString Call::recordingPath() const
648
743
{
649
744
   return m_RecordingPath;
650
745
}
651
746
 
652
 
///Get the current codec
653
 
QString Call::currentCodecName() const
654
 
{
655
 
   CallManagerInterface& callManager = DBus::CallManager::instance();
656
 
   return callManager.getCurrentAudioCodecName(m_CallId);
657
 
}
658
 
 
659
747
///Get the history state
660
748
Call::LegacyHistoryState Call::historyState() const
661
749
{
671
759
      return false;
672
760
   }
673
761
   //BUG this doesn't work
674
 
   return m_Account && ((m_Account->isTlsEnable()) || (m_Account->tlsMethod() != TlsMethodModel::Type::DEFAULT));
 
762
   return m_Account && ((m_Account->isTlsEnabled()) || (m_Account->tlsMethod() != TlsMethodModel::Type::DEFAULT));
675
763
} //isSecure
676
764
 
677
765
///Return the renderer associated with this call or nullptr
700
788
   m_pTransferNumber->setUri(number);
701
789
}
702
790
 
703
 
///This call is a conference
704
 
void Call::setConference(bool value)
705
 
{
706
 
   m_isConference = value;
707
 
}
708
 
 
709
791
///Set the call number
710
792
void Call::setDialNumber(const QString& number)
711
793
{
731
813
   if (m_CurrentState == Call::State::DIALING && !m_pDialNumber) {
732
814
      m_pDialNumber = new TemporaryPhoneNumber(number);
733
815
   }
734
 
   if (m_pDialNumber)
 
816
   if (m_pDialNumber && number)
735
817
      m_pDialNumber->setUri(number->uri());
736
818
   emit dialNumberChanged(m_pDialNumber->uri());
737
819
   emit changed();
738
820
   emit changed(this);
739
821
}
740
822
 
741
 
///Set the conference ID
742
 
void Call::setConfId(const QString& value)
743
 
{
744
 
   m_ConfId = value;
745
 
}
746
 
 
747
823
///Set the recording path
748
824
void Call::setRecordingPath(const QString& path)
749
825
{
768
844
      m_Account = account;
769
845
}
770
846
 
 
847
/// Set the backend to save this call to. It is currently impossible to migrate.
 
848
void Call::setBackend(AbstractHistoryBackend* backend)
 
849
{
 
850
   m_pBackend = backend;
 
851
}
 
852
 
771
853
/*****************************************************************************
772
854
 *                                                                           *
773
855
 *                                  Mutator                                  *
774
856
 *                                                                           *
775
857
 ****************************************************************************/
776
858
 
777
 
///The call state just changed
 
859
///The call state just changed (by the daemon)
778
860
Call::State Call::stateChanged(const QString& newStateName)
779
861
{
780
 
   Call::State previousState = m_CurrentState;
781
 
   if (!m_isConference) {
 
862
   const Call::State previousState = m_CurrentState;
 
863
   if (type() != Call::Type::CONFERENCE) {
782
864
      Call::DaemonState dcs = toDaemonCallState(newStateName);
783
 
      if (dcs == Call::DaemonState::COUNT || m_CurrentState == Call::State::COUNT) {
 
865
      if (dcs == Call::DaemonState::__COUNT || m_CurrentState == Call::State::__COUNT) {
784
866
         qDebug() << "Error: Invalid state change";
785
867
         return Call::State::FAILURE;
786
868
      }
 
869
//       if (previousState == stateChangedStateMap[m_CurrentState][dcs]) {
 
870
// #ifndef NDEBUG
 
871
//          qDebug() << "Trying to change state with the same state" << previousState;
 
872
// #endif
 
873
//          return previousState;
 
874
//       }
787
875
 
788
876
      try {
 
877
         //Validate if the transition respect the expected life cycle
 
878
         if (!metaStateTransitionValidationMap[stateChangedStateMap[m_CurrentState][dcs]][lifeCycleState()]) {
 
879
            qWarning() << "Unexpected state transition from" << state() << "to" << stateChangedStateMap[m_CurrentState][dcs];
 
880
            Q_ASSERT(false);
 
881
         }
789
882
         changeCurrentState(stateChangedStateMap[m_CurrentState][dcs]);
790
883
      }
791
884
      catch(Call::State& state) {
792
885
         qDebug() << "State change failed (stateChangedStateMap)" << state;
793
 
         m_CurrentState = Call::State::ERROR;
794
 
         emit stateChanged();
795
 
         emit changed();
 
886
         FORCE_ERROR_STATE()
796
887
         return m_CurrentState;
797
888
      }
798
889
      catch(Call::DaemonState& state) {
799
890
         qDebug() << "State change failed (stateChangedStateMap)" << state;
800
 
         m_CurrentState = Call::State::ERROR;
801
 
         emit stateChanged();
802
 
         emit changed();
 
891
         FORCE_ERROR_STATE()
803
892
         return m_CurrentState;
804
893
      }
805
894
      catch (...) {
806
895
         qDebug() << "State change failed (stateChangedStateMap) other";;
807
 
         m_CurrentState = Call::State::ERROR;
808
 
         emit stateChanged();
809
 
         emit changed();
 
896
         FORCE_ERROR_STATE()
810
897
         return m_CurrentState;
811
898
      }
812
899
 
820
907
      }
821
908
      catch(Call::State& state) {
822
909
         qDebug() << "State change failed (stateChangedFunctionMap)" << state;
823
 
         m_CurrentState = Call::State::ERROR;
824
 
         emit stateChanged();
825
 
         emit changed();
 
910
         FORCE_ERROR_STATE()
826
911
         return m_CurrentState;
827
912
      }
828
913
      catch(Call::DaemonState& state) {
829
914
         qDebug() << "State change failed (stateChangedFunctionMap)" << state;
830
 
         m_CurrentState = Call::State::ERROR;
831
 
         emit stateChanged();
832
 
         emit changed();
 
915
         FORCE_ERROR_STATE()
833
916
         return m_CurrentState;
834
917
      }
835
918
      catch (...) {
836
919
         qDebug() << "State change failed (stateChangedFunctionMap) other";;
837
 
         m_CurrentState = Call::State::ERROR;
838
 
         emit stateChanged();
839
 
         emit changed();
 
920
         FORCE_ERROR_STATE()
840
921
         return m_CurrentState;
841
922
      }
842
923
   }
843
924
   else {
844
925
      //Until now, it does not worth using stateChangedStateMap, conferences are quite simple
845
 
      m_CurrentState = confStatetoCallState(newStateName);
 
926
      //update 2014: Umm... wrong
 
927
      m_CurrentState = confStatetoCallState(newStateName); //TODO don't do this
846
928
      emit stateChanged();
847
929
   }
848
 
   if ((m_CurrentState == Call::State::HOLD || m_CurrentState == Call::State::CURRENT) && !m_pTimer) {
849
 
      m_pTimer = new QTimer(this);
850
 
      m_pTimer->setInterval(1000);
851
 
      connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated()));
852
 
      m_pTimer->start();
853
 
   }
854
930
   if (m_CurrentState != Call::State::DIALING && m_pDialNumber) {
855
931
      if (!m_pPeerPhoneNumber)
856
932
         m_pPeerPhoneNumber = PhoneDirectoryModel::instance()->fromTemporary(m_pDialNumber);
867
943
Call::State Call::performAction(Call::Action action)
868
944
{
869
945
   const Call::State previousState = m_CurrentState;
 
946
 
 
947
//    if (actionPerformedStateMap[previousState][action] == previousState) {
 
948
// #ifndef NDEBUG
 
949
//       qDebug() << "Trying to change state with the same state" << previousState;
 
950
// #endif
 
951
//       return previousState;
 
952
//    }
 
953
 
870
954
   //update the state
871
955
   try {
872
956
      changeCurrentState(actionPerformedStateMap[previousState][action]);
873
957
   }
874
958
   catch(Call::State& state) {
875
959
      qDebug() << "State change failed (actionPerformedStateMap)" << state;
876
 
      m_CurrentState = Call::State::ERROR;
877
 
      emit stateChanged();
878
 
      emit changed();
 
960
      FORCE_ERROR_STATE()
879
961
      return Call::State::ERROR;
880
962
   }
881
963
   catch (...) {
882
964
      qDebug() << "State change failed (actionPerformedStateMap) other";;
883
 
      m_CurrentState = Call::State::ERROR;
884
 
      emit stateChanged();
885
 
      emit changed();
 
965
      FORCE_ERROR_STATE()
886
966
      return m_CurrentState;
887
967
   }
888
968
 
892
972
   }
893
973
   catch(Call::State& state) {
894
974
      qDebug() << "State change failed (actionPerformedFunctionMap)" << state;
895
 
      m_CurrentState = Call::State::ERROR;
896
 
      emit stateChanged();
897
 
      emit changed();
 
975
      FORCE_ERROR_STATE()
898
976
      return Call::State::ERROR;
899
977
   }
900
978
   catch(Call::Action& action) {
901
979
      qDebug() << "State change failed (actionPerformedFunctionMap)" << action;
902
 
      m_CurrentState = Call::State::ERROR;
903
 
      emit stateChanged();
904
 
      emit changed();
 
980
      FORCE_ERROR_STATE()
905
981
      return Call::State::ERROR;
906
982
   }
907
983
   catch (...) {
908
984
      qDebug() << "State change failed (actionPerformedFunctionMap) other";;
909
 
      m_CurrentState = Call::State::ERROR;
910
 
      emit stateChanged();
911
 
      emit changed();
 
985
      FORCE_ERROR_STATE()
912
986
      return m_CurrentState;
913
987
   }
914
 
   qDebug() << "Calling action " << action << " on call with state " << previousState << ". Become " << m_CurrentState;
 
988
   qDebug() << "Calling action " << action << " on " << id() << " with state " << previousState << ". Become " << m_CurrentState;
915
989
   return m_CurrentState;
916
990
} //actionPerformed
917
991
 
918
 
///Change the state
 
992
///Change the state, do not abuse of this, but it is necessary for error cases
919
993
void Call::changeCurrentState(Call::State newState)
920
994
{
921
 
   if (newState == Call::State::COUNT) {
 
995
   if (newState == Call::State::__COUNT) {
922
996
      qDebug() << "Error: Call reach invalid state";
923
 
      m_CurrentState = Call::State::ERROR;
 
997
      FORCE_ERROR_STATE()
924
998
      throw newState;
925
999
   }
926
1000
 
930
1004
   emit changed();
931
1005
   emit changed(this);
932
1006
 
933
 
   if (m_CurrentState == Call::State::OVER)
 
1007
   initTimer();
 
1008
 
 
1009
   if (lifeCycleState() == Call::LifeCycleState::FINISHED)
934
1010
      emit isOver(this);
935
1011
}
936
1012
 
944
1020
}
945
1021
 
946
1022
///Send a text message
947
 
void Call::sendTextMessage(QString message)
 
1023
void Call::sendTextMessage(const QString& message)
948
1024
{
949
1025
   CallManagerInterface& callManager = DBus::CallManager::instance();
950
 
   Q_NOREPLY callManager.sendTextMessage(isConference()?m_ConfId:m_CallId,message);
 
1026
   Q_NOREPLY callManager.sendTextMessage(m_CallId,message);
951
1027
   if (!m_pImModel) {
952
1028
      m_pImModel = InstantMessagingModelManager::instance()->getModel(this);
953
1029
   }
960
1036
 *                              Automate function                            *
961
1037
 *                                                                           *
962
1038
 ****************************************************************************/
963
 
///@warning DO NOT TOUCH THAT, THEY ARE CALLED FROM AN ARRAY, HIGH FRAGILITY
 
1039
///@warning DO NOT TOUCH THAT, THEY ARE CALLED FROM AN AUTOMATE, HIGH FRAGILITY
964
1040
 
965
1041
///Do nothing (literally)
966
1042
void Call::nothing()
979
1055
   https://projects.savoirfairelinux.com/projects/sflphone/issues");
980
1056
}
981
1057
 
 
1058
///Change history state to failure
 
1059
void Call::failure()
 
1060
{
 
1061
   m_Missed = true;
 
1062
   //This is how it always was done
 
1063
   //The main point is to leave the call in the CallList
 
1064
   start();
 
1065
}
 
1066
 
982
1067
///Accept the call
983
1068
void Call::accept()
984
1069
{
 
1070
   Q_ASSERT_IS_IN_PROGRESS
 
1071
 
985
1072
   CallManagerInterface & callManager = DBus::CallManager::instance();
986
 
   qDebug() << "Accepting call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1073
   qDebug() << "Accepting call. callId : " << m_CallId  << "ConfId:" << id();
987
1074
   Q_NOREPLY callManager.accept(m_CallId);
988
1075
   time_t curTime;
989
1076
   ::time(&curTime);
990
1077
   setStartTimeStamp(curTime);
991
1078
   this->m_HistoryState = LegacyHistoryState::INCOMING;
992
1079
   m_Direction = Call::Direction::INCOMING;
993
 
   if (!m_pTimer) {
994
 
      m_pTimer = new QTimer(this);
995
 
      m_pTimer->setInterval(1000);
996
 
      connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated()));
997
 
      m_pTimer->start();
998
 
   }
999
1080
}
1000
1081
 
1001
1082
///Refuse the call
1002
1083
void Call::refuse()
1003
1084
{
1004
1085
   CallManagerInterface & callManager = DBus::CallManager::instance();
1005
 
   qDebug() << "Refusing call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
1006
 
   Q_NOREPLY callManager.refuse(m_CallId);
 
1086
   qDebug() << "Refusing call. callId : " << m_CallId  << "ConfId:" << id();
 
1087
   const bool ret = callManager.refuse(m_CallId);
1007
1088
   time_t curTime;
1008
1089
   ::time(&curTime);
1009
1090
   setStartTimeStamp(curTime);
1010
1091
   this->m_HistoryState = Call::LegacyHistoryState::MISSED;
1011
1092
   m_Missed = true;
 
1093
 
 
1094
   //If the daemon crashed then re-spawned when a call is ringing, this happen.
 
1095
   if (!ret)
 
1096
      FORCE_ERROR_STATE()
1012
1097
}
1013
1098
 
1014
1099
///Accept the transfer
1015
1100
void Call::acceptTransf()
1016
1101
{
 
1102
   Q_ASSERT_IS_IN_PROGRESS
 
1103
 
1017
1104
   if (!m_pTransferNumber) {
1018
1105
      qDebug() << "Trying to transfer to no one";
1019
1106
      return;
1020
1107
   }
1021
1108
   CallManagerInterface & callManager = DBus::CallManager::instance();
1022
 
   qDebug() << "Accepting call and transferring it to number : " << m_pTransferNumber->uri() << ". callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1109
   qDebug() << "Accepting call and transferring it to number : " << m_pTransferNumber->uri() << ". callId : " << m_CallId  << "ConfId:" << id();
1023
1110
   callManager.accept(m_CallId);
1024
1111
   Q_NOREPLY callManager.transfer(m_CallId, m_pTransferNumber->uri());
1025
1112
}
1027
1114
///Put the call on hold
1028
1115
void Call::acceptHold()
1029
1116
{
 
1117
   Q_ASSERT_IS_IN_PROGRESS
 
1118
 
1030
1119
   CallManagerInterface & callManager = DBus::CallManager::instance();
1031
 
   qDebug() << "Accepting call and holding it. callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1120
   qDebug() << "Accepting call and holding it. callId : " << m_CallId  << "ConfId:" << id();
1032
1121
   callManager.accept(m_CallId);
1033
1122
   Q_NOREPLY callManager.hold(m_CallId);
1034
1123
   this->m_HistoryState = LegacyHistoryState::INCOMING;
1038
1127
///Hang up
1039
1128
void Call::hangUp()
1040
1129
{
 
1130
   Q_ASSERT_IS_IN_PROGRESS
 
1131
 
1041
1132
   CallManagerInterface & callManager = DBus::CallManager::instance();
1042
1133
   time_t curTime;
1043
1134
   ::time(&curTime);
1044
1135
   m_pStopTimeStamp = curTime;
1045
 
   qDebug() << "Hanging up call. callId : " << m_CallId << "ConfId:" << m_ConfId;
 
1136
   qDebug() << "Hanging up call. callId : " << m_CallId << "ConfId:" << id();
1046
1137
   bool ret;
1047
1138
   if (videoRenderer()) { //TODO remove, cheap hack
1048
1139
      videoRenderer()->stopRendering();
1049
1140
   }
1050
 
   if (!isConference())
 
1141
   if (type() != Call::Type::CONFERENCE)
1051
1142
      ret = callManager.hangUp(m_CallId);
1052
1143
   else
1053
 
      ret = callManager.hangUpConference(m_ConfId);
 
1144
      ret = callManager.hangUpConference(id());
1054
1145
   if (!ret) { //Can happen if the daemon crash and open again
1055
1146
      qDebug() << "Error: Invalid call, the daemon may have crashed";
1056
 
      m_CurrentState = Call::State::OVER;
1057
 
      emit stateChanged();
1058
 
      emit changed();
1059
 
      emit changed(this);
 
1147
      changeCurrentState(Call::State::OVER);
1060
1148
   }
1061
1149
   if (m_pTimer)
1062
1150
      m_pTimer->stop();
1065
1153
///Remove the call without contacting the daemon
1066
1154
void Call::remove()
1067
1155
{
1068
 
   m_CurrentState = Call::State::OVER;
 
1156
   if (lifeCycleState() != Call::LifeCycleState::FINISHED)
 
1157
      FORCE_ERROR_STATE()
 
1158
 
 
1159
   CallManagerInterface & callManager = DBus::CallManager::instance();
 
1160
 
 
1161
   //HACK Call hang up again to make sure the busytone stop, this should
 
1162
   //return true or false, both are valid, no point to check the result
 
1163
   if (type() != Call::Type::CONFERENCE)
 
1164
      callManager.hangUp(m_CallId);
 
1165
   else
 
1166
      callManager.hangUpConference(id());
 
1167
 
 
1168
   emit isOver(this);
1069
1169
   emit stateChanged();
1070
1170
   emit changed();
1071
1171
   emit changed(this);
1074
1174
///Cancel this call
1075
1175
void Call::cancel()
1076
1176
{
 
1177
   //This one can be over if the peer server failed to comply with the correct sequence
1077
1178
   CallManagerInterface & callManager = DBus::CallManager::instance();
1078
 
   qDebug() << "Canceling call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1179
   qDebug() << "Canceling call. callId : " << m_CallId  << "ConfId:" << id();
1079
1180
   emit dialNumberChanged(QString());
1080
 
   Q_NOREPLY callManager.hangUp(m_CallId);
 
1181
//    Q_NOREPLY callManager.hangUp(m_CallId);
 
1182
   if (!callManager.hangUp(m_CallId)) {
 
1183
      qWarning() << "HangUp failed, the call was probably already over";
 
1184
      changeCurrentState(Call::State::OVER);
 
1185
   }
1081
1186
}
1082
1187
 
1083
1188
///Put on hold
1084
1189
void Call::hold()
1085
1190
{
 
1191
   Q_ASSERT_IS_IN_PROGRESS
 
1192
 
1086
1193
   CallManagerInterface & callManager = DBus::CallManager::instance();
1087
 
   qDebug() << "Holding call. callId : " << m_CallId << "ConfId:" << m_ConfId;
1088
 
   if (!isConference())
 
1194
   qDebug() << "Holding call. callId : " << m_CallId << "ConfId:" << id();
 
1195
   if (type() != Call::Type::CONFERENCE)
1089
1196
      Q_NOREPLY callManager.hold(m_CallId);
1090
1197
   else
1091
 
      Q_NOREPLY callManager.holdConference(m_ConfId);
 
1198
      Q_NOREPLY callManager.holdConference(id());
1092
1199
}
1093
1200
 
1094
1201
///Start the call
1095
1202
void Call::call()
1096
1203
{
 
1204
   Q_ASSERT_IS_IN_PROGRESS
 
1205
 
1097
1206
   CallManagerInterface& callManager = DBus::CallManager::instance();
1098
1207
   qDebug() << "account = " << m_Account;
1099
1208
   if(!m_Account) {
1101
1210
      this->m_Account = AccountListModel::currentAccount();
1102
1211
   }
1103
1212
   //Calls to empty URI should not be allowed, sflphoned will go crazy
1104
 
   if (m_pDialNumber->uri().isEmpty()) {
 
1213
   if ((!m_pDialNumber) || m_pDialNumber->uri().isEmpty()) {
1105
1214
      qDebug() << "Trying to call an empty URI";
1106
 
      m_CurrentState = Call::State::FAILURE;
1107
 
      if (m_pDialNumber)
 
1215
      changeCurrentState(Call::State::FAILURE);
 
1216
      if (!m_pDialNumber) {
1108
1217
         emit dialNumberChanged(QString());
 
1218
      }
 
1219
      else {
 
1220
         delete m_pDialNumber;
 
1221
         m_pDialNumber = nullptr;
 
1222
      }
1109
1223
      setPeerName(tr("Failure"));
1110
1224
      emit stateChanged();
1111
1225
      emit changed();
1112
 
      delete m_pDialNumber;
1113
 
      m_pDialNumber = nullptr;
1114
1226
   }
1115
1227
   //Normal case
1116
1228
   else if(m_Account) {
1117
 
      qDebug() << "Calling " << peerPhoneNumber()->uri() << " with account " << m_Account << ". callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1229
      qDebug() << "Calling " << peerPhoneNumber()->uri() << " with account " << m_Account << ". callId : " << m_CallId  << "ConfId:" << id();
1118
1230
      callManager.placeCall(m_Account->id(), m_CallId, m_pDialNumber->uri());
1119
1231
      this->m_pPeerPhoneNumber = PhoneDirectoryModel::instance()->getNumber(m_pDialNumber->uri(),account());
1120
 
      if (m_pContactBackend) {
 
1232
      if (ContactModel::instance()->hasBackends()) {
1121
1233
         if (peerPhoneNumber()->contact())
1122
1234
            m_PeerName = peerPhoneNumber()->contact()->formattedName();
1123
1235
      }
1136
1248
      m_pDialNumber = nullptr;
1137
1249
   }
1138
1250
   else {
1139
 
      qDebug() << "Trying to call " << (m_pTransferNumber?m_pTransferNumber->uri():"ERROR") 
1140
 
         << " with no account registered . callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1251
      qDebug() << "Trying to call " << (m_pTransferNumber?QString(m_pTransferNumber->uri()):"ERROR") 
 
1252
         << " with no account registered . callId : " << m_CallId  << "ConfId:" << id();
1141
1253
      this->m_HistoryState = LegacyHistoryState::NONE;
1142
1254
      throw tr("No account registered!");
1143
1255
   }
1146
1258
///Trnasfer the call
1147
1259
void Call::transfer()
1148
1260
{
 
1261
   Q_ASSERT_IS_IN_PROGRESS
 
1262
 
1149
1263
   if (m_pTransferNumber) {
1150
1264
      CallManagerInterface & callManager = DBus::CallManager::instance();
1151
1265
      qDebug() << "Transferring call to number : " << m_pTransferNumber->uri() << ". callId : " << m_CallId;
1159
1273
///Unhold the call
1160
1274
void Call::unhold()
1161
1275
{
 
1276
   Q_ASSERT_IS_IN_PROGRESS
 
1277
 
1162
1278
   CallManagerInterface & callManager = DBus::CallManager::instance();
1163
 
   qDebug() << "Unholding call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
1164
 
   if (!isConference())
 
1279
   qDebug() << "Unholding call. callId : " << m_CallId  << "ConfId:" << id();
 
1280
   if (type() != Call::Type::CONFERENCE)
1165
1281
      Q_NOREPLY callManager.unhold(m_CallId);
1166
1282
   else
1167
 
      Q_NOREPLY callManager.unholdConference(m_ConfId);
 
1283
      Q_NOREPLY callManager.unholdConference(id());
1168
1284
}
1169
1285
 
1170
1286
///Record the call
1171
1287
void Call::setRecord()
1172
1288
{
1173
1289
   CallManagerInterface & callManager = DBus::CallManager::instance();
1174
 
   qDebug() << "Setting record " << !m_Recording << " for call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
1175
 
   callManager.toggleRecording((!m_isConference)?m_CallId:m_ConfId);
 
1290
   qDebug() << "Setting record " << !m_Recording << " for call. callId : " << m_CallId  << "ConfId:" << id();
 
1291
   callManager.toggleRecording(id());
1176
1292
}
1177
1293
 
1178
1294
///Start the timer
1179
1295
void Call::start()
1180
1296
{
1181
 
   qDebug() << "Starting call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1297
   qDebug() << "Starting call. callId : " << m_CallId  << "ConfId:" << id();
1182
1298
   time_t curTime;
1183
1299
   ::time(&curTime);
1184
1300
   emit changed();
1195
1311
///Toggle the timer
1196
1312
void Call::startStop()
1197
1313
{
1198
 
   qDebug() << "Starting and stoping call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1314
   qDebug() << "Starting and stoping call. callId : " << m_CallId  << "ConfId:" << id();
1199
1315
   time_t curTime;
1200
1316
   ::time(&curTime);
1201
1317
   setStartTimeStamp(curTime);
1205
1321
///Stop the timer
1206
1322
void Call::stop()
1207
1323
{
1208
 
   qDebug() << "Stoping call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1324
   qDebug() << "Stoping call. callId : " << m_CallId  << "ConfId:" << id();
1209
1325
   if (videoRenderer()) { //TODO remove, cheap hack
1210
1326
      videoRenderer()->stopRendering();
1211
1327
   }
1217
1333
///Handle error instead of crashing
1218
1334
void Call::startWeird()
1219
1335
{
1220
 
   qDebug() << "Starting call. callId : " << m_CallId  << "ConfId:" << m_ConfId;
 
1336
   qDebug() << "Starting call. callId : " << m_CallId  << "ConfId:" << id();
1221
1337
   time_t curTime;
1222
1338
   ::time(&curTime);
1223
1339
   setStartTimeStamp(curTime);
1231
1347
   switch (m_CurrentState) {
1232
1348
      case Call::State::FAILURE        :
1233
1349
      case Call::State::ERROR          :
1234
 
      case Call::State::COUNT          :
 
1350
      case Call::State::__COUNT          :
1235
1351
         //If not stopped, then the counter will keep going
1236
1352
         //Getting here indicate something wrong happened
1237
1353
         //It can be normal, aka, an invalid URI such as '><'
1241
1357
      case Call::State::TRANSFERRED    :
1242
1358
      case Call::State::TRANSF_HOLD    :
1243
1359
      case Call::State::DIALING        :
 
1360
      case Call::State::INITIALIZATION:
1244
1361
      case Call::State::INCOMING       :
1245
1362
      case Call::State::RINGING        :
1246
1363
      case Call::State::CURRENT        :
1273
1390
   case Call::State::DIALING     :
1274
1391
      editNumber = m_pDialNumber;
1275
1392
      break;
 
1393
   case Call::State::INITIALIZATION:
1276
1394
   case Call::State::INCOMING:
1277
1395
   case Call::State::RINGING:
1278
1396
   case Call::State::CURRENT:
1283
1401
   case Call::State::ERROR:
1284
1402
   case Call::State::CONFERENCE:
1285
1403
   case Call::State::CONFERENCE_HOLD:
1286
 
   case Call::State::COUNT:
 
1404
   case Call::State::__COUNT:
1287
1405
   default:
1288
1406
      qDebug() << "Backspace on call not editable. Doing nothing.";
1289
1407
      return;
1315
1433
      case Call::State::DIALING          :
1316
1434
         editNumber = m_pDialNumber;
1317
1435
         break;
 
1436
      case Call::State::INITIALIZATION:
1318
1437
      case Call::State::INCOMING:
1319
1438
      case Call::State::RINGING:
1320
1439
      case Call::State::CURRENT:
1325
1444
      case Call::State::ERROR:
1326
1445
      case Call::State::CONFERENCE:
1327
1446
      case Call::State::CONFERENCE_HOLD:
1328
 
      case Call::State::COUNT:
 
1447
      case Call::State::__COUNT:
1329
1448
      default                          :
1330
1449
         qDebug() << "Backspace on call not editable. Doing nothing.";
1331
1450
         return;
1359
1478
      case Call::State::DIALING          :
1360
1479
         editNumber = m_pDialNumber;
1361
1480
         break;
 
1481
      case Call::State::INITIALIZATION   :
1362
1482
      case Call::State::INCOMING         :
1363
1483
      case Call::State::RINGING          :
1364
1484
      case Call::State::CURRENT          :
1369
1489
      case Call::State::ERROR            :
1370
1490
      case Call::State::CONFERENCE       :
1371
1491
      case Call::State::CONFERENCE_HOLD  :
1372
 
      case Call::State::COUNT:
 
1492
      case Call::State::__COUNT:
1373
1493
      default                            :
1374
1494
         qDebug() << "Cannot reset" << m_CurrentState << "calls";
1375
1495
         return;
1436
1556
   return m_pUserActionModel;
1437
1557
}
1438
1558
 
 
1559
///Check if creating a timer is necessary
 
1560
void Call::initTimer()
 
1561
{
 
1562
   if (lifeCycleState() == Call::LifeCycleState::PROGRESS) {
 
1563
      if (!m_pTimer) {
 
1564
         m_pTimer = new QTimer(this);
 
1565
         m_pTimer->setInterval(1000);
 
1566
         connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated()));
 
1567
      }
 
1568
      if (!m_pTimer->isActive())
 
1569
         m_pTimer->start();
 
1570
   }
 
1571
   else if (m_pTimer && lifeCycleState() != Call::LifeCycleState::PROGRESS) {
 
1572
      m_pTimer->stop();
 
1573
      delete m_pTimer;
 
1574
      m_pTimer = nullptr;
 
1575
   }
 
1576
}
 
1577
 
1439
1578
///Common source for model data roles
1440
1579
QVariant Call::roleData(int role) const
1441
1580
{
1443
1582
   switch (role) {
1444
1583
      case Call::Role::Name:
1445
1584
      case Qt::DisplayRole:
1446
 
         if (isConference())
 
1585
         if (type() == Call::Type::CONFERENCE)
1447
1586
            return tr("Conference");
1448
1587
         else if (state() == Call::State::DIALING)
1449
1588
            return dialNumber();
1452
1591
         else
1453
1592
            return formattedName();
1454
1593
         break;
 
1594
      case Qt::ToolTipRole:
 
1595
         return tr("Account: ") + (account()?account()->alias():QString());
 
1596
         break;
1455
1597
      case Qt::EditRole:
1456
1598
         return dialNumber();
1457
1599
      case Call::Role::Number:
1458
1600
         return peerPhoneNumber()->uri();
1459
1601
         break;
1460
1602
      case Call::Role::Direction2:
1461
 
         return static_cast<int>(m_Direction);
 
1603
         return static_cast<int>(m_Direction); //TODO Qt5, use the Q_ENUM
1462
1604
         break;
1463
1605
      case Call::Role::Date:
1464
1606
         return (int)startTimeStamp();
1486
1628
         }
1487
1629
         break;
1488
1630
      case Call::Role::FuzzyDate:
1489
 
         return (int)m_HistoryConst;
 
1631
         return (int)m_HistoryConst; //TODO Qt5, use the Q_ENUM
1490
1632
         break;
1491
1633
      case Call::Role::IsBookmark:
1492
1634
         return false;
1503
1645
      case Call::Role::Organisation:
1504
1646
         return ct?ct->organization():QVariant();
1505
1647
         break;
1506
 
      case Call::Role::Codec:
1507
 
         return currentCodecName();
1508
 
         break;
1509
 
      case Call::Role::IsConference:
1510
 
         return isConference();
1511
 
         break;
1512
1648
      case Call::Role::Object:
1513
1649
         return QVariant::fromValue(const_cast<Call*>(this));
1514
1650
         break;
1519
1655
         return QVariant::fromValue((void*)(ct?ct->photo():nullptr));
1520
1656
         break;
1521
1657
      case Call::Role::CallState:
1522
 
         return static_cast<int>(state());
 
1658
         return static_cast<int>(state()); //TODO Qt5, use the Q_ENUM
1523
1659
         break;
1524
1660
      case Call::Role::Id:
1525
 
         return ((m_isConference)?confId():id());
 
1661
         return id();
1526
1662
         break;
1527
1663
      case Call::Role::StartTime:
1528
1664
         return (int) m_pStartTimeStamp;
1546
1682
         return property("dropState");
1547
1683
         break;
1548
1684
      case Call::Role::Missed:
1549
 
         return m_Missed;
 
1685
         return isMissed();
 
1686
      case Call::Role::CallLifeCycleState:
 
1687
         return static_cast<int>(lifeCycleState()); //TODO Qt5, use the Q_ENUM
1550
1688
      case Call::Role::DTMFAnimState:
1551
1689
         return property("DTMFAnimState");
1552
1690
         break;
1568
1706
   Q_NOREPLY DBus::CallManager::instance().playDTMF(str);
1569
1707
   emit dtmfPlayed(str);
1570
1708
}
 
1709
 
 
1710
#undef Q_ASSERT_IS_IN_PROGRESS
 
1711
#undef FORCE_ERROR_STATE