linphonecore.c 233 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
#include "quality_reporting.h"
johan's avatar
johan committed
26
#include "lime.h"
27
#include "conference_private.h"
28

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

Yann Diorcet's avatar
Yann Diorcet committed
33
#include <math.h>
34 35
#include <sys/types.h>
#include <sys/stat.h>
36
#include <ortp/telephonyevents.h>
37
#include <mediastreamer2/zrtp.h>
johan's avatar
johan committed
38
#include <mediastreamer2/dtls_srtp.h>
aymeric's avatar
aymeric committed
39
#include "mediastreamer2/mediastream.h"
40
#include "mediastreamer2/msfactory.h"
41
#include "mediastreamer2/mseventqueue.h"
smorlat's avatar
smorlat committed
42
#include "mediastreamer2/msvolume.h"
43
#include "mediastreamer2/msequalizer.h"
44
#include "mediastreamer2/dtmfgen.h"
45
#include "mediastreamer2/msjpegwriter.h"
aymeric's avatar
aymeric committed
46

47
#ifdef INET6
48
#ifndef _WIN32
49
#include <netdb.h>
aymeric's avatar
aymeric committed
50 51 52
#endif
#endif

53
#ifdef HAVE_CONFIG_H
54
#include "config.h"
55
#include "liblinphone_gitversion.h"
56 57
#endif

58 59 60
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
61

62
#ifdef HAVE_ZLIB
Ghislain MARY's avatar
Ghislain MARY committed
63
#define COMPRESSED_LOG_COLLECTION_EXTENSION "gz"
64
#ifdef _WIN32
65 66
#include <fcntl.h>
#include <io.h>
67
#ifndef fileno
68
#define fileno _fileno
69
#endif
70
#define unlink _unlink
71 72 73 74 75
#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
#define SET_BINARY_MODE(file)
#endif
#include <zlib.h>
76
#else
Ghislain MARY's avatar
Ghislain MARY committed
77
#define COMPRESSED_LOG_COLLECTION_EXTENSION "txt"
78
#endif
Ghislain MARY's avatar
Ghislain MARY committed
79 80 81 82
#define LOG_COLLECTION_DEFAULT_PATH "."
#define LOG_COLLECTION_DEFAULT_PREFIX "linphone"
#define LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE (10 * 1024 * 1024)

83

smorlat's avatar
smorlat committed
84
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
85

86 87 88 89 90 91 92
static const char *liblinphone_version=
#ifdef LIBLINPHONE_GIT_VERSION
	LIBLINPHONE_GIT_VERSION
#else
	LIBLINPHONE_VERSION
#endif
;
93
static OrtpLogFunc liblinphone_log_func = NULL;
Ghislain MARY's avatar
Ghislain MARY committed
94
static LinphoneLogCollectionState liblinphone_log_collection_state = LinphoneLogCollectionDisabled;
95
static char * liblinphone_log_collection_path = NULL;
Ghislain MARY's avatar
Ghislain MARY committed
96
static char * liblinphone_log_collection_prefix = NULL;
97
static size_t liblinphone_log_collection_max_file_size = LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE;
98
static ortp_mutex_t liblinphone_log_collection_mutex;
99 100
static FILE * liblinphone_log_collection_file = NULL;
static size_t liblinphone_log_collection_file_size = 0;
101
static bool_t liblinphone_serialize_logs = FALSE;
102
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
103 104
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
105
static void linphone_core_run_hooks(LinphoneCore *lc);
106
static void linphone_core_uninit(LinphoneCore *lc);
aymeric's avatar
aymeric committed
107 108

#include "enum.h"
109
#include "contact_providers_priv.h"
110

111

112
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
aymeric's avatar
aymeric committed
113 114
static void toggle_video_preview(LinphoneCore *lc, bool_t val);

115

aymeric's avatar
aymeric committed
116
/* relative path where is stored local ring*/
117 118
#define LOCAL_RING_WAV "oldphone-mono.wav"
#define LOCAL_RING_MKV "notes_of_the_optimistic.mkv"
aymeric's avatar
aymeric committed
119
/* same for remote ring (ringback)*/
120
#define REMOTE_RING_WAV "ringback.wav"
121

