linphonecore.c 253 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 18 19 20 21

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
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "linphonecore.h"
smorlat's avatar
smorlat committed
22
#include "sipsetup.h"
aymeric's avatar
aymeric committed
23 24
#include "lpconfig.h"
#include "private.h"
25
#include "quality_reporting.h"
johan's avatar
johan committed
26
#include "lime.h"
27
#include "conference_private.h"
28

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

42
#ifdef INET6
43
#ifndef _WIN32
44
#include <netdb.h>
aymeric's avatar
aymeric committed
45 46 47
#endif
#endif

48
#ifdef HAVE_CONFIG_H
49
#include "config.h"
50 51 52
#ifndef ANDROID /*on Android LIBLINPHONE version is passed from root Makefile*/
	#include "liblinphone_gitversion.h"
#endif
Ghislain MARY's avatar
Ghislain MARY committed
53 54 55
#else
#ifndef LIBLINPHONE_GIT_VERSION
#define LIBLINPHONE_GIT_VERSION "unknown"
56 57 58
#endif
#endif

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

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

84

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

87 88
#define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem"

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

#include "enum.h"
111
#include "contact_providers_priv.h"
112

113

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

117
#if defined(LINPHONE_WINDOWS_PHONE) || defined(LINPHONE_WINDOWS_UNIVERSAL)
118
#define SOUNDS_PREFIX "Assets/Sounds/"
119 120
#else
#define SOUNDS_PREFIX
121
#endif
aymeric's avatar
aymeric committed
122
/* relative path where is stored local ring*/
123 124
#define LOCAL_RING SOUNDS_PREFIX "rings/oldphone-mono.wav"
#define LOCAL_RING_MKV SOUNDS_PREFIX "rings/notes_of_the_optimistic.mkv"
aymeric's avatar
aymeric committed
125
/* same for remote ring (ringback)*/
126
#define REMOTE_RING SOUNDS_PREFIX "ringback.wav"
127

128 129
#define HOLD_MUSIC SOUNDS_PREFIX "toy-mono.wav"
#define HOLD_MUSIC_MKV SOUNDS_PREFIX "dont_wait_too_long.mkv"
aymeric's avatar
aymeric committed
130

Simon Morlat's avatar
Simon Morlat committed
131
extern SalCallbacks linphone_sal_callbacks;
aymeric's avatar
aymeric committed
132 133 134 135 136 137 138 139 140 141 142 143

void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud)
{
  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;
}

144

145 146 147 148 149 150 151 152 153 154 155 156
/**
 * Returns TRUE if the LinphoneCall asked to autoanswer
 *
**/
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;
}

157 158
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
159 160
	if (call)  return linphone_call_get_duration(call);
	return -1;
161 162 163 164
}

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
165
	if (call==NULL) return NULL;
166
	return linphone_call_get_remote_address(call);
smorlat's avatar
smorlat committed
167 168
}

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

171
void linphone_core_set_log_handler(OrtpLogFunc logfunc) {
172 173 174 175 176
	if (ortp_logv_out == linphone_core_log_collection_handler) {
		ms_message("There is already a log collection handler, keep it");
		liblinphone_log_func = logfunc;
	} else
		ortp_set_log_handler(logfunc);
177 178 179 180 181 182 183 184
}

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) {
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	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);
203 204 205
}

void linphone_core_set_log_level_mask(OrtpLogLevel loglevel) {
Simon Morlat's avatar
Simon Morlat committed
206
	ortp_set_log_level_mask(NULL, loglevel);
207
	if (loglevel == 0) {
208
		sal_disable_log();
209
	} else {
210
		sal_enable_log();
211
	}
212 213
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
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);
	if (statbuf.st_size > liblinphone_log_collection_max_file_size) {
		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
269
static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args) {
270 271 272
	const char *lname="undef";
	char *msg;
	struct timeval tp;
273
	struct tm *lt;
274
	time_t tt;
275
	int ret;
276 277

	if (liblinphone_log_func != NULL) {
278
#ifndef _WIN32
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
279 280
		va_list args_copy;
		va_copy(args_copy, args);
Simon Morlat's avatar
Simon Morlat committed
281
		liblinphone_log_func(domain, level, fmt, args_copy);
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
282
		va_end(args_copy);
283 284 285
#else
		/* This works on 32 bits, luckily. */
		/* TODO: va_copy is available in Visual Studio 2013. */
Simon Morlat's avatar
Simon Morlat committed
286
		liblinphone_log_func(domain, level, fmt, args);
287
#endif
288 289 290 291 292
	}

	ortp_gettimeofday(&tp, NULL);
	tt = (time_t)tp.tv_sec;
	lt = localtime((const time_t*)&tt);
293 294 295 296 297 298 299 300 301 302 303 304 305

	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 !");
306 307 308
	}
	msg = ortp_strdup_vprintf(fmt, args);

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
	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();
			}
