managerimpl.cpp 106 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
3
 *  Copyright (C) 2004-2007 Savoir-Faire Linux inc.
 *  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>
9
 *
jpbl's avatar
jpbl committed
10
11
 *  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
12
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
13
 *  (at your option) any later version.
14
 *
jpbl's avatar
jpbl committed
15
16
17
18
 *  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.
19
 *
jpbl's avatar
jpbl committed
20
21
22
23
24
25
26
27
28
29
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
30
#include <sstream>
jpbl's avatar
jpbl committed
31
32
33
34
35
36
37
38
#include <sys/types.h> // mkdir(2)
#include <sys/stat.h>	// mkdir(2)

#include <cc++/socket.h>   // why do I need this here?
#include <ccrtp/channel.h> // why do I need this here?
#include <ccrtp/rtp.h>     // why do I need this here?
#include <cc++/file.h>

39
40
#include "conference.h"

jpbl's avatar
jpbl committed
41
#include "manager.h"
42
#include "account.h"
43
#include "sipaccount.h"
jpbl's avatar
jpbl committed
44
#include "audio/audiolayer.h"
45
46
#include "audio/alsalayer.h"
#include "audio/pulselayer.h"
jpbl's avatar
jpbl committed
47
48
#include "audio/tonelist.h"

yanmorin's avatar
   
yanmorin committed
49
#include "accountcreator.h" // create new account
50
51
#include "sipvoiplink.h"

jpbl's avatar
jpbl committed
52
53
54
55
56
57
58
#include "user_cfg.h"

#define fill_config_str(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
#define fill_config_int(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))

59
ManagerImpl::ManagerImpl (void)
60
        : _hasTriedToRegister (false)
Yun Liu's avatar
Yun Liu committed
61
        , _config()
62
        , _currentCallId2()
63
        , _currentCallMutex()
64
65
66
        , _codecBuilder (NULL)
        , _audiodriver (NULL)
        , _dtmfKey (NULL)
Yun Liu's avatar
Yun Liu committed
67
        , _codecDescriptorMap()
68
        , _toneMutex()
69
        , _telephoneTone (NULL)
Yun Liu's avatar
Yun Liu committed
70
        , _audiofile()
71
72
        , _spkr_volume (0)
        , _mic_volume (0)
73
        , _mutex()
74
        , _dbus (NULL)
Yun Liu's avatar
Yun Liu committed
75
        , _waitingCall()
76
        , _waitingCallMutex()
77
78
79
80
        , _nbIncomingWaitingCall (0)
        , _path ("")
        , _exist (0)
        , _setupLoaded (false)
Yun Liu's avatar
Yun Liu committed
81
        , _firewallPort()
82
83
        , _firewallAddr ("")
        , _hasZeroconf (false)
Yun Liu's avatar
Yun Liu committed
84
        , _callAccountMap()
85
        , _callAccountMapMutex()
Emmanuel Milou's avatar
Emmanuel Milou committed
86
        , _callConfigMap()
Yun Liu's avatar
Yun Liu committed
87
        , _accountMap()
88
        , _cleaner (NULL)
89
        , _history (NULL)
jpbl's avatar
jpbl committed
90
{
91

92
    // initialize random generator for call id
93
    srand (time (NULL));
yanmorin's avatar
   
yanmorin committed
94

95
    _cleaner = new NumberCleaner ();
96
    _history = new HistoryManager ();
97

yanmorin's avatar
   
yanmorin committed
98
#ifdef TEST
99
100
101
102
    testAccountMap();
    loadAccountMap();
    testCallAccountMap();
    unloadAccountMap();
yanmorin's avatar
   
yanmorin committed
103
104
#endif

105
106
    // should be call before initConfigFile
    // loadAccountMap();, called in init() now.
jpbl's avatar
jpbl committed
107
108
109
}

// never call if we use only the singleton...
110
ManagerImpl::~ManagerImpl (void)
jpbl's avatar
jpbl committed
111
{
112
    // terminate();
113
114
115
    delete _cleaner;
    _cleaner=0;
    _debug ("%s stop correctly.\n", PROGNAME);
jpbl's avatar
jpbl committed
116
117
}

