linphonecore.c 261 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3
/*
linphone
Copyright (C) 2000  Simon MORLAT (simon.morlat@linphone.org)
Simon Morlat's avatar
Simon Morlat committed
4
Copyright (C) 2010  Belledonne Communications SARL
aymeric's avatar
aymeric committed
5 6 7 8 9 10 11 12 13 14 15 16 17

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 the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

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.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
aymeric's avatar
aymeric committed
19 20
*/

21 22 23
#include "linphone/core.h"
#include "linphone/sipsetup.h"
#include "linphone/lpconfig.h"
aymeric's avatar
aymeric committed
24
#include "private.h"
25 26 27
#include "quality_reporting.h"
#include "lime.h"
#include "conference_private.h"
28
#include "logger/logger.h"
29

30
#ifdef SQLITE_STORAGE_ENABLED
31
#include "sqlite3_bctbx_vfs.h"
32 33
#endif

34
#include <math.h>
35 36
#include <sys/types.h>
#include <sys/stat.h>
37
#include <ortp/telephonyevents.h>
38
#include <mediastreamer2/zrtp.h>
johan's avatar
johan committed
39
#include <mediastreamer2/dtls_srtp.h>
40
#include <bctoolbox/defs.h>
41
#include <belr/grammarbuilder.h>
42

43
#include "mediastreamer2/dtmfgen.h"
aymeric's avatar
aymeric committed
44
#include "mediastreamer2/mediastream.h"
45
#include "mediastreamer2/msequalizer.h"
46 47
#include "mediastreamer2/mseventqueue.h"
#include "mediastreamer2/msfactory.h"
48
#include "mediastreamer2/msjpegwriter.h"
49 50
#include "mediastreamer2/msogl.h"
#include "mediastreamer2/msvolume.h"
51
#include "bctoolbox/charconv.h"
52

Ronan's avatar
Ronan committed
53
#include "chat/chat-room/client-group-chat-room-p.h"
54
#include "chat/chat-room/client-group-to-basic-chat-room.h"
55
#include "chat/chat-room/server-group-chat-room-p.h"
56
#include "conference/handlers/remote-conference-event-handler.h"
57 58
#include "content/content-manager.h"
#include "content/content-type.h"
59
#include "core/core-p.h"
aymeric's avatar
aymeric committed
60

61 62
// For migration purpose.
#include "address/address-p.h"
63
#include "c-wrapper/c-wrapper.h"
64

65
#ifdef INET6
66
#ifndef _WIN32
67
#include <netdb.h>
aymeric's avatar
aymeric committed
68 69 70
#endif
#endif

71
#ifdef HAVE_CONFIG_H
72
#include "config.h"
73
#include "gitversion.h"
74 75
#endif

76 77 78
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
79

80
#include "c-wrapper/c-wrapper.h"
81 82 83
#include "call/call-p.h"
#include "conference/params/media-session-params-p.h"

84
#ifdef HAVE_ZLIB
85
#define COMPRESSED_LOG_COLLECTION_EXTENSION "gz"
86
#ifdef _WIN32
87 88
#include <fcntl.h>
#include <io.h>
89
#ifndef fileno
90
#define fileno _fileno
91
#endif
92
#define unlink _unlink
93 94 95 96 97
#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
#define SET_BINARY_MODE(file)
#endif
#include <zlib.h>
98
#else
99
#define COMPRESSED_LOG_COLLECTION_EXTENSION "txt"
100
#endif
101 102 103 104
#define LOG_COLLECTION_DEFAULT_PATH "."
#define LOG_COLLECTION_DEFAULT_PREFIX "linphone"
#define LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE (10 * 1024 * 1024)

105

smorlat's avatar
smorlat committed
106
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
107

108 109 110 111 112 113 114
static const char *liblinphone_version=
#ifdef LIBLINPHONE_GIT_VERSION
	LIBLINPHONE_GIT_VERSION
#else
	LIBLINPHONE_VERSION
#endif
;
115 116 117 118 119 120 121

inline OrtpLogLevel operator|=(OrtpLogLevel a, OrtpLogLevel b) {
	int ia = static_cast<int>(a);
	int ib = static_cast<int>(b);
	return static_cast<OrtpLogLevel>(ia |= ib);
}

122 123
static OrtpLogFunc liblinphone_user_log_func = bctbx_logv_out; /*by default, user log handler = stdout*/
static OrtpLogFunc liblinphone_current_log_func = NULL; /*can be either logcolection or user_log*/
124
static LinphoneLogCollectionState liblinphone_log_collection_state = LinphoneLogCollectionDisabled;
125
static char * liblinphone_log_collection_path = NULL;
126
static char * liblinphone_log_collection_prefix = NULL;
127
static size_t liblinphone_log_collection_max_file_size = LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE;
128
static ortp_mutex_t liblinphone_log_collection_mutex;
129 130
static FILE * liblinphone_log_collection_file = NULL;
static size_t liblinphone_log_collection_file_size = 0;
131
static bool_t liblinphone_serialize_logs = FALSE;
132
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
133 134
static void set_sip_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
static void set_media_network_reachable(LinphoneCore* lc,bool_t isReachable);
Simon Morlat's avatar
Simon Morlat committed
135
static void linphone_core_run_hooks(LinphoneCore *lc);
136
static void linphone_core_zrtp_cache_close(LinphoneCore *lc);
137
void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName);
aymeric's avatar
aymeric committed
138

139 140
#include "enum.h"
#include "contact_providers_priv.h"
141

142
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
aymeric's avatar
aymeric committed
143 144
static void toggle_video_preview(LinphoneCore *lc, bool_t val);

145

aymeric's avatar
aymeric committed
146
/* relative path where is stored local ring*/
147 148
#define LOCAL_RING_WAV "oldphone-mono.wav"
#define LOCAL_RING_MKV "notes_of_the_optimistic.mkv"
aymeric's avatar
aymeric committed
149
/* same for remote ring (ringback)*/
150
#define REMOTE_RING_WAV "ringback.wav"
151

152 153
#define HOLD_MUSIC_WAV "toy-mono.wav"
#define HOLD_MUSIC_MKV "dont_wait_too_long.mkv"
aymeric's avatar
aymeric committed
154

155 156
using namespace std;

157 158
using namespace LinphonePrivate;

159
extern Sal::Callbacks linphone_sal_callbacks;
aymeric's avatar
aymeric committed
160

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

static void _linphone_core_cbs_uninit(LinphoneCoreCbs *cbs);

typedef belle_sip_object_t_vptr_t LinphoneCoreCbs_vptr_t;
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCoreCbs);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneCoreCbs, belle_sip_object_t,
	_linphone_core_cbs_uninit, // destroy
	NULL, // clone
	NULL, // Marshall
	FALSE
);

LinphoneCoreCbs *_linphone_core_cbs_new(void) {
	LinphoneCoreCbs *obj = belle_sip_object_new(LinphoneCoreCbs);
	obj->vtable = ms_new0(LinphoneCoreVTable, 1);
	obj->autorelease = TRUE;
	return obj;
}