325
		}
326
		ortp_mutex_unlock(&liblinphone_log_collection_mutex);
327 328 329 330 331
	}

	ortp_free(msg);
}

Ghislain MARY's avatar
Ghislain MARY committed
332 333 334 335 336 337 338
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;
}

339
void linphone_core_set_log_collection_path(const char *path) {
340 341 342 343 344 345 346
	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);
	}
347 348
}

Ghislain MARY's avatar
Ghislain MARY committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
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);
	}
}

int linphone_core_get_log_collection_max_file_size(void) {
	return liblinphone_log_collection_max_file_size;
}

void linphone_core_set_log_collection_max_file_size(int size) {
	liblinphone_log_collection_max_file_size = size;
}

374 375 376 377 378 379 380 381
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
382 383 384 385
LinphoneLogCollectionState linphone_core_log_collection_enabled(void) {
	return liblinphone_log_collection_state;
}

386
void linphone_core_enable_log_collection(LinphoneLogCollectionState state) {
387 388
	if (liblinphone_log_collection_state == state) return;

389 390 391 392 393
	/* at first call of this function, set liblinphone_log_func to the current
	 * ortp log function */
	if( liblinphone_log_func == NULL ){
		liblinphone_log_func = ortp_logv_out;
	}
Ghislain MARY's avatar
Ghislain MARY committed
394 395
	liblinphone_log_collection_state = state;
	if (state != LinphoneLogCollectionDisabled) {
396
		ortp_mutex_init(&liblinphone_log_collection_mutex, NULL);
397 398 399 400 401
		if (state == LinphoneLogCollectionEnabledWithoutPreviousLogHandler) {
			liblinphone_log_func = NULL;
		} else {
			liblinphone_log_func = ortp_logv_out;
		}
402 403 404 405 406 407
		ortp_set_log_handler(linphone_core_log_collection_handler);
	} else {
		ortp_set_log_handler(liblinphone_log_func);
	}
}

jehan's avatar
jehan committed
408
static void clean_log_collection_upload_context(LinphoneCore *lc) {
Ghislain MARY's avatar
Ghislain MARY committed
409 410 411 412
	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);
413
	unlink(filename);
414
	ms_free(filename);
jehan's avatar
jehan committed
415
	if (lc && lc->log_collection_upload_information) {
Ghislain MARY's avatar
Ghislain MARY committed
416
		linphone_content_unref(lc->log_collection_upload_information);
jehan's avatar
jehan committed
417 418
		lc->log_collection_upload_information=NULL;
	}
419 420
}

421 422 423 424
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
425
	clean_log_collection_upload_context(core);
426 427 428 429 430 431
}

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
432
	clean_log_collection_upload_context(core);
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
}

/**
 * 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 */
450
	if (offset < linphone_content_get_size(core->log_collection_upload_information)) {
Ghislain MARY's avatar
Ghislain MARY committed
451 452 453 454
		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);
455 456 457
#ifdef HAVE_ZLIB
		FILE *log_file = fopen(log_filename, "rb");
#else
458
		FILE *log_file = fopen(log_filename, "r");
459
#endif
460
		if (fseek(log_file, (long)offset, SEEK_SET)) {
jehan's avatar
jehan committed
461 462 463 464 465
			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);
		}
466
		fclose(log_file);
467
		ms_free(log_filename);
jehan's avatar
jehan committed
468 469 470 471
		return BELLE_SIP_CONTINUE;
	} else {
		*size=0;
		return BELLE_SIP_STOP;
472 473
	}

jehan's avatar
jehan committed
474

475 476 477 478 479 480 481 482
}

/**
 * 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;
483
	linphone_core_notify_log_collection_upload_progress_indication(core, offset, total);
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
}

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

			/* Create a user body handler to take care of the file and add the content disposition and content-type headers */
517
			first_part_bh = belle_sip_user_body_handler_new(linphone_content_get_size(core->log_collection_upload_information), NULL, NULL, log_collection_upload_on_send_body, core);
518 519
			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);
520 521
			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)));
522 523

			/* Insert it in a multipart body handler which will manage the boundaries of multipart message */
524
			bh = belle_sip_multipart_body_handler_new(log_collection_upload_on_progress, core, (belle_sip_body_handler_t *)first_part_bh, NULL);
525
			ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(core), linphone_core_get_version());
