managerimpl.cpp 99.9 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
219
bool
ManagerImpl::outgoingCall (const std::string& accountid, const CallID& 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
    _debug ("ManagerImpl::outgoingCall(%s)\n", id.c_str());
226

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

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

    /* Check what kind of call we are dealing with */
235
    check_call_configuration (id, to_cleaned, &callConfig);
236

237
238
239
240
241
242
243
244
245
    if (hasCurrentCall()) {
	
	_debug ("ManagerImpl::outgoingCall() Has current call (id %s) put it onhold\n", getCurrentCallId().c_str());	
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(getCurrentCallId()) && !participToConference(getCurrentCallId()))
	{
	    _debug ("ManagerImpl::outgoingCall() Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
	    onHoldCall (getCurrentCallId());
	}
Alexandre Savard's avatar
Alexandre Savard committed
246
	else if (isConference(getCurrentCallId()))
247
	{
Alexandre Savard's avatar
Alexandre Savard committed
248
249
	    _debug ("ManagerImpl::outgoingCall() detach main participant from conference\n");
	    detachParticipant();
250
251
252
	}
    }

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

258
        if (siplink->new_ip_to_ip_call (id, to_cleaned)) {
Emmanuel Milou's avatar
Emmanuel Milou committed
259
260
            switchCall (id);
            return true;
261
        } else {
Emmanuel Milou's avatar
Emmanuel Milou committed
262
263
            callFailure (id);
        }
264

Emmanuel Milou's avatar
Emmanuel Milou committed
265
        return false;
266
    }
267

268
269
    if (!accountExists (accountid)) {
        _debug ("! Manager Error: Outgoing Call: account doesn't exist\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
270
271
        return false;
    }
272

273
274
    if (getAccountFromCall (id) != AccountNULL) {
        _debug ("! Manager Error: Outgoing Call: call id already exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
275
276
        return false;
    }
277
278


279
280
281
282
283
284
    _debug ("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());

    associateCallToAccount (id, accountid);

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

Emmanuel Milou's avatar
Emmanuel Milou committed
291
    return false;
jpbl's avatar
jpbl committed
292
293
}

yanmorin's avatar
   
yanmorin committed
294
//THREAD=Main : for outgoing Call
295
296
bool
ManagerImpl::answerCall (const CallID& id)
jpbl's avatar
jpbl committed
297
{
298
299

    _debug("ManagerImpl::answerCall(%s)", id.c_str());
300
301

    stopTone (true);
302

303
304
305
306
307
308
309
310
311
312
313
314
    AccountID currentAccountId;
    currentAccountId = getAccountFromCall (id);
    if(currentAccountId == AccountNULL) {
        _debug("ManagerImpl::answerCall : AccountId is null\n");
        return false;
    }
    
    Call* currentCall = NULL;
    currentCall = getAccountLink (currentAccountId)->getCall (id);
    if (currentCall == NULL) {
        _debug("ManagerImpl::answerCall : currentCall is null\n");
    }
Alexandre Savard's avatar
Alexandre Savard committed
315
    /*
316
317
318
319
320
321
    Call* lastCall = NULL;
    if (!getCurrentCallId().empty()) {
        lastCall = getAccountLink (currentAccountId)->getCall (getCurrentCallId());
        if (lastCall == NULL) {
            _debug("ManagerImpl::answerCall : lastCall is null\n");
        }
322
    }
323

324
325
    _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
326

327
    if (lastCall != NULL ) {
328
        if (lastCall->getState() == Call::Active && !participToConference(getCurrentCallId())) {
329
330
331
            _debug ("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall (getCurrentCallId());
        }
Alexandre Savard's avatar
Alexandre Savard committed
332
	else if (isConference(getCurrentCallId()))
333
	{
334
	    _debug("Current call particips to a conference! Do not hold it!\n");
335
	}
336
    }
Alexandre Savard's avatar
Alexandre Savard committed
337
338
339
340
341
342
343
344
345
346
    */
    if (hasCurrentCall()) {
	
	_debug ("ManagerImpl::answerCall() Has current call (id %s) put it onhold\n", getCurrentCallId().c_str());	
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(getCurrentCallId()) && !participToConference(getCurrentCallId()))
	{
	    _debug ("ManagerImpl::answerCall() Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
	    onHoldCall (getCurrentCallId());
	}
347
	else if (isConference(getCurrentCallId()) && !participToConference(id))
Alexandre Savard's avatar
Alexandre Savard committed
348
349
350
351
352
	{
	    _debug ("ManagerImpl::answerCall() detach main participant from conference\n");
	    detachParticipant();
	}
    }
353

354
    if (!getAccountLink (currentAccountId)->answer (id)) {
355
356
357
358
        // error when receiving...
        removeCallAccount (id);
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
359

360
361
    // if it was waiting, it's waiting no more
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "CURRENT");
362
363
364
365
        
    std::string codecName = Manager::instance().getCurrentCodecName (id);
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
        
366
    removeWaitingCall (id);
367

368
369
370
    switchCall (id);

    return true;
jpbl's avatar
jpbl committed
371
372
}

yanmorin's avatar
   
yanmorin committed
373
//THREAD=Main
374
375
bool
ManagerImpl::hangupCall (const CallID& id)
jpbl's avatar
jpbl committed
376
{
377
    _debug ("ManagerImpl::hangupCall()\n");
378
379
380
    PulseLayer *pulselayer;
    AccountID accountid;
    bool returnValue;
381
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
382

383
    stopTone (false);
384
    switchCall (id);
yanmorin's avatar
   
yanmorin committed
385

386
    /* Broadcast a signal over DBus */
387

388
    _debug("ManagerImpl::hangupCall: Send DBUS call state change (HUNGUP) for id %s\n", id.c_str());
389
390
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

391
392
    int nbCalls = getCallList().size();

393
    audiolayer = getAudioDriver();
394
    // stop streamx
395
396
397
    if (! (nbCalls >= 1))
    {
	_debug("ManagerImpl::stop audio stream, ther is only %i call(s) remaining\n", nbCalls);
398
        audiolayer->stopStream();
399
    }
400

Emmanuel Milou's avatar
Emmanuel Milou committed
401
402
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
403
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);
404
    }
405

Emmanuel Milou's avatar
Emmanuel Milou committed
406
    /* Classic call, attached to an account */
407
    else {
408
409
        accountid = getAccountFromCall (id);

410
411
        if (accountid == AccountNULL) 
	{
412
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
413
414
            return false;
        }
415
416
417
418

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
419
    }
420

421
    _debug("ManagerImpl::hangupCall CURRENT CALL ID %s\n", getCurrentCallId().c_str());
422

423
    switchCall ("");
424

425
    _debug("ManagerImpl::hangupCall CURRENT CALL ID %s\n", getCurrentCallId().c_str());
426

427
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
428
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
429
430

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
431
    }
