linphonecore.c 266 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

Yann Diorcet's avatar
Yann Diorcet committed
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

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

Ronan's avatar
Ronan committed
51
#include "chat/chat-room/client-group-chat-room-p.h"
52
#include "chat/chat-room/server-group-chat-room-p.h"
53
#include "conference/handlers/remote-conference-event-handler.h"
54
#include "core/core.h"
aymeric's avatar
aymeric committed
55

56 57
// For migration purpose.
#include "address/address-p.h"
58
#include "c-wrapper/c-wrapper.h"
59

60
#ifdef INET6
61
#ifndef _WIN32
62
#include <netdb.h>
aymeric's avatar
aymeric committed
63 64 65
#endif
#endif

66
#ifdef HAVE_CONFIG_H
67
#include "config.h"
68
#include "gitversion.h"
69 70
#endif

71 72 73
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
74

75
#include "c-wrapper/c-wrapper.h"
76 77 78
#include "call/call-p.h"
#include "conference/params/media-session-params-p.h"

79
#ifdef HAVE_ZLIB
Ghislain MARY's avatar
Ghislain MARY committed
80
#define COMPRESSED_LOG_COLLECTION_EXTENSION "gz"
81
#ifdef _WIN32
82 83
#include <fcntl.h>
#include <io.h>
84
#ifndef fileno
85
#define fileno _fileno
86
#endif
87
#define unlink _unlink
88 89 90 91 92
#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
#define SET_BINARY_MODE(file)
#endif
#include <zlib.h>
93
#else
Ghislain MARY's avatar
Ghislain MARY committed
94
#define COMPRESSED_LOG_COLLECTION_EXTENSION "txt"
95
#endif
Ghislain MARY's avatar
Ghislain MARY committed
96 97 98 99
#define LOG_COLLECTION_DEFAULT_PATH "."
#define LOG_COLLECTION_DEFAULT_PREFIX "linphone"
#define LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE (10 * 1024 * 1024)

100

smorlat's avatar
smorlat committed
101
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
102

103 104 105 106 107 108 109
static const char *liblinphone_version=
#ifdef LIBLINPHONE_GIT_VERSION
	LIBLINPHONE_GIT_VERSION
#else
	LIBLINPHONE_VERSION
#endif
;
Ghislain MARY's avatar
Ghislain MARY committed
110 111 112 113 114 115 116

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);
}

117 118
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*/
Ghislain MARY's avatar
Ghislain MARY committed
119
static LinphoneLogCollectionState liblinphone_log_collection_state = LinphoneLogCollectionDisabled;
120
static char * liblinphone_log_collection_path = NULL;
Ghislain MARY's avatar
Ghislain MARY committed
121
static char * liblinphone_log_collection_prefix = NULL;
122
static size_t liblinphone_log_collection_max_file_size = LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE;
123
static ortp_mutex_t liblinphone_log_collection_mutex;
124 125
static FILE * liblinphone_log_collection_file = NULL;
static size_t liblinphone_log_collection_file_size = 0;
126
static bool_t liblinphone_serialize_logs = FALSE;
127
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
128 129
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
130
static void linphone_core_run_hooks(LinphoneCore *lc);
131
static void linphone_core_uninit(LinphoneCore *lc);
johan's avatar
johan committed
132
static void linphone_core_zrtp_cache_close(LinphoneCore *lc);
133
void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName);
aymeric's avatar
aymeric committed
134

135 136
#include "enum.h"
#include "contact_providers_priv.h"
137

138
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
aymeric's avatar
aymeric committed
139 140
static void toggle_video_preview(LinphoneCore *lc, bool_t val);

141

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

148 149
#define HOLD_MUSIC_WAV "toy-mono.wav"
#define HOLD_MUSIC_MKV "dont_wait_too_long.mkv"
aymeric's avatar
aymeric committed
150

151 152
using namespace std;

Ronan's avatar
Ronan committed
153 154
using namespace LinphonePrivate;

155
extern Sal::Callbacks linphone_sal_callbacks;
aymeric's avatar
aymeric committed
156

157 158 159 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

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
198
void *linphone_core_cbs_get_user_data(const LinphoneCoreCbs *cbs) {
199 200 201 202 203 204 205
	return cbs->vtable->user_data;
}

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