526
			uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
527
			req = belle_http_request_create("POST", uri, belle_sip_header_create("User-Agent", ua), NULL);
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
			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);
			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
567
			clean_log_collection_upload_context(core);
568 569 570 571
		}
	}
}

572
#ifdef HAVE_ZLIB
573 574 575
#define COMPRESS_FILE_PTR gzFile
#define COMPRESS_OPEN gzopen
#define COMPRESS_CLOSE gzclose
576
#else
577 578 579 580
#define COMPRESS_FILE_PTR FILE*
#define COMPRESS_OPEN fopen
#define COMPRESS_CLOSE fclose
#endif
581 582 583 584

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

Simon Morlat's avatar
Simon Morlat committed
590
	while ((bytes = fread(buffer, 1, sizeof(buffer), input_file)) > 0) {
591
#ifdef HAVE_ZLIB
592 593
		int res = gzwrite(output_file, buffer, (unsigned int)bytes);
		if (res < 0) return 0;
Sylvain Berfini's avatar
Sylvain Berfini committed
594
		total_bytes += (size_t)res;
595
#else
Sylvain Berfini's avatar
Sylvain Berfini committed
596
		total_bytes += fwrite(buffer, 1, bytes, output_file);
597
#endif
598
	}
Sylvain Berfini's avatar
Sylvain Berfini committed
599
	return total_bytes;
600 601
}

602
static int prepare_log_collection_file_to_upload(const char *filename) {
603 604 605
	char *input_filename = NULL;
	char *output_filename = NULL;
	FILE *input_file = NULL;
606 607
	COMPRESS_FILE_PTR output_file = NULL;
	int ret = 0;
608

609
	ortp_mutex_lock(&liblinphone_log_collection_mutex);
Ghislain MARY's avatar
Ghislain MARY committed
610 611
	output_filename = ms_strdup_printf("%s/%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
612
	output_file = COMPRESS_OPEN(output_filename, "w");
613
	if (output_file == NULL) goto error;
Ghislain MARY's avatar
Ghislain MARY committed
614 615 616
	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);
617 618 619
	input_file = fopen(input_filename, "r");
	if (input_file == NULL) goto error;
	ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
620
	if (ret <= 0) goto error;
621
	fclose(input_file);
622
	ms_free(input_filename);
Ghislain MARY's avatar
Ghislain MARY committed
623 624 625
	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);
626 627 628
	input_file = fopen(input_filename, "r");
	if (input_file != NULL) {
		ret = compress_file(input_file, output_file);
Sylvain Berfini's avatar
Sylvain Berfini committed
629
		if (ret <= 0) goto error;
630
	}
631

632 633
error:
	if (input_file != NULL) fclose(input_file);
634
	if (output_file != NULL) COMPRESS_CLOSE(output_file);
635 636
	if (input_filename != NULL) ms_free(input_filename);
	if (output_filename != NULL) ms_free(output_filename);
637
	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
638 639 640 641 642
	return ret;
}

