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"
26
#include "lime.h"
27
#include "conference_private.h"
28

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
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
78
#define COMPRESSED_LOG_COLLECTION_EXTENSION "txt"
79
#endif
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;
97
static LinphoneLogCollectionState liblinphone_log_collection_state = LinphoneLogCollectionDisabled;
98
static char * liblinphone_log_collection_path = NULL;
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
}

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

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);
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. */
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);
}

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
}

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

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

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

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",
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) {
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) {
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) {
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);
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);
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
	}
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

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));
939 940
	sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));

aymeric's avatar
aymeric committed
941 942 943 944 945
	ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
	if (ipv6==-1){
		ipv6=0;
	}
	linphone_core_enable_ipv6(lc,ipv6);
946
	memset(&tr,0,sizeof(tr));
947

948 949 950 951
	tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060);
	tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060);
	/*we are not listening inbound connection for tls, port has no meaning*/
	tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM);
952

953
	certificates_config_read(lc);
954 955
	/*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/
	sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
956
	/*start listening on ports*/
957
	linphone_core_set_sip_transports(lc,&tr);
958

aymeric's avatar
aymeric committed
959 960
	tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL);
	if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) {
smorlat's avatar
smorlat committed
961 962
		const char *hostname=NULL;
		const char *username=NULL;
963
#ifdef HAVE_GETENV
smorlat's avatar
smorlat committed
964 965
		hostname=getenv("HOST");
		username=getenv("USER");
aymeric's avatar
aymeric committed
966
		if (hostname==NULL) hostname=getenv("HOSTNAME");
967
#endif /*HAVE_GETENV*/
aymeric's avatar
aymeric committed
968 969 970
		if (hostname==NULL)
			hostname="unknown-host";
		if (username==NULL){
971
			username="linphone";
aymeric's avatar
aymeric committed
972 973 974 975 976 977 978 979
		}
		contact=ortp_strdup_printf("sip:%s@%s",username,hostname);
		linphone_core_set_primary_contact(lc,contact);
		ms_free(contact);
	}

	tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1);
	linphone_core_set_guess_hostname(lc,tmp);
980

Simon Morlat's avatar
Simon Morlat committed
981 982
	tmp=lp_config_get_int(lc->config,"sip","lime",FALSE);
	linphone_core_enable_lime(lc,tmp);
983

984
	tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30);
aymeric's avatar
aymeric committed
985 986
	linphone_core_set_inc_timeout(lc,tmp);

Yann Diorcet's avatar
Yann Diorcet committed
987 988
	tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
	linphone_core_set_in_call_timeout(lc,tmp);
989

990 991
	tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4);
	linphone_core_set_delayed_timeout(lc,tmp);
Yann Diorcet's avatar
Yann Diorcet committed
992

aymeric's avatar
aymeric committed
993 994
	/* get proxies config */
	for(i=0;; i++){
jehan's avatar
jehan committed
995
		LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc,i);
aymeric's avatar
aymeric committed
996 997
		if (cfg!=NULL){
			linphone_core_add_proxy_config(lc,cfg);
998
			linphone_proxy_config_unref(cfg);
aymeric's avatar
aymeric committed
999 1000 1001 1002 1003 1004 1005
		}else{
			break;
		}
	}
	/* get the default proxy */
	tmp=lp_config_get_int(lc->config,"sip","default_proxy",-1);
	linphone_core_set_default_proxy_index(lc,tmp);
1006

aymeric's avatar
aymeric committed
1007 1008 1009 1010 1011
	/* read authentication information */
	for(i=0;; i++){
		LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i);
		if (ai!=NULL){
			linphone_core_add_auth_info(lc,ai);
Simon Morlat's avatar
Simon Morlat committed
1012
			linphone_auth_info_destroy(ai);
aymeric's avatar
aymeric committed
1013 1014 1015 1016
		}else{
			break;
		}
	}
1017 1018
	/*this is to filter out unsupported encryption schemes*/
	linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
1019

1020
	/*for tuning or test*/
aymeric's avatar
aymeric committed
1021
	lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
1022
	lc->sip_conf.register_only_when_network_is_up=
1023
		lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
1024 1025
	lc->sip_conf.register_only_when_upnp_is_ok=
		lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1);
1026
	lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",0);
1027
	lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1);
1028
	lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000);
1029 1030
	lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0);
	linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
1031
	sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
1032
	sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
1033
	sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1));
1034
	lc->sip_conf.vfu_with_info=lp_config_get_int(lc->config,"sip","vfu_with_info",1);
1035
	linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000));
1036
	sal_set_supported_tags(lc->sal,lp_config_get_string(lc->config,"sip","supported","replaces, outbound"));
1037
	lc->sip_conf.save_auth_info = lp_config_get_int(lc->config, "sip", "save_auth_info", 1);