static void _linphone_core_cbs_uninit(LinphoneCoreCbs *cbs) {
	if (cbs->autorelease) ms_free(cbs->vtable);
}

void _linphone_core_cbs_set_v_table(LinphoneCoreCbs *cbs, LinphoneCoreVTable *vtable, bool_t autorelease) {
	ms_free(cbs->vtable);
	cbs->vtable = vtable;
	cbs->autorelease = autorelease;
}

LinphoneCoreCbs *linphone_core_cbs_ref(LinphoneCoreCbs *cbs) {
	return (LinphoneCoreCbs *)belle_sip_object_ref(cbs);
}

void linphone_core_cbs_unref(LinphoneCoreCbs *cbs) {
	belle_sip_object_unref(cbs);
}

void linphone_core_cbs_set_user_data(LinphoneCoreCbs *cbs, void *user_data) {
	cbs->vtable->user_data = user_data;
}

Ghislain MARY's avatar
Ghislain MARY committed
202
void *linphone_core_cbs_get_user_data(const LinphoneCoreCbs *cbs) {
203 204 205 206 207 208 209
	return cbs->vtable->user_data;
}

LinphoneCoreCbs *linphone_core_get_current_callbacks(const LinphoneCore *lc) {
	return lc->current_cbs;
}

210 211 212 213
LinphoneCoreCbsGlobalStateChangedCb linphone_core_cbs_get_global_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->global_state_changed;
}

214
void linphone_core_cbs_set_global_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsGlobalStateChangedCb cb) {
215 216 217
	cbs->vtable->global_state_changed = cb;
}

218 219 220 221
LinphoneCoreCbsRegistrationStateChangedCb linphone_core_cbs_get_registration_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->registration_state_changed;
}

222 223 224 225
void linphone_core_cbs_set_registration_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsRegistrationStateChangedCb cb) {
	cbs->vtable->registration_state_changed = cb;
}

226 227 228 229
LinphoneCoreCbsCallStateChangedCb linphone_core_cbs_get_call_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_state_changed;
}

230 231 232 233
void linphone_core_cbs_set_call_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStateChangedCb cb) {
	cbs->vtable->call_state_changed = cb;
}

234 235 236 237
LinphoneCoreCbsNotifyPresenceReceivedCb linphone_core_cbs_get_notify_presence_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_presence_received;
}

238 239 240 241
void linphone_core_cbs_set_notify_presence_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedCb cb) {
	cbs->vtable->notify_presence_received = cb;
}

242 243 244 245
LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb linphone_core_cbs_get_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_presence_received_for_uri_or_tel;
}

246 247 248 249
void linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb cb) {
	cbs->vtable->notify_presence_received_for_uri_or_tel = cb;
}

250 251 252 253
LinphoneCoreCbsNewSubscriptionRequestedCb linphone_core_cbs_get_new_subscription_requested(LinphoneCoreCbs *cbs) {
	return cbs->vtable->new_subscription_requested;
}

254 255 256 257
void linphone_core_cbs_set_new_subscription_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsNewSubscriptionRequestedCb cb) {
	cbs->vtable->new_subscription_requested = cb;
}

258 259 260 261
LinphoneCoreCbsAuthenticationRequestedCb linphone_core_cbs_get_authentication_requested(LinphoneCoreCbs *cbs) {
	return cbs->vtable->authentication_requested;
}

262 263 264 265
void linphone_core_cbs_set_authentication_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsAuthenticationRequestedCb cb) {
	cbs->vtable->authentication_requested = cb;
}

266 267 268 269
LinphoneCoreCbsCallLogUpdatedCb linphone_core_cbs_get_call_log_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_log_updated;
}

270 271 272 273
void linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallLogUpdatedCb cb) {
	cbs->vtable->call_log_updated = cb;
}

274 275 276 277
LinphoneCoreCbsMessageReceivedCb linphone_core_cbs_get_message_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->message_received;
}

278 279 280 281
void linphone_core_cbs_set_message_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedCb cb) {
	cbs->vtable->message_received = cb;
}

282 283 284 285
LinphoneCoreCbsMessageReceivedUnableDecryptCb linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs *cbs) {
	return cbs->vtable->message_received_unable_decrypt;
}

286 287 288 289
void linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedUnableDecryptCb cb) {
	cbs->vtable->message_received_unable_decrypt = cb;
}

290 291 292 293
LinphoneCoreCbsIsComposingReceivedCb linphone_core_cbs_get_is_composing_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->is_composing_received;
}

294 295 296 297
void linphone_core_cbs_set_is_composing_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsIsComposingReceivedCb cb) {
	cbs->vtable->is_composing_received = cb;
}

298 299 300 301
LinphoneCoreCbsDtmfReceivedCb linphone_core_cbs_get_dtmf_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->dtmf_received;
}

302 303 304 305
void linphone_core_cbs_set_dtmf_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsDtmfReceivedCb cb) {
	cbs->vtable->dtmf_received = cb;
}

306 307 308 309
LinphoneCoreCbsReferReceivedCb linphone_core_cbs_get_refer_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->refer_received;
}

310 311 312 313
void linphone_core_cbs_set_refer_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsReferReceivedCb cb) {
	cbs->vtable->refer_received = cb;
}

314 315 316 317
LinphoneCoreCbsCallEncryptionChangedCb linphone_core_cbs_get_call_encryption_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_encryption_changed;
}

318 319 320 321
void linphone_core_cbs_set_call_encryption_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallEncryptionChangedCb cb) {
	cbs->vtable->call_encryption_changed = cb;
}

322 323 324 325
LinphoneCoreCbsTransferStateChangedCb linphone_core_cbs_get_transfer_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->transfer_state_changed;
}

326 327 328 329
void linphone_core_cbs_set_transfer_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsTransferStateChangedCb cb) {
	cbs->vtable->transfer_state_changed = cb;
}

330 331 332 333
LinphoneCoreCbsBuddyInfoUpdatedCb linphone_core_cbs_get_buddy_info_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->buddy_info_updated;
}

334 335 336 337
void linphone_core_cbs_set_buddy_info_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsBuddyInfoUpdatedCb cb) {
	cbs->vtable->buddy_info_updated = cb;
}

338 339 340 341
LinphoneCoreCbsCallStatsUpdatedCb linphone_core_cbs_get_call_stats_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_stats_updated;
}

342 343 344 345
void linphone_core_cbs_set_call_stats_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStatsUpdatedCb cb) {
	cbs->vtable->call_stats_updated = cb;
}

346 347 348 349
LinphoneCoreCbsInfoReceivedCb linphone_core_cbs_get_info_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->info_received;
}

350 351 352 353
void linphone_core_cbs_set_info_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsInfoReceivedCb cb) {
	cbs->vtable->info_received = cb;
}

354 355 356 357
LinphoneCoreCbsSubscriptionStateChangedCb linphone_core_cbs_get_subscription_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->subscription_state_changed;
}

