managerimpl.cpp 119 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
3
 *  Copyright (C) 2004-2007 Savoir-Faire Linux inc.
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
jpbl's avatar
jpbl committed
4
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
5
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
6
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
7
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
8
 *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
9
 *
jpbl's avatar
jpbl committed
10
11
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
13
 *  (at your option) any later version.
14
 *
jpbl's avatar
jpbl committed
15
16
17
18
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
19
 *
jpbl's avatar
jpbl committed
20
21
22
23
24
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

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

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

33
34
35
36
37
38
39
40
41
42
#include "audio/audiolayer.h"
#include "audio/alsa/alsalayer.h"
#include "audio/pulseaudio/pulselayer.h"
#include "audio/sound/tonelist.h"
#include "history/historymanager.h"
#include "accountcreator.h" // create new account
#include "sip/sipvoiplink.h"
#include "manager.h"
#include "dbus/configurationmanager.h"

43
44
#include "conference.h"

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

#define fill_config_str(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
#define fill_config_int(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))

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

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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();
79

yanmorin's avatar
   
yanmorin committed
80
#ifdef TEST
81
82
83
84
	testAccountMap();
	loadAccountMap();
	testCallAccountMap();
	unloadAccountMap();
yanmorin's avatar
   
yanmorin committed
85
86
#endif

87
88
	// should be call before initConfigFile
	// loadAccountMap();, called in init() now.
jpbl's avatar
jpbl committed
89
90
91
}

// never call if we use only the singleton...
92
93
94
95
96
ManagerImpl::~ManagerImpl (void) {
	// terminate();
	delete _cleaner;
	_cleaner = 0;
	_debug ("%s stop correctly.", PROGNAME);
jpbl's avatar
jpbl committed
97
98
}