aymeric's avatar
aymeric committed
1038 1039
}

1040
static void rtp_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
1041
{
1042
	int min_port, max_port;
aymeric's avatar
aymeric committed
1043 1044
	int jitt_comp;
	int nortp_timeout;
Simon Morlat's avatar
Simon Morlat committed
1045
	bool_t rtp_no_xmit_on_audio_mute;
1046
	bool_t adaptive_jitt_comp_enabled;
jehan's avatar
jehan committed
1047 1048
	const char* tmp;
	int tmp_int;
Simon Morlat's avatar
Simon Morlat committed
1049

1050 1051 1052 1053 1054 1055 1056 1057
	if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
		if (min_port <= 0) min_port = 1;
		if (max_port > 65535) max_port = 65535;
		linphone_core_set_audio_port_range(lc, min_port, max_port);
	} else {
		min_port = lp_config_get_int(lc->config, "rtp", "audio_rtp_port", 7078);
		linphone_core_set_audio_port(lc, min_port);
	}
1058

1059 1060 1061 1062 1063 1064 1065 1066
	if (lp_config_get_range(lc->config, "rtp", "video_rtp_port", &min_port, &max_port, 9078, 9078) == TRUE) {
		if (min_port <= 0) min_port = 1;
		if (max_port > 65535) max_port = 65535;
		linphone_core_set_video_port_range(lc, min_port, max_port);
	} else {
		min_port = lp_config_get_int(lc->config, "rtp", "video_rtp_port", 9078);
		linphone_core_set_video_port(lc, min_port);
	}
1067

1068 1069 1070 1071 1072 1073 1074 1075 1076
	if (lp_config_get_range(lc->config, "rtp", "text_rtp_port", &min_port, &max_port, 11078, 11078) == TRUE) {
		if (min_port <= 0) min_port = 1;
		if (max_port > 65535) max_port = 65535;
		linphone_core_set_text_port_range(lc, min_port, max_port);
	} else {
		min_port = lp_config_get_int(lc->config, "rtp", "text_rtp_port", 11078);
		linphone_core_set_text_port(lc, min_port);
	}

aymeric's avatar
aymeric committed
1077
	jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
1078
	linphone_core_set_audio_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
1079
	jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
1080
	if (jitt_comp==0) jitt_comp=60;
1081
	linphone_core_set_video_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
1082
	nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
1083
	linphone_core_set_nortp_timeout(lc,nortp_timeout);
Simon Morlat's avatar
Simon Morlat committed
1084
	rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE);
1085
	linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_no_xmit_on_audio_mute);
1086 1087 1088 1089
	adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "audio_adaptive_jitt_comp_enabled", TRUE);
	linphone_core_enable_audio_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
	adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE);
	linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
1090
	lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE);
1091
	linphone_core_set_avpf_mode(lc,lp_config_get_int(lc->config,"rtp","avpf",0));
jehan's avatar
jehan committed
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
	if ((tmp=lp_config_get_string(lc->config,"rtp","audio_multicast_addr",NULL)))
		linphone_core_set_audio_multicast_addr(lc,tmp);
	else
		lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3");
	if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1)
		linphone_core_enable_audio_multicast(lc,tmp_int);
	if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0)
			linphone_core_set_audio_multicast_ttl(lc,tmp_int);
	else
		lc->rtp_conf.audio_multicast_ttl=1;/*local network*/
	if ((tmp=lp_config_get_string(lc->config,"rtp","video_multicast_addr",NULL)))
		linphone_core_set_video_multicast_addr(lc,tmp);
	else
		lc->rtp_conf.video_multicast_addr=ms_strdup("224.1.2.3");
	if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_ttl",-1))>-1)
		linphone_core_set_video_multicast_ttl(lc,tmp_int);
	else
		lc->rtp_conf.video_multicast_ttl=1;/*local network*/
	if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_enabled",-1)) >0)
		linphone_core_enable_video_multicast(lc,tmp_int);
aymeric's avatar
aymeric committed
1112 1113
}

1114
static PayloadType * find_payload(const MSList *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
1115 1116
	PayloadType *candidate=NULL;
	PayloadType *it;
1117
	const MSList *elem;
1118

1119 1120
	for(elem=default_list;elem!=NULL;elem=elem->next){
		it=(PayloadType*)elem->data;
1121
		if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
1122 1123
			&& (clock_rate==it->clock_rate || clock_rate<=0)
			&& (channels==it->channels || channels<=0) ){
1124
			if ( (recv_fmtp && it->recv_fmtp && strstr(recv_fmtp,it->recv_fmtp)!=NULL) ||
1125 1126
				(recv_fmtp==NULL && it->recv_fmtp==NULL) ){
				/*exact match*/
1127
				if (recv_fmtp) payload_type_set_recv_fmtp(it,recv_fmtp);
1128
				return it;
1129 1130 1131 1132 1133
			}else {
				if (candidate){
					if (it->recv_fmtp==NULL) candidate=it;
				}else candidate=it;
			}
1134 1135
		}
	}