122 123
#define HOLD_MUSIC_WAV "toy-mono.wav"
#define HOLD_MUSIC_MKV "dont_wait_too_long.mkv"
aymeric's avatar
aymeric committed
124

Simon Morlat's avatar
Simon Morlat committed
125
extern SalCallbacks linphone_sal_callbacks;
aymeric's avatar
aymeric committed
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

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
168
void *linphone_core_cbs_get_user_data(const LinphoneCoreCbs *cbs) {
169 170 171 172 173 174 175
	return cbs->vtable->user_data;
}

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

176 177 178 179
LinphoneCoreCbsGlobalStateChangedCb linphone_core_cbs_get_global_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->global_state_changed;
}

180
void linphone_core_cbs_set_global_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsGlobalStateChangedCb cb) {
181 182 183
	cbs->vtable->global_state_changed = cb;
}

184 185 186 187
LinphoneCoreCbsRegistrationStateChangedCb linphone_core_cbs_get_registration_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->registration_state_changed;
}

188 189 190 191
void linphone_core_cbs_set_registration_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsRegistrationStateChangedCb cb) {
	cbs->vtable->registration_state_changed = cb;
}

192 193 194 195
LinphoneCoreCbsCallStateChangedCb linphone_core_cbs_get_call_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_state_changed;
}

196 197 198 199
void linphone_core_cbs_set_call_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStateChangedCb cb) {
	cbs->vtable->call_state_changed = cb;
}

200 201 202 203
LinphoneCoreCbsNotifyPresenceReceivedCb linphone_core_cbs_get_notify_presence_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_presence_received;
}

204 205 206 207
void linphone_core_cbs_set_notify_presence_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedCb cb) {
	cbs->vtable->notify_presence_received = cb;
}

208 209 210 211
LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb linphone_core_cbs_get_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_presence_received_for_uri_or_tel;
}

212 213 214 215
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;
}

216 217 218 219
LinphoneCoreCbsNewSubscriptionRequestedCb linphone_core_cbs_get_new_subscription_requested(LinphoneCoreCbs *cbs) {
	return cbs->vtable->new_subscription_requested;
}

220 221 222 223
void linphone_core_cbs_set_new_subscription_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsNewSubscriptionRequestedCb cb) {
	cbs->vtable->new_subscription_requested = cb;
}

224 225 226 227
LinphoneCoreCbsAuthenticationRequestedCb linphone_core_cbs_get_authentication_requested(LinphoneCoreCbs *cbs) {
	return cbs->vtable->authentication_requested;
}

228 229 230 231
void linphone_core_cbs_set_authentication_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsAuthenticationRequestedCb cb) {
	cbs->vtable->authentication_requested = cb;
}

232 233 234 235
LinphoneCoreCbsCallLogUpdatedCb linphone_core_cbs_get_call_log_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_log_updated;
}

236 237 238 239
void linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallLogUpdatedCb cb) {
	cbs->vtable->call_log_updated = cb;
}

240 241 242 243
LinphoneCoreCbsMessageReceivedCb linphone_core_cbs_get_message_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->message_received;
}

244 245 246 247
void linphone_core_cbs_set_message_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedCb cb) {
	cbs->vtable->message_received = cb;
}

248 249 250 251
LinphoneCoreCbsMessageReceivedUnableDecryptCb linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs *cbs) {
	return cbs->vtable->message_received_unable_decrypt;
}

252 253 254 255
void linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedUnableDecryptCb cb) {
	cbs->vtable->message_received_unable_decrypt = cb;
}

256 257 258 259
LinphoneCoreCbsIsComposingReceivedCb linphone_core_cbs_get_is_composing_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->is_composing_received;
}

260 261 262 263
void linphone_core_cbs_set_is_composing_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsIsComposingReceivedCb cb) {
	cbs->vtable->is_composing_received = cb;
}

264 265 266 267
LinphoneCoreCbsDtmfReceivedCb linphone_core_cbs_get_dtmf_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->dtmf_received;
}