358 359 360 361
void linphone_core_cbs_set_subscription_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsSubscriptionStateChangedCb cb) {
	cbs->vtable->subscription_state_changed = cb;
}

362 363 364 365
LinphoneCoreCbsNotifyReceivedCb linphone_core_cbs_get_notify_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_received;
}

366 367 368 369
void linphone_core_cbs_set_notify_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyReceivedCb cb) {
	cbs->vtable->notify_received = cb;
}

370 371 372 373
LinphoneCoreCbsPublishStateChangedCb linphone_core_cbs_get_rpublish_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->publish_state_changed;
}

374 375 376 377
void linphone_core_cbs_set_publish_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsPublishStateChangedCb cb) {
	cbs->vtable->publish_state_changed = cb;
}

378 379 380 381
LinphoneCoreCbsConfiguringStatusCb linphone_core_cbs_get_configuring_status(LinphoneCoreCbs *cbs) {
	return cbs->vtable->configuring_status;
}

382 383 384 385
void linphone_core_cbs_set_configuring_status(LinphoneCoreCbs *cbs, LinphoneCoreCbsConfiguringStatusCb cb) {
	cbs->vtable->configuring_status = cb;
}

386 387 388 389
LinphoneCoreCbsNetworkReachableCb linphone_core_cbs_get_network_reachable(LinphoneCoreCbs *cbs) {
	return cbs->vtable->network_reachable;
}

390 391 392 393
void linphone_core_cbs_set_network_reachable(LinphoneCoreCbs *cbs, LinphoneCoreCbsNetworkReachableCb cb) {
	cbs->vtable->network_reachable = cb;
}

394 395 396 397
LinphoneCoreCbsLogCollectionUploadStateChangedCb linphone_core_cbs_log_collection_upload_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->log_collection_upload_state_changed;
}

398 399 400 401
void linphone_core_cbs_set_log_collection_upload_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadStateChangedCb cb) {
	cbs->vtable->log_collection_upload_state_changed = cb;
}

402 403 404 405
LinphoneCoreCbsLogCollectionUploadProgressIndicationCb linphone_core_cbs_get_rlog_collection_upload_progress_indication(LinphoneCoreCbs *cbs) {
	return cbs->vtable->log_collection_upload_progress_indication;
}

406 407 408 409
void linphone_core_cbs_set_log_collection_upload_progress_indication(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadProgressIndicationCb cb) {
	cbs->vtable->log_collection_upload_progress_indication = cb;
}

410 411 412 413
LinphoneCoreCbsFriendListCreatedCb linphone_core_cbs_get_friend_list_created(LinphoneCoreCbs *cbs) {
	return cbs->vtable->friend_list_created;
}

414 415 416 417
void linphone_core_cbs_set_friend_list_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListCreatedCb cb) {
	cbs->vtable->friend_list_created = cb;
}

418 419 420 421
LinphoneCoreCbsFriendListRemovedCb linphone_core_cbs_get_friend_list_removed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->friend_list_removed;
}

422 423 424 425
void linphone_core_cbs_set_friend_list_removed(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListRemovedCb cb) {
	cbs->vtable->friend_list_removed = cb;
}

426 427 428 429 430 431 432 433
LinphoneCoreCbsCallCreatedCb linphone_core_cbs_get_call_created(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_created;
}

void linphone_core_cbs_set_call_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallCreatedCb cb) {
	cbs->vtable->call_created = cb;
}

Ghislain MARY's avatar
Ghislain MARY committed
434 435 436 437 438 439 440 441
LinphoneCoreCbsVersionUpdateCheckResultReceivedCb linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->version_update_check_result_received;
}

void linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsVersionUpdateCheckResultReceivedCb cb) {
	cbs->vtable->version_update_check_result_received = cb;
}

442 443
LinphoneCoreCbsChatRoomStateChangedCb linphone_core_cbs_get_chat_room_state_changed (LinphoneCoreCbs *cbs) {
	return cbs->vtable->chat_room_state_changed;
444 445
}

446 447
void linphone_core_cbs_set_chat_room_state_changed (LinphoneCoreCbs *cbs, LinphoneCoreCbsChatRoomStateChangedCb cb) {
	cbs->vtable->chat_room_state_changed = cb;
448 449
}

450 451 452 453 454 455 456 457 458 459 460 461
void linphone_core_cbs_set_ec_calibration_result(LinphoneCoreCbs *cbs, LinphoneCoreCbsEcCalibrationResultCb cb) {
	cbs->vtable->ec_calibration_result = cb;
}

void linphone_core_cbs_set_ec_calibration_audio_init(LinphoneCoreCbs *cbs, LinphoneCoreCbsEcCalibrationAudioInitCb cb) {
	cbs->vtable->ec_calibration_audio_init = cb;
}

void linphone_core_cbs_set_ec_calibration_audio_uninit(LinphoneCoreCbs *cbs, LinphoneCoreCbsEcCalibrationAudioUninitCb cb) {
	cbs->vtable->ec_calibration_audio_uninit = cb;
}

Ghislain MARY's avatar
Ghislain MARY committed
462

463
void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) {
464 465
	obj->_func=func;
	obj->_user_data=ud;
aymeric's avatar
aymeric committed
466 467 468 469 470 471 472
}

int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
	if (obj->_func!=NULL) obj->_func(lc,obj->_user_data);
	return 0;
}

473 474
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
475 476
	if (call)  return linphone_call_get_duration(call);
	return -1;
477 478 479 480
}

const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call(lc);
Simon Morlat's avatar
Simon Morlat committed
481
	if (call==NULL) return NULL;
482
	return linphone_call_get_remote_address(call);
smorlat's avatar
smorlat committed
483 484
}

485
static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args);
jehan's avatar
jehan committed
486

487
void linphone_core_set_log_handler(OrtpLogFunc logfunc) {
488 489
	liblinphone_user_log_func = logfunc;
	if (liblinphone_current_log_func == linphone_core_log_collection_handler) {
490
		ms_message("There is already a log collection handler, keep it");
491
	} else {
492
		bctbx_set_log_handler(liblinphone_current_log_func=liblinphone_user_log_func);
493
	}
494 495 496 497
}

void linphone_core_set_log_file(FILE *file) {
	if (file == NULL) file = stdout;
498
	linphone_core_set_log_handler(NULL);
499
	bctbx_set_log_file(file); /*gather everythings*/
500 501 502
}

void linphone_core_set_log_level(OrtpLogLevel loglevel) {
503
	unsigned int mask = loglevel;
504 505 506 507
	switch (loglevel) {
		case ORTP_TRACE:
		case ORTP_DEBUG:
			mask |= ORTP_DEBUG;
508
			BCTBX_NO_BREAK;
509 510
		case ORTP_MESSAGE:
			mask |= ORTP_MESSAGE;
511
			BCTBX_NO_BREAK;
512 513
		case ORTP_WARNING:
			mask |= ORTP_WARNING;
514
			BCTBX_NO_BREAK;
515 516
		case ORTP_ERROR:
			mask |= ORTP_ERROR;
517
			BCTBX_NO_BREAK;
518 519 520 521 522 523 524
		case ORTP_FATAL:
			mask |= ORTP_FATAL;
			break;
		case ORTP_LOGLEV_END:
			break;
	}
	linphone_core_set_log_level_mask(mask);
525 526
}

