managerimpl.cpp 103 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: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
8
 *
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
22
23
24
25
26
27
28
 *  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>
29
#include <sstream>
jpbl's avatar
jpbl committed
30
31
32
33
34
35
36
37
#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>

38
39
#include "conference.h"

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

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

jpbl's avatar
jpbl committed
51
52
53
54
55
56
57
#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)))

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

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

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

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

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

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

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

123
    initVolume();
124

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

129
    initAudioDriver();
130

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

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

136
    AudioLayer *audiolayer = getAudioDriver();
137

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

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

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

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


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

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

162
    unloadAccountMap();
163

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

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

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

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

jpbl's avatar
jpbl committed
178
179
}

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

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

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

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

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

void
205
206
207
ManagerImpl::switchCall (const CallID& id)
{
    ost::MutexLock m (_currentCallMutex);
208
    _debug("------------------------- SWITCH %s ---------------------------\n", id.c_str());
209
    _currentCallId2 = id;
jpbl's avatar
jpbl committed
210
211
212
213
214
215
}


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

218
bool
219
ManagerImpl::outgoingCall (const std::string& account_id, const CallID& call_id, const std::string& to)
yanmorin's avatar
   
yanmorin committed
220
{
221
    std::string pattern, to_cleaned;
Emmanuel Milou's avatar
Emmanuel Milou committed
222
223
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
224

225
226
227
    _debug ("ManagerImpl::outgoingCall(%s)\n", call_id.c_str());

    CallID current_call_id = getCurrentCallId();
228

229
230
    if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) ==  "1")
        _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX));
231
232
    else
        _cleaner->set_phone_number_prefix ("");
233

234
    to_cleaned = _cleaner->clean (to);
Emmanuel Milou's avatar
Emmanuel Milou committed
235
236

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

239
    // in any cases we have to detach from current communication