118
void
119
ManagerImpl::init()
jpbl's avatar
jpbl committed
120
{
121
122
    // Load accounts, init map
    loadAccountMap();
123

124
    initVolume();
125

126
    if (_exist == 0) {
127
        _debug ("Cannot create config file in your home directory\n");
128
    }
129

130
    initAudioDriver();
131

132
    selectAudioDriver();
jpbl's avatar
jpbl committed
133

134
135
    // Initialize the list of supported audio codecs
    initAudioCodec();
136

137
    AudioLayer *audiolayer = getAudioDriver();
138

139
    if (audiolayer != 0) {
140
        unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
141

142
143
144
        _debugInit ("Load Telephone Tone");
        std::string country = getConfigString (PREFERENCES, ZONE_TONE);
        _telephoneTone = new TelephoneTone (country, sampleRate);
jpbl's avatar
jpbl committed
145

146
147
        _debugInit ("Loading DTMF key");
        _dtmfKey = new DTMF (sampleRate);
148
    }
149
150

    if (audiolayer == 0)
151
        audiolayer->stopStream();
152
153
154


    // Load the history
155
    _history->load_history (getConfigInt (PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
156
157
158
159
}

void ManagerImpl::terminate()
{
160
    _debug ("ManagerImpl::terminate \n");
161
    saveConfig();
jpbl's avatar
jpbl committed
162

163
    unloadAccountMap();
164

165
    _debug ("Unload DTMF Key \n");
166
    delete _dtmfKey;
jpbl's avatar
jpbl committed
167

168
169
170
    _debug ("Unload Audio Driver \n");
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
171

172
173
174
    _debug ("Unload Telephone Tone \n");
    delete _telephoneTone;
    _telephoneTone = NULL;
175

176
    _debug ("Unload Audio Codecs \n");
177
    _codecDescriptorMap.deleteHandlePointer();
178

jpbl's avatar
jpbl committed
179
180
}

yanmorin's avatar
   
yanmorin committed
181
bool
182
183
184
ManagerImpl::isCurrentCall (const CallID& callId)
{
    return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
185
186
}

yanmorin's avatar
   
yanmorin committed
187
bool
188
189
ManagerImpl::hasCurrentCall()
{
190
    _debug ("ManagerImpl::hasCurrentCall current call ID = %s\n", _currentCallId2.c_str());
191
192
193
194
195
196

    if (_currentCallId2 != "") {
        return true;
    }

    return false;
jpbl's avatar
jpbl committed
197
198
}

199
const CallID&
200
201
202
ManagerImpl::getCurrentCallId()
{
    return _currentCallId2;
jpbl's avatar
jpbl committed
203
204
205
}

void
206
207
208
ManagerImpl::switchCall (const CallID& id)
{
    ost::MutexLock m (_currentCallMutex);
209
    _debug("------------------------- SWITCH %s ---------------------------\n", id.c_str());
210
    _currentCallId2 = id;
211

212
213
    /*
    AudioLayer *al = getAudioDriver();
214

215
    if (id != "") {
216

217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
	if(isConference(id)) {

	    Conference *conf;

	    ConferenceMap::iterator iter = _conferencemap.find(id);
	    if(iter != _conferencemap.end())
	    {
		_debug("    set call recordable in audio layer\n");
		conf = iter->second;
		al->setRecorderInstance((Recordable*)conf);
	    }
	}
	else {

	    // set the recordable instance in audiolayer
	    AccountID account_id = getAccountFromCall(id);
	

	    Call *call = NULL;
	    call = getAccountLink (account_id)->getCall(id);

	    _debug("    set call recordable in audio layer\n");
	    al->setRecorderInstance((Recordable*)call);
	}
    }
    */
jpbl's avatar
jpbl committed
243
244
245
246
247
248
}


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

251
bool
252
ManagerImpl::outgoingCall (const std::string& account_id, const CallID& call_id, const std::string& to)
yanmorin's avatar
   
yanmorin committed
253
{
254
    std::string pattern, to_cleaned;
Emmanuel Milou's avatar
Emmanuel Milou committed
255
256
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
257

258
259
260
    _debug ("ManagerImpl::outgoingCall(%s)\n", call_id.c_str());

    CallID current_call_id = getCurrentCallId();
261

262
263
    if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) ==  "1")
        _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX));