268 269 270 271
void linphone_core_cbs_set_dtmf_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsDtmfReceivedCb cb) {
	cbs->vtable->dtmf_received = cb;
}

272 273 274 275
LinphoneCoreCbsReferReceivedCb linphone_core_cbs_get_refer_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->refer_received;
}

276 277 278 279
void linphone_core_cbs_set_refer_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsReferReceivedCb cb) {
	cbs->vtable->refer_received = cb;
}

280 281 282 283
LinphoneCoreCbsCallEncryptionChangedCb linphone_core_cbs_get_call_encryption_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_encryption_changed;
}

284 285 286 287
void linphone_core_cbs_set_call_encryption_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallEncryptionChangedCb cb) {
	cbs->vtable->call_encryption_changed = cb;
}

288 289 290 291
LinphoneCoreCbsTransferStateChangedCb linphone_core_cbs_get_transfer_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->transfer_state_changed;
}

292 293 294 295
void linphone_core_cbs_set_transfer_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsTransferStateChangedCb cb) {
	cbs->vtable->transfer_state_changed = cb;
}

296 297 298 299
LinphoneCoreCbsBuddyInfoUpdatedCb linphone_core_cbs_get_buddy_info_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->buddy_info_updated;
}

300 301 302 303
void linphone_core_cbs_set_buddy_info_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsBuddyInfoUpdatedCb cb) {
	cbs->vtable->buddy_info_updated = cb;
}

304 305 306 307
LinphoneCoreCbsCallStatsUpdatedCb linphone_core_cbs_get_call_stats_updated(LinphoneCoreCbs *cbs) {
	return cbs->vtable->call_stats_updated;
}

308 309 310 311
void linphone_core_cbs_set_call_stats_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStatsUpdatedCb cb) {
	cbs->vtable->call_stats_updated = cb;
}

312 313 314 315
LinphoneCoreCbsInfoReceivedCb linphone_core_cbs_get_info_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->info_received;
}

316 317 318 319
void linphone_core_cbs_set_info_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsInfoReceivedCb cb) {
	cbs->vtable->info_received = cb;
}

320 321 322 323
LinphoneCoreCbsSubscriptionStateChangedCb linphone_core_cbs_get_subscription_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->subscription_state_changed;
}

324 325 326 327
void linphone_core_cbs_set_subscription_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsSubscriptionStateChangedCb cb) {
	cbs->vtable->subscription_state_changed = cb;
}

328 329 330 331
LinphoneCoreCbsNotifyReceivedCb linphone_core_cbs_get_notify_received(LinphoneCoreCbs *cbs) {
	return cbs->vtable->notify_received;
}

332 333 334 335
void linphone_core_cbs_set_notify_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyReceivedCb cb) {
	cbs->vtable->notify_received = cb;
}

336 337 338 339
LinphoneCoreCbsPublishStateChangedCb linphone_core_cbs_get_rpublish_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->publish_state_changed;
}

340 341 342 343
void linphone_core_cbs_set_publish_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsPublishStateChangedCb cb) {
	cbs->vtable->publish_state_changed = cb;
}

344 345 346 347
LinphoneCoreCbsConfiguringStatusCb linphone_core_cbs_get_configuring_status(LinphoneCoreCbs *cbs) {
	return cbs->vtable->configuring_status;
}

348 349 350 351
void linphone_core_cbs_set_configuring_status(LinphoneCoreCbs *cbs, LinphoneCoreCbsConfiguringStatusCb cb) {
	cbs->vtable->configuring_status = cb;
}

352 353 354 355
LinphoneCoreCbsNetworkReachableCb linphone_core_cbs_get_network_reachable(LinphoneCoreCbs *cbs) {
	return cbs->vtable->network_reachable;
}

356 357 358 359
void linphone_core_cbs_set_network_reachable(LinphoneCoreCbs *cbs, LinphoneCoreCbsNetworkReachableCb cb) {
	cbs->vtable->network_reachable = cb;
}

360 361 362 363
LinphoneCoreCbsLogCollectionUploadStateChangedCb linphone_core_cbs_log_collection_upload_state_changed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->log_collection_upload_state_changed;
}

