managerimpl.cpp 122 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010 Savoir-Faire Linux Inc.
3
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
jpbl's avatar
jpbl committed
4
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
5
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
6
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
7
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
8
 *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
9
 *
jpbl's avatar
jpbl committed
10
11
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
13
 *  (at your option) any later version.
14
 *
jpbl's avatar
jpbl committed
15
16
17
18
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
19
 *
jpbl's avatar
jpbl committed
20
21
22
 *  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.
23
24
25
26
27
28
29
30
31
32
33
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
jpbl's avatar
jpbl committed
34
35
 */

36
37
38
39
40
#include "managerimpl.h"

#include "account.h"
#include "dbus/callmanager.h"
#include "user_cfg.h"
41
#include "global.h"
42
#include "sip/sipaccount.h"
43

44
45
46
47
48
49
50
51
52
53
#include "audio/audiolayer.h"
#include "audio/alsa/alsalayer.h"
#include "audio/pulseaudio/pulselayer.h"
#include "audio/sound/tonelist.h"
#include "history/historymanager.h"
#include "accountcreator.h" // create new account
#include "sip/sipvoiplink.h"
#include "manager.h"
#include "dbus/configurationmanager.h"

54
55
#include "conference.h"

jpbl's avatar
jpbl committed
56
57
58
59
60
#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
61
#include <sstream>
jpbl's avatar
jpbl committed
62
#include <sys/types.h> // mkdir(2)
63
64
#include <sys/stat.h>  // mkdir(2)
#include <pwd.h>       // getpwuid
65

66
#define DIRECT_IP_CALL	"IP CALL"
jpbl's avatar
jpbl committed
67
68
69
70
71
72

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

73
74
#define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len)