527
void linphone_core_set_log_level_mask(unsigned int loglevel) {
Ghislain MARY's avatar
Ghislain MARY committed
528 529
	bctbx_set_log_level_mask("bctbx", (int)loglevel);
	bctbx_set_log_level_mask("ortp", (int)loglevel);
Ghislain MARY's avatar
Ghislain MARY committed
530
	bctbx_set_log_level_mask("mediastreamer", (int)loglevel);
Ghislain MARY's avatar
Ghislain MARY committed
531 532
	bctbx_set_log_level_mask("bzrtp", (int)loglevel); /*need something to set log level for all domains*/
	bctbx_set_log_level_mask("linphone", (int)loglevel);
533 534 535 536
	sal_set_log_level((OrtpLogLevel)loglevel);
}
unsigned int linphone_core_get_log_level_mask(void) {
	return bctbx_get_log_level_mask(ORTP_LOG_DOMAIN);
537
}
538 539 540 541 542 543 544 545 546 547 548 549 550
static int _open_log_collection_file_with_idx(int idx) {
	struct stat statbuf;
	char *log_filename;

	log_filename = ortp_strdup_printf("%s/%s%d.log",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
		idx);
	liblinphone_log_collection_file = fopen(log_filename, "a");
	ortp_free(log_filename);
	if (liblinphone_log_collection_file == NULL) return -1;

	fstat(fileno(liblinphone_log_collection_file), &statbuf);
551
	if ((size_t)statbuf.st_size > liblinphone_log_collection_max_file_size) {
552 553 554 555
		fclose(liblinphone_log_collection_file);
		return -1;
	}

Benjamin REIS's avatar
Benjamin REIS committed
556
	liblinphone_log_collection_file_size = (size_t)statbuf.st_size;
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
	return 0;
}

static void _rotate_log_collection_files(void) {
	char *log_filename1;
	char *log_filename2;

	log_filename1 = ortp_strdup_printf("%s/%s1.log",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
	log_filename2 = ortp_strdup_printf("%s/%s2.log",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
	unlink(log_filename1);
	rename(log_filename2, log_filename1);
	ortp_free(log_filename1);
	ortp_free(log_filename2);
}

static void _open_log_collection_file(void) {
	if (_open_log_collection_file_with_idx(1) < 0) {
		if (_open_log_collection_file_with_idx(2) < 0) {
			_rotate_log_collection_files();
			_open_log_collection_file_with_idx(2);
		}
	}
}

static void _close_log_collection_file(void) {
	if (liblinphone_log_collection_file) {
		fclose(liblinphone_log_collection_file);
		liblinphone_log_collection_file = NULL;
		liblinphone_log_collection_file_size = 0;
	}
}

593
static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args) {
594 595 596
	const char *lname="undef";
	char *msg;
	struct timeval tp;
597
	struct tm *lt;
598
	time_t tt;
599
	int ret;
600

601
	if (liblinphone_user_log_func != NULL && liblinphone_user_log_func != linphone_core_log_collection_handler) {
602
#ifndef _WIN32
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
603 604
		va_list args_copy;
		va_copy(args_copy, args);
605
		liblinphone_user_log_func(domain, level, fmt, args_copy);
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
606
		va_end(args_copy);
607 608 609
#else
		/* This works on 32 bits, luckily. */
		/* TODO: va_copy is available in Visual Studio 2013. */
610
		liblinphone_user_log_func(domain, level, fmt, args);
611
#endif
612 613 614 615 616
	}

	ortp_gettimeofday(&tp, NULL);
	tt = (time_t)tp.tv_sec;
	lt = localtime((const time_t*)&tt);
617 618 619 620 621 622 623 624 625 626 627 628 629

	if ((level & ORTP_DEBUG) != 0) {
		lname = "DEBUG";
	} else if ((level & ORTP_MESSAGE) != 0) {
		lname = "MESSAGE";
	} else if ((level & ORTP_WARNING) != 0) {
		lname = "WARNING";
	} else if ((level & ORTP_ERROR) != 0) {
		lname = "ERROR";
	} else if ((level & ORTP_FATAL) != 0) {
		lname = "FATAL";
	} else {
		ortp_fatal("Bad level !");
630 631 632
	}
	msg = ortp_strdup_vprintf(fmt, args);

633 634 635 636 637 638 639 640 641 642 643
	if (liblinphone_log_collection_file == NULL) {
		ortp_mutex_lock(&liblinphone_log_collection_mutex);
		_open_log_collection_file();
		ortp_mutex_unlock(&liblinphone_log_collection_mutex);
	}
	if (liblinphone_log_collection_file) {
		ortp_mutex_lock(&liblinphone_log_collection_mutex);
		ret = fprintf(liblinphone_log_collection_file,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s %s\n",
			1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, (int)(tp.tv_usec / 1000), lname, msg);
		fflush(liblinphone_log_collection_file);
		if (ret > 0) {
Benjamin REIS's avatar
Benjamin REIS committed
644
			liblinphone_log_collection_file_size += (size_t)ret;
645 646 647 648
			if (liblinphone_log_collection_file_size > liblinphone_log_collection_max_file_size) {
				_close_log_collection_file();
				_open_log_collection_file();
			}
649
		}
650
		ortp_mutex_unlock(&liblinphone_log_collection_mutex);
651 652 653 654 655
	}

	ortp_free(msg);
}

656 657 658 659 660 661 662
const char * linphone_core_get_log_collection_path(void) {
	if (liblinphone_log_collection_path != NULL) {
		return liblinphone_log_collection_path;
	}
	return LOG_COLLECTION_DEFAULT_PATH;
}

663
void linphone_core_set_log_collection_path(const char *path) {
664 665 666 667 668 669 670
	if (liblinphone_log_collection_path != NULL) {
		ms_free(liblinphone_log_collection_path);
		liblinphone_log_collection_path = NULL;
	}
	if (path != NULL) {
		liblinphone_log_collection_path = ms_strdup(path);
	}
671 672
}

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
const char * linphone_core_get_log_collection_prefix(void) {
	if (liblinphone_log_collection_prefix != NULL) {
		return liblinphone_log_collection_prefix;
	}
	return LOG_COLLECTION_DEFAULT_PREFIX;
}

void linphone_core_set_log_collection_prefix(const char *prefix) {
	if (liblinphone_log_collection_prefix != NULL) {
		ms_free(liblinphone_log_collection_prefix);
		liblinphone_log_collection_prefix = NULL;
	}
	if (prefix != NULL) {
		liblinphone_log_collection_prefix = ms_strdup(prefix);
	}
}

690
size_t linphone_core_get_log_collection_max_file_size(void) {
691 692 693
	return liblinphone_log_collection_max_file_size;
}

694
void linphone_core_set_log_collection_max_file_size(size_t size) {
695 696 697
	liblinphone_log_collection_max_file_size = size;
}

698 699 700 701 702 703 704 705
const char *linphone_core_get_log_collection_upload_server_url(LinphoneCore *core) {
	return lp_config_get_string(core->config, "misc", "log_collection_upload_server_url", NULL);
}

void linphone_core_set_log_collection_upload_server_url(LinphoneCore *core, const char *server_url) {
	lp_config_set_string(core->config, "misc", "log_collection_upload_server_url", server_url);
}

706 707 708 709
LinphoneLogCollectionState linphone_core_log_collection_enabled(void) {
	return liblinphone_log_collection_state;
}

710
void linphone_core_enable_log_collection(LinphoneLogCollectionState state) {
711 712
	if (liblinphone_log_collection_state == state) return;

713 714
	liblinphone_log_collection_state = state;
	if (state != LinphoneLogCollectionDisabled) {
715
		ortp_mutex_init(&liblinphone_log_collection_mutex, NULL);
716
		if (state == LinphoneLogCollectionEnabledWithoutPreviousLogHandler) {
717
			liblinphone_user_log_func = NULL; /*remove user log handler*/
718
		}
719
		bctbx_set_log_handler(liblinphone_current_log_func = linphone_core_log_collection_handler);
720
	} else {
721
		bctbx_set_log_handler(liblinphone_user_log_func); /*restaure */
722 723 724
	}
}

jehan's avatar
jehan committed
725
static void clean_log_collection_upload_context(LinphoneCore *lc) {
726 727 728 729
	char *filename = ms_strdup_printf("%s/%s_log.%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
		COMPRESSED_LOG_COLLECTION_EXTENSION);
730
	unlink(filename);
731
	ms_free(filename);
jehan's avatar
jehan committed
732
	if (lc && lc->log_collection_upload_information) {
733
		linphone_content_unref(lc->log_collection_upload_information);
jehan's avatar
jehan committed
734 735
		lc->log_collection_upload_information=NULL;
	}
736 737
}

738 739 740 741
static void process_io_error_upload_log_collection(void *data, const belle_sip_io_error_event_t *event) {
	LinphoneCore *core = (LinphoneCore *)data;
	ms_error("I/O Error during log collection upload to %s", linphone_core_get_log_collection_upload_server_url(core));
	linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "I/O Error");
jehan's avatar
jehan committed
742
	clean_log_collection_upload_context(core);
743 744 745 746 747 748
}