364 365 366 367
void linphone_core_cbs_set_log_collection_upload_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadStateChangedCb cb) {
	cbs->vtable->log_collection_upload_state_changed = cb;
}

368 369 370 371
LinphoneCoreCbsLogCollectionUploadProgressIndicationCb linphone_core_cbs_get_rlog_collection_upload_progress_indication(LinphoneCoreCbs *cbs) {
	return cbs->vtable->log_collection_upload_progress_indication;
}

372 373 374 375
void linphone_core_cbs_set_log_collection_upload_progress_indication(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadProgressIndicationCb cb) {
	cbs->vtable->log_collection_upload_progress_indication = cb;
}

376 377 378 379
LinphoneCoreCbsFriendListCreatedCb linphone_core_cbs_get_friend_list_created(LinphoneCoreCbs *cbs) {
	return cbs->vtable->friend_list_created;
}

380 381 382 383
void linphone_core_cbs_set_friend_list_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListCreatedCb cb) {
	cbs->vtable->friend_list_created = cb;
}

384 385 386 387
LinphoneCoreCbsFriendListRemovedCb linphone_core_cbs_get_friend_list_removed(LinphoneCoreCbs *cbs) {
	return cbs->vtable->friend_list_removed;
}

388 389 390 391 392 393 394 395 396 397 398 399 400
void linphone_core_cbs_set_friend_list_removed(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListRemovedCb cb) {
	cbs->vtable->friend_list_removed = cb;
}

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

401
void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) {
aymeric's avatar
aymeric committed
402 403 404 405 406 407 408 409 410
  obj->_func=func;
  obj->_user_data=ud;
}

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

411 412 413 414 415 416 417 418
bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){
	//return TRUE if the unique(for the moment) incoming call asked to be autoanswered
	if(call)
		return sal_call_autoanswer_asked(call->op);
	else
		return FALSE;
}

419 420
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
421 422
	if (call)  return linphone_call_get_duration(call);
	return -1;
423 424 425 426
}

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
427
	if (call==NULL) return NULL;
428
	return linphone_call_get_remote_address(call);
smorlat's avatar
smorlat committed
429 430
}

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

433
void linphone_core_set_log_handler(OrtpLogFunc logfunc) {
434
	if (ortp_get_log_handler() == linphone_core_log_collection_handler) {
435 436 437 438
		ms_message("There is already a log collection handler, keep it");
		liblinphone_log_func = logfunc;
	} else
		ortp_set_log_handler(logfunc);
439 440 441 442 443 444 445 446
}

void linphone_core_set_log_file(FILE *file) {
	if (file == NULL) file = stdout;
	ortp_set_log_file(file);
}

void linphone_core_set_log_level(OrtpLogLevel loglevel) {
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
	OrtpLogLevel mask = loglevel;
	switch (loglevel) {
		case ORTP_TRACE:
		case ORTP_DEBUG:
			mask |= ORTP_DEBUG;
		case ORTP_MESSAGE:
			mask |= ORTP_MESSAGE;
		case ORTP_WARNING:
			mask |= ORTP_WARNING;
		case ORTP_ERROR:
			mask |= ORTP_ERROR;
		case ORTP_FATAL:
			mask |= ORTP_FATAL;
			break;
		case ORTP_LOGLEV_END:
			break;
	}
	linphone_core_set_log_level_mask(mask);
465 466
}

467
void linphone_core_set_log_level_mask(unsigned int loglevel) {
Simon Morlat's avatar
Simon Morlat committed
468
	ortp_set_log_level_mask(NULL, loglevel);
469
	bctbx_set_log_level_mask(NULL, loglevel);
470
	if (loglevel == 0) {
471
		sal_disable_log();
472
	} else {
473
		sal_enable_log();
474
	}
475 476
}

477 478 479 480 481 482 483 484 485 486 487 488 489
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);
490
	if ((size_t)statbuf.st_size > liblinphone_log_collection_max_file_size) {
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
		fclose(liblinphone_log_collection_file);
		return -1;
	}

	liblinphone_log_collection_file_size = statbuf.st_size;
	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
