managerimpl.cpp 128 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
 *  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.
 */

25
26
27
28
29
#include "managerimpl.h"

#include "account.h"
#include "dbus/callmanager.h"
#include "user_cfg.h"
30
#include "global.h"
31
#include "sip/sipaccount.h"
32

33
34
35
36
37
38
39
40
41
42
#include "audio/audiolayer.h"
#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"
#include "manager.h"
#include "dbus/configurationmanager.h"

43
44
#include "conference.h"

jpbl's avatar
jpbl committed
45
46
47
48
49
#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
50
#include <sstream>
jpbl's avatar
jpbl committed
51
#include <sys/types.h> // mkdir(2)
52
53
#include <sys/stat.h>  // mkdir(2)
#include <pwd.h>       // getpwuid
jpbl's avatar
jpbl committed
54
55
56
57
58
59
60


#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)))

61
62
#define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len)

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

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

97
    _cleaner = new NumberCleaner ();
98
    _history = new HistoryManager ();
99

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

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

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

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

126
    initVolume();
127

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

132
    initAudioDriver();
133

134
    selectAudioDriver();
jpbl's avatar
jpbl committed
135

136
137
    // Initialize the list of supported audio codecs
    initAudioCodec();
138

139
    AudioLayer *audiolayer = getAudioDriver();
140

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

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

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

    if (audiolayer == 0)
153
        audiolayer->stopStream();
154
155
156


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

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

165
    unloadAccountMap();
166

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

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

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

178
    _debug ("Unload Audio Codecs \n");
179
    _codecDescriptorMap.deleteHandlePointer();
180

jpbl's avatar
jpbl committed
181
182
}

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

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

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

    return false;
jpbl's avatar
jpbl committed
199
200
}

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

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

214
215
    /*
    AudioLayer *al = getAudioDriver();
216

217
    if (id != "") {
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
243
244
	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
245
246
247
248
249
250
}


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

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

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

    CallID current_call_id = getCurrentCallId();
263

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

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

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

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

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

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
304
        return false;
305
    }
306

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

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


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

320
    associateCallToAccount (call_id, account_id);
321

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

Emmanuel Milou's avatar
Emmanuel Milou committed
330
    return false;
jpbl's avatar
jpbl committed
331
332
}

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

338
    _debug("ManagerImpl::answerCall(%s)", call_id.c_str());
339
340

    stopTone (true);
341

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

    AccountID account_id = getAccountFromCall (call_id);
    if(account_id == AccountNULL) {
347
        _debug("    answerCall : AccountId is null\n");
348
349
    }
    
350
351
352
    Call* call = NULL;
    call = getAccountLink (account_id)->getCall (call_id);
    if (call == NULL) {
353
        _debug("    answerCall: Call is null\n");
354
    }
355
356

    // in any cases we have to detach from current communication
Alexandre Savard's avatar
Alexandre Savard committed
357
358
    if (hasCurrentCall()) {
	
359
	_debug ("    answerCall: Currently conversing with %s\n", current_call_id.c_str());	
360
361
	// 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
362
	{
363
364
	    _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
365
	}
366
367
	// 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
368
	{
369
	    _debug ("    answerCall: Detach main participant from conference\n");
370
	    detachParticipant(default_id, current_call_id);
Alexandre Savard's avatar
Alexandre Savard committed
371
372
	}
    }
373

374
    if (!getAccountLink (account_id)->answer (call_id)) {
375
        // error when receiving...
376
        removeCallAccount (call_id);
377
378
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
379

380
    // if it was waiting, it's waiting no more
381
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "CURRENT");
382
        
383
384
    std::string codecName = Manager::instance().getCurrentCodecName (call_id);
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str());
385
        
386
    removeWaitingCall (call_id);
387

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
    // if we dragged this call into a conference already
    if ( participToConference(call_id) ) {
	 
	// AccountID currentAccountId;
        // Call* call = NULL;

	// currentAccountId = getAccountFromCall (call_id);
	// call = getAccountLink (currentAccountId)->getCall (call_id);
	
	switchCall(call->getConfId());
    }
    else
    {
	switchCall(call_id);
    }
403
404

    return true;
jpbl's avatar
jpbl committed
405
406
}

yanmorin's avatar
   
yanmorin committed
407
//THREAD=Main
408
bool
409
ManagerImpl::hangupCall (const CallID& call_id)
jpbl's avatar
jpbl committed
410
{
411
    _debug ("ManagerImpl::hangupCall(%s)\n", call_id.c_str());
412
    PulseLayer *pulselayer;
413
    AccountID account_id;
414
    bool returnValue;
415
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
416

417
    // store the current call id
418
419
    CallID current_call_id = getCurrentCallId();

420
    stopTone (false);
421
    // switchCall (call_id);
yanmorin's avatar
   
yanmorin committed
422

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

427
428
    int nbCalls = getCallList().size();

429
    audiolayer = getAudioDriver();
430
    // stop streamx
431
432
    if (! (nbCalls >= 1))
    {
433
	_debug("    hangupCall: stop audio stream, ther is only %i call(s) remaining\n", nbCalls);
434
        audiolayer->stopStream();
435
    }
436
   
437
    if(participToConference(call_id))
438
    {
439

440
	Conference *conf = getConferenceFromCallID(call_id);
441

442
	if(conf != NULL)
443
	{
444
445
	    // remove this participant
	    removeParticipant(call_id);
446

447
	    processRemainingParticipant(current_call_id, conf);
448
	}
449
    }
450
451
452
453
454
455
    else
    {
	// we are not participating to a conference, current call switched to ""
	if (!isConference(current_call_id))
	    switchCall("");
    }
456

Emmanuel Milou's avatar
Emmanuel Milou committed
457
    /* Direct IP to IP call */