static void process_auth_requested_upload_log_collection(void *data, belle_sip_auth_event_t *event) {
	LinphoneCore *core = (LinphoneCore *)data;
	ms_error("Error during log collection upload: auth requested to connect %s", linphone_core_get_log_collection_upload_server_url(core));
	linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Auth requested");
jehan's avatar
jehan committed
749
	clean_log_collection_upload_context(core);
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
}

/**
 * Callback called when posting a log collection file to server (following rcs5.1 recommendation)
 * @param[in] bh The body handler
 * @param[in] msg The belle sip message
 * @param[in] data The user data associated with the handler, contains the LinphoneCore object
 * @param[in] offset The current position in the input buffer
 * @param[in] buffer The ouput buffer where to copy the data to be uploaded
 * @param[in,out] size The size in byte of the data requested, as output it will contain the effective copied size
 */
static int log_collection_upload_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, uint8_t *buffer, size_t *size) {
	LinphoneCore *core = (LinphoneCore *)data;

	/* If we've not reach the end of file yet, fill the buffer with more data */
765
	if (offset < linphone_content_get_size(core->log_collection_upload_information)) {
766 767 768 769
		char *log_filename = ms_strdup_printf("%s/%s_log.%s",
			liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
			COMPRESSED_LOG_COLLECTION_EXTENSION);
770 771 772
#ifdef HAVE_ZLIB
		FILE *log_file = fopen(log_filename, "rb");
#else
773
		FILE *log_file = fopen(log_filename, "r");
774
#endif
775
		if (fseek(log_file, (long)offset, SEEK_SET)) {
jehan's avatar
jehan committed
776 777 778 779 780
			ms_error("Cannot seek file [%s] at position [%lu] errno [%s]",log_filename,(unsigned long)offset,strerror(errno));

		} else {
			*size = fread(buffer, 1, *size, log_file);
		}
781
		fclose(log_file);
782
		ms_free(log_filename);
jehan's avatar
jehan committed
783 784 785 786
		return BELLE_SIP_CONTINUE;
	} else {
		*size=0;
		return BELLE_SIP_STOP;
787 788 789 790 791 792 793 794 795
	}
}

/**
 * Callback called during upload of a log collection to server.
 * It is just forwarding the call and some parameters to the vtable defined callback.
 */
static void log_collection_upload_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total) {
	LinphoneCore *core = (LinphoneCore *)data;
796
	linphone_core_notify_log_collection_upload_progress_indication(core, offset, total);
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
}

/**
 * Callback function called when we have a response from server during the upload of the log collection to the server (rcs5.1 recommandation)
 * Note: The first post is empty and the server shall reply a 204 (No content) message, this will trigger a new post request to the server
 * to upload the file. The server response to this second post is processed by this same function
 *
 * @param[in] data The user-defined pointer associated with the request, it contains the LinphoneCore object
 * @param[in] event The response from server
 */
static void process_response_from_post_file_log_collection(void *data, const belle_http_response_event_t *event) {
	LinphoneCore *core = (LinphoneCore *)data;

	/* Check the answer code */
	if (event->response) {
		int code = belle_http_response_get_status_code(event->response);
		if (code == 204) { /* This is the reply to the first post to the server - an empty file */
			/* Start uploading the file */
			belle_http_request_listener_callbacks_t cbs = { 0 };
			belle_http_request_listener_t *l;
			belle_generic_uri_t *uri;
			belle_http_request_t *req;
			belle_sip_multipart_body_handler_t *bh;
			char* ua;
			char *first_part_header;
			belle_sip_user_body_handler_t *first_part_bh;

			linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateInProgress, NULL);

			/* Temporary storage for the Content-disposition header value */
827
			first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", linphone_content_get_name(core->log_collection_upload_information));
828 829

			/* Create a user body handler to take care of the file and add the content disposition and content-type headers */
830
			first_part_bh = belle_sip_user_body_handler_new(linphone_content_get_size(core->log_collection_upload_information), NULL, NULL, NULL, log_collection_upload_on_send_body, NULL, core);
831 832
			belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh, belle_sip_header_create("Content-disposition", first_part_header));
			belle_sip_free(first_part_header);
833 834
			belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh,
				(belle_sip_header_t *)belle_sip_header_content_type_create(linphone_content_get_type(core->log_collection_upload_information), linphone_content_get_subtype(core->log_collection_upload_information)));
835 836

			/* Insert it in a multipart body handler which will manage the boundaries of multipart message */
837
			bh = belle_sip_multipart_body_handler_new(log_collection_upload_on_progress, core, (belle_sip_body_handler_t *)first_part_bh, NULL);