206 207 208 209
LinphoneCoreCbsGlobalStateChangedCb linphone_core_cbs_get_global_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->global_state_changed;
}

210
void linphone_core_cbs_set_global_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsGlobalStateChangedCb cb) {
211 212 213
	cbs->vtable->global_state_changed = cb;
}

214 215 216 217
LinphoneCoreCbsRegistrationStateChangedCb linphone_core_cbs_get_registration_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->registration_state_changed;
}

218 219 220 221
void linphone_core_cbs_set_registration_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsRegistrationStateChangedCb cb) {
	cbs->vtable->registration_state_changed = cb;
}

222 223 224 225
LinphoneCoreCbsCallStateChangedCb linphone_core_cbs_get_call_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_state_changed;
}

226 227 228 229
void linphone_core_cbs_set_call_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStateChangedCb cb) {
	cbs->vtable->call_state_changed = cb;
}

230 231 232 233
LinphoneCoreCbsNotifyPresenceReceivedCb linphone_core_cbs_get_notify_presence_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_presence_received;
}

234 235 236 237
void linphone_core_cbs_set_notify_presence_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedCb cb) {
	cbs->vtable->notify_presence_received = cb;
}

238 239 240 241
LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb linphone_core_cbs_get_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_presence_received_for_uri_or_tel;
}

242 243 244 245
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;
}

246 247 248 249
LinphoneCoreCbsNewSubscriptionRequestedCb linphone_core_cbs_get_new_subscription_requested(LinphoneCoreCbs *cbs) {
	return cbs->vtable->new_subscription_requested;
}

250 251 252 253
void linphone_core_cbs_set_new_subscription_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsNewSubscriptionRequestedCb cb) {
	cbs->vtable->new_subscription_requested = cb;
}

254 255 256 257
LinphoneCoreCbsAuthenticationRequestedCb linphone_core_cbs_get_authentication_requested(LinphoneCoreCbs *cbs) {
	return cbs->vtable->authentication_requested;
}

258 259 260 261
void linphone_core_cbs_set_authentication_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsAuthenticationRequestedCb cb) {
	cbs->vtable->authentication_requested = cb;
}

262 263 264 265
LinphoneCoreCbsCallLogUpdatedCb linphone_core_cbs_get_call_log_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_log_updated;
}

266 267 268 269
void linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallLogUpdatedCb cb) {
	cbs->vtable->call_log_updated = cb;
}

270 271 272 273
LinphoneCoreCbsMessageReceivedCb linphone_core_cbs_get_message_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->message_received;
}

274 275 276 277
void linphone_core_cbs_set_message_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedCb cb) {
	cbs->vtable->message_received = cb;
}

278 279 280 281
LinphoneCoreCbsMessageReceivedUnableDecryptCb linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs *cbs) {
	return cbs->vtable->message_received_unable_decrypt;
}

282 283 284 285
void linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedUnableDecryptCb cb) {
	cbs->vtable->message_received_unable_decrypt = cb;
}

286 287 288 289
LinphoneCoreCbsIsComposingReceivedCb linphone_core_cbs_get_is_composing_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->is_composing_received;
}

290 291 292 293
void linphone_core_cbs_set_is_composing_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsIsComposingReceivedCb cb) {
	cbs->vtable->is_composing_received = cb;
}

294 295 296 297
LinphoneCoreCbsDtmfReceivedCb linphone_core_cbs_get_dtmf_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->dtmf_received;
}

298 299 300 301
void linphone_core_cbs_set_dtmf_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsDtmfReceivedCb cb) {
	cbs->vtable->dtmf_received = cb;
}

302 303 304 305
LinphoneCoreCbsReferReceivedCb linphone_core_cbs_get_refer_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->refer_received;
}

306 307 308 309
void linphone_core_cbs_set_refer_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsReferReceivedCb cb) {
	cbs->vtable->refer_received = cb;
}

310 311 312 313
LinphoneCoreCbsCallEncryptionChangedCb linphone_core_cbs_get_call_encryption_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_encryption_changed;
}

314 315 316 317
void linphone_core_cbs_set_call_encryption_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallEncryptionChangedCb cb) {
	cbs->vtable->call_encryption_changed = cb;
}

