managerimpl.cpp 100 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
    if(participToConference(id))
    {
435
	_debug("??????????????????? STILL PARTICIP TO A CONFERENCE ?????????????????\n");
436
437
438
	removeParticipant(id);
    }

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

Alexandre Savard's avatar
Alexandre Savard committed
442
443
444
445
446
447
448
449
450
451
452

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

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

    AccountID currentAccountId;

453
    // Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
454
455
456
457
458

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

462
	while(iter_participant != participants.end())
Alexandre Savard's avatar
Alexandre Savard committed
463
	{
464
	    _debug("ManagerImpl::hangupConference participant %s\n", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
465

466
	    hangupCall (*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
467
468
469
470
471
472
473

	    iter_participant++;

	}

    }

474
475
    switchCall ("");

Alexandre Savard's avatar
Alexandre Savard committed
476
477
478
479
    return true;
}


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

487
    stopTone (true);
488

Emmanuel Milou's avatar
Emmanuel Milou committed
489
    /* Direct IP to IP call */
490

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

    /* Classic call, attached to an account */
496
    else {
497
498
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
507
    }
508

Emmanuel Milou's avatar
Emmanuel Milou committed
509
    // it could be a waiting call?
510
511
512
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
513
514

    return returnValue;
jpbl's avatar
jpbl committed
515
516
}

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

525
    stopTone (true);
526

527
528
    call_id = id;

529
    switchCall (id);
530

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

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
541
        if (accountid == AccountNULL) {
542
            _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
543
544
            return false;
        }
545
546

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

549
550
551
    removeWaitingCall (id);

    switchCall ("");
552

553
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
554

Emmanuel Milou's avatar
Emmanuel Milou committed
555
    return returnValue;
yanmorin's avatar
   
yanmorin committed
556
557
558
}

//THREAD=Main
559
560
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
561
{
562

Emmanuel Milou's avatar
Emmanuel Milou committed
563
564
565
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
566
    CallID call_id, current_call_id;
567

568
    stopTone (false);
569

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

574
    if (hasCurrentCall()) 
575
    {
576
577
578
	// 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
579
	    _debug ("ManagerImpl::offHoldCall put current call (ID=%s) on hold\n", current_call_id.c_str());
580
581
	    onHoldCall (current_call_id);
	}
Alexandre Savard's avatar
Alexandre Savard committed
582
	else if (isConference(current_call_id))
583
	{
Alexandre Savard's avatar
Alexandre Savard committed
584
585
	    _debug ("ManagerImpl::offHoldCall Put current conference (ID=%s) on hold\n", current_call_id.c_str());
	    detachParticipant();
586
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
587
    }
588

589
    // switch current call id to id since sipvoip link need it to amke a call 
590
591
    switchCall(id);

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

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

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

        _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
611
    }
alexandresavard's avatar
alexandresavard committed
612

613

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

Emmanuel Milou's avatar
Emmanuel Milou committed
620
    }
621

622
    if ( participToConference(id) ) {
623
624
625
626
627
628
629
630
631

	 
	AccountID currentAccountId;
        Call* call = NULL;

	currentAccountId = getAccountFromCall (id);
	call = getAccountLink (currentAccountId)->getCall (id);
	
	switchCall(call->getConfId());
632
633
634
    }
    // else the 
  
635

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
641
    return returnValue;
jpbl's avatar
jpbl committed
642
643
}

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

651
    stopTone (true);
652

Emmanuel Milou's avatar
Emmanuel Milou committed
653
    /* Direct IP to IP call */
654

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

    /* Classic call, attached to an account */
660
    else {
661
662
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
671
    }
672

673
674
675
676
677
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
679
    return returnValue;
jpbl's avatar
jpbl committed
680
681
}

682
683
void ManagerImpl::transferFailed()
{
684
    if (_dbus) _dbus->getCallManager()->transferFailed();
685
686
687
688
}

void ManagerImpl::transferSucceded()
{
689
    if (_dbus) _dbus->getCallManager()->transferSucceded();
690
691
692
693

}


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

701
702
703
    stopTone (true);

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

    if (getConfigFromCall (id) == Call::IPtoIP) {
706
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
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 OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
715
716
            return false;
        }
717
718
719
720

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

        removeCallAccount (id);
721
722
    }

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

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
731
    }
732

Emmanuel Milou's avatar
Emmanuel Milou committed
733
    return returnValue;
jpbl's avatar
jpbl committed
734
735
}

736

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

744
745
    // _conferencecall.insert(pair<CallID, Conference*>(id1, conf));
    // _conferencecall.insert(pair<CallID, Conference*>(id2, conf));
746
    _conferencemap.insert(pair<CallID, Conference*>(default_conf, conf));
747

748
749
    conf->add(id1);
    conf->add(id2);
750

751
    // broadcast a signal over dbus
752
    _dbus->getCallManager()->conferenceCreated(default_conf);
753
754
    
    return conf;
755
756
757
}

void
758
ManagerImpl::removeConference(const ConfID& conference_id)
759
{
760
761
762

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

763
764
765
    Conference* conf;
    conf = NULL;

766
    _debug("ManagerImpl::removeConference _conferencemap.size: %i\n", _conferencemap.size());
767
768
    ConferenceMap::iterator iter = _conferencemap.find(conference_id);

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

    if(conf == NULL)
	return;
776

777
778
779
780
781
782
783
    // broadcast a signal over dbus
    _debug("ManagerImpl::removeConference broadcast call removed on dbus: %s\n", conference_id.c_str());
    _dbus->getCallManager()->conferenceRemoved(conference_id);


    /*
    ParticipantSet participants = conf->getParticipantList();
784

785
786
787
    _debug("ManagerImpl::removeConference _conferencecall.size: %i\n", _conferencecall.size());
    ConferenceCallMap::iterator iter_p = participants.begin();
    while (iter_p != participants.end()) {
788

789
	
790
	    _conferencecall.erase(iter_p->first);
791
	
792
793

	iter_p++;
794
    }
795
    */
796

797
798
    

799
800
801
802
803
    _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());
804

805
    // broadcast a signal over dbus
806
807
    // _debug("ManagerImpl:: broadcast call removed on dbus: %s\n", conference_id.c_str());
    // _dbus->getCallManager()->conferenceRemoved(conference_id);
808

809