432

433
434
435
436
437
    if(participToConference(id))
    {
	removeParticipant(id);
    }

438
    return returnValue;
jpbl's avatar
jpbl committed
439
440
}

Alexandre Savard's avatar
Alexandre Savard committed
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476

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

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

    ConferenceCallMap tempmap = _conferencecall;

    AccountID currentAccountId;

    Call* call = NULL;

    if(iter_conf != _conferencemap.end())
    {
	conf = iter_conf->second;
 
	ConferenceCallMap::iterator iter_participant = tempmap.begin();

	while(iter_participant != tempmap.end())
	{
	    _debug("ManagerImpl::hangupConference participant %s\n", iter_participant->first.c_str());
	    currentAccountId = getAccountFromCall (iter_participant->first);
	    call = getAccountLink (currentAccountId)->getCall (iter_participant->first);

	    if(call->getConfId() == id)
	        hangupCall (iter_participant->first);

	    iter_participant++;

	}

    }

477
478
    switchCall ("");

Alexandre Savard's avatar
Alexandre Savard committed
479
480
481
482
    return true;
}


yanmorin's avatar
   
yanmorin committed
483
//THREAD=Main
484
bool
yanmorin's avatar
   
yanmorin committed
485
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
486
{
Emmanuel Milou's avatar
Emmanuel Milou committed
487
488
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
489

490
    stopTone (true);
491

Emmanuel Milou's avatar
Emmanuel Milou committed
492
    /* Direct IP to IP call */
493

Emmanuel Milou's avatar
Emmanuel Milou committed
494
    if (getConfigFromCall (id) == Call::IPtoIP) {
495
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
496
497
498
    }

    /* Classic call, attached to an account */
499
    else {
500
501
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
502
        if (accountid == AccountNULL) {
503
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
504
505
            return false;
        }
506
507
508
509

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
510
    }
511

Emmanuel Milou's avatar
Emmanuel Milou committed
512
    // it could be a waiting call?
513
514
515
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
516
517

    return returnValue;
jpbl's avatar
jpbl committed
518
519
}

yanmorin's avatar
   
