managerimpl.cpp 87.2 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
189
190
191
192
193
194
195
ManagerImpl::hasCurrentCall()
{
    _debug ("Current call ID = %s\n", _currentCallId2.c_str());

    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
208
ManagerImpl::switchCall (const CallID& id)
{
    ost::MutexLock m (_currentCallMutex);
    _currentCallId2 = id;
jpbl's avatar
jpbl committed
209
210
211
212
213
214
}


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

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

224
    _debug ("ManagerImpl::outgoingCall() method \n");
225

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

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
236
237
238
    if (callConfig == Call::IPtoIP) {
        _debug ("Start IP to IP call\n");
        /* We need to retrieve the sip voiplink instance */
239
240
        siplink = SIPVoIPLink::instance ("");

241
        if (siplink->new_ip_to_ip_call (id, to_cleaned)) {
Emmanuel Milou's avatar
Emmanuel Milou committed
242
243
            switchCall (id);
            return true;
244
        } else {
Emmanuel Milou's avatar
Emmanuel Milou committed
245
246
            callFailure (id);
        }
247

Emmanuel Milou's avatar
Emmanuel Milou committed
248
        return false;
249
    }
250

251
252
    if (!accountExists (accountid)) {
        _debug ("! Manager Error: Outgoing Call: account doesn't exist\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
253
254
        return false;
    }
255

256
257
    if (getAccountFromCall (id) != AccountNULL) {
        _debug ("! Manager Error: Outgoing Call: call id already exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
258
259
        return false;
    }
260

Emmanuel Milou's avatar
Emmanuel Milou committed
261
    if (hasCurrentCall()) {
262
263
        _debug ("* Manager Info: there is currently a call, try to hold it\n");
        onHoldCall (getCurrentCallId());
Emmanuel Milou's avatar
Emmanuel Milou committed
264
    }
265

266
267
268
269
270
271
    _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
272
273
        return true;
    } else {
274
275
        callFailure (id);
        _debug ("! Manager Error: An error occur, the call was not created\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
276
    }
277

Emmanuel Milou's avatar
Emmanuel Milou committed
278
    return false;
jpbl's avatar
jpbl committed
279
280
}

yanmorin's avatar
   
yanmorin committed
281
//THREAD=Main : for outgoing Call
282
283
bool
ManagerImpl::answerCall (const CallID& id)
jpbl's avatar
jpbl committed
284
{
285
286
287
    bool isActive = false;

    stopTone (true);
288

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
    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");
    }
    
    Call* lastCall = NULL;
    if (!getCurrentCallId().empty()) {
        lastCall = getAccountLink (currentAccountId)->getCall (getCurrentCallId());
        if (lastCall == NULL) {
            _debug("ManagerImpl::answerCall : lastCall is null\n");
        }
308
    }
309

310
311
    _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
312

313
    if (lastCall != NULL ) {
314
        if (lastCall->getState() == Call::Active && !participToConference(getCurrentCallId())) {
315
316
317
            _debug ("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall (getCurrentCallId());
        }
318
319
	else
	{
320
	    _debug("Current call particips to a conference! Do not hold it!\n");
321
	}
322
323
    }

324
    if (!getAccountLink (currentAccountId)->answer (id)) {
325
326
327
328
        // error when receiving...
        removeCallAccount (id);
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
329

330
331
    // if it was waiting, it's waiting no more
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "CURRENT");
332
333
334
335
        
    std::string codecName = Manager::instance().getCurrentCodecName (id);
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
        
336
    removeWaitingCall (id);
337

338
339
340
    switchCall (id);

    return true;
jpbl's avatar
jpbl committed
341
342
}

yanmorin's avatar
   
yanmorin committed
343
//THREAD=Main
344
345
bool
ManagerImpl::hangupCall (const CallID& id)
jpbl's avatar
jpbl committed
346
{
347
    _debug ("ManagerImpl::hangupCall()\n");
348
349
350
    PulseLayer *pulselayer;
    AccountID accountid;
    bool returnValue;
351
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
352

353
    stopTone (false);
354
    switchCall (id);
yanmorin's avatar
   
yanmorin committed
355

356
    /* Broadcast a signal over DBus */
357

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

361
362
    int nbCalls = getCallList().size();

363
    audiolayer = getAudioDriver();
364
    // stop streamx
365
366
367
    if (! (nbCalls >= 1))
    {
	_debug("ManagerImpl::stop audio stream, ther is only %i call(s) remaining\n", nbCalls);
368
        audiolayer->stopStream();
369
    }
370

Emmanuel Milou's avatar
Emmanuel Milou committed
371
372
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
373
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);
374
    }
375

Emmanuel Milou's avatar
Emmanuel Milou committed
376
    /* Classic call, attached to an account */
377
    else {
378
379
        accountid = getAccountFromCall (id);

380
381
        if (accountid == AccountNULL) 
	{
382
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
383
384
            return false;
        }
385
386
387
388

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
389
    }
390

391
392
393
    if(participToConference(id))
	removeParticipant(id);

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

396
    switchCall ("");
397

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

400
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
401
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
402
403

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
404
    }