99
void ManagerImpl::init () {
100

101
102
	// Load accounts, init map
	loadAccountMap();
103

104
	initVolume();
105

106
107
108
	if (_exist == 0) {
		_debug ("Cannot create config file in your home directory");
	}
109

110
	initAudioDriver();
jpbl's avatar
jpbl committed
111

112
	selectAudioDriver();
113

114
115
	// Initialize the list of supported audio codecs
	initAudioCodec();
116

117
	AudioLayer *audiolayer = getAudioDriver();
jpbl's avatar
jpbl committed
118

119
120
	if (audiolayer != 0) {
		unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
121

122
123
124
		_debugInit ("Load Telephone Tone");
		std::string country = getConfigString(PREFERENCES, ZONE_TONE);
		_telephoneTone = new TelephoneTone(country, sampleRate);
125

126
127
128
		_debugInit ("Loading DTMF key");
		_dtmfKey = new DTMF(sampleRate);
	}
129

130
131
	if (audiolayer == 0)
		audiolayer->stopStream();
132

133
134
	// Load the history
	_history->load_history(getConfigInt(PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
135
136
}

137
138
139
void ManagerImpl::terminate () {
	_debug ("ManagerImpl::terminate ");
	saveConfig();
jpbl's avatar
jpbl committed
140

141
	unloadAccountMap();
142

143
144
	_debug ("Unload DTMF Key ");
	delete _dtmfKey;
jpbl's avatar
jpbl committed
145

146
147
148
	_debug ("Unload Audio Driver ");
	delete _audiodriver;
	_audiodriver = NULL;
jpbl's avatar
jpbl committed
149

150
151
152
	_debug ("Unload Telephone Tone ");
	delete _telephoneTone;
	_telephoneTone = NULL;
153

154
155
	_debug ("Unload Audio Codecs ");
	_codecDescriptorMap.deleteHandlePointer();
156

jpbl's avatar
jpbl committed
157
158
}

159
160
bool ManagerImpl::isCurrentCall (const CallID& callId) {
	return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
161
162
}

163
164
bool ManagerImpl::hasCurrentCall () {
	// _debug ("ManagerImpl::hasCurrentCall current call ID = %s", _currentCallId2.c_str());
165

166
167
168
	if (_currentCallId2 != "") {
		return true;
	}
169

170
	return false;
jpbl's avatar
jpbl committed
171
172
}

173
const CallID&
174
175
ManagerImpl::getCurrentCallId () {
	return _currentCallId2;
jpbl's avatar
jpbl committed
176
177
}

178
179
180
181
void ManagerImpl::switchCall (const CallID& id) {
	ost::MutexLock m(_currentCallMutex);
	_debug ("----- Switch current call id to %s -----", id.c_str());
	_currentCallId2 = id;
182

183
184
	/*
	 AudioLayer *al = getAudioDriver();
185

186
	 if (id != "") {
187

188
	 if(isConference(id)) {
189

190
	 Conference *conf;
191

192
193
194
195
196
197
198
199
200
	 ConferenceMap::iterator iter = _conferencemap.find(id);
	 if(iter != _conferencemap.end())
	 {
	 _debug("    set call recordable in audio layer");
	 conf = iter->second;
	 al->setRecorderInstance((Recordable*)conf);
	 }
	 }
	 else {
201

202
203
	 // set the recordable instance in audiolayer
	 AccountID account_id = getAccountFromCall(id);
204
205


206
207
	 Call *call = NULL;
	 call = getAccountLink (account_id)->getCall(id);
208

209
210
211
212
213
	 _debug("    set call recordable in audio layer");
	 al->setRecorderInstance((Recordable*)call);
	 }
	 }
	 */
jpbl's avatar
jpbl committed
214
215
216
217
218
}

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

221
222
223
224
225
bool ManagerImpl::outgoingCall (const std::string& account_id,
		const CallID& call_id, const std::string& to) {
	std::string pattern, to_cleaned;
	Call::CallConfiguration callConfig;
	SIPVoIPLink *siplink;
226

227
	_debug ("ManagerImpl::outgoingCall(%s)", call_id.c_str());
228

229
	CallID current_call_id = getCurrentCallId();
Emmanuel Milou's avatar
Emmanuel Milou committed
230

231
232
233
234
235
	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
236

237
	to_cleaned = _cleaner->clean(to);
238

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

242
243
	// in any cases we have to detach from current communication
	if (hasCurrentCall()) {
244

245
		_debug ("    outgoingCall: Has current call (%s) put it onhold", current_call_id.c_str());
246

247
		// if this is not a conferenceand this and is not a conference participant
248

249
250
251
252
253
254
255
256
257
258
		if (!isConference(current_call_id) && !participToConference(
				current_call_id)) {
			_debug ("    outgoingCall: Put the current call (%s) on hold", current_call_id.c_str());
			onHoldCall(current_call_id);
		} else if (isConference(current_call_id) && !participToConference(
				call_id)) {
			_debug ("    outgoingCall: detach main participant from conference");
			detachParticipant(default_id, current_call_id);
		}
	}
259

260
261
262
263
	if (callConfig == Call::IPtoIP) {
		_debug ("    outgoingCall: Start IP to IP call");
		/* We need to retrieve the sip voiplink instance */
		siplink = SIPVoIPLink::instance("");
264

265
266
267
268
269
270
		if (siplink->new_ip_to_ip_call(call_id, to_cleaned)) {
			switchCall(call_id);
			return true;
		} else {
			callFailure(call_id);
		}
271

272
273
		return false;
	}
274

275
276
277
278
	if (!accountExists(account_id)) {
		_debug ("! Manager Error: Outgoing Call: account doesn't exist");
		return false;
	}
279

280
281
282
283
	if (getAccountFromCall(call_id) != AccountNULL) {
		_debug ("! Manager Error: Outgoing Call: call id already exists");
		return false;
	}
284

285
	_debug ("- Manager Action: Adding Outgoing Call %s on account %s", call_id.data(), account_id.data());
286

287
	associateCallToAccount(call_id, account_id);
288

289
290
291
292
293
294
295
	if (getAccountLink(account_id)->newOutgoingCall(call_id, to_cleaned)) {
		switchCall(call_id);
		return true;
	} else {
		callFailure(call_id);
		_debug ("! Manager Error: An error occur, the call was not created");
	}
296

297
	return false;
jpbl's avatar
jpbl committed
298
299
}

yanmorin's avatar
   
yanmorin committed
300
//THREAD=Main : for outgoing Call
301
bool ManagerImpl::answerCall (const CallID& call_id) {
302

303
	_debug ("ManagerImpl::answerCall(%s)", call_id.c_str());
304

305
	stopTone();
306

307
308
	// store the current call id
	CallID current_call_id = getCurrentCallId();
309

310
	AccountID account_id = getAccountFromCall(call_id);
311

312
313
314
	if (account_id == AccountNULL) {
		_debug ("    answerCall: AccountId is null");
	}
315

316
	Call* call = NULL;
317

318
	call = getAccountLink(account_id)->getCall(call_id);
319

320
321
322
	if (call == NULL) {
		_debug ("    answerCall: Call is null");
	}
323

324
325
	// in any cases we have to detach from current communication
	if (hasCurrentCall()) {
326

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

330
331
332
333
334
		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);
		}
335

336
337
338
339
340
341
		// 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);
		}
342

343
	}