1136 1137 1138
	if (candidate && recv_fmtp){
		payload_type_set_recv_fmtp(candidate,recv_fmtp);
	}
1139 1140
	return candidate;
}
aymeric's avatar
aymeric committed
1141

1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
static PayloadType* find_payload_type_from_list(const char* type, int rate, int channels, const MSList* from) {
	const MSList *elem;
	for(elem=from;elem!=NULL;elem=elem->next){
		PayloadType *pt=(PayloadType*)elem->data;
		if ((strcasecmp(type, payload_type_get_mime(pt)) == 0)
			&& (rate == LINPHONE_FIND_PAYLOAD_IGNORE_RATE || rate==pt->clock_rate)
			&& (channels == LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS || channels==pt->channels)) {
			return pt;
		}
	}
	return NULL;
}

1155 1156 1157
static bool_t linphone_core_codec_supported(LinphoneCore *lc, SalStreamType type, const char *mime){
	if (type == SalVideo && lp_config_get_int(lc->config, "video", "rtp_io", FALSE)){
		return TRUE; /*in rtp io mode, we don't transcode video, thus we can support a format for which we have no encoder nor decoder.*/
Sylvain Berfini's avatar
Sylvain Berfini committed
1158 1159
	} else if (type == SalText) {
		return TRUE;
1160
	}
1161 1162
	//ms_filter_codec_supported(mime)
	return ms_factory_codec_supported (lc->factory, mime );
1163 1164 1165
}


1166
static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, PayloadType **ret){
aymeric's avatar
aymeric committed
1167 1168
	char codeckey[50];
	const char *mime,*fmtp;
1169
	int rate,channels,enabled;
aymeric's avatar
aymeric committed
1170
	PayloadType *pt;
1171
	LpConfig *config=lc->config;
1172

1173
	*ret=NULL;
1174
	snprintf(codeckey,50,"%s_codec_%i",type == SalAudio ? "audio" : type == SalVideo ? "video" : "text", index);
aymeric's avatar
aymeric committed
1175
	mime=lp_config_get_string(config,codeckey,"mime",NULL);
1176
	if (mime==NULL || strlen(mime)==0 ) return FALSE;
1177

aymeric's avatar
aymeric committed
1178 1179
	rate=lp_config_get_int(config,codeckey,"rate",8000);
	fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
1180
	channels=lp_config_get_int(config,codeckey,"channels",0);
aymeric's avatar
aymeric committed
1181
	enabled=lp_config_get_int(config,codeckey,"enabled",1);
1182
	if (!linphone_core_codec_supported(lc, type, mime)){
1183 1184 1185
		ms_warning("Codec %s/%i read from conf is not supported by mediastreamer2, ignored.",mime,rate);
		return TRUE;
	}
1186
	pt = find_payload(type == SalAudio ? lc->default_audio_codecs : type == SalVideo ? lc->default_video_codecs : lc->default_text_codecs ,mime,rate,channels,fmtp);
1187
	if (!pt){
1188 1189
		MSList **default_list = (type==SalAudio) ? &lc->default_audio_codecs : type == SalVideo ? &lc->default_video_codecs : &lc->default_text_codecs;
		if (type == SalAudio)
1190
			ms_warning("Codec %s/%i/%i read from conf is not in the default list.",mime,rate,channels);
1191
		else if (type == SalVideo)
1192
			ms_warning("Codec %s/%i read from conf is not in the default list.",mime,rate);
1193 1194
		else
			ms_warning("Codec %s read from conf is not in the default list.",mime);
1195
		pt=payload_type_new();
1196
		pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : type == SalVideo ? PAYLOAD_VIDEO : PAYLOAD_TEXT;
1197 1198 1199
		pt->mime_type=ortp_strdup(mime);
		pt->clock_rate=rate;
		pt->channels=channels;
1200
		payload_type_set_number(pt,-1); /*dynamic assignment*/
1201 1202 1203 1204
		payload_type_set_recv_fmtp(pt,fmtp);
		*default_list=ms_list_append(*default_list, pt);
	}
	if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
1205
	else pt->flags&=~PAYLOAD_TYPE_ENABLED;
1206 1207 1208 1209
	*ret=pt;
	return TRUE;
}

1210 1211 1212 1213 1214 1215
/*this function merges the payload types from the codec default list with the list read from configuration file.
 * If a new codec becomes supported in Liblinphone or if the list from configuration file is empty or incomplete, all the supported codecs are added
 * autom