532
static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args) {
533 534 535
	const char *lname="undef";
	char *msg;
	struct timeval tp;
536
	struct tm *lt;
537
	time_t tt;
538
	int ret;
539

540
	if (liblinphone_log_func != NULL && liblinphone_log_func != linphone_core_log_collection_handler) {
541
#ifndef _WIN32
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
542 543
		va_list args_copy;
		va_copy(args_copy, args);
Simon Morlat's avatar
Simon Morlat committed
544
		liblinphone_log_func(domain, level, fmt, args_copy);
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
545
		va_end(args_copy);
546 547 548
#else
		/* This works on 32 bits, luckily. */
		/* TODO: va_copy is available in Visual Studio 2013. */
Simon Morlat's avatar
Simon Morlat committed
549
		liblinphone_log_func(domain, level, fmt, args);
550
#endif
551 552 553 554 555
	}

	ortp_gettimeofday(&tp, NULL);
	tt = (time_t)tp.tv_sec;
	lt = localtime((const time_t*)&tt);
556 557 558 559 560 561 562 563 564 565 566 567 568

	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 !");
569 570 571
	}
	msg = ortp_strdup_vprintf(fmt, args);

572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
	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) {
			liblinphone_log_collection_file_size += ret;
			if (liblinphone_log_collection_file_size > liblinphone_log_collection_max_file_size) {
				_close_log_collection_file();
				_open_log_collection_file();
			}
588
		}
589
		ortp_mutex_unlock(&liblinphone_log_collection_mutex);
590 591 592 593 594
	}

	ortp_free(msg);
}

Ghislain MARY's avatar
Ghislain MARY committed
595 596 597 598 599 600 601
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;
}

602
void linphone_core_set_log_collection_path(const char *path) {
603 604 605 606 607 608 609
	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);
	}
610 611
}

Ghislain MARY's avatar
Ghislain MARY committed
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
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);
	}
}

629
size_t linphone_core_get_log_collection_max_file_size(void) {
Ghislain MARY's avatar
Ghislain MARY committed
630 631 632
	return liblinphone_log_collection_max_file_size;
}

633
void linphone_core_set_log_collection_max_file_size(size_t size) {
Ghislain MARY's avatar
Ghislain MARY committed
634 635 636
	liblinphone_log_collection_max_file_size = size;
}

637 638 639 640 641 642 643 644
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
645 646 647 648
LinphoneLogCollectionState linphone_core_log_collection_enabled(void) {
	return liblinphone_log_collection_state;
}

649
void linphone_core_enable_log_collection(LinphoneLogCollectionState state) {
650 651
	if (liblinphone_log_collection_state == state) return;

652 653 654
	/* at first call of this function, set liblinphone_log_func to the current
	 * ortp log function */
	if( liblinphone_log_func == NULL ){
655
		liblinphone_log_func = ortp_get_log_handler();
656
	}
Ghislain MARY's avatar
Ghislain MARY committed
657 658
	liblinphone_log_collection_state = state;
	if (state != LinphoneLogCollectionDisabled) {
659
		ortp_mutex_init(&liblinphone_log_collection_mutex, NULL);
660 661 662
		if (state == LinphoneLogCollectionEnabledWithoutPreviousLogHandler) {
			liblinphone_log_func = NULL;
		} else {
663
			liblinphone_log_func = ortp_get_log_handler();
664
		}
665 666 667 668 669 670
		ortp_set_log_handler(linphone_core_log_collection_handler);
	} else {
		ortp_set_log_handler(liblinphone_log_func);
	}
}

jehan's avatar
jehan committed
671
static void clean_log_collection_upload_context(LinphoneCore *lc) {
Ghislain MARY's avatar
Ghislain MARY committed
672 673 674 675
	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);
676
	unlink(filename);
677
	ms_free(filename);
jehan's avatar
jehan committed
678
	if (lc && lc->log_collection_upload_information) {
Ghislain MARY's avatar
Ghislain MARY committed
679
		linphone_content_unref(lc->log_collection_upload_information);
jehan's avatar
jehan committed
680 681
		lc->log_collection_upload_information=NULL;
	}
682 683
}