344

345
346
347
348
349
	if (!getAccountLink(account_id)->answer(call_id)) {
		// error when receiving...
		removeCallAccount(call_id);
		return false;
	}
Alexandre Savard's avatar
Alexandre Savard committed
350

351
352
353
	// if it was waiting, it's waiting no more
	if (_dbus)
		_dbus->getCallManager()->callStateChanged(call_id, "CURRENT");
Emmanuel Milou's avatar
Emmanuel Milou committed
354

355
356
	// std::string codecName = Manager::instance().getCurrentCodecName (call_id);
	// if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str());
357

358
	removeWaitingCall(call_id);
359

360
361
	// if we dragged this call into a conference already
	if (participToConference(call_id)) {
362

363
364
		// AccountID currentAccountId;
		// Call* call = NULL;
365

366
367
		// currentAccountId = getAccountFromCall (call_id);
		// call = getAccountLink (currentAccountId)->getCall (call_id);
368

369
370
371
372
		switchCall(call->getConfId());
	} else {
		switchCall(call_id);
	}
373

374
	return true;
jpbl's avatar
jpbl committed
375
376
}

yanmorin's avatar
   
yanmorin committed
377
//THREAD=Main
378
bool ManagerImpl::hangupCall (const CallID& call_id) {
379
380
381

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

382
383
384
	PulseLayer *pulselayer;
	AccountID account_id;
	bool returnValue = true;
Emmanuel Milou's avatar
Emmanuel Milou committed
385

386
387
	// store the current call id
	CallID current_call_id = getCurrentCallId();
388

389
	stopTone();
yanmorin's avatar
   
yanmorin committed
390

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

394
395
	if (_dbus)
		_dbus->getCallManager()->callStateChanged(call_id, "HUNGUP");
396

397
	if (participToConference(call_id)) {
398

399
		Conference *conf = getConferenceFromCallID(call_id);
400

401
402
403
		if (conf != NULL) {
			// remove this participant
			removeParticipant(call_id);
404

405
406
			processRemainingParticipant(current_call_id, conf);
		}
407

408
409
410
411
412
	} else {
		// we are not participating to a conference, current call switched to ""
		if (!isConference(current_call_id))
			switchCall("");
	}
413

414
415
416
417
418
419
420
	/* 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);
421

422
		if (account_id == AccountNULL) {
423

424
			_error ("Manager: Error: account id is NULL in hangup");
425
426
			returnValue = false;
		} else {
427

428
429
430
			returnValue = getAccountLink(account_id)->hangup(call_id);
			removeCallAccount(call_id);
		}
431
	}
432

433
	int nbCalls = getCallList().size();
434

435
	AudioLayer *audiolayer = getAudioDriver();
436

437
438
	// stop streams
	if (audiolayer && (nbCalls <= 0)) {
439
		_debug ("Manager: stop audio stream, ther is only %i call(s) remaining", nbCalls);
440
441
		audiolayer->stopStream();
	}
442

443
444
445
	if (_audiodriver->getLayerType() == PULSEAUDIO) {
		pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
	}
446

447
	return returnValue;
jpbl's avatar
jpbl committed
448
449
}

450
bool ManagerImpl::hangupConference (const ConfID& id) {
451
452

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

454
455
	Conference *conf;
	ConferenceMap::iterator iter_conf = _conferencemap.find(id);
Alexandre Savard's avatar
Alexandre Savard committed
456

457
	AccountID currentAccountId;
Alexandre Savard's avatar
Alexandre Savard committed
458

459
	// Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
460
461


462
463
	if (iter_conf != _conferencemap.end()) {
		conf = iter_conf->second;
Alexandre Savard's avatar
Alexandre Savard committed
464

465
466
		ParticipantSet participants = conf->getParticipantList();
		ParticipantSet::iterator iter_participant = participants.begin();
Alexandre Savard's avatar
Alexandre Savard committed
467

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

471
			hangupCall(*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
472

473
			iter_participant++;
474

475
		}
Alexandre Savard's avatar
Alexandre Savard committed
476

477
	}
Alexandre Savard's avatar
Alexandre Savard committed
478

479
	switchCall("");
480

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

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

489
	stopTone();
490

491
	/* Direct IP to IP call */
492

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

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

501
502
503
504
		if (accountid == AccountNULL) {
			_debug ("! Manager Cancel Call: Call doesn't exists");
			return false;
		}
505

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

508
509
		removeCallAccount(id);
	}