static size_t get_size_of_file_to_upload(const char *filename) {
	struct stat statbuf;
Ghislain MARY's avatar
Ghislain MARY committed
643 644
	char *output_filename = ms_strdup_printf("%s/%s",
		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
645 646 647
	FILE *output_file = fopen(output_filename, "rb");
	fstat(fileno(output_file), &statbuf);
	fclose(output_file);
648
	ms_free(output_filename);
649
	return statbuf.st_size;
650 651
}

652
void linphone_core_upload_log_collection(LinphoneCore *core) {
Ghislain MARY's avatar
Ghislain MARY committed
653
	if ((core->log_collection_upload_information == NULL) && (linphone_core_get_log_collection_upload_server_url(core) != NULL) && (liblinphone_log_collection_state != LinphoneLogCollectionDisabled)) {
654 655 656 657 658
		/* 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;
659
		char *name;
660

Ghislain MARY's avatar
Ghislain MARY committed
661
		core->log_collection_upload_information = linphone_core_create_content(core);
662
#ifdef HAVE_ZLIB
663 664
		linphone_content_set_type(core->log_collection_upload_information, "application");
		linphone_content_set_subtype(core->log_collection_upload_information, "gzip");
665
#else
666 667
		linphone_content_set_type(core->log_collection_upload_information, "text");
		linphone_content_set_subtype(core->log_collection_upload_information,"plain");
668
#endif
669
		name = ms_strdup_printf("%s_log.%s",
Ghislain MARY's avatar
Ghislain MARY committed
670 671
			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
			COMPRESSED_LOG_COLLECTION_EXTENSION);
672
		linphone_content_set_name(core->log_collection_upload_information, name);
Sylvain Berfini's avatar
Sylvain Berfini committed
673
		if (prepare_log_collection_file_to_upload(name) <= 0) {
Ghislain MARY's avatar
Ghislain MARY committed
674
		    linphone_content_unref(core->log_collection_upload_information);
Sylvain Berfini's avatar
Sylvain Berfini committed
675 676 677
			core->log_collection_upload_information = NULL;
		    return;
		}
678
		linphone_content_set_size(core->log_collection_upload_information, get_size_of_file_to_upload(name));
679 680 681 682 683 684 685
		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);
		belle_http_provider_send_request(core->http_provider, req, l);
686
		ms_free(name);
687 688 689
	}
}

690
char * linphone_core_compress_log_collection(void) {
Ghislain MARY's avatar
Ghislain MARY committed
691 692 693 694 695
	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);
696
	if (prepare_log_collection_file_to_upload(filename) <= 0) {
Ghislain MARY's avatar
Ghislain MARY committed
697 698 699 700 701 702 703 704
		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);
705 706
}

707
void linphone_core_reset_log_collection(void) {
708 709
	char *filename;
	ortp_mutex_lock(&liblinphone_log_collection_mutex);
jehan's avatar
jehan committed
710
	clean_log_collection_upload_context(NULL);
Ghislain MARY's avatar
Ghislain MARY committed
711 712 713
	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);
714 715
	unlink(filename);
	ms_free(filename);
Ghislain MARY's avatar
Ghislain MARY committed
716 717 718
	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);
719 720
	unlink(filename);
	ms_free(filename);
721 722
	liblinphone_log_collection_file = NULL;
	liblinphone_log_collection_file_size = 0;
723 724 725
	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
}

aymeric's avatar
aymeric committed
726 727 728
void linphone_core_enable_logs(FILE *file){
	if (file==NULL) file=stdout;
	ortp_set_log_file(file);
729
	linphone_core_set_log_level(ORTP_MESSAGE);
aymeric's avatar
aymeric committed
730 731 732
}

void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){
733
	linphone_core_set_log_level(ORTP_MESSAGE);
734
	linphone_core_set_log_handler(logfunc);
aymeric's avatar
aymeric committed
735 736
}

737
void linphone_core_disable_logs(void){
738
	linphone_core_set_log_level(ORTP_ERROR);
aymeric's avatar
aymeric committed
739 740
}

741 742 743 744
void linphone_core_serialize_logs(void) {
	liblinphone_serialize_logs = TRUE;
}

aymeric's avatar
aymeric committed
745

746
static void net_config_read (LinphoneCore *lc)
aymeric's avatar
aymeric committed
747 748 749 750 751
{
	int tmp;
	const char *tmpstr;
	LpConfig *config=lc->config;

752
	lc->net_conf.nat_address_ip = NULL;
aymeric's avatar
aymeric committed
753 754 755 756 757 758 759 760 761 762
	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);
	linphone_core_set_stun_server(lc,lp_config_get_string(config,"net","stun_server",NULL));
	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);
	lc->net_conf.nat_sdp_only=tmp;
763
	tmp=lp_config_get_int(lc->config,"net","mtu",1300);
aymeric's avatar
aymeric committed
764
	linphone_core_set_mtu(lc,tmp);
765 766 767 768 769
	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);
	}
770 771
	tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1);
	linphone_core_enable_dns_srv(lc, tmp);
772 773 774

	/* This is to filter out unsupported firewall policies */
	linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc));
aymeric's avatar
aymeric committed
775 776
}

777 778 779 780 781
static void build_sound_devices_table(LinphoneCore *lc){
	const char **devices;
	const char **old;
	int ndev;
	int i;
782
	const MSList *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(lc->factory));
783 784 785 786 787 788 789 790 791 792
	ndev=ms_list_size(elem);
	devices=ms_malloc((ndev+1)*sizeof(const char *));
	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;
	if (old!=NULL) ms_free(old);
}
aymeric's avatar
aymeric committed
793

794 795 796 797 798 799 800 801 802 803 804 805 806 807
static const char *get_default_local_ring(LinphoneCore * lc){
	if (linphone_core_file_format_supported(lc, "mkv")){
		return PACKAGE_SOUND_DIR "/" LOCAL_RING_MKV;
	}
	return PACKAGE_SOUND_DIR "/" LOCAL_RING;
}

static const char *get_default_onhold_music(LinphoneCore * lc){
	if (linphone_core_file_format_supported(lc, "mkv")){
		return PACKAGE_SOUND_DIR "/" HOLD_MUSIC_MKV;
	}
	return PACKAGE_SOUND_DIR "/" HOLD_MUSIC;
}