405

406
    return returnValue;
jpbl's avatar
jpbl committed
407
408
}

yanmorin's avatar
   
yanmorin committed
409
//THREAD=Main
410
bool
yanmorin's avatar
   
yanmorin committed
411
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
412
{
Emmanuel Milou's avatar
Emmanuel Milou committed
413
414
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
415

416
    stopTone (true);
417

Emmanuel Milou's avatar
Emmanuel Milou committed
418
    /* Direct IP to IP call */
419

Emmanuel Milou's avatar
Emmanuel Milou committed
420
    if (getConfigFromCall (id) == Call::IPtoIP) {
421
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
422
423
424
    }

    /* Classic call, attached to an account */
425
    else {
426
427
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
428
        if (accountid == AccountNULL) {
429
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
430
431
            return false;
        }
432
433
434
435

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
436
    }
437

Emmanuel Milou's avatar
Emmanuel Milou committed
438
    // it could be a waiting call?
439
440
441
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
442
443

    return returnValue;
jpbl's avatar
jpbl committed
444
445
}

yanmorin's avatar
   
yanmorin committed
446
//THREAD=Main
447
448
bool
ManagerImpl::onHoldCall (const CallID& id)
jpbl's avatar
jpbl committed
449
{
Emmanuel Milou's avatar
Emmanuel Milou committed
450
451
    AccountID accountid;
    bool returnValue;
452
    CallID call_id;
yanmorin's avatar
   
yanmorin committed
453

454
    stopTone (true);
455

456
457
    call_id = id;

458
459
460
    if(participToConference(id))
	removeParticipant(id);

Emmanuel Milou's avatar
Emmanuel Milou committed
461
    /* Direct IP to IP call */
462

Emmanuel Milou's avatar
Emmanuel Milou committed
463
    if (getConfigFromCall (id) == Call::IPtoIP) {
464
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
465
    }
466

Emmanuel Milou's avatar
Emmanuel Milou committed
467
    /* Classic call, attached to an account */
468
    else {
469
470
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
471
        if (accountid == AccountNULL) {
472
            _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
473
474
            return false;
        }
475
476

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

479
480
481
    removeWaitingCall (id);

    switchCall ("");
482

483
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
484

Emmanuel Milou's avatar
Emmanuel Milou committed
485
    return returnValue;
yanmorin's avatar
   
yanmorin committed
486
487
488
}

//THREAD=Main
489
490
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
491
{
492

Emmanuel Milou's avatar
Emmanuel Milou committed
493
494
495
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
496
    CallID call_id;
497

498
    stopTone (false);
499

500
    call_id = id;
Emmanuel Milou's avatar
Emmanuel Milou committed
501
    //Place current call on hold if it isn't
502
503

    if (hasCurrentCall()) {
504
        _debug ("Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
505
        onHoldCall (getCurrentCallId());
Emmanuel Milou's avatar
Emmanuel Milou committed
506
    }
507

Emmanuel Milou's avatar
Emmanuel Milou committed
508
509
510
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
511
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
512
    }
alexandresavard's avatar
alexandresavard committed
513

Emmanuel Milou's avatar
Emmanuel Milou committed
514
    /* Classic call, attached to an account */
515
    else {
516
517
        accountid = getAccountFromCall (id);

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

        _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
527
    }
alexandresavard's avatar
alexandresavard committed
528

529

530
    if (_dbus) {
Emmanuel Milou's avatar
Emmanuel Milou committed
531
        if (rec)
532
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
533
        else
534
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
535

Emmanuel Milou's avatar
Emmanuel Milou committed
536
    }
537

538
    switchCall (id);
539

540
    codecName = getCurrentCodecName (id);
541
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
542
543

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

Emmanuel Milou's avatar
Emmanuel Milou committed
545
    return returnValue;
jpbl's avatar
jpbl committed
546
547
}

yanmorin's avatar
   
yanmorin committed
548
//THREAD=Main
549
550
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
551
{
Emmanuel Milou's avatar
Emmanuel Milou committed
552
553
    AccountID accountid;
    bool returnValue;
554

555
    stopTone (true);
556

Emmanuel Milou's avatar
Emmanuel Milou committed
557
    /* Direct IP to IP call */
558

Emmanuel Milou's avatar
Emmanuel Milou committed
559
    if (getConfigFromCall (id) == Call::IPtoIP) {
560
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
561
562
563
    }

    /* Classic call, attached to an account */
564
    else {
565
566
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
567
        if (accountid == AccountNULL) {
568
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
569
570
            return false;
        }
571
572
573
574

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
575
    }
576

577
578
579
580
581
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
583
    return returnValue;
jpbl's avatar
jpbl committed
584
585
}

586
587
void ManagerImpl::transferFailed()
{
588
    if (_dbus) _dbus->getCallManager()->transferFailed();
589
590
591
592
}

void ManagerImpl::transferSucceded()
{
593
    if (_dbus) _dbus->getCallManager()->transferSucceded();
594
595
596
597

}


yanmorin's avatar
   
yanmorin committed
598
//THREAD=Main : Call:Incoming
599
bool
yanmorin's avatar
   
yanmorin committed
600
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
601
{
Emmanuel Milou's avatar
Emmanuel Milou committed
602
603
    AccountID accountid;
    bool returnValue;
604

605
606
607
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
608
609

    if (getConfigFromCall (id) == Call::IPtoIP) {
610
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
611
612
613
    }

    /* Classic call, attached to an account */
614
    else {
615
616
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
625
626
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
627
628
629
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
630
631
632
633
634
        removeWaitingCall (id);

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
635
    }
636

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

640
641

void
642
ManagerImpl::createConference(const CallID& id)
643
644
{
    _debug("ManagerImpl::createConference()\n");
645
646
    
    Conference* conf = new Conference();
647
648

    _conferencecall.insert(pair<CallID, Conference*>(id, conf));
649
    _conferencecall.insert(pair<CallID, Conference*>(getCurrentCallId(), conf));
650
    _conferencemap.insert(pair<CallID, Conference*>(default_conf, conf));
651
652
653
654
655
656
657

    conf->add(getCurrentCallId());
    conf->add(id);

}

void
658
ManagerImpl::removeConference(const CallID& conference_id)
659
{
660
661
662

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

663
664
665
666
    Conference* conf;
    conf = NULL;

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

669
670
671
672
673
674
675
676
    if (iter != _conferencemap.end())
    {
	_debug("Found conference id %s in conferencemap\n", conference_id.c_str());
        conf = iter->second;
    }

    if(conf == NULL)
	return;
677

678
679
    ConferenceCallMap temp_map = _conferencecall;

680
    _debug("ManagerImpl:: _conferencecall.size: %i\n", _conferencecall.size());
681
682
    ConferenceCallMap::iterator iter_p = temp_map.begin();
    while (iter_p != temp_map.end())
683
    {
684
	_debug("ManagerImpl:: iterate participant %s\n", iter_p->first.c_str());
685
686
	if(iter_p->second == conf)
	{
687
	    _debug("ManagerImpl:: remove particiant (%s) from conference %s\n", iter_p->first.c_str(), conference_id.c_str());
688
	    _conferencecall.erase(iter_p->first);
689
	}
690
691

	iter_p++;
692
693
    }

694
695
696
697
698
    _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());
699

700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
}

bool
ManagerImpl::participToConference(const CallID& call_id)
{
    ConferenceCallMap::iterator iter = _conferencecall.find(call_id);
    if(iter == _conferencecall.end())
    {
	return false;
    }
    else
    {
	return true;
    }
}

void
ManagerImpl::addParticipant(const CallID& call_id)
{
    _debug("ManagerImpl::addParticipant(%s)\n", call_id.c_str());
720
721
    _debug("    Current call ID %s\n", getCurrentCallId().c_str());

722
    // TODO: add conference_id as a second parameter
723
    ConferenceMap::iterator iter = _conferencemap.find(default_conf);
724
725

    if(iter == _conferencemap.end())
726
727
    {
	_debug("NO CONFERENCE YET, CREATE ONE\n");
728
	createConference(call_id);
729
730
731

	answerCall(call_id);

732
733
734
735
    }
    else
    {
	_debug("ALREADY A CONFERENCE CREATED, ADD PARTICIPANT TO IT\n");
736
	Conference* conf = iter->second;
737

738
739
740
	conf->add(call_id);
	
	_conferencecall.insert(pair<CallID, Conference*>(call_id, conf));
741

742
	answerCall(call_id);
743
744
    }
    
745
746
}

747
748
749
750
751
752
753
void
ManagerImpl::removeParticipant(const CallID& call_id)
{
    _debug("ManagerImpl::removeParticipant(%s)\n", call_id.c_str());

    // TODO: add conference_id as a second parameter
    Conference* conf;
754
755
756

    ConferenceMap conf_map = _conferencemap;
    ConferenceMap::iterator iter = conf_map.find(default_conf);
757
758
759
760
761
762
763
764
765
766
767
768

    if(iter == _conferencemap.end())
    {
	_debug("NO CONFERENCE CREATED, CANNOT REMOVE PARTICIPANT\n");
    }
    else
    {
	conf = iter->second;

	_debug("REMOVE PARTICIPANT %s\n", call_id.c_str());
	conf->remove(call_id);

769
	_conferencecall.erase(iter->first);
770
771

	if (conf->getNbParticipants() <= 1)
772
	    removeConference(default_conf);
773
774
775
    }
}

776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
void
ManagerImpl::addStream(const CallID& call_id)
{
    _debug("ManagerImpl::addStream %s\n", call_id.c_str());

    if(participToConference(call_id))
    {
	ConferenceMap::iterator iter = _conferencemap.find(default_conf);
	
	Conference* conf = iter->second;

	conf->bindParticipant(call_id);
    }
    else
    {
	getAudioDriver()->getMainBuffer()->bindCallID(call_id);
    }
}

yanmorin's avatar
   
yanmorin committed
795
//THREAD=Main
796
bool
jpbl's avatar
jpbl committed
797
798
ManagerImpl::saveConfig (void)
{
799
800
801
    _debug ("Saving Configuration...\n");
    setConfig (AUDIO, VOLUME_SPKR, getSpkrVolume());
    setConfig (AUDIO, VOLUME_MICRO, getMicVolume());
jpbl's avatar
jpbl committed
802

803
804
    _setupLoaded = _config.saveConfigTree (_path.data());
    return _setupLoaded;
jpbl's avatar
jpbl committed
805
806
}

yanmorin's avatar
   
yanmorin committed
807
//THREAD=Main
808
int
809
ManagerImpl::initRegisterAccounts()
jpbl's avatar
jpbl committed
810
{
811
    int status;
812
    bool flag = true;
813
814
    AccountMap::iterator iter;

815
    _debugInit ("Initiate VoIP Links Registration");
816
817
    iter = _accountMap.begin();

818
    /* Loop on the account map previously loaded */
819
820
821

    while (iter != _accountMap.end()) {
        if (iter->second) {
822
823
            iter->second->loadConfig();
            /* If the account is set as enabled, try to register */
824
825
826
827
828
829

            if (iter->second->isEnabled()) {
                status = iter->second->registerVoIPLink();

                if (status != SUCCESS) {
                    flag = false;
830
831
                }
            }
832
        }
833

834
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
835
    }
836

837
    // calls the client notification here in case of errors at startup...
838
839
840
841