managerimpl.cpp 114 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc.
3
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
jpbl's avatar
jpbl committed
4
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
5
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
6
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
7
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
8
 *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
jpbl's avatar
jpbl committed
9
10
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
12
 *  (at your option) any later version.
13
 *
jpbl's avatar
jpbl committed
14
15
16
17
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
18
 *
jpbl's avatar
jpbl committed
19
20
21
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23
24
25
26
27
28
29
30
31
32
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
jpbl's avatar
jpbl committed
33
34
 */

35
36
#include "config.h"

37
38
39
40
#include "managerimpl.h"

#include "account.h"
#include "dbus/callmanager.h"
41
#include "global.h"
42
#include "sip/sipaccount.h"
43

44
45
46
47
48
49
#include "audio/alsa/alsalayer.h"
#include "audio/pulseaudio/pulselayer.h"
#include "audio/sound/tonelist.h"
#include "history/historymanager.h"
#include "accountcreator.h" // create new account
#include "sip/sipvoiplink.h"
50
#include "iax/iaxvoiplink.h"
51
52
53
#include "manager.h"
#include "dbus/configurationmanager.h"

54
55
#include "conference.h"

56
57
#include <cerrno>
#include <ctime>
jpbl's avatar
jpbl committed
58
59
60
#include <cstdlib>
#include <iostream>
#include <fstream>
61
#include <sstream>
jpbl's avatar
jpbl committed
62
#include <sys/types.h> // mkdir(2)
63
#include <sys/stat.h>  // mkdir(2)
64

65
ManagerImpl::ManagerImpl (void) :
Alexandre Savard's avatar
Alexandre Savard committed
66
    _hasTriedToRegister (false), _config(), _currentCallId2(),
67
68
69
    _currentCallMutex(), _audiodriver (0),
    _dtmfKey (0), _audioCodecFactory(), _toneMutex(),
    _telephoneTone (0), _audiofile (0), _spkr_volume (0),
70
    _mic_volume (0), _waitingCall(),
Alexandre Savard's avatar
Alexandre Savard committed
71
    _waitingCallMutex(), _nbIncomingWaitingCall (0), _path (""),
72
    _setupLoaded (false), _callAccountMap(),
Alexandre Savard's avatar
Alexandre Savard committed
73
    _callAccountMapMutex(), _callConfigMap(), _accountMap(),
74
    _directIpAccount (0), _cleaner (new NumberCleaner),
75
76
    _history (new HistoryManager), _imModule(new sfl::InstantMessaging),
    parser_(0)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
77
{
78
79
    // initialize random generator for call id
    srand (time (NULL));
jpbl's avatar
jpbl committed
80
81
82
}