808
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
809
{
810
	int tmp;
aymeric's avatar
aymeric committed
811 812
	const char *tmpbuf;
	const char *devid;
813
#ifdef __linux
aymeric's avatar
aymeric committed
814 815 816
	/*alsadev let the user use custom alsa device within linphone*/
	devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
	if (devid){
817 818 819 820 821 822 823 824 825 826
		MSSndCard* card;
		const char* delim=",";
		size_t l=strlen(devid);
		char* d=malloc(l+1);
		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);
827
			ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
828 829 830 831 832
			*i=s;
			l=i-d+1;
		}
		if(d[l]!='\0') {
			card=ms_alsa_card_new_custom(d+l,d+l);
833
			ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
834 835
		}
		free(d);
aymeric's avatar
aymeric committed
836
	}
Simon Morlat's avatar
Simon Morlat committed
837
	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
838
	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
aymeric's avatar
aymeric committed
839 840
#endif
	/* retrieve all sound devices */
841 842
	build_sound_devices_table(lc);

aymeric's avatar
aymeric committed
843 844
	devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
	linphone_core_set_playback_device(lc,devid);
845

aymeric's avatar
aymeric committed
846 847
	devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
	linphone_core_set_ringer_device(lc,devid);
848

aymeric's avatar
aymeric committed
849 850
	devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
	linphone_core_set_capture_device(lc,devid);
851

aymeric's avatar
aymeric committed
852 853 854 855 856 857 858 859 860 861
/*
	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]);
*/
862

863
	tmpbuf = get_default_local_ring(lc);
aymeric's avatar
aymeric committed
864
	tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
865
	if (ortp_file_exist(tmpbuf)==-1) {
866
		ms_warning("%s does not exist",tmpbuf);
867
		tmpbuf = get_default_local_ring(lc);
aymeric's avatar
aymeric committed
868 869
	}
	linphone_core_set_ring(lc,tmpbuf);
870

871
	tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
872
	tmpbuf=lp_config_get_string(lc->config,"sound","remote_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
873
	if (ortp_file_exist(tmpbuf)==-1){
874
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
875 876 877
	}
	if (strstr(tmpbuf,".wav")==NULL){
		/* it currently uses old sound files, so replace them */
878
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
879
	}
880
	linphone_core_set_ringback(lc,tmpbuf);
881

882
	linphone_core_set_play_file(lc,lp_config_get_string(lc->config,"sound","hold_music", get_default_onhold_music(lc)));
aymeric's avatar
aymeric committed
883
	lc->sound_conf.latency=0;
884
#ifndef __ios
Simon Morlat's avatar
Simon Morlat committed
885
	tmp=TRUE;
886
#else
Simon Morlat's avatar
Simon Morlat committed
887
	tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
888
#endif
Simon Morlat's avatar
Simon Morlat committed
889
	tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp);
890
	linphone_core_enable_echo_cancellation(lc,tmp);
smorlat's avatar
smorlat committed
891 892
	linphone_core_enable_echo_limiter(lc,
		lp_config_get_int(lc->config,"sound","echolimiter",0));
893 894
	linphone_core_enable_agc(lc,
		lp_config_get_int(lc->config,"sound","agc",0));
895

Yann Diorcet's avatar
Yann Diorcet committed
896 897
	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));
898 899

	linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
900 901 902

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

904
	_linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL);
aymeric's avatar
aymeric committed
905 906
}

907 908
static void certificates_config_read(LinphoneCore *lc)
{
909
	const char *rootca;
910
#ifdef __linux
911
	struct stat sb;
912
	rootca=lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs");
913 914 915 916 917
	if (stat("/etc/ssl/certs", &sb) != 0 || !S_ISDIR(sb.st_mode))
	{
		ms_warning("/etc/ssl/certs not found, using %s instead", ROOT_CA_FILE);
		rootca=lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE);
	}
918
#else
919
	rootca=lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE);
920
#endif
921
	linphone_core_set_root_ca(lc,rootca);
922
	linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE));
923
	linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE));
924 925
}

926
static void sip_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
927 928 929
{
	char *contact;
	const char *tmpstr;
930
	LCSipTransports tr;
aymeric's avatar
aymeric committed
931 932
	int i,tmp;
	int ipv6;
933 934 935 936

	if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
		sal_use_session_timers(lc->sal,200);
	}
aymeric's avatar
aymeric committed
937

938
	sal_use_no_initial_route(lc->sal,lp_config_get_int(lc->config,"sip","use_no_initial_route",0