264
265
    else
        _cleaner->set_phone_number_prefix ("");
266

267
    to_cleaned = _cleaner->clean (to);
Emmanuel Milou's avatar
Emmanuel Milou committed
268
269

    /* Check what kind of call we are dealing with */
270
    check_call_configuration (call_id, to_cleaned, &callConfig);
271

272
    // in any cases we have to detach from current communication
273
274
    if (hasCurrentCall()) {
	
275
276
	_debug ("    outgoingCall: Has current call (%s) put it onhold\n", current_call_id.c_str());

277
	// if this is not a conferenceand this and is not a conference participant
278
	if (!isConference(current_call_id) && !participToConference(current_call_id))
279
	{
280
281
	    _debug ("    outgoingCall: Put the current call (%s) on hold\n", current_call_id.c_str());
	    onHoldCall (current_call_id);
282
	}
283
	else if (isConference(current_call_id) && !participToConference(call_id))
284
	{
285
	    _debug ("    outgoingCall: detach main participant from conference\n");
286
	    detachParticipant(default_id, current_call_id);
287
288
289
	}
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
290
    if (callConfig == Call::IPtoIP) {
291
        _debug ("    outgoingCall: Start IP to IP call\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
292
        /* We need to retrieve the sip voiplink instance */
293
294
        siplink = SIPVoIPLink::instance ("");

295
296
        if (siplink->new_ip_to_ip_call (call_id, to_cleaned)) {
            switchCall (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
297
            return true;
298
        } else {
299
            callFailure (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
300
        }
301

Emmanuel Milou's avatar
Emmanuel Milou committed
302
        return false;
303
    }
304

305
    if (!accountExists (account_id)) {
306
        _debug ("! Manager Error: Outgoing Call: account doesn't exist\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
307
308
        return false;
    }
309

310
    if (getAccountFromCall (call_id) != AccountNULL) {
311
        _debug ("! Manager Error: Outgoing Call: call id already exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
312
313
        return false;
    }
314
315


316
    _debug ("- Manager Action: Adding Outgoing Call %s on account %s\n", call_id.data(), account_id.data());
317

318
    associateCallToAccount (call_id, account_id);
319

320
321
    if (getAccountLink (account_id)->newOutgoingCall (call_id, to_cleaned)) {
        switchCall (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
322
323
        return true;
    } else {
324
        callFailure (call_id);
325
        _debug ("! Manager Error: An error occur, the call was not created\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
326
    }
327

Emmanuel Milou's avatar
Emmanuel Milou committed
328
    return false;
jpbl's avatar
jpbl committed
329
330
}

yanmorin's avatar
   
yanmorin committed
331
//THREAD=Main : for outgoing Call
332
bool
333
ManagerImpl::answerCall (const CallID& call_id)
jpbl's avatar
jpbl committed
334
{
335

336
    _debug("ManagerImpl::answerCall(%s)", call_id.c_str());
337
338

    stopTone (true);
339

340
341
342
343
344
    // store the current call id
    CallID current_call_id = getCurrentCallId();

    AccountID account_id = getAccountFromCall (call_id);
    if(account_id == AccountNULL) {
345
346
347
348
        _debug("ManagerImpl::answerCall : AccountId is null\n");
        return false;
    }
    
349
350
351
352
    Call* call = NULL;
    call = getAccountLink (account_id)->getCall (call_id);
    if (call == NULL) {
        _debug("    answerCall: currentCall is null\n");
353
    }
Alexandre Savard's avatar
Alexandre Savard committed
354
    /*
355
356
357
358
359
360
    Call* lastCall = NULL;
    if (!getCurrentCallId().empty()) {
        lastCall = getAccountLink (currentAccountId)->getCall (getCurrentCallId());
        if (lastCall == NULL) {
            _debug("ManagerImpl::answerCall : lastCall is null\n");
        }
361
    }
362

363
364
    _debug ("ManagerImpl::answerCall :: current call->getState %i \n", currentCall->getState());
    _debug ("Try to answer call: %s\n", id.data());
Yun Liu's avatar
Yun Liu committed
365

366
    if (lastCall != NULL ) {
367
        if (lastCall->getState() == Call::Active && !participToConference(getCurrentCallId())) {
368
369
370
            _debug ("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall (getCurrentCallId());
        }
Alexandre Savard's avatar
Alexandre Savard committed
371
	else if (isConference(getCurrentCallId()))
372
	{
373
	    _debug("Current call particips to a conference! Do not hold it!\n");
374
	}
375
    }
Alexandre Savard's avatar
Alexandre Savard committed
376
    */
377
378

    // in any cases we have to detach from current communication
Alexandre Savard's avatar
Alexandre Savard committed
379
380
    if (hasCurrentCall()) {
	
381
382
383
	_debug ("    answerCall: Has current call or conference (%s)\n", current_call_id.c_str());	
	// if it is not a conference and is not a conference participant
	if (!isConference(current_call_id) && !participToConference(current_call_id))
Alexandre Savard's avatar
Alexandre Savard committed
384
	{
385
386
	    _debug ("    answerCall: Put the current call (%s) on hold\n", current_call_id.c_str());
	    onHoldCall (current_call_id);
Alexandre Savard's avatar
Alexandre Savard committed
387
	}
388
389
	// if we are talking to a conference and we are answering an incoming call
	else if (isConference(current_call_id) && !participToConference(call_id))
Alexandre Savard's avatar
Alexandre Savard committed
390
	{
391
	    _debug ("    answerCall: detach main participant from conference\n");
392
	    detachParticipant(default_id, current_call_id);
Alexandre Savard's avatar
Alexandre Savard committed
393
394
	}
    }
395

396
    if (!getAccountLink (account_id)->answer (call_id)) {
397
        // error when receiving...
398
        removeCallAccount (call_id);
399
400
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
401

402
    // if it was waiting, it's waiting no more
403
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "CURRENT");
404
        
405
406
    std::string codecName = Manager::instance().getCurrentCodecName (call_id);
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str());
407
        
408
    removeWaitingCall (call_id);
409

410
    switchCall (call_id);
411
412

    return true;
jpbl's avatar
jpbl committed
413
414
}

yanmorin's avatar
   
yanmorin committed
415
//THREAD=Main
416
bool
417
ManagerImpl::hangupCall (const CallID& call_id)
jpbl's avatar
jpbl committed
418
{
419
    _debug ("ManagerImpl::hangupCall(%s)\n", call_id.c_str());
420
    PulseLayer *pulselayer;
421
    AccountID account_id;
422
    bool returnValue;
423
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
424

425
    // store the current call id
426
427
    CallID current_call_id = getCurrentCallId();

428
    stopTone (false);
429
    // switchCall (call_id);
yanmorin's avatar
   
yanmorin committed
430

431
    /* Broadcast a signal over DBus */
432
433
    _debug("    hangupCall: Send DBUS call state change (HUNGUP) for id %s\n", call_id.c_str());
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HUNGUP");
434

435
436
    int nbCalls = getCallList().size();

437
    audiolayer = getAudioDriver();
438
    // stop streamx
439
440
    if (! (nbCalls >= 1))
    {
441
	_debug("    hangupCall: stop audio stream, ther is only %i call(s) remaining\n", nbCalls);
442
        audiolayer->stopStream();
443
    }
444
   
445
    if(participToConference(call_id))
446
    {
447

448
	Conference *conf = getConferenceFromCallID(call_id);
449

450
	if(conf != NULL)
451
	{
452
453
	    // remove this participant
	    removeParticipant(call_id);
454

455
	    processRemainingParticipant(current_call_id, conf);
456
	}
457
    }
458
459
460
461
462
463
    else
    {
	// we are not participating to a conference, current call switched to ""
	if (!isConference(current_call_id))
	    switchCall("");
    }
464

Emmanuel Milou's avatar
Emmanuel Milou committed
465
    /* Direct IP to IP call */
466
467
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (call_id);
468
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
469
    /* Classic call, attached to an account */
470
    else {
471
        account_id = getAccountFromCall (call_id);
472

473
        if (account_id == AccountNULL) 
474
	{
475
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
476
477
            return false;
        }
478

479
        returnValue = getAccountLink (account_id)->hangup (call_id);
480

481
        removeCallAccount (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
482
    }
483

484
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
485
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
486
487

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
488
    }
489

490
    return returnValue;
jpbl's avatar
jpbl committed
491
492
}

Alexandre Savard's avatar
Alexandre Savard committed
493
494
495
496
497
498
499
500
501
502
503

bool
ManagerImpl::hangupConference (const ConfID& id)
{
    _debug ("ManagerImpl::hangupConference()\n");

    Conference *conf;
    ConferenceMap::iterator iter_conf = _conferencemap.find(id);

    AccountID currentAccountId;

504
    // Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
505
506
507
508
509

    if(iter_conf != _conferencemap.end())
    {
	conf = iter_conf->second;
 
510
511
	ParticipantSet participants = conf->getParticipantList();
	ParticipantSet::iterator iter_participant = participants.begin();
Alexandre Savard's avatar
Alexandre Savard committed
512

513
	while(iter_participant != participants.end())
Alexandre Savard's avatar
Alexandre Savard committed
514
	{
515
	    _debug("ManagerImpl::hangupConference participant %s\n", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
516

517
	    hangupCall (*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
518
519
520
521
522
523
524

	    iter_participant++;

	}

    }

525
526
    switchCall ("");

Alexandre Savard's avatar
Alexandre Savard committed
527
528
529
530
    return true;
}


yanmorin's avatar
   
yanmorin committed
531
//THREAD=Main
532
bool
yanmorin's avatar
   
yanmorin committed
533
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
534
{
Emmanuel Milou's avatar
Emmanuel Milou committed
535
536
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
537

538
    stopTone (true);
539

Emmanuel Milou's avatar
Emmanuel Milou committed
540
    /* Direct IP to IP call */
541

Emmanuel Milou's avatar
Emmanuel Milou committed
542
    if (getConfigFromCall (id) == Call::IPtoIP) {
543
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
544
545
546
    }

    /* Classic call, attached to an account */
547
    else {
548
549
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
550
        if (accountid == AccountNULL) {
551
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
552
553
            return false;
        }
554
555
556
557

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
558
    }
559

Emmanuel Milou's avatar
Emmanuel Milou committed
560
    // it could be a waiting call?
561
562
563
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
564
565

    return returnValue;
jpbl's avatar
jpbl committed
566
567
}

yanmorin's avatar
   
yanmorin committed
568
//THREAD=Main
569
bool
570
ManagerImpl::onHoldCall (const CallID& call_id)
jpbl's avatar
jpbl committed
571
{
572
    AccountID account_id;
Emmanuel Milou's avatar
Emmanuel Milou committed
573
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
574

575
    _debug("ManagerImpl::onHoldCall(%s)\n", call_id.c_str());
576

577
    stopTone (true);
578

579
    // switchCall (id);
580

Emmanuel Milou's avatar
Emmanuel Milou committed
581
    /* Direct IP to IP call */
582

583
584
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
585
    }
586

Emmanuel Milou's avatar
Emmanuel Milou committed
587
    /* Classic call, attached to an account */
588
    else {
589
        account_id = getAccountFromCall (call_id);
590

591
592
        if (account_id == AccountNULL) {
            _debug ("    onHoldCall: Account ID %s or callid %s doesn't exists\n", account_id.c_str(), call_id.c_str());
Emmanuel Milou's avatar
Emmanuel Milou committed
593
594
            return false;
        }
595

596
        returnValue = getAccountLink (account_id)->onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
597
    }
598
    
599
    removeWaitingCall (call_id);
600

601
    // switchCall ("");
602

603
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
604

Emmanuel Milou's avatar
Emmanuel Milou committed
605
    return returnValue;
yanmorin's avatar
   
yanmorin committed
606
607
608
}

//THREAD=Main
609
bool
610
ManagerImpl::offHoldCall (const CallID& call_id)
yanmorin's avatar
   
yanmorin committed
611
{
612

613
    AccountID account_id;
614
    bool returnValue, is_rec;
Emmanuel Milou's avatar
Emmanuel Milou committed
615
    std::string codecName;
616
617
618


    _debug ("ManagerImpl::offHoldCall(%s)\n", call_id.c_str());
619

620
    stopTone (false);
621

622
    CallID current_call_id = getCurrentCallId();
623

624
    //Place current call on hold if it isn't
625
    if (hasCurrentCall()) 
626
    {
627
628
629
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(current_call_id) && !participToConference(current_call_id))
	{
630
	    _debug ("    offHoldCall: put current call (%s) on hold\n", current_call_id.c_str());
631
632
	    onHoldCall (current_call_id);
	}
633
	else if (isConference(current_call_id) && !participToConference(call_id))
634
	{
635
	    _debug ("    offHoldCall Put current conference (%s) on hold\n", current_call_id.c_str());
636
	    detachParticipant(default_id, current_call_id);
637
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
638
    }
639

640
    // switch current call id to id since sipvoip link need it to amke a call 
641
    // switchCall(id);
642

Emmanuel Milou's avatar
Emmanuel Milou committed
643
    /* Direct IP to IP call */
644
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
645
        // is_rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id);
646
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
647
    }
alexandresavard's avatar
alexandresavard committed
648

Emmanuel Milou's avatar
Emmanuel Milou committed
649
    /* Classic call, attached to an account */
650
    else {
651
        account_id = getAccountFromCall (call_id);
652

653
        if (account_id == AccountNULL) {
654
            _debug ("Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
655
656
            return false;
        }
657

658
        _debug ("Setting OFFHOLD, Account %s, callid %s\n", account_id.c_str(), call_id.c_str());
659

660
        is_rec = getAccountLink (account_id)->getCall(call_id)->isRecording();
661
        returnValue = getAccountLink (account_id)->offhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
662
    }
alexandresavard's avatar
alexandresavard committed
663

664

665
    if (_dbus) {
666
        if (is_rec)
667
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
668
        else
669
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
670

Emmanuel Milou's avatar
Emmanuel Milou committed
671
    }
672

673
    if ( participToConference(call_id) ) {
674
675
676
677
	 
	AccountID currentAccountId;
        Call* call = NULL;

678
679
	currentAccountId = getAccountFromCall (call_id);
	call = getAccountLink (currentAccountId)->getCall (call_id);
680
681
	
	switchCall(call->getConfId());
682
    }
683
684
685
686
    else
    {
	switchCall(call_id);
    }
687

688
    codecName = getCurrentCodecName (call_id);
689
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
690

691
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id,codecName.c_str());
692

Emmanuel Milou's avatar
Emmanuel Milou committed
693
    return returnValue;
jpbl's avatar
jpbl committed
694
695
}

yanmorin's avatar
   
yanmorin committed
696
//THREAD=Main
697
698
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
699
{
Emmanuel Milou's avatar
Emmanuel Milou committed
700
701
    AccountID accountid;
    bool returnValue;
702

703
    stopTone (true);
704

Emmanuel Milou's avatar
Emmanuel Milou committed
705
    /* Direct IP to IP call */
706

Emmanuel Milou's avatar
Emmanuel Milou committed
707
    if (getConfigFromCall (id) == Call::IPtoIP) {
708
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
709
710
711
    }

    /* Classic call, attached to an account */
712
    else {
713
714
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
715
        if (accountid == AccountNULL) {
716
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
717
718
            return false;
        }
719
720
721
722

        returnValue = getAccountLink (accountid)->transfer (id, to);

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
723
    }
724

725
726
727
728
729
    removeWaitingCall (id);

    switchCall ("");

    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");
730

Emmanuel Milou's avatar
Emmanuel Milou committed
731
    return returnValue;
jpbl's avatar
jpbl committed
732
733
}

734
735
void ManagerImpl::transferFailed()
{
736
    if (_dbus) _dbus->getCallManager()->transferFailed();
737
738
739
740
}

void ManagerImpl::transferSucceded()
{
741
    if (_dbus) _dbus->getCallManager()->transferSucceded();
742
743
744
745

}


yanmorin's avatar
   
yanmorin committed
746
//THREAD=Main : Call:Incoming