684 685 686 687
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
688
	clean_log_collection_upload_context(core);
689 690 691 692 693 694
}

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
695
	clean_log_collection_upload_context(core);
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
}

/**
 * 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 */
711
	if (offset < linphone_content_get_size(core->log_collection_upload_information)) {
Ghislain MARY's avatar
Ghislain MARY committed
712 713 714 715
		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);
716 717 718
#ifdef HAVE_ZLIB
		FILE *log_file = fopen(log_filename, "rb");
#else
719
		FILE *log_file = fopen(log_filename, "r");
720
#endif
721
		if (fseek(log_file, (long)offset, SEEK_SET)) {
jehan's avatar
jehan committed
722 723 724 725 726
			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);
		}
727
		fclose(log_file);
728
		ms_free(log_filename);
jehan's avatar
jehan committed
729 730 731 732
		return BELLE_SIP_CONTINUE;
	} else {
		*size=0;
		return BELLE_SIP_STOP;
733 734 735 736 737 738 739 740 741
	}
}

/**
 * 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;
742
	linphone_core_notify_log_collection_upload_progress_indication(core, offset, total);
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
}

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

			/* Create a user body handler to take care of the file and add the content disposition and content-type headers */
776
			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);
777 778
			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);
779 780
			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)));
781 782

			/* Insert it in a multipart body handler which will manage the boundaries of multipart message */
783
			bh = belle_sip_multipart_body_handler_new(log_collection_upload_on_progress, core, (belle_sip_body_handler_t *)first_part_bh, NULL);
784
			ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(core), linphone_core_get_version());
785
			uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
786
			req = belle_http_request_create("POST", uri, belle_sip_header_create("User-Agent", ua), NULL);
787 788 789 790 791 792
			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);
793
			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
794 795 796 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
			belle_http_provider_send_request(core->http_provider, req, l);
		}
		if (code == 200) { /* The file has been uploaded correctly, get the server reply */
			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
827
			clean_log_collection_upload_context(core);
828 829 830 831
		}
	}
}

832
#ifdef HAVE_ZLIB
833 834 835
#define COMPRESS_FILE_PTR gzFile
#define COMPRESS_OPEN gzopen
#define COMPRESS_CLOSE gzclose
836
#else
837 838 839 840
#define COMPRESS_FILE_PTR FILE*
#define COMPRESS_OPEN fopen
#define COMPRESS_CLOSE fclose
#endif
841 842 843 844

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

Simon Morlat's avatar
Simon Morlat committed
850
	while ((bytes = fread(buffer, 1, sizeof(buffer), input_file)) > 0) {
851
#ifdef HAVE_ZLIB
852 853
		int res = gzwrite(output_file, buffer, (unsigned int)bytes);
		if (res < 0) return 0;
Sylvain Berfini's avatar
Sylvain Berfini committed
854
		total_bytes += (size_t)res;
855
#else
Sylvain Berfini's avatar
Sylvain Berfini committed
856
		total_bytes += fwrite(buffer, 1, bytes, output_file);
857
#endif
858
	}
Ghislain MARY's avatar
Ghislain MARY committed
859
	return (int)total_bytes;
860 861
}

862
static int prepare_log_collection_file_to_upload(const char *filename) {
863 864 865
	char *input_filename = NULL;
	char *output_filename = NULL;
	FILE *input_file = NULL;
866 867
	COMPRESS_FILE_PTR output_file = NULL;
	int ret = 0;
868

869
	ortp_mutex_lock(&liblinphone_log_collection_mutex);
Ghislain MARY's avatar
Ghislain MARY committed
870 871
	output_filename = ms_strdup_printf("%s/%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
872
	output_file = COMPRESS_OPEN(output_filename, "wb");
873
	if (output_file == NULL) goto error;
Ghislain MARY's avatar
Ghislain MARY committed
874 875 876
	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);
877
	input_file = fopen(input_filename, "rb");
878 879
	if (input_file == NULL) goto error;
	ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
880
	if (ret <= 0) goto error;
881
	fclose(input_file);
882
	ms_free(input_filename);
Ghislain MARY's avatar
Ghislain MARY committed
883 884 885
	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);