yanmorin committed
520
//THREAD=Main
521
522
bool
ManagerImpl::onHoldCall (const CallID& id)
jpbl's avatar
jpbl committed
523
{
Emmanuel Milou's avatar
Emmanuel Milou committed
524
525
    AccountID accountid;
    bool returnValue;
526
    CallID call_id;
yanmorin's avatar
   
yanmorin committed
527

528
    stopTone (true);
529

530
531
    call_id = id;

532
    switchCall (id);
533

Emmanuel Milou's avatar
Emmanuel Milou committed
534
    /* Direct IP to IP call */
535

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

Emmanuel Milou's avatar
Emmanuel Milou committed
540
    /* Classic call, attached to an account */
541
    else {
542
543
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
544
        if (accountid == AccountNULL) {
545
            _debug ("Manager On Hold Call: Account ID %s or callid %s doesn't exists\n", accountid.c_str(), id.c_str());
Emmanuel Milou's avatar
Emmanuel Milou committed
546
547
            return false;
        }
548
549

        returnValue = getAccountLink (accountid)->onhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
550
    }
551

552
553
554
    removeWaitingCall (id);

    switchCall ("");
555

556
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
557

Emmanuel Milou's avatar
Emmanuel Milou committed
558
    return returnValue;
yanmorin's avatar
   
yanmorin committed
559
560
561
}

//THREAD=Main
562
563
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
564
{
565

Emmanuel Milou's avatar
Emmanuel Milou committed
566
567
568
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
569
    CallID call_id, current_call_id;
570

571
    stopTone (false);
572

573
    call_id = id;
574
    current_call_id = getCurrentCallId();
Emmanuel Milou's avatar
Emmanuel Milou committed
575
    //Place current call on hold if it isn't
576

577
    if (hasCurrentCall()) 
578
    {
579
580
581
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(current_call_id) && !participToConference(current_call_id))
	{
Alexandre Savard's avatar
Alexandre Savard committed
582
	    _debug ("ManagerImpl::offHoldCall put current call (ID=%s) on hold\n", current_call_id.c_str());
583
584
	    onHoldCall (current_call_id);
	}
Alexandre Savard's avatar
Alexandre Savard committed
585
	else if (isConference(current_call_id))
586
	{
Alexandre Savard's avatar
Alexandre Savard committed
587
588
	    _debug ("ManagerImpl::offHoldCall Put current conference (ID=%s) on hold\n", current_call_id.c_str());
	    detachParticipant();
589
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
590
    }
591

592
    // switch current call id to id since sipvoip link need it to amke a call 
593
594
    switchCall(id);

Emmanuel Milou's avatar
Emmanuel Milou committed
595
596
597
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
598
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
599
    }
alexandresavard's avatar
alexandresavard committed
600

Emmanuel Milou's avatar
Emmanuel Milou committed
601
    /* Classic call, attached to an account */