318 319 320 321
LinphoneCoreCbsTransferStateChangedCb linphone_core_cbs_get_transfer_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->transfer_state_changed;
}

322 323 324 325
void linphone_core_cbs_set_transfer_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsTransferStateChangedCb cb) {
	cbs->vtable->transfer_state_changed = cb;
}

326 327 328 329
LinphoneCoreCbsBuddyInfoUpdatedCb linphone_core_cbs_get_buddy_info_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->buddy_info_updated;
}

330 331 332 333
void linphone_core_cbs_set_buddy_info_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsBuddyInfoUpdatedCb cb) {
	cbs->vtable->buddy_info_updated = cb;
}

334 335 336 337
LinphoneCoreCbsCallStatsUpdatedCb linphone_core_cbs_get_call_stats_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_stats_updated;
}

338 339 340 341
void linphone_core_cbs_set_call_stats_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStatsUpdatedCb cb) {
	cbs->vtable->call_stats_updated = cb;
}

342 343 344 345
LinphoneCoreCbsInfoReceivedCb linphone_core_cbs_get_info_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->info_received;
}

346 347 348 349
void linphone_core_cbs_set_info_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsInfoReceivedCb cb) {
	cbs->vtable->info_received = cb;
}

350 351 352 353
LinphoneCoreCbsSubscriptionStateChangedCb linphone_core_cbs_get_subscription_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->subscription_state_changed;
}

354 355 356 357
void linphone_core_cbs_set_subscription_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsSubscriptionStateChangedCb cb) {
	cbs->vtable->subscription_state_changed = cb;
}

358 359 360 361
LinphoneCoreCbsNotifyReceivedCb linphone_core_cbs_get_notify_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_received;
}

362 363 364 365
void linphone_core_cbs_set_notify_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyReceivedCb cb) {
	cbs->vtable->notify_received = cb;
}

366 367 368 369
LinphoneCoreCbsPublishStateChangedCb linphone_core_cbs_get_rpublish_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->publish_state_changed;
}

370 371 372 373
void linphone_core_cbs_set_publish_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsPublishStateChangedCb cb) {
	cbs->vtable->publish_state_changed = cb;
}

374 375 376 377
LinphoneCoreCbsConfiguringStatusCb linphone_core_cbs_get_configuring_status(LinphoneCoreCbs *cbs) {
	return cbs->vtable->configuring_status;
}

378 379 380 381
void linphone_core_cbs_set_configuring_status(LinphoneCoreCbs *cbs, LinphoneCoreCbsConfiguringStatusCb cb) {
	cbs->vtable->configuring_status = cb;
}

382 383 384 385
LinphoneCoreCbsNetworkReachableCb linphone_core_cbs_get_network_reachable(LinphoneCoreCbs *cbs) {
	return cbs->vtable->network_reachable;
}

386 387 388 389
void linphone_core_cbs_set_network_reachable(LinphoneCoreCbs *cbs, LinphoneCoreCbsNetworkReachableCb cb) {
	cbs->vtable->network_reachable = cb;
}

390 391 392 393
LinphoneCoreCbsLogCollectionUploadStateChangedCb linphone_core_cbs_log_collection_upload_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->log_collection_upload_state_changed;
}

394 395 396 397
void linphone_core_cbs_set_log_collection_upload_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadStateChangedCb cb) {
	cbs->vtable->log_collection_upload_state_changed = cb;
}

398 399 400 401
LinphoneCoreCbsLogCollectionUploadProgressIndicationCb linphone_core_cbs_get_rlog_collection_upload_progress_indication(LinphoneCoreCbs *cbs) {
	return cbs->vtable->log_collection_upload_progress_indication;
}

402 403 404 405
void linphone_core_cbs_set_log_collection_upload_progress_indication(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadProgressIndicationCb cb) {
	cbs->vtable->log_collection_upload_progress_indication = cb;
}

406 407 408 409
LinphoneCoreCbsFriendListCreatedCb linphone_core_cbs_get_friend_list_created(LinphoneCoreCbs *cbs) {
	return cbs->vtable->friend_list_created;
}