458
459
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (call_id);
460
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
461
    /* Classic call, attached to an account */
462
    else {
463
        account_id = getAccountFromCall (call_id);
464

465
        if (account_id == AccountNULL) 
466
	{
467
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
468
469
            return false;
        }
470

471
        returnValue = getAccountLink (account_id)->hangup (call_id);
472

473
        removeCallAccount (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
474
    }
475

476
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
477
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
478
479

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
480
    }
481

482
    return returnValue;
jpbl's avatar
jpbl committed
483
484
}

Alexandre Savard's avatar
Alexandre Savard committed
485
486
487
488
489
490
491
492
493
494
495

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

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

    AccountID currentAccountId;

496
    // Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
497
498
499
500
501

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

505
	while(iter_participant != participants.end())
Alexandre Savard's avatar
Alexandre Savard committed
506
	{
507
	    _debug("ManagerImpl::hangupConference participant %s\n", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
508

509
	    hangupCall (*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
510
511
512
513
514
515
516

	    iter_participant++;

	}

    }

517
518
    switchCall ("");

Alexandre Savard's avatar
Alexandre Savard committed
519
520
521
522
    return true;
}


yanmorin's avatar
   
yanmorin committed
523
//THREAD=Main
524
bool
yanmorin's avatar
   
yanmorin committed
525
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
526
{
Emmanuel Milou's avatar
Emmanuel Milou committed
527
528
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
529

530
    stopTone (true);
531

Emmanuel Milou's avatar
Emmanuel Milou committed
532
    /* Direct IP to IP call */
533

Emmanuel Milou's avatar
Emmanuel Milou committed
534
    if (getConfigFromCall (id) == Call::IPtoIP) {
535
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
536
537
538
    }

    /* Classic call, attached to an account */
539
    else {
540
541
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
542
        if (accountid == AccountNULL) {
543
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
544
545
            return false;
        }
546
547
548
549

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
550
    }
551

Emmanuel Milou's avatar
Emmanuel Milou committed
552
    // it could be a waiting call?
553
554
555
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
556
557

    return returnValue;
jpbl's avatar
jpbl committed
558
559
}

yanmorin's avatar
   
yanmorin committed
560
//THREAD=Main
561
bool
562
ManagerImpl::onHoldCall (const CallID& call_id)
jpbl's avatar
jpbl committed
563
{
564
    AccountID account_id;
Emmanuel Milou's avatar
Emmanuel Milou committed
565
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
566

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

569
    stopTone (true);
570

571
    // switchCall (id);
572

573
574
575
    CallID current_call_id = getCurrentCallId();

    _debug("    onHoldCall: try to put call %s on hold\n", call_id.c_str());
576

577
    /* Direct IP to IP call */
578
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
579
	returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
580
    }
581

Emmanuel Milou's avatar
Emmanuel Milou committed
582
    /* Classic call, attached to an account */
583
    else {
584
585
586
587
588
589
	account_id = getAccountFromCall (call_id);
	    
	if (account_id == AccountNULL) {
	    _debug ("    onHoldCall: Account ID %s or callid %s doesn't exists\n", account_id.c_str(), call_id.c_str());
	    return false;
	}
590

591
	returnValue = getAccountLink (account_id)->onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
592
    }
593

594
    removeWaitingCall (call_id);
595

596
597
598
599
    if(current_call_id == call_id) {

	switchCall ("");
    }
600

601
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
602

Emmanuel Milou's avatar
Emmanuel Milou committed
603
    return returnValue;
yanmorin's avatar
   
yanmorin committed
604
605
606
}

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

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


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

618
    stopTone (false);
619

620
    CallID current_call_id = getCurrentCallId();
621

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

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

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

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

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

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

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

662

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

Emmanuel Milou's avatar
Emmanuel Milou committed
669
    }
670

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

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

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

689
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id,codecName.c_str());
690

Emmanuel Milou's avatar
Emmanuel Milou committed
691
    return returnValue;
jpbl's avatar
jpbl committed
692
693
}

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

701
    stopTone (true);
702

Emmanuel Milou's avatar
Emmanuel Milou committed
703
    /* Direct IP to IP call */
704

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

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

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
721
    }
722

723
724
725
726
727
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
729
    return returnValue;
jpbl's avatar
jpbl committed
730
731
}

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

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

}


yanmorin's avatar
   
yanmorin committed
744
//THREAD=Main : Call:Incoming
745
bool
yanmorin's avatar
   
yanmorin committed
746
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
747
{
Emmanuel Milou's avatar
Emmanuel Milou committed
748
749
    AccountID accountid;
    bool returnValue;
750

751
752
753
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
754
755

    if (getConfigFromCall (id) == Call::IPtoIP) {
756
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
757
758
759
    }

    /* Classic call, attached to an account */
760
    else {
761
762
</