838
			ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(core), linphone_core_get_version());
839
			uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
840
			req = belle_http_request_create("POST", uri, belle_sip_header_create("User-Agent", ua), NULL);
841 842 843 844 845 846
			ms_free(ua);
			belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh));
			cbs.process_response = process_response_from_post_file_log_collection;
			cbs.process_io_error = process_io_error_upload_log_collection;
			cbs.process_auth_requested = process_auth_requested_upload_log_collection;
			l = belle_http_request_listener_create_from_callbacks(&cbs, core);
847
			belle_sip_object_data_set(BELLE_SIP_OBJECT(req), "http_request_listener", l, belle_sip_object_unref); // Ensure the listener object is destroyed when the request is destroyed
848
			belle_http_provider_send_request(core->http_provider, req, l);
849
		} else if (code == 200) { /* The file has been uploaded correctly, get the server reply */
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
			xmlDocPtr xmlMessageBody;
			xmlNodePtr cur;
			xmlChar *file_url = NULL;
			const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
			xmlMessageBody = xmlParseDoc((const xmlChar *)body);
			cur = xmlDocGetRootElement(xmlMessageBody);
			if (cur != NULL) {
				cur = cur->xmlChildrenNode;
				while (cur != NULL) {
					if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */
						xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type");
						if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */
							cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */
							while (cur != NULL) {
								if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) {
									file_url = 	xmlGetProp(cur, (const xmlChar *)"url");
								}
								cur=cur->next;
							}
							xmlFree(typeAttribute);
							break;
						}
						xmlFree(typeAttribute);
					}
					cur = cur->next;
				}
			}
			if (file_url != NULL) {
				linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateDelivered, (const char *)file_url);
			}
jehan's avatar
jehan committed
880
			clean_log_collection_upload_context(core);
881 882 883 884
		} else {
			ms_error("Unexpected HTTP response code %i during log collection upload to %s", code, linphone_core_get_log_collection_upload_server_url(core));
			linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Unexpected HTTP response");
			clean_log_collection_upload_context(core);
885 886 887 888
		}
	}
}

889
#ifdef HAVE_ZLIB
890 891 892
#define COMPRESS_FILE_PTR gzFile
#define COMPRESS_OPEN gzopen
#define COMPRESS_CLOSE gzclose
893
#else
894 895 896 897
#define COMPRESS_FILE_PTR FILE*
#define COMPRESS_OPEN fopen
#define COMPRESS_CLOSE fclose
#endif
898 899 900 901

/**
 * If zlib is not available the two log files are simply concatenated.
 */
902
static int compress_file(FILE *input_file, COMPRESS_FILE_PTR output_file) {
903
	char buffer[131072]; /* 128kB */
904
	size_t bytes;
Sylvain Berfini's avatar
Sylvain Berfini committed
905
	size_t total_bytes = 0;
906

907
	while ((bytes = fread(buffer, 1, sizeof(buffer), input_file)) > 0) {
908
#ifdef HAVE_ZLIB
909 910
		int res = gzwrite(output_file, buffer, (unsigned int)bytes);
		if (res < 0) return 0;
Sylvain Berfini's avatar
Sylvain Berfini committed
911
		total_bytes += (size_t)res;
912
#else
Sylvain Berfini's avatar
Sylvain Berfini committed
913
		total_bytes += fwrite(buffer, 1, bytes, output_file);
914
#endif
915
	}
916
	return (int)total_bytes;
917 918
}