510

511
512
	// it could be a waiting call?
	removeWaitingCall(id);
513

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

516
	return returnValue;
jpbl's avatar
jpbl committed
517
518
}

yanmorin's avatar
   
yanmorin committed
519
//THREAD=Main
520
521
522
bool ManagerImpl::onHoldCall (const CallID& call_id) {
	AccountID account_id;
	bool returnValue;
yanmorin's avatar
   
yanmorin committed
523

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

526
	stopTone();
527

528
	CallID current_call_id = getCurrentCallId();
529

530

531
	/* Direct IP to IP call */
532

533
534
535
	if (getConfigFromCall(call_id) == Call::IPtoIP) {
		returnValue = SIPVoIPLink::instance(AccountNULL)-> onhold(call_id);
	}
536

537
538
539
	/* Classic call, attached to an account */
	else {
		account_id = getAccountFromCall(call_id);
540

541
		if (account_id == AccountNULL) {
542
			_debug ("Manager: Account ID %s or callid %s doesn't exists in call onHold", account_id.c_str(), call_id.c_str());
543
544
			return false;
		}
545

546
547
		returnValue = getAccountLink(account_id)->onhold(call_id);
	}
548

549
	removeWaitingCall(call_id);
550

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

553
	if (current_call_id == call_id) {
554

555
556
		switchCall("");
	}
557

558
559
	if (_dbus)
		_dbus->getCallManager()->callStateChanged(call_id, "HOLD");
560

561
	return returnValue;
yanmorin's avatar
   
yanmorin committed
562
563
564
}

//THREAD=Main
565
bool ManagerImpl::offHoldCall (const CallID& call_id) {
566

567
568
569
	AccountID account_id;
	bool returnValue, is_rec;
	std::string codecName;
570

571
	is_rec = false;
572

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

575
	stopTone();
576

577
	CallID current_call_id = getCurrentCallId();
578

579
	//Place current call on hold if it isn't
580

581
582
583
584
585
586
587
588
589
590
	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
591

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

595
596
597
598
599
	/* 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);
	}
600

601
602
603
	/* Classic call, attached to an account */
	else {
		account_id = getAccountFromCall(call_id);
604

605
		if (account_id == AccountNULL) {
606
			_warn ("Manager: Error: Call doesn't exists in off hold");
607
608
			return false;
		}
alexandresavard's avatar
alexandresavard committed
609

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

612
613
614
		is_rec = getAccountLink(account_id)->getCall(call_id)->isRecording();
		returnValue = getAccountLink(account_id)->offhold(call_id);
	}
615

616
617
618
619
620
	if (_dbus) {
		if (is_rec)
			_dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_RECORD");
		else
			_dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_CURRENT");
621

622
	}
623

624
	if (participToConference(call_id)) {
625

626
627
		AccountID currentAccountId;
		Call* call = NULL;
628

629
630
		currentAccountId = getAccountFromCall(call_id);
		call = getAccountLink(currentAccountId)->getCall(call_id);
631

632
		switchCall(call->getConfId());
633

634
635
636
637
	} else {
		switchCall(call_id);
		_audiodriver->flushMain();
	}
638

639
	return returnValue;
jpbl's avatar
jpbl committed
640
641
}

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

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

649
	CallID current_call_id = getCurrentCallId();
650

651
	// Direct IP to IP call
652
	if (getConfigFromCall(call_id) == Call::IPtoIP) {
653
		returnValue = SIPVoIPLink::instance(AccountNULL)-> transfer(call_id, to);
654
	}