// never call if we use only the singleton...
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
83
84
ManagerImpl::~ManagerImpl (void)
{
85
    delete _imModule;
86
87
88
    delete _history;
    delete _cleaner;
	delete _audiofile;
jpbl's avatar
jpbl committed
89
90
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
91
92
void ManagerImpl::init ()
{
93
    // Load accounts, init map
Julien Bonjean's avatar
Julien Bonjean committed
94
    buildConfiguration();
95
96
97
    initVolume();
    initAudioDriver();
    selectAudioDriver();
98

99
100
    // Initialize the list of supported audio codecs
    initAudioCodec();
101

102
103
    audioLayerMutexLock();

104
    if (_audiodriver) {
105
        unsigned int sampleRate = _audiodriver->getSampleRate();
jpbl's avatar
jpbl committed
106

107
        _debugInit ("Manager: Load telephone tone");
108
        std::string country(preferences.getZoneToneChoice());
109
        _telephoneTone = new TelephoneTone (country, sampleRate);
110

111
112
113
114
        _debugInit ("Manager: Loading DTMF key (%d)", sampleRate);

        sampleRate = 8000;

115
116
        _dtmfKey = new DTMF (sampleRate);
    }
117

118
119
    audioLayerMutexUnlock();

120
    // Load the history
Julien Bonjean's avatar
Julien Bonjean committed
121
    _history->load_history (preferences.getHistoryLimit());
122
123
124

    // Init the instant messaging module
    _imModule->init();
125

126
127
    // Register accounts
    initRegisterAccounts(); //getEvents();
jpbl's avatar
jpbl committed
128
129
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
130
131
void ManagerImpl::terminate ()
{
132
    _debug ("Manager: Terminate ");
jpbl's avatar
jpbl committed
133

134
    std::vector<std::string> callList(getCallList());
135
136
137
138
139
140
141
142
    _debug ("Manager: Hangup %d remaining call", callList.size());
    std::vector<std::string>::iterator iter = callList.begin();

    while (iter != callList.end()) {
        hangupCall (*iter);
        iter++;
    }

143
    unloadAccountMap();
144

145
146
    _debug ("Manager: Unload DTMF key");
    delete _dtmfKey;
jpbl's avatar
jpbl committed
147

148
149
150
    _debug ("Manager: Unload telephone tone");
    delete _telephoneTone;
    _telephoneTone = NULL;
151

152
153
    audioLayerMutexLock();

154
155
156
    _debug ("Manager: Unload audio driver");
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
157

158
    _debug ("Manager: Unload audio codecs ");
159
    _audioCodecFactory.deleteHandlePointer();
160
    audioLayerMutexUnlock();
jpbl's avatar
jpbl committed
161
162
}

163
bool ManagerImpl::isCurrentCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
164
{
Rafaël Carré's avatar
Rafaël Carré committed
165
    return _currentCallId2 == callId;
jpbl's avatar
jpbl committed
166
167
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
168
169
bool ManagerImpl::hasCurrentCall ()
{
170
	return not _currentCallId2.empty();
jpbl's avatar
jpbl committed
171
172
}

173
const std::string&
174
ManagerImpl::getCurrentCallId () const
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
175
{
176
    return _currentCallId2;
jpbl's avatar
jpbl committed
177
178
}

179
void ManagerImpl::switchCall (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
180
{
181
182
183
    ost::MutexLock m (_currentCallMutex);
    _debug ("----- Switch current call id to %s -----", id.c_str());
    _currentCallId2 = id;
jpbl's avatar
jpbl committed
184
185
186
187
188
}

///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
189
/* Main Thread */
Emmanuel Milou's avatar
Emmanuel Milou committed
190

191
bool ManagerImpl::outgoingCall (const std::string& account_id,
192
                                const std::string& call_id, const std::string& to, const std::string& conf_id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
193
{
194
195
196
197

    std::string pattern, to_cleaned;
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
198

199
200
201
202
203
    if (call_id.empty()) {
        _debug ("Manager: New outgoing call abbort, missing callid");
        return false;
    }

204
    // Call ID must be unique
205
    if (not getAccountFromCall (call_id).empty()) {
206
207
208
209
        _error ("Manager: Error: Call id already exists in outgoing call");
        return false;
    }

210
    _debug ("Manager: New outgoing call %s to %s", call_id.c_str(), to.c_str());
211

212
213
    stopTone();

214
    std::string current_call_id(getCurrentCallId());
215

216
    if (hookPreference.getNumberEnabled())
Julien Bonjean's avatar
Julien Bonjean committed
217
        _cleaner->set_phone_number_prefix (hookPreference.getNumberAddPrefix());
218
    else
219
        _cleaner->set_phone_number_prefix ("");
220

221
    to_cleaned = _cleaner->clean (to);
Emmanuel Milou's avatar
Emmanuel Milou committed
222

223
    /* Check what kind of call we are dealing with */
224
    checkCallConfiguration (call_id, to_cleaned, &callConfig);
225

226
227
228
    // in any cases we have to detach from current communication
    if (hasCurrentCall()) {
        _debug ("Manager: Has current call (%s) put it onhold", current_call_id.c_str());
229

230
        // if this is not a conferenceand this and is not a conference participant
231
        if (!isConference (current_call_id) && !participToConference (current_call_id))
232
       	    onHoldCall (current_call_id);
233
        else if (isConference (current_call_id) && !participToConference (call_id))
234
            detachParticipant (Call::DEFAULT_ID, current_call_id);
235
    }
236

237
238
239
    if (callConfig == Call::IPtoIP) {
        _debug ("Manager: Start IP2IP call");
        /* We need to retrieve the sip voiplink instance */
240
        siplink = SIPVoIPLink::instance ();
241

242
        if (siplink->SIPNewIpToIpCall(call_id, to_cleaned)) {
243
244
            switchCall (call_id);
            return true;
245
        } else
246
            callFailure (call_id);
247

248
249
        return false;
    }
250

251
    _debug ("Manager: Selecting account %s", account_id.c_str());
252

253
    // Is this account exist
254
255
256
257
    if (!accountExists (account_id)) {
        _error ("Manager: Error: Account doesn't exist in new outgoing call");
        return false;
    }
258

259
260
261
    if(!associateCallToAccount (call_id, account_id)) {
    	_warn("Manager: Warning: Could not associate call id %s to account id %s", call_id.c_str(), account_id.c_str());
    }
262

263
    Call *call = NULL;
264
265
    try {
        call = getAccountLink(account_id)->newOutgoingCall (call_id, to_cleaned);
266

267
        switchCall (call_id);
268

269
        call->setConfId(conf_id);
270
    } catch (const VoipLinkException &e) {
271
        callFailure (call_id);
272
        _error ("Manager: %s", e.what());
273
        return false;
274
275
    }

Alexandre Savard's avatar
Alexandre Savard committed
276
277
    getMainBuffer()->stateInfo();

278
    return true;
jpbl's avatar
jpbl committed
279
280
}

yanmorin's avatar
   
yanmorin committed
281
//THREAD=Main : for outgoing Call
282
bool ManagerImpl::answerCall (const std::string& call_id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
283
{
284
    _debug ("Manager: Answer call %s", call_id.c_str());
285

286
    // If sflphone is ringing
287
    stopTone();
288

289
    // store the current call id
290
    std::string current_call_id(getCurrentCallId());
291

292
    // Retreive call coresponding to this id
293
    std::string account_id = getAccountFromCall (call_id);
294
    Call *call = getAccountLink (account_id)->getCall (call_id);
295
    if (call == NULL) {
296
        _error("Manager: Error: Call is null");
297
    }
298

299
300
    // in any cases we have to detach from current communication
    if (hasCurrentCall()) {
301

302
        _debug ("Manager: Currently conversing with %s", current_call_id.c_str());
303

304
305
306
        if (!isConference(current_call_id) && !participToConference (current_call_id)) {
            // if it is not a conference and is not a conference participant
            _debug ("Manager: Answer call: Put the current call (%s) on hold", current_call_id.c_str());
307
            onHoldCall (current_call_id);
308
309
310
        } else if (isConference (current_call_id) && !participToConference (call_id)) {
            // if we are talking to a conference and we are answering an incoming call
            _debug ("Manager: Detach main participant from conference");
311
            detachParticipant (Call::DEFAULT_ID, current_call_id);
312
313
        }
    }
314

315
316
317
318
319
320
    try {
        if (!getAccountLink (account_id)->answer (call_id)) {
            removeCallAccount (call_id);
            return false;
        }
    }
321
    catch (const VoipLinkException &e) {
322
    	_error("Manager: Error: %s", e.what());
323
    }
Alexandre Savard's avatar
Alexandre Savard committed
324

325
    // if it was waiting, it's waiting no more
326
    removeWaitingCall (call_id);
327

328
    // if we dragged this call into a conference already
329
    if (participToConference (call_id))
330
        switchCall (call->getConfId());
331
    else
332
        switchCall (call_id);
333

334
335
336
    // Connect streams
    addStream (call_id);

Alexandre Savard's avatar
Alexandre Savard committed
337
338
    getMainBuffer()->stateInfo();

339
    // Start recording if set in preference
340
    if (audioPreference.getIsAlwaysRecording())
341
342
343
    	setRecordingCall(call_id);

    // update call state on client side
344
    if (audioPreference.getIsAlwaysRecording())
345
        _dbus.getCallManager()->callStateChanged (call_id, "RECORD");
346
    else
347
    	_dbus.getCallManager()->callStateChanged(call_id, "CURRENT");
348

349
    return true;
jpbl's avatar
jpbl committed
350
351
}

yanmorin's avatar
   
yanmorin committed
352
//THREAD=Main
353
bool ManagerImpl::hangupCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
354
{
355
    bool returnValue = true;
356

357
358
    _info ("Manager: Hangup call %s", callId.c_str());

359
    // First stop audio layer if there is no call anymore
360
    if (getCallList().empty()) {
361
362
363

    	audioLayerMutexLock();

364
        if(_audiodriver == NULL) {
365
        	audioLayerMutexUnlock();
366
367
368
369
        	_error("Manager: Error: Audio layer was not instantiated");
        	return returnValue;
        }

370
        _debug ("Manager: stop audio stream, there is no call remaining");
371
        _audiodriver->stopStream();
372
        audioLayerMutexUnlock();
373
374
    }

375
    // store the current call id
376
    std::string currentCallId(getCurrentCallId());
yanmorin's avatar
   
yanmorin committed
377

378
    stopTone();
379

380
    /* Broadcast a signal over DBus */
381
    _debug ("Manager: Send DBUS call state change (HUNGUP) for id %s", callId.c_str());
382
    _dbus.getCallManager()->callStateChanged (callId, "HUNGUP");
383

384
    if (not isValidCall(callId) and not getConfigFromCall(callId) == Call::IPtoIP) {
385
    	_error("Manager: Error: Could not hang up call, call not valid");
386
        return false;
387
388
    }

389
390
391
    // Disconnect streams
    removeStream(callId);

392
    if (participToConference (callId)) {
393
    	Conference *conf = getConferenceFromCallID (callId);
394
395
        if (conf != NULL) {
            // remove this participant
396
397
            removeParticipant (callId);
            processRemainingParticipant (currentCallId, conf);
398
399
400
        }
    } else {
        // we are not participating to a conference, current call switched to ""
401
        if (!isConference (currentCallId))
402
403
            switchCall ("");
    }
404

405
406
    if (getConfigFromCall (callId) == Call::IPtoIP) {
        /* Direct IP to IP call */
407
        try {
408
            returnValue = SIPVoIPLink::instance()->hangup (callId);
409
410
411
412
413
414
        }
        catch (const VoipLinkException &e)
        {
            _error("%s", e.what());
            returnValue = 1;
        }
415
416
    }
    else {
417
    	std::string accountId (getAccountFromCall (callId));
418
419
        returnValue = getAccountLink (accountId)->hangup (callId);
        removeCallAccount (callId);
420
    }
421

Alexandre Savard's avatar
Alexandre Savard committed
422
423
    getMainBuffer()->stateInfo();

424
    return returnValue;
jpbl's avatar
jpbl committed
425
426
}

427
bool ManagerImpl::hangupConference (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
428
{
429
    _debug ("Manager: Hangup conference %s", id.c_str());
Alexandre Savard's avatar
Alexandre Savard committed
430

431
    ConferenceMap::iterator iter_conf = _conferencemap.find (id);
Alexandre Savard's avatar
Alexandre Savard committed
432

433
    std::string currentAccountId;
Alexandre Savard's avatar
Alexandre Savard committed
434

435
    if (iter_conf != _conferencemap.end()) {
436
        Conference *conf = iter_conf->second;
Alexandre Savard's avatar
Alexandre Savard committed
437

438
439
        ParticipantSet participants = conf->getParticipantList();
        ParticipantSet::iterator iter_participant = participants.begin();
Alexandre Savard's avatar
Alexandre Savard committed
440

441
        while (iter_participant != participants.end()) {
442
            _debug ("Manager: Hangup conference participant %s", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
443

444
            hangupCall (*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
445

446
447
448
            iter_participant++;
        }
    }
Alexandre Savard's avatar
Alexandre Savard committed
449

450
    switchCall ("");
451

Alexandre Savard's avatar
Alexandre Savard committed
452
    getMainBuffer()->stateInfo();
453

454
    return true;
Alexandre Savard's avatar
Alexandre Savard committed
455
456
}

yanmorin's avatar
   
yanmorin committed
457
//THREAD=Main
458
bool ManagerImpl::cancelCall (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
459
{
460
    std::string accountid;
461
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
462

463
    _debug ("Manager: Cancel call");
464

465
    stopTone();
466

467
    /* Direct IP to IP call */
468

469
470
    if (getConfigFromCall (id) == Call::IPtoIP)
        returnValue = SIPVoIPLink::instance()->cancel (id);
471
    else {
472
        /* Classic call, attached to an account */
473
        accountid = getAccountFromCall (id);
474

475
        if (accountid.empty()) {
476
477
478
            _debug ("! Manager Cancel Call: Call doesn't exists");
            return false;
        }
479

480
        returnValue = getAccountLink (accountid)->cancel (id);
481

482
483
        removeCallAccount (id);
    }
484

485
486
    // it could be a waiting call?
    removeWaitingCall (id);
487

488
    removeStream (id);
489

490
    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
491

Alexandre Savard's avatar
Alexandre Savard committed
492
493
    getMainBuffer()->stateInfo();

494
    return returnValue;
jpbl's avatar
jpbl committed
495
496
}

yanmorin's avatar
   
yanmorin committed
497
//THREAD=Main
498
bool ManagerImpl::onHoldCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
499
{
500
    bool returnValue = false;
yanmorin's avatar
   
yanmorin committed
501

502
    _debug ("Manager: Put call %s on hold", callId.c_str());
503

504
    stopTone();
505

506
    std::string current_call_id = getCurrentCallId();
507

508
    try {
509

510
511
    	if (getConfigFromCall (callId) == Call::IPtoIP) {
    		/* Direct IP to IP call */
512
    		returnValue = SIPVoIPLink::instance ()-> onhold (callId);
513
514
515
    	}
    	else {
    		/* Classic call, attached to an account */
516
            std::string account_id(getAccountFromCall (callId));
517

518
    		if (account_id == "") {
519
520
521
522
523
524
    			_debug ("Manager: Account ID %s or callid %s doesn't exists in call onHold", account_id.c_str(), callId.c_str());
    			return false;
    		}
    		returnValue = getAccountLink (account_id)->onhold (callId);
    	}
    }
525
    catch (const VoipLinkException &e){
526
    	_error("Manager: Error: %s", e.what());
527
    }
528

529
    // Unbind calls in main buffer
530
    removeStream (callId);
531

532
    // Remove call from teh queue if it was still there
533
    removeWaitingCall (callId);
534

535
    // keeps current call id if the action is not holding this call or a new outgoing call
536
    // this could happen in case of a conference
537
    if (current_call_id == callId)
538
        switchCall ("");
539

540
    _dbus.getCallManager()->callStateChanged (callId, "HOLD");
541

Alexandre Savard's avatar
Alexandre Savard committed
542
    getMainBuffer()->stateInfo();
543

544
    return returnValue;
yanmorin's avatar
   
yanmorin committed
545
546
547
}

//THREAD=Main
548
bool ManagerImpl::offHoldCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
549
{
550
    std::string accountId;
551
    bool returnValue = true;
552
    std::string codecName;
553

554
    _debug ("Manager: Put call %s off hold", callId.c_str());
555

556
    stopTone();
557

558
    std::string currentCallId = getCurrentCallId();
559

560
    //Place current call on hold if it isn't
561

562
    if (hasCurrentCall()) {
563

564
        // if this is not a conference and this and is not a conference participant
565
566
567
        if (!isConference (currentCallId) && !participToConference (currentCallId)) {
        	_debug ("Manager: Has current call (%s), put on hold", currentCallId.c_str());
            onHoldCall (currentCallId);
568
        } else if (isConference (currentCallId) && !participToConference (callId))
569
            detachParticipant (Call::DEFAULT_ID, currentCallId);
570
    }
alexandresavard's avatar
alexandresavard committed
571

572
573
    bool isRec = false;

574
    /* Direct IP to IP call */
575
    if (getConfigFromCall (callId) == Call::IPtoIP)
576
        returnValue = SIPVoIPLink::instance ()-> offhold (callId);
577
    else {
578
        /* Classic call, attached to an account */
579
        accountId = getAccountFromCall (callId);
580

581
        _debug ("Manager: Setting offhold, Account %s, callid %s", accountId.c_str(), callId.c_str());
582

583
584
585
586
587
588
        Call * call = getAccountLink (accountId)->getCall (callId);
        if (call)
        {
            isRec = call->isRecording();
            returnValue = getAccountLink (accountId)->offhold (callId);
        }
589
    }
590

591
    _dbus.getCallManager()->callStateChanged (callId, isRec ? "UNHOLD_RECORD" : "UNHOLD_CURRENT");
592
593

    if (participToConference (callId)) {
594
        std::string currentAccountId;
595

596
        currentAccountId = getAccountFromCall (callId);
597
        Call *call = getAccountLink (currentAccountId)->getCall (callId);
598

599
600
        if (call)
            switchCall (call->getConfId());
601

602
    } else
603
        switchCall (callId);
604

605
606
    addStream(callId);

Alexandre Savard's avatar
Alexandre Savard committed
607
608
    getMainBuffer()->stateInfo();

609
    return returnValue;
jpbl's avatar
jpbl committed
610
611
}

yanmorin's avatar
   
yanmorin committed
612
//THREAD=Main
613
bool ManagerImpl::transferCall (const std::string& callId, const std::string& to)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
614
{
615
    bool returnValue = false;;
616

617
618
    _info ("Manager: Transfer call %s", callId.c_str());

619
    std::string currentCallId = getCurrentCallId();
620

621
622
623
624
    if (participToConference(callId)) {
        Conference *conf = getConferenceFromCallID(callId);
        if (conf == NULL)
            _error("Manager: Error: Could not find conference from call id");
625

626
627
        removeParticipant (callId);
        processRemainingParticipant (callId, conf);
628
    }
629
    else if (!isConference(currentCallId))
630
            switchCall("");
631

632
    // Direct IP to IP call
633
    if (getConfigFromCall (callId) == Call::IPtoIP)
634
        returnValue = SIPVoIPLink::instance ()-> transfer (callId, to);
635
    else {
636
        std::string accountid (getAccountFromCall (callId));
637

638
        if (accountid == "") {
639
640
641
            _warn ("Manager: Call doesn't exists");
            return false;
        }
642

643
        returnValue = getAccountLink (accountid)->transfer (callId, to);
644
    }
645

646
    // remove waiting call in case we make transfer without even answer
647
    removeWaitingCall (callId);
648

Alexandre Savard's avatar
Alexandre Savard committed
649
650
    getMainBuffer()->stateInfo();

651
    return returnValue;
jpbl's avatar
jpbl committed
652
653
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
654
655
void ManagerImpl::transferFailed ()
{
656
	_dbus.getCallManager()->transferFailed();
657
658
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
659
660
void ManagerImpl::transferSucceded ()
{
661
	_dbus.getCallManager()->transferSucceded();
662
663
}

664
bool ManagerImpl::attendedTransfer(const std::string& transferID, const std::string& targetID)
665
{
666
    bool returnValue = false;
667

668
    _debug("Manager: Attended transfer");
669

670
    // Direct IP to IP call
671
    if (getConfigFromCall (transferID) == Call::IPtoIP)
672
        returnValue = SIPVoIPLink::instance ()-> attendedTransfer(transferID, targetID);
673
    else {	// Classic call, attached to an account
674

675
        std::string accountid = getAccountFromCall (transferID);
676

677
        if (accountid.empty()) {
678
            _warn ("Manager: Call doesn't exists");
679
            return false;
680
        }
681

682
683
        returnValue = getAccountLink (accountid)->attendedTransfer (transferID, targetID);
    }
684

685
    getMainBuffer()->stateInfo();
Alexandre Savard's avatar
Alexandre Savard committed
686

687
    return returnValue;