410 411 412 413
void linphone_core_cbs_set_friend_list_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListCreatedCb cb) {
	cbs->vtable->friend_list_created = cb;
}

414 415 416 417
LinphoneCoreCbsFriendListRemovedCb linphone_core_cbs_get_friend_list_removed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->friend_list_removed;
}

418 419 420 421
void linphone_core_cbs_set_friend_list_removed(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListRemovedCb cb) {
	cbs->vtable->friend_list_removed = cb;
}

422 423 424 425 426 427 428 429
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
430 431 432 433 434 435 436 437
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;
}

438 439 440 441 442 443 444 445
LinphoneCoreCbsChatRoomInstantiatedCb linphone_core_cbs_get_chat_room_instantiated (LinphoneCoreCbs *cbs) {
	return cbs->vtable->chat_room_instantiated;
}

void linphone_core_cbs_set_chat_room_instantiated (LinphoneCoreCbs *cbs, LinphoneCoreCbsChatRoomInstantiatedCb cb) {
	cbs->vtable->chat_room_instantiated = cb;
}

446 447 448 449 450 451 452 453 454 455 456 457
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
458

459 460 461 462 463 464 465 466 467
typedef belle_sip_object_t_vptr_t LinphoneCore_vptr_t;
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCore);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneCore, belle_sip_object_t,
	linphone_core_uninit, // destroy
	NULL, // clone
	NULL, // Marshall
	FALSE
);

468
void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) {
Ronan's avatar
Ronan committed
469 470
	obj->_func=func;
	obj->_user_data=ud;
aymeric's avatar
aymeric committed
471 472 473 474 475 476 477
}

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

478 479
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
480 481
	if (call)  return linphone_call_get_duration(call);
	return -1;
482 483 484 485
}

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
486
	if (call==NULL) return NULL;
487
	return linphone_call_get_remote_address(call);
smorlat's avatar
smorlat committed
488 489
}

Simon Morlat's avatar
Simon Morlat committed
490
static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args);
jehan's avatar
jehan committed
491

492
void linphone_core_set_log_handler(OrtpLogFunc logfunc) {
493 494
	liblinphone_user_log_func = logfunc;
	if (liblinphone_current_log_func == linphone_core_log_collection_handler) {
495
		ms_message("There is already a log collection handler, keep it");
496
	} else {
497
		bctbx_set_log_handler(liblinphone_current_log_func=liblinphone_user_log_func);
498
	}
499 500 501 502
}

void linphone_core_set_log_file(FILE *file) {
	if (file == NULL) file = stdout;
503
	linphone_core_set_log_handler(NULL);
504
	bctbx_set_log_file(file); /*gather everythings*/
505 506 507
}

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

532
void linphone_core_set_log_level_mask(unsigned int loglevel) {
533
	//we only have 2 domain for now ortp and belle-sip
Benjamin REIS's avatar
Benjamin REIS committed
534
	bctbx_set_log_level_mask(ORTP_LOG_DOMAIN, (int)loglevel);
Ghislain MARY's avatar
Ghislain MARY committed
535
	bctbx_set_log_level_mask("mediastreamer", (int)loglevel);
Benjamin REIS's avatar
Benjamin REIS committed
536
	bctbx_set_log_level_mask("bzrtp", (int)loglevel); /*need something to set log lvel for all domains*/
537 538 539 540
	sal_set_log_level((OrtpLogLevel)loglevel);
}
unsigned int linphone_core_get_log_level_mask(void) {
	return bctbx_get_log_level_mask(ORTP_LOG_DOMAIN);
541
}
542 543 544 545 546 547 548 549 550 551 552 553 554
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);
555
	if ((size_t)statbuf.st_size > liblinphone_log_collection_max_file_size) {
556 557 558 559
		fclose(liblinphone_log_collection_file);
		return -1;
	}

Benjamin REIS's avatar
Benjamin REIS committed
560
	liblinphone_log_collection_file_size = (size_t)statbuf.st_size;
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 593 594 595 596
	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;
	}
}