886
	input_file = fopen(input_filename, "rb");
887 888
	if (input_file != NULL) {
		ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
889
		if (ret <= 0) goto error;
890
	}
891

892 893
error:
	if (input_file != NULL) fclose(input_file);
894
	if (output_file != NULL) COMPRESS_CLOSE(output_file);
895 896
	if (input_filename != NULL) ms_free(input_filename);
	if (output_filename != NULL) ms_free(output_filename);
897
	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
898 899 900 901 902
	return ret;
}

static size_t get_size_of_file_to_upload(const char *filename) {
	struct stat statbuf;
Ghislain MARY's avatar
Ghislain MARY committed
903 904
	char *output_filename = ms_strdup_printf("%s/%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
905 906 907
	FILE *output_file = fopen(output_filename, "rb");
	fstat(fileno(output_file), &statbuf);
	fclose(output_file);
908
	ms_free(output_filename);
909
	return statbuf.st_size;
910 911
}

912
void linphone_core_upload_log_collection(LinphoneCore *core) {
Ghislain MARY's avatar
Ghislain MARY committed
913
	if ((core->log_collection_upload_information == NULL) && (linphone_core_get_log_collection_upload_server_url(core) != NULL) && (liblinphone_log_collection_state != LinphoneLogCollectionDisabled)) {
914 915 916 917 918
		/* 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;
919
		char *name;
920

Ghislain MARY's avatar
Ghislain MARY committed
921
		core->log_collection_upload_information = linphone_core_create_content(core);
922
#ifdef HAVE_ZLIB
923 924
		linphone_content_set_type(core->log_collection_upload_information, "application");
		linphone_content_set_subtype(core->log_collection_upload_information, "gzip");
925
#else
926 927
		linphone_content_set_type(core->log_collection_upload_information, "text");
		linphone_content_set_subtype(core->log_collection_upload_information,"plain");
928
#endif
929
		name = ms_strdup_printf("%s_log.%s",
Ghislain MARY's avatar
Ghislain MARY committed
930 931
			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
			COMPRESSED_LOG_COLLECTION_EXTENSION);
932
		linphone_content_set_name(core->log_collection_upload_information, name);
Sylvain Berfini's avatar
Sylvain Berfini committed
933
		if (prepare_log_collection_file_to_upload(name) <= 0) {
934
			linphone_content_unref(core->log_collection_upload_information);
Sylvain Berfini's avatar
Sylvain Berfini committed
935
			core->log_collection_upload_information = NULL;
936 937
			ms_error("prepare_log_collection_file_to_upload(): error.");
			return;
Sylvain Berfini's avatar
Sylvain Berfini committed
938
		}
939
		linphone_content_set_size(core->log_collection_upload_information, get_size_of_file_to_upload(name));
940 941 942 943 944 945
		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);
946
		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
947
		belle_http_provider_send_request(core->http_provider, req, l);
948
		ms_free(name);
949 950 951
	} else {
		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);
952 953 954
	}
}

955
char * linphone_core_compress_log_collection(void) {
Ghislain MARY's avatar
Ghislain MARY committed
956 957 958 959 960
	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);
961
	if (prepare_log_collection_file_to_upload(filename) <= 0) {
Ghislain MARY's avatar
Ghislain MARY committed
962 963 964 965 966 967 968 969
		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);
970 971
}

972
void linphone_core_reset_log_collection(void) {
973 974
	char *filename;
	ortp_mutex_lock(&liblinphone_log_collection_mutex);
975
	_close_log_collection_file();
jehan's avatar
jehan committed
976
	clean_log_collection_upload_context(NULL);
Ghislain MARY's avatar
Ghislain MARY committed
977 978 979
	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);
980 981
	unlink(filename);
	ms_free(filename);
Ghislain MARY's avatar
Ghislain MARY committed
982 983 984
	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);
985 986
	unlink(filename);
	ms_free(filename);
987 988
	liblinphone_log_collection_file = NULL;
	liblinphone_log_collection_file_size = 0;
989 990 991
	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
}

aymeric's avatar
aymeric committed
992