655
	// Classic call, attached to an account
656
	else {
657
658

	accountid = getAccountFromCall(call_id);
659

660
		if (accountid == AccountNULL) {
661
			_warn ("Manager: Call doesn't exists");
662
663
			return false;
		}
664

665
		returnValue = getAccountLink(accountid)->transfer(call_id, to);
666

667
	}
668

669
	// remove waiting call in case we make transfer without even answer
670
	removeWaitingCall(call_id);
671

672
	return returnValue;
jpbl's avatar
jpbl committed
673
674
}

675
void ManagerImpl::transferFailed () {
676
677
678

	_debug("UserAgent: Transfer failed");

679
680
	if (_dbus)
		_dbus->getCallManager()->transferFailed();
681
682
}

683
void ManagerImpl::transferSucceded () {
684
685
686

	_debug("UserAgent: Transfer succeded");

687
688
	if (_dbus)
		_dbus->getCallManager()->transferSucceded();
689
690
691

}

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

697
	CallID current_call_id = getCurrentCallId();
698

699
	stopTone();
700

701
	int nbCalls = getCallList().size();
702

703
	// AudioLayer* audiolayer = getAudioDriver();
704

705
706
	if (nbCalls <= 1) {
		_debug ("    hangupCall: stop audio stream, ther is only %i call(s) remaining", nbCalls);
707

708
709
710
		AudioLayer* audiolayer = getAudioDriver();
		audiolayer->stopStream();
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
711

712
	/* Direct IP to IP call */
713

714
715
716
	if (getConfigFromCall(id) == Call::IPtoIP) {
		returnValue = SIPVoIPLink::instance(AccountNULL)-> refuse(id);
	}
717

718
719
720
	/* Classic call, attached to an account */
	else {
		accountid = getAccountFromCall(id);
721

722
723
724
725
		if (accountid == AccountNULL) {
			_debug ("! Manager OffHold Call: Call doesn't exists");
			return false;
		}
726

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

729
730
		removeCallAccount(id);
	}
731

732
733
734
735
	// if the call was outgoing or established, we didn't refuse it
	// so the method did nothing
	if (returnValue) {
		removeWaitingCall(id);
736

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

740
741
742
		// if(current_call_id.compare("") != 0)
		// switchCall ("");
	}
743

744
	return returnValue;
jpbl's avatar
jpbl committed
745
746
}

747
Conference*
748
749
ManagerImpl::createConference (const CallID& id1, const CallID& id2) {
	_debug ("ManagerImpl::createConference()");
750

751
	Conference* conf = new Conference();
752

753
754
755
	// _conferencecall.insert(pair<CallID, Conference*>(id1, conf));
	// _conferencecall.insert(pair<CallID, Conference*>(id2, conf));
	_conferencemap.insert(pair<CallID, Conference*> (conf->getConfID(), conf));
756

757
758
	conf->add(id1);
	conf->add(id2);
759

760
761
	// broadcast a signal over dbus
	_dbus->getCallManager()->conferenceCreated(conf->getConfID());
762

763
	return conf;
764
765
}

766
void ManagerImpl::removeConference (const ConfID& conference_id) {
767

768
	_debug ("ManagerImpl::removeConference(%s)", conference_id.c_str());
769

770
	Conference* conf = NULL;
771

772
773
	_debug ("    removeConference: _conferencemap.size: %i", (int) _conferencemap.size());
	ConferenceMap::iterator iter = _conferencemap.find(conference_id);
774

775
776
777
778
	if (iter != _conferencemap.end()) {
		_debug ("    removeConference: Found conference id %s in conferencemap", conference_id.c_str());
		conf = iter->second;
	}
779

780
	if (conf == NULL) {
781

782
783
784
		_debug ("    removeConference: Error conference not found");
		return;
	}
785

786
	// We now need to bind the audio to the remain participant
787

788
789
	// unbind main participant from conference (just to be sure)
	_audiodriver->getMainBuffer()->unBindAll(default_id);
790

791
	ParticipantSet participants = conf->getParticipantList();
792

793
794
	// bind main participant to remaining conference call
	ParticipantSet::iterator iter_p = participants.begin();
795

Emmanuel Milou's avatar