Simon Morlat's avatar
Simon Morlat committed
597
static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args) {
598 599 600
	const char *lname="undef";
	char *msg;
	struct timeval tp;
601
	struct tm *lt;
602
	time_t tt;
603
	int ret;
604

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

	ortp_gettimeofday(&tp, NULL);
	tt = (time_t)tp.tv_sec;
	lt = localtime((const time_t*)&tt);
621 622 623 624 625 626 627 628 629 630 631 632 633

	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 !");
634 635 636
	}
	msg = ortp_strdup_vprintf(fmt, args);

637 638 639 640 641 642 643 644 645 646 647
	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
648
			liblinphone_log_collection_file_size += (size_t)ret;
649 650 651 652
			if (liblinphone_log_collection_file_size > liblinphone_log_collection_max_file_size) {
				_close_log_collection_file();
				_open_log_collection_file();
			}
653
		}
654
		ortp_mutex_unlock(&liblinphone_log_collection_mutex);
655 656 657 658 659
	}

	ortp_free(msg);
}

Ghislain MARY's avatar
Ghislain MARY committed
660 661 662 663 664 665 666
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;
}

667
void linphone_core_set_log_collection_path(const char *path) {
668 669 670 671 672 673 674
	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);
	}
675 676
}

Ghislain MARY's avatar
Ghislain MARY committed
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
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);
	}
}

694
size_t linphone_core_get_log_collection_max_file_size(void) {
Ghislain MARY's avatar
Ghislain MARY committed
695 696 697
	return liblinphone_log_collection_max_file_size;
}

698
void linphone_core_set_log_collection_max_file_size(size_t size) {
Ghislain MARY's avatar
Ghislain MARY committed
699 700 701
	liblinphone_log_collection_max_file_size = size;
}

702 703 704 705 706 707 708 709
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);
}

Ghislain MARY's avatar
Ghislain MARY committed
710 711 712 713
LinphoneLogCollectionState linphone_core_log_collection_enabled(void) {
	return liblinphone_log_collection_state;
}

714
void linphone_core_enable_log_collection(LinphoneLogCollectionState state) {
715 716
	if (liblinphone_log_collection_state == state) return;

Ghislain MARY's avatar
Ghislain MARY committed
717 718
	liblinphone_log_collection_state = state;
	if (state != LinphoneLogCollectionDisabled) {
719
		ortp_mutex_init(&liblinphone_log_collection_mutex, NULL);
720
		if (state == LinphoneLogCollectionEnabledWithoutPreviousLogHandler) {
721
			liblinphone_user_log_func = NULL; /*remove user log handler*/
722
		}
723
		bctbx_set_log_handler(liblinphone_current_log_func = linphone_core_log_collection_handler);
724
	} else {
725
		bctbx_set_log_handler(liblinphone_user_log_func); /*restaure */
726 727 728
	}
}

jehan's avatar
jehan committed
729
static void clean_log_collection_upload_context(LinphoneCore *lc) {
Ghislain MARY's avatar
Ghislain MARY committed
730 731 732 733
	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);
734
	unlink(filename);
735
	ms_free(filename);
jehan's avatar
jehan committed
736
	if (lc && lc->log_collection_upload_information) {
Ghislain MARY's avatar
Ghislain MARY committed
737
		linphone_content_unref(lc->log_collection_upload_information);
jehan's avatar
jehan committed
738 739
		lc->log_collection_upload_information=NULL;
	}
740 741
}

742 743 744 745
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
746
	clean_log_collection_upload_context(core);
747 748 749 750 751 752
}

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
753
	clean_log_collection_upload_context(core);
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
}

/**
 * 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 */
769
	if (offset < linphone_content_get_size(core->log_collection_upload_information)) {
Ghislain MARY's avatar
Ghislain MARY committed
770 771 772 773
		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);
774 775 776
#ifdef HAVE_ZLIB
		FILE *log_file = fopen(log_filename, "rb");
#else
777
		FILE *log_file = fopen(log_filename, "r");
778
#endif
779
		if (fseek(log_file, (long)offset, SEEK_SET)) {
jehan's avatar
jehan committed
780 781 782 783 784
			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);
		}
785
		fclose(log_file);
786
		ms_free(log_filename);
jehan's avatar
jehan committed
787 788 789 790
		return BELLE_SIP_CONTINUE;
	} else {
		*size=0;
		return BELLE_SIP_STOP;
791 792 793 794 795 796 797 798 799
	}
}