919
static int prepare_log_collection_file_to_upload(const char *filename) {
920 921 922
	char *input_filename = NULL;
	char *output_filename = NULL;
	FILE *input_file = NULL;
923 924
	COMPRESS_FILE_PTR output_file = NULL;
	int ret = 0;
925

926
	ortp_mutex_lock(&liblinphone_log_collection_mutex);
927 928
	output_filename = ms_strdup_printf("%s/%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
929
	output_file = COMPRESS_OPEN(output_filename, "wb");
930
	if (output_file == NULL) goto error;
931 932 933
	input_filename = ms_strdup_printf("%s/%s1.log",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
934
	input_file = fopen(input_filename, "rb");
935 936
	if (input_file == NULL) goto error;
	ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
937
	if (ret <= 0) goto error;
938
	fclose(input_file);
939
	ms_free(input_filename);
940 941 942
	input_filename = ms_strdup_printf("%s/%s2.log",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
943
	input_file = fopen(input_filename, "rb");
944 945
	if (input_file != NULL) {
		ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
946
		if (ret <= 0) goto error;
947
	}
948

949 950
error:
	if (input_file != NULL) fclose(input_file);
951
	if (output_file != NULL) COMPRESS_CLOSE(output_file);
952 953
	if (input_filename != NULL) ms_free(input_filename);
	if (output_filename != NULL) ms_free(output_filename);
954
	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
955 956 957 958 959
	return ret;
}

static size_t get_size_of_file_to_upload(const char *filename) {
	struct stat statbuf;
960 961
	char *output_filename = ms_strdup_printf("%s/%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
962 963 964
	FILE *output_file = fopen(output_filename, "rb");
	fstat(fileno(output_file), &statbuf);
	fclose(output_file);
965
	ms_free(output_filename);
Benjamin REIS's avatar
Benjamin REIS committed
966
	return (size_t)statbuf.st_size;
967 968
}

969
void linphone_core_upload_log_collection(LinphoneCore *core) {
970
	if ((core->log_collection_upload_information == NULL) && (linphone_core_get_log_collection_upload_server_url(core) != NULL) && (liblinphone_log_collection_state != LinphoneLogCollectionDisabled)) {
971 972 973 974 975
		/* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */
		belle_http_request_listener_callbacks_t cbs = { 0 };
		belle_http_request_listener_t *l;
		belle_generic_uri_t *uri;
		belle_http_request_t *req;
976
		char *name;
977

978
		core->log_collection_upload_information = linphone_core_create_content(core);
979
#ifdef HAVE_ZLIB
980 981
		linphone_content_set_type(core->log_collection_upload_information, "application");
		linphone_content_set_subtype(core->log_collection_upload_information, "gzip");
982
#else
983 984
		linphone_content_set_type(core->log_collection_upload_information, "text");
		linphone_content_set_subtype(core->log_collection_upload_information,"plain");
985
#endif
986
		name = ms_strdup_printf("%s_log.%s",
987 988
			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
			COMPRESSED_LOG_COLLECTION_EXTENSION);
989
		linphone_content_set_name(core->log_collection_upload_information, name);
Sylvain Berfini's avatar
Sylvain Berfini committed
990
		if (prepare_log_collection_file_to_upload(name) <= 0) {
991
			linphone_content_unref(core->log_collection_upload_information);
Sylvain Berfini's avatar
Sylvain Berfini committed
992
			core->log_collection_upload_information = NULL;
993
			ms_error("prepare_log_collection_file_to_upload(): error.");
994
			linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Error while preparing log collection upload");
995
			return;
Sylvain Berfini's avatar
Sylvain Berfini committed
996
		}
997
		linphone_content_set_size(core->log_collection_upload_information, get_size_of_file_to_upload(name));
998 999 1000 1001 1002 1003
		uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
		req = belle_http_request_create("POST", uri, NULL, NULL, NULL);
		cbs.process_response = process_response_from_post_file_log_collection;
		cbs.process_io_error = process_io_error_upload_log_collection;
		cbs.process_auth_requested = process_auth_requested_upload_log_collection;
		l = belle_http_request_listener_create_from_callbacks(&cbs, core);
1004
		belle_sip_object_data_set(BELLE_SIP_OBJECT(req), "http_request_listener", l, belle_sip_object_unref); // Ensure the listener object is destroyed when the request is destroyed
1005
		belle_http_provider_send_request(core->http_provider, req, l);
1006
		ms_free(name);
1007
	} else {
1008
		const char *msg = NULL;
1009 1010
		ms_warning("Could not upload log collection: log_collection_upload_information=%p, server_url=%s, log_collection_state=%d",
			core->log_collection_upload_information, linphone_core_get_log_collection_upload_server_url(core), liblinphone_log_collection_state);
1011 1012 1013 1014 1015 1016 1017 1018
		if (core->log_collection_upload_information != NULL) {
			msg = "Log collection upload already in progress";
		} else if (linphone_core_get_log_collection_upload_server_url(core) == NULL) {
			msg = "Log collection upload server not set";
		} else if (liblinphone_log_collection_state == LinphoneLogCollectionDisabled) {
			msg = "Log collection is disabled";
		}
		linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, msg);
1019 1020 1021
	}
}

1022
char * linphone_core_compress_log_collection(void) {
1023 1024 1025 1026 1027
	char *filename = NULL;
	if (liblinphone_log_collection_state == LinphoneLogCollectionDisabled) return NULL;
	filename = ms_strdup_printf("%s_log.%s",
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
		COMPRESSED_LOG_COLLECTION_EXTENSION);
1028
	if (prepare_log_collection_file_to_upload(filename) <= 0) {
1029 1030 1031 1032 1033 1034 1035 1036
		ms_free(filename);
		return NULL;
	}
	ms_free(filename);
	return ms_strdup_printf("%s/%s_log.%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
		COMPRESSED_LOG_COLLECTION_EXTENSION);
1037 1038
}

1039
void linphone_core_reset_log_collection(void) {
1040 1041
	char *filename;
	ortp_mutex_lock(&liblinphone_log_collection_mutex);
1042
	_close_log_collection_file();
jehan's avatar
jehan committed
1043
	clean_log_collection_upload_context(NULL);
1044 1045 1046
	filename = ms_strdup_printf("%s/%s1.log",
			liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
1047 1048
	unlink(filename);
	ms_free(filename);
1049 1050 1051
	filename = ms_strdup_printf("%s/%s2.log",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
1052 1053
	unlink(filename);
	ms_free(filename);
1054 1055
	liblinphone_log_collection_file = NULL;
	liblinphone_log_collection_file_size = 0;
1056
	liblinphone_log_collection_max_file_size = LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE; /*also reset size*/
1057 1058 1059
	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
}

aymeric's avatar
aymeric committed
1060 1061 1062
void linphone_core_enable_logs(FILE *file){
	if (file==NULL) file=stdout;
	ortp_set_log_file(file);
1063
	linphone_core_set_log_level(ORTP_MESSAGE);
aymeric's avatar
aymeric committed
1064 1065 1066
}

void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){
1067
	linphone_core_set_log_level(ORTP_MESSAGE);
1068
	linphone_core_set_log_handler(logfunc);
aymeric's avatar
aymeric committed
1069 1070
}

1071
void linphone_core_disable_logs(void){
1072
	linphone_core_set_log_level(ORTP_ERROR);
aymeric's avatar
aymeric committed
1073 1074
}

1075 1076 1077 1078
void linphone_core_serialize_logs(void) {
	liblinphone_serialize_logs = TRUE;
}

aymeric's avatar
aymeric committed
1079

1080
static void net_config_read(LinphoneCore *lc) {
aymeric's avatar
aymeric committed
1081 1082 1083
	int tmp;
	const char *tmpstr;
	LpConfig *config=lc->config;
1084 1085 1086 1087
	const char *nat_policy_ref;

	nat_policy_ref = lp_config_get_string(lc->config, "net", "nat_policy_ref", NULL);
	if (nat_policy_ref != NULL) {
1088 1089 1090
		LinphoneNatPolicy *nat_policy = linphone_core_create_nat_policy_from_config(lc, nat_policy_ref);
		linphone_core_set_nat_policy(lc, nat_policy);
		linphone_nat_policy_unref(nat_policy);
1091
	}
1092 1093 1094 1095
	if (lc->nat_policy == NULL){
		/*this will create a default nat policy according to deprecated config keys, or an empty nat policy otherwise*/
		linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc));
	}
aymeric's avatar
aymeric committed
1096

1097
	lc->net_conf.nat_address_ip = NULL;
aymeric's avatar
aymeric committed
1098 1099 1100 1101
	tmp=lp_config_get_int(config,"net","download_bw",0);
	linphone_core_set_download_bandwidth(lc,tmp);
	tmp=lp_config_get_int(config,"net","upload_bw",0);
	linphone_core_set_upload_bandwidth(lc,tmp);
1102 1103
	tmp=lp_config_get_int(config, "net", "expected_bw", 0);
	linphone_core_set_expected_bandwidth(lc, tmp);
1104

aymeric's avatar
aymeric committed
1105 1106 1107 1108
	tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL);
	if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL;
	linphone_core_set_nat_address(lc,tmpstr);
	tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0);
1109
	lc->net_conf.nat_sdp_only=!!tmp;
1110
	tmp=lp_config_get_int(lc->config,"net","mtu",1300);
aymeric's avatar
aymeric committed
1111
	linphone_core_set_mtu(lc,tmp);
1112 1113 1114 1115 1116
	tmp=lp_config_get_int(lc->config,"net","download_ptime",-1);
	if (tmp !=-1 && linphone_core_get_download_ptime(lc) !=0) {
		/*legacy parameter*/
		linphone_core_set_download_ptime(lc,tmp);
	}
1117
	tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1);
1118
	linphone_core_enable_dns_srv(lc, !!tmp);
1119
	tmp = lp_config_get_int(lc->config, "net", "dns_search_enabled", 1);
1120
	linphone_core_enable_dns_search(lc, !!tmp);
aymeric's avatar
aymeric committed
1121 1122
}

1123 1124 1125
static void build_sound_devices_table(LinphoneCore *lc){
	const char **devices;
	const char **old;
1126
	size_t ndev;
1127
	int i;
1128 1129
	const bctbx_list_t *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(lc->factory));
	ndev=bctbx_list_size(elem);
1130
	devices=reinterpret_cast<const char **>(ms_malloc((ndev+1)*sizeof(const char *)));