602
    else {
603
604
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
605
        if (accountid == AccountNULL) {
606
            _debug ("Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
607
608
            return false;
        }
609
610
611
612
613

        _debug ("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());

        rec = getAccountLink (accountid)->isRecording (id);
        returnValue = getAccountLink (accountid)->offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
614
    }
alexandresavard's avatar
alexandresavard committed
615

616

617
    if (_dbus) {
Emmanuel Milou's avatar
Emmanuel Milou committed
618
        if (rec)
619
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
620
        else
621
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
622

Emmanuel Milou's avatar
Emmanuel Milou committed
623
    }
624

625
626
627
628
629
630
631
    if ( participToConference(id) ) {
	ConferenceCallMap::iterator iter = _conferencecall.find(id);
	if(iter != _conferencecall.end())
	    switchCall(iter->second->getConfID());
    }
    // else the 
  
632

633
    codecName = getCurrentCodecName (id);
634
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
635
636

    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
637

Emmanuel Milou's avatar
Emmanuel Milou committed
638
    return returnValue;
jpbl's avatar
jpbl committed
639
640
}

yanmorin's avatar
   
yanmorin committed
641
//THREAD=Main
642
643
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
644
{
Emmanuel Milou's avatar
Emmanuel Milou committed
645
646
    AccountID accountid;
    bool returnValue;
647

648
    stopTone (true);
649

Emmanuel Milou's avatar
Emmanuel Milou committed
650
    /* Direct IP to IP call */
651

Emmanuel Milou's avatar
Emmanuel Milou committed
652
    if (getConfigFromCall (id) == Call::IPtoIP) {
653
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
654
655
656
    }

    /* Classic call, attached to an account */
657
    else {
658
659
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
660
        if (accountid == AccountNULL) {
661
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
662
663
            return false;
        }
664
665
666
667

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
668
    }
669

670
671
672
673
674
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
676
    return returnValue;
jpbl's avatar
jpbl committed
677
678
}

679
680
void ManagerImpl::transferFailed()
{
681
    if (_dbus) _dbus->getCallManager()->transferFailed();
682
683
684
685
}

void ManagerImpl::transferSucceded()
{
686
    if (_dbus) _dbus->getCallManager()->transferSucceded();
687
688
689
690

}


yanmorin's avatar
   
yanmorin committed
691
//THREAD=Main : Call:Incoming
692
bool
yanmorin's avatar
   
yanmorin committed
693
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
694
{
Emmanuel Milou's avatar
Emmanuel Milou committed
695
696
    AccountID accountid;
    bool returnValue;
697

698
699
700
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
701
702

    if (getConfigFromCall (id) == Call::IPtoIP) {
703
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
704
705
706
    }

    /* Classic call, attached to an account */
707
    else {
708
709
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
718
719
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
720
721
722
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
723
724
725
726
727
        removeWaitingCall (id);

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
728
    }
729

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

733

734
Conference*
735
ManagerImpl::createConference(const CallID& id1, const CallID& id2)
736
737
{
    _debug("ManagerImpl::createConference()\n");
738
    
739
    Conference* conf = new Conference(default_conf);
740

741
742
    _conferencecall.insert(pair<CallID, Conference*>(id1, conf));
    _conferencecall.insert(pair<CallID, Conference*>(id2, conf));
743
    _conferencemap.insert(pair<CallID, Conference*>(default_conf, conf));
744

745
746
    conf->add(id1);
    conf->add(id2);
747

748
    // broadcast a signal over dbus
749
    _dbus->getCallManager()->conferenceCreated(default_conf);
750
751
    
    return conf;
752
753
754
}

void
755
ManagerImpl::removeConference(const ConfID& conference_id)
756
{
757
758
759

    _debug("ManagerImpl::removeConference(%s)\n", conference_id.c_str());

760
761
762
763
    Conference* conf;
    conf = NULL;

    _debug("ManagerImpl:: _conferencemap.size: %i\n", _conferencemap.size());
764
765
    ConferenceMap::iterator iter = _conferencemap.find(conference_id);

766
    if (iter != _conferencemap.end()) {
767
768
769
770
771
772
	_debug("Found conference id %s in conferencemap\n", conference_id.c_str());
        conf = iter->second;
    }

    if(conf == NULL)
	return;
773

774
775
    ConferenceCallMap temp_map = _conferencecall;

776
    _debug("ManagerImpl:: _conferencecall.size: %i\n", _conferencecall.size());
777
    ConferenceCallMap::iterator iter_p = temp_map.begin();
778
779
780
    while (iter_p != temp_map.end()) {

	if(iter_p->second == conf) {
781
	    _debug("ManagerImpl:: remove particiant (%s) from conference %s\n", iter_p->first.c_str(), conference_id.c_str());
782
	    _conferencecall.erase(iter_p->first);
783
	}
784
785

	iter_p++;
786
787
    }

788
789
    

790
791
792
793
794
    _debug("ManagerImpl:: remove conference %s\n", conference_id.c_str());
    if (_conferencemap.erase(conference_id) == 1)
        _debug("ManagerImpl:: conference %s removed succesfully\n", conference_id.c_str());
    else
	_debug("ManagerImpl:: error cannot remove conference id: %s\n", conference_id.c_str());
795

796
    // broadcast a signal over dbus
797
798
    _debug("ManagerImpl:: broadcast call removed on dbus: %s\n", conference_id.c_str());
    _dbus->getCallManager()->conferenceRemoved(conference_id);
799

800
801
}

802
803
804
void
ManagerImpl::holdConference(const CallID& id)
{
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
    _debug ("ManagerImpl::holdConference()\n");

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

    AccountID currentAccountId;

    Call* call = NULL;

    if(iter_conf != _conferencemap.end())
    {
	conf = iter_conf->second;
 
	ConferenceCallMap::iterator iter_participant = _conferencecall.begin();

	while(iter_participant != _conferencecall.end())
	{
822
	    _debug("ManagerImpl::holdConference participant %s\n", iter_participant->first.c_str());
823
824
825
826
	    currentAccountId = getAccountFromCall (iter_participant->first);
	    call = getAccountLink (currentAccountId)->getCall (iter_participant->first);

	    if(call->getConfId() == id)
827
828
	    {
		switchCall(iter_participant->first);
829
	        onHoldCall (iter_participant->first);
830
	    }
831
832
833
834
835
836
837

	    iter_participant++;

	}

    }

838
839