/**
 * 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;
800
	linphone_core_notify_log_collection_upload_progress_indication(core, offset, total);
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 827 828 829 830
}

/**
 * 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 */
831
			first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", linphone_content_get_name(core->log_collection_upload_information));
832 833

			/* Create a user body handler to take care of the file and add the content disposition and content-type headers */
834
			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);
835 836
			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);
837 838
			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)));
839 840

			/* Insert it in a multipart body handler which will manage the boundaries of multipart message */
841
			bh = belle_sip_multipart_body_handler_new(log_collection_upload_on_progress, core, (belle_sip_body_handler_t *)first_part_bh, NULL);
842
			ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(core), linphone_core_get_version());
843
			uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
844
			req = belle_http_request_create("POST", uri, belle_sip_header_create("User-Agent", ua), NULL);
845 846 847 848 849 850
			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);
851
			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
852
			belle_http_provider_send_request(core->http_provider, req, l);
853
		} else if (code == 200) { /* The file has been uploaded correctly, get the server reply */
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 880 881 882 883
			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
884
			clean_log_collection_upload_context(core);
885 886 887 888
		} 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);
889 890 891 892
		}
	}
}

893
#ifdef HAVE_ZLIB
894 895 896
#define COMPRESS_FILE_PTR gzFile
#define COMPRESS_OPEN gzopen
#define COMPRESS_CLOSE gzclose
897
#else
898 899 900 901
#define COMPRESS_FILE_PTR FILE*
#define COMPRESS_OPEN fopen
#define COMPRESS_CLOSE fclose
#endif
902 903 904 905

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

Simon Morlat's avatar
Simon Morlat committed
911
	while ((bytes = fread(buffer, 1, sizeof(buffer), input_file)) > 0) {
912
#ifdef HAVE_ZLIB
913 914
		int res = gzwrite(output_file, buffer, (unsigned int)bytes);
		if (res < 0) return 0;
Sylvain Berfini's avatar
Sylvain Berfini committed
915
		total_bytes += (size_t)res;
916
#else
Sylvain Berfini's avatar
Sylvain Berfini committed
917
		total_bytes += fwrite(buffer, 1, bytes, output_file);
918
#endif
919
	}
Ghislain MARY's avatar
Ghislain MARY committed
920
	return (int)total_bytes;
921 922
}

923
static int prepare_log_collection_file_to_upload(const char *filename) {
924 925 926
	char *input_filename = NULL;
	char *output_filename = NULL;
	FILE *input_file = NULL;
927 928
	COMPRESS_FILE_PTR output_file = NULL;
	int ret = 0;
929

930
	ortp_mutex_lock(&liblinphone_log_collection_mutex);
Ghislain MARY's avatar
Ghislain MARY committed
931 932
	output_filename = ms_strdup_printf("%s/%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
933
	output_file = COMPRESS_OPEN(output_filename, "wb");
934
	if (output_file == NULL) goto error;
Ghislain MARY's avatar
Ghislain MARY committed
935 936 937
	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);
938
	input_file = fopen(input_filename, "rb");
939 940
	if (input_file == NULL) goto error;
	ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
941
	if (ret <= 0) goto error;
942
	fclose(input_file);
943
	ms_free(input_filename);
Ghislain MARY's avatar
Ghislain MARY committed
944 945 946
	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);
947
	input_file = fopen(input_filename, "rb");
948 949
	if (input_file != NULL) {
		ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
950
		if (ret <= 0) goto error;
951
	}
952

953 954
error:
	if (input_file != NULL) fclose(input_file);
955
	if (output_file != NULL) COMPRESS_CLOSE(output_file);
956 957
	if (input_filename != NULL) ms_free(input_filename);
	if (output_filename != NULL) ms_free(output_filename);
958
	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
959 960 961 962 963
	return ret;
}

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

973
void linphone_core_upload_log_collection(LinphoneCore *core) {
Ghislain MARY's avatar
Ghislain MARY committed
974
	if ((core->log_collection_upload_information == NULL) && (linphone_core_get_log_collection_upload_server_url(core) != NULL) && (liblinphone_log_collection_state != LinphoneLogCollectionDisabled)) {
975 976 977 978 979
		/* 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;
980
		char *name;