1131 1132 1133 1134 1135 1136
	for (i=0;elem!=NULL;elem=elem->next,i++){
		devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data);
	}
	devices[ndev]=NULL;
	old=lc->sound_conf.cards;
	lc->sound_conf.cards=devices;
1137
	if (old!=NULL) ms_free((void *)old);
1138
}
aymeric's avatar
aymeric committed
1139

1140 1141 1142 1143
static char *get_default_local_ring(LinphoneCore * lc) {
	LinphoneFactory *factory = linphone_factory_get();
	if (linphone_core_file_format_supported(lc, "mkv")) {
		return bctbx_strdup_printf("%s/%s", linphone_factory_get_ring_resources_dir(factory), LOCAL_RING_MKV);
1144
	}
1145
	return bctbx_strdup_printf("%s/%s", linphone_factory_get_ring_resources_dir(factory), LOCAL_RING_WAV);
1146 1147
}

1148 1149 1150 1151
static char *get_default_onhold_music(LinphoneCore * lc) {
	LinphoneFactory *factory = linphone_factory_get();
	if (linphone_core_file_format_supported(lc, "mkv")) {
		return bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), HOLD_MUSIC_MKV);
1152
	}
1153
	return bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), HOLD_MUSIC_WAV);
1154 1155
}

1156
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
1157
{
1158
	int tmp;
1159
	char *default_remote_ring;
aymeric's avatar
aymeric committed
1160 1161
	const char *tmpbuf;
	const char *devid;
1162 1163
	LinphoneFactory *factory = linphone_factory_get();

1164
#ifdef __linux
aymeric's avatar
aymeric committed
1165 1166 1167
	/*alsadev let the user use custom alsa device within linphone*/
	devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
	if (devid){
1168 1169 1170
		MSSndCard* card;
		const char* delim=",";
		size_t l=strlen(devid);
1171
		char* d=reinterpret_cast<char *>(malloc(l+1));
1172 1173 1174 1175 1176 1177
		char* i;
		memcpy(d,devid,l+1);
		for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){
			char s=*i;
			*i='\0';
			card=ms_alsa_card_new_custom(d+l,d+l);
1178
			ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
1179
			*i=s;
1180
			l=(size_t)(i-d)+1;
1181 1182 1183
		}
		if(d[l]!='\0') {
			card=ms_alsa_card_new_custom(d+l,d+l);
1184
			ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
1185 1186
		}
		free(d);
aymeric's avatar
aymeric committed
1187
	}
1188
	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
1189
	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
aymeric's avatar
aymeric committed
1190 1191
#endif
	/* retrieve all sound devices */
1192 1193
	build_sound_devices_table(lc);

aymeric's avatar
aymeric committed
1194 1195
	devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
	linphone_core_set_playback_device(lc,devid);
1196

aymeric's avatar
aymeric committed
1197 1198
	devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
	linphone_core_set_ringer_device(lc,devid);
1199

aymeric's avatar
aymeric committed
1200 1201
	devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
	linphone_core_set_capture_device(lc,devid);
1202

aymeric's avatar
aymeric committed
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
/*
	tmp=lp_config_get_int(lc->config,"sound","play_lev",80);
	linphone_core_set_play_level(lc,tmp);
	tmp=lp_config_get_int(lc->config,"sound","ring_lev",80);
	linphone_core_set_ring_level(lc,tmp);
	tmp=lp_config_get_int(lc->config,"sound","rec_lev",80);
	linphone_core_set_rec_level(lc,tmp);
	tmpbuf=lp_config_get_string(lc->config,"sound","source","m");
	linphone_core_set_sound_source(lc,tmpbuf[0]);
*/
1213

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
	tmpbuf = lp_config_get_string(lc->config, "sound", "local_ring", NULL);
	if (tmpbuf) {
		if (bctbx_file_exist(tmpbuf) == 0) {
			linphone_core_set_ring(lc, tmpbuf);
		} else {
			ms_warning("'%s' ring file does not exist", tmpbuf);
		}
	} else {
		char *default_local_ring = get_default_local_ring(lc);
		linphone_core_set_ring(lc, default_local_ring);
		bctbx_free(default_local_ring);
aymeric's avatar
aymeric committed
1225
	}
1226

1227 1228 1229 1230 1231
	default_remote_ring = bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), REMOTE_RING_WAV);
	tmpbuf = default_remote_ring;
	tmpbuf = lp_config_get_string(lc->config, "sound", "remote_ring", tmpbuf);
	if (bctbx_file_exist(tmpbuf) == -1){
		tmpbuf = default_remote_ring;
aymeric's avatar
aymeric committed
1232
	}
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
	if (strstr(tmpbuf, ".wav") == NULL) {
		/* It currently uses old sound files, so replace them */
		tmpbuf = default_remote_ring;
	}
	linphone_core_set_ringback(lc, tmpbuf);
	bctbx_free(default_remote_ring);

	tmpbuf = lp_config_get_string(lc->config, "sound", "hold_music", NULL);
	if (tmpbuf) {
		if (bctbx_file_exist(tmpbuf) == 0) {
			linphone_core_set_play_file(lc, tmpbuf);
		} else {
			ms_warning("'%s' on-hold music file does not exist", tmpbuf);
		}
	} else {
		char *default_onhold_music = get_default_onhold_music(lc);
		linphone_core_set_play_file(lc, default_onhold_music);
		bctbx_free(default_onhold_music);
aymeric's avatar
aymeric committed
1251
	}
1252

aymeric's avatar
aymeric committed
1253
	lc->sound_conf.latency=0;
Benjamin REIS's avatar
Benjamin REIS committed
1254
#if !TARGET_OS_IPHONE
Simon Morlat's avatar
Simon Morlat committed
1255
	tmp=TRUE;
1256
#else
Simon Morlat's avatar
Simon Morlat committed
1257
	tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
1258
#endif
Simon Morlat's avatar
Simon Morlat committed
1259
	tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp);
1260
	linphone_core_enable_echo_cancellation(lc, !!tmp);
1261
	linphone_core_set_echo_canceller_filter_name(lc, linphone_core_get_echo_canceller_filter_name(lc));
1262 1263
	linphone_core_enable_echo_limiter(lc, !!lp_config_get_int(lc->config,"sound","echolimiter",0));
	linphone_core_enable_agc(lc, !!lp_config_get_int(lc->config,"sound","agc",0));
1264

1265 1266
	linphone_core_set_playback_gain_db (lc,lp_config_get_float(lc->config,"sound","playback_gain_db",0));
	linphone_core_set_mic_gain_db (lc,lp_config_get_float(lc->config,"sound","mic_gain_db",0));
1267 1268

	linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
1269 1270 1271

	/*just parse requested stream feature once at start to print out eventual errors*/
	linphone_core_get_audio_features(lc);
1272

1273
	_linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL);
aymeric's avatar
aymeric committed
1274 1275
}

1276
static void certificates_config_read(LinphoneCore *lc) {
1277
	LinphoneFactory *factory = linphone_factory_get();