240
241
    if (hasCurrentCall()) {
	
242
243
	_debug ("    outgoingCall: Has current call (%s) put it onhold\n", current_call_id.c_str());

244
	// if this is not a conferenceand this and is not a conference participant
245
	if (!isConference(current_call_id) && !participToConference(current_call_id))
246
	{
247
248
	    _debug ("    outgoingCall: Put the current call (%s) on hold\n", current_call_id.c_str());
	    onHoldCall (current_call_id);
249
	}
250
	else if (isConference(current_call_id) && !participToConference(call_id))
251
	{
252
	    _debug ("    outgoingCall: detach main participant from conference\n");
Alexandre Savard's avatar
Alexandre Savard committed
253
	    detachParticipant();
254
255
256
	}
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
257
    if (callConfig == Call::IPtoIP) {
258
        _debug ("    outgoingCall: Start IP to IP call\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
259
        /* We need to retrieve the sip voiplink instance */
260
261
        siplink = SIPVoIPLink::instance ("");

262
263
        if (siplink->new_ip_to_ip_call (call_id, to_cleaned)) {
            switchCall (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
264
            return true;
265
        } else {
266
            callFailure (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
267
        }
268

Emmanuel Milou's avatar
Emmanuel Milou committed
269
        return false;
270
    }
271

272
    if (!accountExists (account_id)) {
273
        _debug ("! Manager Error: Outgoing Call: account doesn't exist\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
274
275
        return false;
    }
276

277
    if (getAccountFromCall (call_id) != AccountNULL) {
278
        _debug ("! Manager Error: Outgoing Call: call id already exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
279
280
        return false;
    }
281
282


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

285
    associateCallToAccount (call_id, account_id);
286

287
288
    if (getAccountLink (account_id)->newOutgoingCall (call_id, to_cleaned)) {
        switchCall (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
289
290
        return true;
    } else {
291
        callFailure (call_id);
292
        _debug ("! Manager Error: An error occur, the call was not created\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
293
    }
294

Emmanuel Milou's avatar
Emmanuel Milou committed
295
    return false;
jpbl's avatar
jpbl committed
296
297
}

yanmorin's avatar
   
yanmorin committed
298
//THREAD=Main : for outgoing Call
299
bool
300
ManagerImpl::answerCall (const CallID& call_id)
jpbl's avatar
jpbl committed
301
{
302

303
    _debug("ManagerImpl::answerCall(%s)", call_id.c_str());
304
305

    stopTone (true);
306

307
308
309
310
311
    // store the current call id
    CallID current_call_id = getCurrentCallId();

    AccountID account_id = getAccountFromCall (call_id);
    if(account_id == AccountNULL) {
312
313
314
315
        _debug("ManagerImpl::answerCall : AccountId is null\n");
        return false;
    }
    
316
317
318
319
    Call* call = NULL;
    call = getAccountLink (account_id)->getCall (call_id);
    if (call == NULL) {
        _debug("    answerCall: currentCall is null\n");
320
    }
Alexandre Savard's avatar
Alexandre Savard committed
321
    /*
322
323
324
325
326
327
    Call* lastCall = NULL;
    if (!getCurrentCallId().empty()) {
        lastCall = getAccountLink (currentAccountId)->getCall (getCurrentCallId());
        if (lastCall == NULL) {
            _debug("ManagerImpl::answerCall : lastCall is null\n");
        }
328
    }
329

330
331
    _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
332

333
    if (lastCall != NULL ) {
334
        if (lastCall->getState() == Call::Active && !participToConference(getCurrentCallId())) {
335
336
337
            _debug ("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall (getCurrentCallId());
        }
Alexandre Savard's avatar
Alexandre Savard committed
338
	else if (isConference(getCurrentCallId()))
339
	{
340
	    _debug("Current call particips to a conference! Do not hold it!\n");
341
	}
342
    }
Alexandre Savard's avatar
Alexandre Savard committed
343
    */
344
345

    // in any cases we have to detach from current communication
Alexandre Savard's avatar
Alexandre Savard committed
346
347
    if (hasCurrentCall()) {
	
348
349
350
	_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
351
	{
352
353
	    _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
354
	}
355
356
	// 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
357
	{
358
	    _debug ("    answerCall: detach main participant from conference\n");
Alexandre Savard's avatar
Alexandre Savard committed
359
360
361
	    detachParticipant();
	}
    }
362

363
    if (!getAccountLink (account_id)->answer (call_id)) {
364
        // error when receiving...
365
        removeCallAccount (call_id);
366
367
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
368

369
    // if it was waiting, it's waiting no more
370
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "CURRENT");
371
        
372
373
    std::string codecName = Manager::instance().getCurrentCodecName (call_id);
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str());
374
        
375
    removeWaitingCall (call_id);
376

377
    switchCall (call_id);
378
379

    return true;
jpbl's avatar
jpbl committed
380
381
}

yanmorin's avatar
   
yanmorin committed
382
//THREAD=Main
383
bool
384
ManagerImpl::hangupCall (const CallID& call_id)
jpbl's avatar
jpbl committed
385
{
386
    _debug ("ManagerImpl::hangupCall(%s)\n", call_id.c_str());
387
    PulseLayer *pulselayer;
388
    AccountID account_id;
389
    bool returnValue;
390
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
391

392
    // store the current call id
393
394
    CallID current_call_id = getCurrentCallId();

395
    stopTone (false);
396
    // switchCall (call_id);
yanmorin's avatar
   
yanmorin committed
397

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

402
403
    int nbCalls = getCallList().size();

404
    audiolayer = getAudioDriver();
405
    // stop streamx
406
407
    if (! (nbCalls >= 1))
    {
408
	_debug("    hangupCall: stop audio stream, ther is only %i call(s) remaining\n", nbCalls);
409
        audiolayer->stopStream();
410
    }
411
   
412
    if(participToConference(call_id))
413
    {
414

415
	Conference *conf = getConferenceFromCallID(call_id);
416

417
	if(conf != NULL)
418
	{
419
420
	    // remove this participant
	    removeParticipant(call_id);
421

422
	    processRemainingParticipant(current_call_id, conf);
423
	}
424
    }
425
426
427
428
429
430
    else
    {
	// we are not participating to a conference, current call switched to ""
	if (!isConference(current_call_id))
	    switchCall("");
    }
431

Emmanuel Milou's avatar
Emmanuel Milou committed
432
    /* Direct IP to IP call */
433
434
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (call_id);
435
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
436
    /* Classic call, attached to an account */
437
    else {
438
        account_id = getAccountFromCall (call_id);
439

440
        if (account_id == AccountNULL) 
441
	{
442
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
443
444
            return false;
        }
445

446
        returnValue = getAccountLink (account_id)->hangup (call_id);
447

448
        removeCallAccount (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
449
    }
450

451
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
452
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
453
454

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
455
    }
456

457
    return returnValue;
jpbl's avatar
jpbl committed
458
459
}

Alexandre Savard's avatar
Alexandre Savard committed
460
461
462
463
464
465
466
467
468
469
470

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

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

    AccountID currentAccountId;

471
    // Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
472
473
474
475
476

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

480
	while(iter_participant != participants.end())
Alexandre Savard's avatar
Alexandre Savard committed
481
	{
482
	    _debug("ManagerImpl::hangupConference participant %s\n", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
483

484
	    hangupCall (*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
485
486
487
488
489
490
491

	    iter_participant++;

	}

    }

492
493
    switchCall ("");

Alexandre Savard's avatar
Alexandre Savard committed
494
495
496
497
    return true;
}


yanmorin's avatar
   
yanmorin committed
498
//THREAD=Main
499
bool
yanmorin's avatar
   
yanmorin committed
500
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
501
{
Emmanuel Milou's avatar
Emmanuel Milou committed
502
503
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
504

505
    stopTone (true);
506

Emmanuel Milou's avatar
Emmanuel Milou committed
507
    /* Direct IP to IP call */
508

Emmanuel Milou's avatar
Emmanuel Milou committed
509
    if (getConfigFromCall (id) == Call::IPtoIP) {
510
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
511
512
513
    }

    /* Classic call, attached to an account */
514
    else {
515
516
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
517
        if (accountid == AccountNULL) {
518
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
519
520
            return false;
        }
521
522
523
524

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
525
    }
526

Emmanuel Milou's avatar
Emmanuel Milou committed
527
    // it could be a waiting call?
528
529
530
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
531
532

    return returnValue;
jpbl's avatar
jpbl committed
533
534
}

yanmorin's avatar
   
yanmorin committed
535
//THREAD=Main
536
bool
537
ManagerImpl::onHoldCall (const CallID& call_id)
jpbl's avatar
jpbl committed
538
{
539
    AccountID account_id;
Emmanuel Milou's avatar
Emmanuel Milou committed
540
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
541

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

544
    stopTone (true);
545

546
    // switchCall (id);
547

Emmanuel Milou's avatar
Emmanuel Milou committed
548
    /* Direct IP to IP call */
549

550
551
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
552
    }
553

Emmanuel Milou's avatar
Emmanuel Milou committed
554
    /* Classic call, attached to an account */
555
    else {
556
        account_id = getAccountFromCall (call_id);
557

558
559
        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
560
561
            return false;
        }
562

563
        returnValue = getAccountLink (account_id)->onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
564
    }
565
    
566
    removeWaitingCall (call_id);
567

568
    // switchCall ("");
569

570
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
571

Emmanuel Milou's avatar
Emmanuel Milou committed
572
    return returnValue;
yanmorin's avatar
   
yanmorin committed
573
574
575
}

//THREAD=Main
576
bool
577
ManagerImpl::offHoldCall (const CallID& call_id)
yanmorin's avatar
   
yanmorin committed
578
{
579

580
    AccountID account_id;
Emmanuel Milou's avatar
Emmanuel Milou committed
581
582
    bool returnValue, rec;
    std::string codecName;
583
584
585


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

587
    stopTone (false);
588

589
    CallID current_call_id = getCurrentCallId();
590

591
    //Place current call on hold if it isn't
592
    if (hasCurrentCall()) 
593
    {
594
595
596
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(current_call_id) && !participToConference(current_call_id))
	{
597
	    _debug ("    offHoldCall: put current call (%s) on hold\n", current_call_id.c_str());
598
599
	    onHoldCall (current_call_id);
	}
600
	else if (isConference(current_call_id) && !participToConference(call_id))
601
	{
602
	    _debug ("    offHoldCall Put current conference (%s) on hold\n", current_call_id.c_str());
Alexandre Savard's avatar
Alexandre Savard committed
603
	    detachParticipant();
604
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
605
    }
606

607
    // switch current call id to id since sipvoip link need it to amke a call 
608
    // switchCall(id);
609

Emmanuel Milou's avatar
Emmanuel Milou committed
610
    /* Direct IP to IP call */
611
612
613
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id);
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
614
    }
alexandresavard's avatar
alexandresavard committed
615

Emmanuel Milou's avatar
Emmanuel Milou committed
616
    /* Classic call, attached to an account */
617
    else {
618
        account_id = getAccountFromCall (call_id);
619

620
        if (account_id == AccountNULL) {
621
            _debug ("Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
622
623
            return false;
        }
624

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

627
628
        rec = getAccountLink (account_id)->isRecording (call_id);
        returnValue = getAccountLink (account_id)->offhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
629
    }
alexandresavard's avatar
alexandresavard committed
630

631

632
    if (_dbus) {
Emmanuel Milou's avatar
Emmanuel Milou committed
633
        if (rec)
634
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
635
        else
636
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
637

Emmanuel Milou's avatar
Emmanuel Milou committed
638
    }
639

640
    if ( participToConference(call_id) ) {
641

642
	_debug("?????????????????????????  Particip to conference ????????????????????????????");
643
644
645
646
	 
	AccountID currentAccountId;
        Call* call = NULL;

647
648
	currentAccountId = getAccountFromCall (call_id);
	call = getAccountLink (currentAccountId)->getCall (call_id);
649
650
	
	switchCall(call->getConfId());
651
    }
652
653
654
655
    else
    {
	switchCall(call_id);
    }
656

657
    codecName = getCurrentCodecName (call_id);
658
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
659

660
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id,codecName.c_str());
661

Emmanuel Milou's avatar
Emmanuel Milou committed
662
    return returnValue;
jpbl's avatar
jpbl committed
663
664
}

yanmorin's avatar
   
yanmorin committed
665
//THREAD=Main
666
667
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
668
{
Emmanuel Milou's avatar
Emmanuel Milou committed
669
670
    AccountID accountid;
    bool returnValue;
671

672
    stopTone (true);
673

Emmanuel Milou's avatar
Emmanuel Milou committed
674
    /* Direct IP to IP call */
675

Emmanuel Milou's avatar
Emmanuel Milou committed
676
    if (getConfigFromCall (id) == Call::IPtoIP) {
677
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
678
679
680
    }

    /* Classic call, attached to an account */
681
    else {
682
683
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
684
        if (accountid == AccountNULL) {
685
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
686
687
            return false;
        }
688
689
690
691

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
692
    }
693

694
695
696
697
698
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
700
    return returnValue;
jpbl's avatar
jpbl committed
701
702
}

703
704
void ManagerImpl::transferFailed()
{
705
    if (_dbus) _dbus->getCallManager()->transferFailed();
706
707
708
709
}

void ManagerImpl::transferSucceded()
{
710
    if (_dbus) _dbus->getCallManager()->transferSucceded();
711
712
713
714

}


yanmorin's avatar
   
yanmorin committed
715
//THREAD=Main : Call:Incoming
716
bool
yanmorin's avatar
   
yanmorin committed
717
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
718
{
Emmanuel Milou's avatar
Emmanuel Milou committed
719
720
    AccountID accountid;
    bool returnValue;
721

722
723
724
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
725
726

    if (getConfigFromCall (id) == Call::IPtoIP) {
727
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
728
729
730
    }

    /* Classic call, attached to an account */
731
    else {
732
733
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
734
        if (accountid == AccountNULL) {