75
76
#define find_in_map(X, Y)  if((iter = map_cpy.find(X)) != map_cpy.end()) { Y = iter->second; }

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
ManagerImpl::ManagerImpl (void) :
	_hasTriedToRegister(false), _config(), _currentCallId2(),
			_currentCallMutex(), _codecBuilder(NULL), _audiodriver(NULL),
			_dtmfKey(NULL), _codecDescriptorMap(), _toneMutex(),
			_telephoneTone(NULL), _audiofile(), _spkr_volume(0),
			_mic_volume(0), _mutex(), _dbus(NULL), _waitingCall(),
			_waitingCallMutex(), _nbIncomingWaitingCall(0), _path(""),
			_exist(0), _setupLoaded(false), _callAccountMap(),
			_callAccountMapMutex(), _callConfigMap(), _accountMap(),
			_directIpAccount(NULL), _cleaner(NULL), _history(NULL) {

	// initialize random generator for call id
	srand(time(NULL));

	_cleaner = new NumberCleaner();
	_history = new HistoryManager();
93

yanmorin's avatar
   
yanmorin committed
94
#ifdef TEST
95
96
97
98
	testAccountMap();
	loadAccountMap();
	testCallAccountMap();
	unloadAccountMap();
yanmorin's avatar
   
yanmorin committed
99
100
#endif

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

// never call if we use only the singleton...
106
107
ManagerImpl::~ManagerImpl (void) {
	// terminate();
108
109
110
111
	delete _cleaner; _cleaner = NULL;
	delete _history; _history = NULL;

	_debug ("Manager: %s stop correctly.", PROGNAME);
jpbl's avatar
jpbl committed
112
113
}

114
void ManagerImpl::init () {
115

116
117
	// Load accounts, init map
	loadAccountMap();
118

119
	initVolume();
120

121
	if (_exist == 0) {
122
		_warn ("Manager: Cannot create config file in your home directory");
123
	}
124

125
	initAudioDriver();
jpbl's avatar
jpbl committed
126

127
	selectAudioDriver();
128

129
130
	// Initialize the list of supported audio codecs
	initAudioCodec();
131

132
	AudioLayer *audiolayer = getAudioDriver();
jpbl's avatar
jpbl committed
133

134
	if (audiolayer) {
135
		unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
136

137
		_debugInit ("Manager: Load telephone tone");
138
139
		std::string country = getConfigString(PREFERENCES, ZONE_TONE);
		_telephoneTone = new TelephoneTone(country, sampleRate);
140

141
		_debugInit ("Manager: Loading DTMF key");
142
143
		_dtmfKey = new DTMF(sampleRate);
	}
144

145
146
	// Load the history
	_history->load_history(getConfigInt(PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
147
148
}

149
void ManagerImpl::terminate () {
150
151

	_debug ("Manager: Terminate ");
152
	saveConfig();
jpbl's avatar
jpbl committed
153

154
	unloadAccountMap();
155

156
	_debug ("Manager: Unload DTMF key");
157
	delete _dtmfKey;
jpbl's avatar
jpbl committed
158

159
160
161
162
163
	_debug("Manager: Unload telephone tone");
	delete _telephoneTone; _telephoneTone = NULL;

	_debug ("Manager: Unload audio driver");
	delete _audiodriver; _audiodriver = NULL;
jpbl's avatar
jpbl committed
164

165
166
	_debug ("Manager: Unload telephone tone");
	delete _telephoneTone; _telephoneTone = NULL;
167

168
	_debug ("Manager: Unload audio codecs ");
169
	_codecDescriptorMap.deleteHandlePointer();
170

jpbl's avatar
jpbl committed
171
172
}

173
174
bool ManagerImpl::isCurrentCall (const CallID& callId) {
	return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
175
176
}

177
178
bool ManagerImpl::hasCurrentCall () {
	// _debug ("ManagerImpl::hasCurrentCall current call ID = %s", _currentCallId2.c_str());
179

180
181
182
	if (_currentCallId2 != "") {
		return true;
	}
183

184
	return false;
jpbl's avatar
jpbl committed
185
186
}

187
const CallID&
188
189
ManagerImpl::getCurrentCallId () {
	return _currentCallId2;
jpbl's avatar
jpbl committed
190
191
}

192
193
194
195
void ManagerImpl::switchCall (const CallID& id) {
	ost::MutexLock m(_currentCallMutex);
	_debug ("----- Switch current call id to %s -----", id.c_str());
	_currentCallId2 = id;
jpbl's avatar
jpbl committed
196
197
198
199
200
}

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

203
204
bool ManagerImpl::outgoingCall (const std::string& account_id,
		const CallID& call_id, const std::string& to) {
205

206
207
208
	std::string pattern, to_cleaned;
	Call::CallConfiguration callConfig;
	SIPVoIPLink *siplink;
209

210
	_debug ("Manager: New outgoing call %s to %s", call_id.c_str(), to.c_str());
211

212
	CallID current_call_id = getCurrentCallId();
Emmanuel Milou's avatar
Emmanuel Milou committed
213

214
215
216
217
218
	if (getConfigString(HOOKS, PHONE_NUMBER_HOOK_ENABLED) == "1")
		_cleaner->set_phone_number_prefix(getConfigString(HOOKS,
				PHONE_NUMBER_HOOK_ADD_PREFIX));
	else
		_cleaner->set_phone_number_prefix("");
Emmanuel Milou's avatar
Emmanuel Milou committed
219

220
	to_cleaned = _cleaner->clean(to);
221

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

225
226
	// in any cases we have to detach from current communication
	if (hasCurrentCall()) {
227

228
		_debug ("Manager: Has current call (%s) put it onhold", current_call_id.c_str());
229
		// if this is not a conferenceand this and is not a conference participant
230
		if (!isConference(current_call_id) && !participToConference(current_call_id)) {
231
			onHoldCall(current_call_id);
232
		} else if (isConference(current_call_id) && !participToConference(call_id)) {
233
234
235
			detachParticipant(default_id, current_call_id);
		}
	}
236

237
	if (callConfig == Call::IPtoIP) {
238
		_debug ("Manager: Start IP2IP call");
239
240
		/* We need to retrieve the sip voiplink instance */
		siplink = SIPVoIPLink::instance("");
241

242
243
244
245
246
247
		if (siplink->new_ip_to_ip_call(call_id, to_cleaned)) {
			switchCall(call_id);
			return true;
		} else {
			callFailure(call_id);
		}
248

249
250
		return false;
	}
251

252
	_debug("Manager: Selecting account %s", account_id.c_str());
253
	if (!accountExists(account_id)) {
254
		_error ("Manager: Error: Account doesn't exist in new outgoing call");
255
256
		return false;
	}
257

258
	if (getAccountFromCall(call_id) != AccountNULL) {
259
		_error ("Manager: Error: Call id already exists in outgoing call");
260
261
		return false;
	}
262

263
	_debug ("Manager: Adding Outgoing Call %s on account %s", call_id.data(), account_id.data());
264
	associateCallToAccount(call_id, account_id);
265

266
	if (getAccountLink(account_id)->newOutgoingCall(call_id, to_cleaned)) {
267
268
	    switchCall(call_id);
	    return true;
269
	} else {
270
271
	    callFailure(call_id);
	    _debug ("Manager: Error: An error occur, the call was not created");
272
	}
273

274
	return false;
jpbl's avatar
jpbl committed
275
276
}

yanmorin's avatar
   
yanmorin committed
277
//THREAD=Main : for outgoing Call
278
bool ManagerImpl::answerCall (const CallID& call_id) {
279

280
	_debug ("ManagerImpl: Answer call %s", call_id.c_str());
281

282
	stopTone();
283

284
285
	// store the current call id
	CallID current_call_id = getCurrentCallId();
286

287
	AccountID account_id = getAccountFromCall(call_id);
288

289
290
291
	if (account_id == AccountNULL) {
		_debug ("    answerCall: AccountId is null");
	}
292

293
	Call* call = NULL;
294

295
	call = getAccountLink(account_id)->getCall(call_id);
296

297
298
299
	if (call == NULL) {
		_debug ("    answerCall: Call is null");
	}
300

301
302
	// in any cases we have to detach from current communication
	if (hasCurrentCall()) {
303

304
305
		_debug ("    answerCall: Currently conversing with %s", current_call_id.c_str());
		// if it is not a conference and is not a conference participant
306

307
308
309
310
311
		if (!isConference(current_call_id) && !participToConference(
				current_call_id)) {
			_debug ("    answerCall: Put the current call (%s) on hold", current_call_id.c_str());
			onHoldCall(current_call_id);
		}
312

313
314
315
316
317
318
		// if we are talking to a conference and we are answering an incoming call
		else if (isConference(current_call_id)
				&& !participToConference(call_id)) {
			_debug ("    answerCall: Detach main participant from conference");
			detachParticipant(default_id, current_call_id);
		}
319

320
	}
321

322
323
324
325
326
	if (!getAccountLink(account_id)->answer(call_id)) {
		// error when receiving...
		removeCallAccount(call_id);
		return false;
	}
Alexandre Savard's avatar
Alexandre Savard committed
327

328
329
330
	// if it was waiting, it's waiting no more
	if (_dbus)
		_dbus->getCallManager()->callStateChanged(call_id, "CURRENT");
Emmanuel Milou's avatar
Emmanuel Milou committed
331

332
333
	// std::string codecName = Manager::instance().getCurrentCodecName (call_id);
	// if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str());
334

335
	removeWaitingCall(call_id);
336

337
338
	// if we dragged this call into a conference already
	if (participToConference(call_id)) {
339

340
341
		// AccountID currentAccountId;
		// Call* call = NULL;
342

343
344
		// currentAccountId = getAccountFromCall (call_id);
		// call = getAccountLink (currentAccountId)->getCall (call_id);
345

346
347
348
349
		switchCall(call->getConfId());
	} else {
		switchCall(call_id);
	}
350

351
	return true;
jpbl's avatar
jpbl committed
352
353
}

yanmorin's avatar
   
yanmorin committed
354
//THREAD=Main
355
bool ManagerImpl::hangupCall (const CallID& call_id) {
356
357
358

	_info("Manager: Hangup call %s", call_id.c_str());

359
360
361
	PulseLayer *pulselayer;
	AccountID account_id;
	bool returnValue = true;
Emmanuel Milou's avatar
Emmanuel Milou committed
362

363
364
	// store the current call id
	CallID current_call_id = getCurrentCallId();
365

366
	stopTone();
yanmorin's avatar
   
yanmorin committed
367

368
	/* Broadcast a signal over DBus */
369
	_debug ("Manager: Send DBUS call state change (HUNGUP) for id %s", call_id.c_str());
370

371
372
	if (_dbus)
		_dbus->getCallManager()->callStateChanged(call_id, "HUNGUP");
373

374
	if (participToConference(call_id)) {
375

376
		Conference *conf = getConferenceFromCallID(call_id);
377

378
379
380
		if (conf != NULL) {
			// remove this participant
			removeParticipant(call_id);
381

382
383
			processRemainingParticipant(current_call_id, conf);
		}
384

385
386
387
388
389
	} else {
		// we are not participating to a conference, current call switched to ""
		if (!isConference(current_call_id))
			switchCall("");
	}
390

391
392
393
394
395
396
397
	/* Direct IP to IP call */
	if (getConfigFromCall(call_id) == Call::IPtoIP) {
		returnValue = SIPVoIPLink::instance(AccountNULL)->hangup(call_id);
	}
	/* Classic call, attached to an account */
	else {
		account_id = getAccountFromCall(call_id);
398

399
		// Account may be NULL if call have not been sent yet
400
		if (account_id == AccountNULL) {
401
			_error ("Manager: Error: account id is NULL in hangup");
402
403
404
405
406
			returnValue = false;
		} else {
			returnValue = getAccountLink(account_id)->hangup(call_id);
			removeCallAccount(call_id);
		}
407
	}
408

409
	int nbCalls = getCallList().size();
410

411
	AudioLayer *audiolayer = getAudioDriver();
412

413
414
	// stop streams
	if (audiolayer && (nbCalls <= 0)) {
415
		_debug ("Manager: stop audio stream, ther is only %i call(s) remaining", nbCalls);
416
417
		audiolayer->stopStream();
	}
418

419
420
421
	if (_audiodriver->getLayerType() == PULSEAUDIO) {
		pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
	}
422

423
	return returnValue;
jpbl's avatar
jpbl committed
424
425
}

426
bool ManagerImpl::hangupConference (const ConfID& id) {
427
428

	_debug ("Manager: Hangup conference %s", id.c_str());
Alexandre Savard's avatar
Alexandre Savard committed
429

430
431
	Conference *conf;
	ConferenceMap::iterator iter_conf = _conferencemap.find(id);
Alexandre Savard's avatar
Alexandre Savard committed
432

433
	AccountID currentAccountId;
Alexandre Savard's avatar
Alexandre Savard committed
434

435
	// Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
436
437


438
439
	if (iter_conf != _conferencemap.end()) {
		conf = iter_conf->second;
Alexandre Savard's avatar
Alexandre Savard committed
440

441
442
		ParticipantSet participants = conf->getParticipantList();
		ParticipantSet::iterator iter_participant = participants.begin();
Alexandre Savard's avatar
Alexandre Savard committed
443

444
		while (iter_participant != participants.end()) {
445
			_debug ("Manager: Hangup onference participant %s", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
446

447
			hangupCall(*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
448

449
			iter_participant++;
450

451
		}
Alexandre Savard's avatar
Alexandre Savard committed
452

453
	}
Alexandre Savard's avatar
Alexandre Savard committed
454

455
	switchCall("");
456

457
	return true;
Alexandre Savard's avatar
Alexandre Savard committed
458
459
}

yanmorin's avatar
   
yanmorin committed
460
//THREAD=Main
461
462
463
bool ManagerImpl::cancelCall (const CallID& id) {
	AccountID accountid;
	bool returnValue;
yanmorin's avatar
   
yanmorin committed
464

465
466
	_debug("Manager: Cancel call");

467
	stopTone();
468

469
	/* Direct IP to IP call */
470

471
472
473
	if (getConfigFromCall(id) == Call::IPtoIP) {
		returnValue = SIPVoIPLink::instance(AccountNULL)->cancel(id);
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
474

475
476
477
	/* Classic call, attached to an account */
	else {
		accountid = getAccountFromCall(id);
478

479
480
481
482
		if (accountid == AccountNULL) {
			_debug ("! Manager Cancel Call: Call doesn't exists");
			return false;
		}
483

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

486
487
		removeCallAccount(id);
	}
488

489
490
	// it could be a waiting call?
	removeWaitingCall(id);
491

492
	switchCall("");
Emmanuel Milou's avatar
Emmanuel Milou committed
493

494
	return returnValue;
jpbl's avatar
jpbl committed
495
496
}

yanmorin's avatar
   
yanmorin committed
497
//THREAD=Main
498
499
500
bool ManagerImpl::onHoldCall (const CallID& call_id) {
	AccountID account_id;
	bool returnValue;
yanmorin's avatar
   
yanmorin committed
501

502
	_debug ("Manager: Put call %s on hold", call_id.c_str());
503

504
	stopTone();
505

506
	CallID current_call_id = getCurrentCallId();
507

508

509
	/* Direct IP to IP call */
510

511
512
513
	if (getConfigFromCall(call_id) == Call::IPtoIP) {
		returnValue = SIPVoIPLink::instance(AccountNULL)-> onhold(call_id);
	}
514

515
516
517
	/* Classic call, attached to an account */
	else {
		account_id = getAccountFromCall(call_id);
518

519
		if (account_id == AccountNULL) {
520
			_debug ("Manager: Account ID %s or callid %s doesn't exists in call onHold", account_id.c_str(), call_id.c_str());
521
522
			return false;
		}
523

524
525
		returnValue = getAccountLink(account_id)->onhold(call_id);
	}
526

527
	removeWaitingCall(call_id);
528

529
	// keeps current call id if the action is not holding this call or a new outgoing call
530

531
	if (current_call_id == call_id) {
532

533
534
		switchCall("");
	}
535

536
537
	if (_dbus)
		_dbus->getCallManager()->callStateChanged(call_id, "HOLD");
538

539
	return returnValue;
yanmorin's avatar
   
yanmorin committed
540
541
542
}

//THREAD=Main
543
bool ManagerImpl::offHoldCall (const CallID& call_id) {
544

545
546
547
	AccountID account_id;
	bool returnValue, is_rec;
	std::string codecName;
548

549
	is_rec = false;
550

551
	_debug ("Manager: Put call %s off hold", call_id.c_str());
552

553
	stopTone();
554

555
	CallID current_call_id = getCurrentCallId();
556

557
	//Place current call on hold if it isn't
558

559
560
561
562
563
564
565
566
567
568
	if (hasCurrentCall()) {
		// if this is not a conferenceand this and is not a conference participant
		if (!isConference(current_call_id) && !participToConference(
				current_call_id)) {
			onHoldCall(current_call_id);
		} else if (isConference(current_call_id) && !participToConference(
				call_id)) {
			detachParticipant(default_id, current_call_id);
		}
	}
alexandresavard's avatar
alexandresavard committed
569

570
571
	// switch current call id to id since sipvoip link need it to amke a call
	// switchCall(id);
572

573
574
575
576
577
	/* Direct IP to IP call */
	if (getConfigFromCall(call_id) == Call::IPtoIP) {
		// is_rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id);
		returnValue = SIPVoIPLink::instance(AccountNULL)-> offhold(call_id);
	}
578

579
580
581
	/* Classic call, attached to an account */
	else {
		account_id = getAccountFromCall(call_id);
582

583
		if (account_id == AccountNULL) {
584
			_warn ("Manager: Error: Call doesn't exists in off hold");
585
586
			return false;
		}
alexandresavard's avatar
alexandresavard committed
587

588
		_debug ("Manager: Setting offhold, Account %s, callid %s", account_id.c_str(), call_id.c_str());
589

590
591
592
		is_rec = getAccountLink(account_id)->getCall(call_id)->isRecording();
		returnValue = getAccountLink(account_id)->offhold(call_id);
	}
593

594
595
596
597
598
	if (_dbus) {
		if (is_rec)
			_dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_RECORD");
		else
			_dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_CURRENT");
599

600
	}
601

602
	if (participToConference(call_id)) {
603

604
605
		AccountID currentAccountId;
		Call* call = NULL;
606

607
608
		currentAccountId = getAccountFromCall(call_id);
		call = getAccountLink(currentAccountId)->getCall(call_id);
609

610
		switchCall(call->getConfId());
611

612
613
614
615
	} else {
		switchCall(call_id);
		_audiodriver->flushMain();
	}
616

617
	return returnValue;
jpbl's avatar
jpbl committed
618
619
}

yanmorin's avatar
   
yanmorin committed
620
//THREAD=Main
621
622
623
bool ManagerImpl::transferCall (const CallID& call_id, const std::string& to) {
	AccountID accountid;
	bool returnValue;
624

625
	_info("Manager: Transfer call %s\n", call_id.c_str());
626

627
	CallID current_call_id = getCurrentCallId();
628

629
	// Direct IP to IP call
630
	if (getConfigFromCall(call_id) == Call::IPtoIP) {
631
		returnValue = SIPVoIPLink::instance(AccountNULL)-> transfer(call_id, to);
632
	}
633
	// Classic call, attached to an account
634
	else {
635
636

	accountid = getAccountFromCall(call_id);
637

638
		if (accountid == AccountNULL) {
639
			_warn ("Manager: Call doesn't exists");
640
641
			return false;
		}
642

643
		returnValue = getAccountLink(accountid)->transfer(call_id, to);
644

645
	}
646

647
	// remove waiting call in case we make transfer without even answer
648
	removeWaitingCall(call_id);
649

650
	return returnValue;
jpbl's avatar
jpbl committed
651
652
}

653
void ManagerImpl::transferFailed () {
654
655
656

	_debug("UserAgent: Transfer failed");

657
658
	if (_dbus)
		_dbus->getCallManager()->transferFailed();
659
660
}

661
void ManagerImpl::transferSucceded () {
662
663
664

	_debug("UserAgent: Transfer succeded");

665
666
	if (_dbus)
		_dbus->getCallManager()->transferSucceded();
667
668
669

}

yanmorin's avatar
   
yanmorin committed
670
//THREAD=Main : Call:Incoming
671
672
673
bool ManagerImpl::refuseCall (const CallID& id) {
	AccountID accountid;
	bool returnValue;
674

675
676
	_debug("Manager: Refuse call %s", id.c_str());

677
	CallID current_call_id = getCurrentCallId();
678

679
	stopTone();
680

681
	int nbCalls = getCallList().size();
682

683
	// AudioLayer* audiolayer = getAudioDriver();
684

685
	if (nbCalls <= 1) {
Emmanuel Milou's avatar
Emmanuel Milou committed
686
		_debug ("    refuseCall: stop audio stream, there is only %i call(s) remaining", nbCalls);
687

688
689
690
		AudioLayer* audiolayer = getAudioDriver();
		audiolayer->stopStream();
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
691

692
	/* Direct IP to IP call */
693

694
695
696
	if (getConfigFromCall(id) == Call::IPtoIP) {
		returnValue = SIPVoIPLink::instance(AccountNULL)-> refuse(id);
	}
697

698
699
700
	/* Classic call, attached to an account */
	else {
		accountid = getAccountFromCall(id);
701

702
		if (accountid == AccountNULL) {
703
			_warn ("Manager: Call doesn't exists");
704
705
			return false;
		}
706

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

709
710
		removeCallAccount(id);
	}
711

712
713
714
715
	// if the call was outgoing or established, we didn't refuse it
	// so the method did nothing
	if (returnValue) {
		removeWaitingCall(id);
716

717
718
719
		if (_dbus)
			_dbus->getCallManager()->callStateChanged(id, "HUNGUP");
	}
720

721
	return returnValue;
jpbl's avatar
jpbl committed
722
723
}

724
Conference*
725
ManagerImpl::createConference (const CallID& id1, const CallID& id2) {
Alexandre Savard's avatar
Alexandre Savard committed
726
	_debug ("Manager: Create conference with call %s and %s", id1.c_str(), id2.c_str());
727

728
	Conference* conf = new Conference();
729

730
731
	conf->add(id1);
	conf->add(id2);
732

Alexandre Savard's avatar
Alexandre Savard committed
733
734
735
	// Add conference to map
	_conferencemap.insert( std::pair<CallID, Conference*>(conf->getConfID(), conf));

736
737
	// broadcast a signal over dbus
	_dbus->getCallManager()->conferenceCreated(conf->getConfID());
738

739
	return conf;
740
741
}

742
void ManagerImpl::removeConference (const ConfID& conference_id) {
743

Alexandre Savard's avatar
Alexandre Savard committed
744
	_debug ("Manager: Remove conference %s", conference_id.c_str());
745

746
	Conference* conf = NULL;
747

Alexandre Savard's avatar
Alexandre Savard committed
748
	_debug ("Manager: number of participant: %d", (int) _conferencemap.size());
749
	ConferenceMap::iterator iter = _conferencemap.find(conference_id);
750

751
752
753
	if (iter != _conferencemap.end()) {
		conf = iter->second;
	}
754

755
	if (conf == NULL) {
Alexandre Savard's avatar
Alexandre Savard committed
756
		_error ("Manager: Error: Conference not found");
757
758
		return;
	}
759

760
	// We now need to bind the audio to the remain participant
761

Alexandre Savard's avatar
Alexandre Savard committed
762
	// Unbind main participant audio from conference