1 /*
2 linphone
3 Copyright (C) 2000  Simon MORLAT (simon.morlat@linphone.org)
4 Copyright (C) 2010  Belledonne Communications SARL
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20 
21 #include "linphone/core.h"
22 #include "linphone/sipsetup.h"
23 #include "linphone/lpconfig.h"
24 #include "private.h"
25 #include "quality_reporting.h"
26 #include "lime.h"
27 #include "conference_private.h"
28 
29 #ifdef SQLITE_STORAGE_ENABLED
30 #include "sqlite3_bctbx_vfs.h"
31 #endif
32 
33 #include <math.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <ortp/telephonyevents.h>
37 #include <mediastreamer2/zrtp.h>
38 #include <mediastreamer2/dtls_srtp.h>
39 #include <bctoolbox/defs.h>
40 #include "mediastreamer2/dtmfgen.h"
41 #include "mediastreamer2/mediastream.h"
42 #include "mediastreamer2/msequalizer.h"
43 #include "mediastreamer2/mseventqueue.h"
44 #include "mediastreamer2/msfactory.h"
45 #include "mediastreamer2/msjpegwriter.h"
46 #include "mediastreamer2/msogl.h"
47 #include "mediastreamer2/msvolume.h"
48 
49 #ifdef INET6
50 #ifndef _WIN32
51 #include <netdb.h>
52 #endif
53 #endif
54 
55 #ifdef HAVE_CONFIG_H
56 #include "config.h"
57 #include "gitversion.h"
58 #endif
59 
60 #ifdef __APPLE__
61 #include "TargetConditionals.h"
62 #endif
63 
64 #ifdef HAVE_ZLIB
65 #define COMPRESSED_LOG_COLLECTION_EXTENSION "gz"
66 #ifdef _WIN32
67 #include <fcntl.h>
68 #include <io.h>
69 #ifndef fileno
70 #define fileno _fileno
71 #endif
72 #define unlink _unlink
73 #define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
74 #else
75 #define SET_BINARY_MODE(file)
76 #endif
77 #include <zlib.h>
78 #else
79 #define COMPRESSED_LOG_COLLECTION_EXTENSION "txt"
80 #endif
81 #define LOG_COLLECTION_DEFAULT_PATH "."
82 #define LOG_COLLECTION_DEFAULT_PREFIX "linphone"
83 #define LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE (10 * 1024 * 1024)
84 
85 
86 /*#define UNSTANDART_GSM_11K 1*/
87 
88 static const char *liblinphone_version=
89 #ifdef LIBLINPHONE_GIT_VERSION
90 	LIBLINPHONE_GIT_VERSION
91 #else
92 	LIBLINPHONE_VERSION
93 #endif
94 ;
95 static OrtpLogFunc liblinphone_log_func = NULL;
96 static LinphoneLogCollectionState liblinphone_log_collection_state = LinphoneLogCollectionDisabled;
97 static char * liblinphone_log_collection_path = NULL;
98 static char * liblinphone_log_collection_prefix = NULL;
99 static size_t liblinphone_log_collection_max_file_size = LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE;
100 static ortp_mutex_t liblinphone_log_collection_mutex;
101 static FILE * liblinphone_log_collection_file = NULL;
102 static size_t liblinphone_log_collection_file_size = 0;
103 static bool_t liblinphone_serialize_logs = FALSE;
104 static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
105 static void set_sip_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
106 static void set_media_network_reachable(LinphoneCore* lc,bool_t isReachable);
107 static void linphone_core_run_hooks(LinphoneCore *lc);
108 static void linphone_core_uninit(LinphoneCore *lc);
109 static void linphone_core_zrtp_cache_close(LinphoneCore *lc);
110 void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName);
111 
112 #include "enum.h"
113 #include "contact_providers_priv.h"
114 
115 
116 const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
117 static void toggle_video_preview(LinphoneCore *lc, bool_t val);
118 
119 
120 /* relative path where is stored local ring*/
121 #define LOCAL_RING_WAV "oldphone-mono.wav"
122 #define LOCAL_RING_MKV "notes_of_the_optimistic.mkv"
123 /* same for remote ring (ringback)*/
124 #define REMOTE_RING_WAV "ringback.wav"
125 
126 #define HOLD_MUSIC_WAV "toy-mono.wav"
127 #define HOLD_MUSIC_MKV "dont_wait_too_long.mkv"
128 
129 extern SalCallbacks linphone_sal_callbacks;
130 
131 
132 static void _linphone_core_cbs_uninit(LinphoneCoreCbs *cbs);
133 
134 typedef belle_sip_object_t_vptr_t LinphoneCoreCbs_vptr_t;
135 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCoreCbs);
136 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCoreCbs, belle_sip_object_t,
137 	_linphone_core_cbs_uninit, // destroy
138 	NULL, // clone
139 	NULL, // Marshall
140 	FALSE
141 );
142 
_linphone_core_cbs_new(void)143 LinphoneCoreCbs *_linphone_core_cbs_new(void) {
144 	LinphoneCoreCbs *obj = belle_sip_object_new(LinphoneCoreCbs);
145 	obj->vtable = ms_new0(LinphoneCoreVTable, 1);
146 	obj->autorelease = TRUE;
147 	return obj;
148 }
149 
_linphone_core_cbs_uninit(LinphoneCoreCbs * cbs)150 static void _linphone_core_cbs_uninit(LinphoneCoreCbs *cbs) {
151 	if (cbs->autorelease) ms_free(cbs->vtable);
152 }
153 
_linphone_core_cbs_set_v_table(LinphoneCoreCbs * cbs,LinphoneCoreVTable * vtable,bool_t autorelease)154 void _linphone_core_cbs_set_v_table(LinphoneCoreCbs *cbs, LinphoneCoreVTable *vtable, bool_t autorelease) {
155 	ms_free(cbs->vtable);
156 	cbs->vtable = vtable;
157 	cbs->autorelease = autorelease;
158 }
159 
linphone_core_cbs_ref(LinphoneCoreCbs * cbs)160 LinphoneCoreCbs *linphone_core_cbs_ref(LinphoneCoreCbs *cbs) {
161 	return (LinphoneCoreCbs *)belle_sip_object_ref(cbs);
162 }
163 
linphone_core_cbs_unref(LinphoneCoreCbs * cbs)164 void linphone_core_cbs_unref(LinphoneCoreCbs *cbs) {
165 	belle_sip_object_unref(cbs);
166 }
167 
linphone_core_cbs_set_user_data(LinphoneCoreCbs * cbs,void * user_data)168 void linphone_core_cbs_set_user_data(LinphoneCoreCbs *cbs, void *user_data) {
169 	cbs->vtable->user_data = user_data;
170 }
171 
linphone_core_cbs_get_user_data(const LinphoneCoreCbs * cbs)172 void *linphone_core_cbs_get_user_data(const LinphoneCoreCbs *cbs) {
173 	return cbs->vtable->user_data;
174 }
175 
linphone_core_get_current_callbacks(const LinphoneCore * lc)176 LinphoneCoreCbs *linphone_core_get_current_callbacks(const LinphoneCore *lc) {
177 	return lc->current_cbs;
178 }
179 
linphone_core_cbs_get_global_state_changed(LinphoneCoreCbs * cbs)180 LinphoneCoreCbsGlobalStateChangedCb linphone_core_cbs_get_global_state_changed(LinphoneCoreCbs *cbs) {
181 	return cbs->vtable->global_state_changed;
182 }
183 
linphone_core_cbs_set_global_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsGlobalStateChangedCb cb)184 void linphone_core_cbs_set_global_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsGlobalStateChangedCb cb) {
185 	cbs->vtable->global_state_changed = cb;
186 }
187 
linphone_core_cbs_get_registration_state_changed(LinphoneCoreCbs * cbs)188 LinphoneCoreCbsRegistrationStateChangedCb linphone_core_cbs_get_registration_state_changed(LinphoneCoreCbs *cbs) {
189 	return cbs->vtable->registration_state_changed;
190 }
191 
linphone_core_cbs_set_registration_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsRegistrationStateChangedCb cb)192 void linphone_core_cbs_set_registration_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsRegistrationStateChangedCb cb) {
193 	cbs->vtable->registration_state_changed = cb;
194 }
195 
linphone_core_cbs_get_call_state_changed(LinphoneCoreCbs * cbs)196 LinphoneCoreCbsCallStateChangedCb linphone_core_cbs_get_call_state_changed(LinphoneCoreCbs *cbs) {
197 	return cbs->vtable->call_state_changed;
198 }
199 
linphone_core_cbs_set_call_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallStateChangedCb cb)200 void linphone_core_cbs_set_call_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStateChangedCb cb) {
201 	cbs->vtable->call_state_changed = cb;
202 }
203 
linphone_core_cbs_get_notify_presence_received(LinphoneCoreCbs * cbs)204 LinphoneCoreCbsNotifyPresenceReceivedCb linphone_core_cbs_get_notify_presence_received(LinphoneCoreCbs *cbs) {
205 	return cbs->vtable->notify_presence_received;
206 }
207 
linphone_core_cbs_set_notify_presence_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsNotifyPresenceReceivedCb cb)208 void linphone_core_cbs_set_notify_presence_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedCb cb) {
209 	cbs->vtable->notify_presence_received = cb;
210 }
211 
linphone_core_cbs_get_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs * cbs)212 LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb linphone_core_cbs_get_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs) {
213 	return cbs->vtable->notify_presence_received_for_uri_or_tel;
214 }
215 
linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs * cbs,LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb cb)216 void linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb cb) {
217 	cbs->vtable->notify_presence_received_for_uri_or_tel = cb;
218 }
219 
linphone_core_cbs_get_new_subscription_requested(LinphoneCoreCbs * cbs)220 LinphoneCoreCbsNewSubscriptionRequestedCb linphone_core_cbs_get_new_subscription_requested(LinphoneCoreCbs *cbs) {
221 	return cbs->vtable->new_subscription_requested;
222 }
223 
linphone_core_cbs_set_new_subscription_requested(LinphoneCoreCbs * cbs,LinphoneCoreCbsNewSubscriptionRequestedCb cb)224 void linphone_core_cbs_set_new_subscription_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsNewSubscriptionRequestedCb cb) {
225 	cbs->vtable->new_subscription_requested = cb;
226 }
227 
linphone_core_cbs_get_authentication_requested(LinphoneCoreCbs * cbs)228 LinphoneCoreCbsAuthenticationRequestedCb linphone_core_cbs_get_authentication_requested(LinphoneCoreCbs *cbs) {
229 	return cbs->vtable->authentication_requested;
230 }
231 
linphone_core_cbs_set_authentication_requested(LinphoneCoreCbs * cbs,LinphoneCoreCbsAuthenticationRequestedCb cb)232 void linphone_core_cbs_set_authentication_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsAuthenticationRequestedCb cb) {
233 	cbs->vtable->authentication_requested = cb;
234 }
235 
linphone_core_cbs_get_call_log_updated(LinphoneCoreCbs * cbs)236 LinphoneCoreCbsCallLogUpdatedCb linphone_core_cbs_get_call_log_updated(LinphoneCoreCbs *cbs) {
237 	return cbs->vtable->call_log_updated;
238 }
239 
linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallLogUpdatedCb cb)240 void linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallLogUpdatedCb cb) {
241 	cbs->vtable->call_log_updated = cb;
242 }
243 
linphone_core_cbs_get_message_received(LinphoneCoreCbs * cbs)244 LinphoneCoreCbsMessageReceivedCb linphone_core_cbs_get_message_received(LinphoneCoreCbs *cbs) {
245 	return cbs->vtable->message_received;
246 }
247 
linphone_core_cbs_set_message_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsMessageReceivedCb cb)248 void linphone_core_cbs_set_message_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedCb cb) {
249 	cbs->vtable->message_received = cb;
250 }
251 
linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs * cbs)252 LinphoneCoreCbsMessageReceivedUnableDecryptCb linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs *cbs) {
253 	return cbs->vtable->message_received_unable_decrypt;
254 }
255 
linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs * cbs,LinphoneCoreCbsMessageReceivedUnableDecryptCb cb)256 void linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedUnableDecryptCb cb) {
257 	cbs->vtable->message_received_unable_decrypt = cb;
258 }
259 
linphone_core_cbs_get_is_composing_received(LinphoneCoreCbs * cbs)260 LinphoneCoreCbsIsComposingReceivedCb linphone_core_cbs_get_is_composing_received(LinphoneCoreCbs *cbs) {
261 	return cbs->vtable->is_composing_received;
262 }
263 
linphone_core_cbs_set_is_composing_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsIsComposingReceivedCb cb)264 void linphone_core_cbs_set_is_composing_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsIsComposingReceivedCb cb) {
265 	cbs->vtable->is_composing_received = cb;
266 }
267 
linphone_core_cbs_get_dtmf_received(LinphoneCoreCbs * cbs)268 LinphoneCoreCbsDtmfReceivedCb linphone_core_cbs_get_dtmf_received(LinphoneCoreCbs *cbs) {
269 	return cbs->vtable->dtmf_received;
270 }
271 
linphone_core_cbs_set_dtmf_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsDtmfReceivedCb cb)272 void linphone_core_cbs_set_dtmf_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsDtmfReceivedCb cb) {
273 	cbs->vtable->dtmf_received = cb;
274 }
275 
linphone_core_cbs_get_refer_received(LinphoneCoreCbs * cbs)276 LinphoneCoreCbsReferReceivedCb linphone_core_cbs_get_refer_received(LinphoneCoreCbs *cbs) {
277 	return cbs->vtable->refer_received;
278 }
279 
linphone_core_cbs_set_refer_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsReferReceivedCb cb)280 void linphone_core_cbs_set_refer_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsReferReceivedCb cb) {
281 	cbs->vtable->refer_received = cb;
282 }
283 
linphone_core_cbs_get_call_encryption_changed(LinphoneCoreCbs * cbs)284 LinphoneCoreCbsCallEncryptionChangedCb linphone_core_cbs_get_call_encryption_changed(LinphoneCoreCbs *cbs) {
285 	return cbs->vtable->call_encryption_changed;
286 }
287 
linphone_core_cbs_set_call_encryption_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallEncryptionChangedCb cb)288 void linphone_core_cbs_set_call_encryption_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallEncryptionChangedCb cb) {
289 	cbs->vtable->call_encryption_changed = cb;
290 }
291 
linphone_core_cbs_get_transfer_state_changed(LinphoneCoreCbs * cbs)292 LinphoneCoreCbsTransferStateChangedCb linphone_core_cbs_get_transfer_state_changed(LinphoneCoreCbs *cbs) {
293 	return cbs->vtable->transfer_state_changed;
294 }
295 
linphone_core_cbs_set_transfer_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsTransferStateChangedCb cb)296 void linphone_core_cbs_set_transfer_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsTransferStateChangedCb cb) {
297 	cbs->vtable->transfer_state_changed = cb;
298 }
299 
linphone_core_cbs_get_buddy_info_updated(LinphoneCoreCbs * cbs)300 LinphoneCoreCbsBuddyInfoUpdatedCb linphone_core_cbs_get_buddy_info_updated(LinphoneCoreCbs *cbs) {
301 	return cbs->vtable->buddy_info_updated;
302 }
303 
linphone_core_cbs_set_buddy_info_updated(LinphoneCoreCbs * cbs,LinphoneCoreCbsBuddyInfoUpdatedCb cb)304 void linphone_core_cbs_set_buddy_info_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsBuddyInfoUpdatedCb cb) {
305 	cbs->vtable->buddy_info_updated = cb;
306 }
307 
linphone_core_cbs_get_call_stats_updated(LinphoneCoreCbs * cbs)308 LinphoneCoreCbsCallStatsUpdatedCb linphone_core_cbs_get_call_stats_updated(LinphoneCoreCbs *cbs) {
309 	return cbs->vtable->call_stats_updated;
310 }
311 
linphone_core_cbs_set_call_stats_updated(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallStatsUpdatedCb cb)312 void linphone_core_cbs_set_call_stats_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStatsUpdatedCb cb) {
313 	cbs->vtable->call_stats_updated = cb;
314 }
315 
linphone_core_cbs_get_info_received(LinphoneCoreCbs * cbs)316 LinphoneCoreCbsInfoReceivedCb linphone_core_cbs_get_info_received(LinphoneCoreCbs *cbs) {
317 	return cbs->vtable->info_received;
318 }
319 
linphone_core_cbs_set_info_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsInfoReceivedCb cb)320 void linphone_core_cbs_set_info_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsInfoReceivedCb cb) {
321 	cbs->vtable->info_received = cb;
322 }
323 
linphone_core_cbs_get_subscription_state_changed(LinphoneCoreCbs * cbs)324 LinphoneCoreCbsSubscriptionStateChangedCb linphone_core_cbs_get_subscription_state_changed(LinphoneCoreCbs *cbs) {
325 	return cbs->vtable->subscription_state_changed;
326 }
327 
linphone_core_cbs_set_subscription_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsSubscriptionStateChangedCb cb)328 void linphone_core_cbs_set_subscription_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsSubscriptionStateChangedCb cb) {
329 	cbs->vtable->subscription_state_changed = cb;
330 }
331 
linphone_core_cbs_get_notify_received(LinphoneCoreCbs * cbs)332 LinphoneCoreCbsNotifyReceivedCb linphone_core_cbs_get_notify_received(LinphoneCoreCbs *cbs) {
333 	return cbs->vtable->notify_received;
334 }
335 
linphone_core_cbs_set_notify_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsNotifyReceivedCb cb)336 void linphone_core_cbs_set_notify_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyReceivedCb cb) {
337 	cbs->vtable->notify_received = cb;
338 }
339 
linphone_core_cbs_get_rpublish_state_changed(LinphoneCoreCbs * cbs)340 LinphoneCoreCbsPublishStateChangedCb linphone_core_cbs_get_rpublish_state_changed(LinphoneCoreCbs *cbs) {
341 	return cbs->vtable->publish_state_changed;
342 }
343 
linphone_core_cbs_set_publish_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsPublishStateChangedCb cb)344 void linphone_core_cbs_set_publish_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsPublishStateChangedCb cb) {
345 	cbs->vtable->publish_state_changed = cb;
346 }
347 
linphone_core_cbs_get_configuring_status(LinphoneCoreCbs * cbs)348 LinphoneCoreCbsConfiguringStatusCb linphone_core_cbs_get_configuring_status(LinphoneCoreCbs *cbs) {
349 	return cbs->vtable->configuring_status;
350 }
351 
linphone_core_cbs_set_configuring_status(LinphoneCoreCbs * cbs,LinphoneCoreCbsConfiguringStatusCb cb)352 void linphone_core_cbs_set_configuring_status(LinphoneCoreCbs *cbs, LinphoneCoreCbsConfiguringStatusCb cb) {
353 	cbs->vtable->configuring_status = cb;
354 }
355 
linphone_core_cbs_get_network_reachable(LinphoneCoreCbs * cbs)356 LinphoneCoreCbsNetworkReachableCb linphone_core_cbs_get_network_reachable(LinphoneCoreCbs *cbs) {
357 	return cbs->vtable->network_reachable;
358 }
359 
linphone_core_cbs_set_network_reachable(LinphoneCoreCbs * cbs,LinphoneCoreCbsNetworkReachableCb cb)360 void linphone_core_cbs_set_network_reachable(LinphoneCoreCbs *cbs, LinphoneCoreCbsNetworkReachableCb cb) {
361 	cbs->vtable->network_reachable = cb;
362 }
363 
linphone_core_cbs_log_collection_upload_state_changed(LinphoneCoreCbs * cbs)364 LinphoneCoreCbsLogCollectionUploadStateChangedCb linphone_core_cbs_log_collection_upload_state_changed(LinphoneCoreCbs *cbs) {
365 	return cbs->vtable->log_collection_upload_state_changed;
366 }
367 
linphone_core_cbs_set_log_collection_upload_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsLogCollectionUploadStateChangedCb cb)368 void linphone_core_cbs_set_log_collection_upload_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadStateChangedCb cb) {
369 	cbs->vtable->log_collection_upload_state_changed = cb;
370 }
371 
linphone_core_cbs_get_rlog_collection_upload_progress_indication(LinphoneCoreCbs * cbs)372 LinphoneCoreCbsLogCollectionUploadProgressIndicationCb linphone_core_cbs_get_rlog_collection_upload_progress_indication(LinphoneCoreCbs *cbs) {
373 	return cbs->vtable->log_collection_upload_progress_indication;
374 }
375 
linphone_core_cbs_set_log_collection_upload_progress_indication(LinphoneCoreCbs * cbs,LinphoneCoreCbsLogCollectionUploadProgressIndicationCb cb)376 void linphone_core_cbs_set_log_collection_upload_progress_indication(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadProgressIndicationCb cb) {
377 	cbs->vtable->log_collection_upload_progress_indication = cb;
378 }
379 
linphone_core_cbs_get_friend_list_created(LinphoneCoreCbs * cbs)380 LinphoneCoreCbsFriendListCreatedCb linphone_core_cbs_get_friend_list_created(LinphoneCoreCbs *cbs) {
381 	return cbs->vtable->friend_list_created;
382 }
383 
linphone_core_cbs_set_friend_list_created(LinphoneCoreCbs * cbs,LinphoneCoreCbsFriendListCreatedCb cb)384 void linphone_core_cbs_set_friend_list_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListCreatedCb cb) {
385 	cbs->vtable->friend_list_created = cb;
386 }
387 
linphone_core_cbs_get_friend_list_removed(LinphoneCoreCbs * cbs)388 LinphoneCoreCbsFriendListRemovedCb linphone_core_cbs_get_friend_list_removed(LinphoneCoreCbs *cbs) {
389 	return cbs->vtable->friend_list_removed;
390 }
391 
linphone_core_cbs_set_friend_list_removed(LinphoneCoreCbs * cbs,LinphoneCoreCbsFriendListRemovedCb cb)392 void linphone_core_cbs_set_friend_list_removed(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListRemovedCb cb) {
393 	cbs->vtable->friend_list_removed = cb;
394 }
395 
linphone_core_cbs_get_call_created(LinphoneCoreCbs * cbs)396 LinphoneCoreCbsCallCreatedCb linphone_core_cbs_get_call_created(LinphoneCoreCbs *cbs) {
397 	return cbs->vtable->call_created;
398 }
399 
linphone_core_cbs_set_call_created(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallCreatedCb cb)400 void linphone_core_cbs_set_call_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallCreatedCb cb) {
401 	cbs->vtable->call_created = cb;
402 }
403 
linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs * cbs)404 LinphoneCoreCbsVersionUpdateCheckResultReceivedCb linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs *cbs) {
405 	return cbs->vtable->version_update_check_result_received;
406 }
407 
linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsVersionUpdateCheckResultReceivedCb cb)408 void linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsVersionUpdateCheckResultReceivedCb cb) {
409 	cbs->vtable->version_update_check_result_received = cb;
410 }
411 
412 
413 typedef belle_sip_object_t_vptr_t LinphoneCore_vptr_t;
414 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCore);
415 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCore, belle_sip_object_t,
416 	linphone_core_uninit, // destroy
417 	NULL, // clone
418 	NULL, // Marshall
419 	FALSE
420 );
421 
lc_callback_obj_init(LCCallbackObj * obj,LinphoneCoreCbFunc func,void * ud)422 void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) {
423   obj->_func=func;
424   obj->_user_data=ud;
425 }
426 
lc_callback_obj_invoke(LCCallbackObj * obj,LinphoneCore * lc)427 int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
428 	if (obj->_func!=NULL) obj->_func(lc,obj->_user_data);
429 	return 0;
430 }
431 
linphone_call_asked_to_autoanswer(LinphoneCall * call)432 bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){
433 	//return TRUE if the unique(for the moment) incoming call asked to be autoanswered
434 	if(call)
435 		return sal_call_autoanswer_asked(call->op);
436 	else
437 		return FALSE;
438 }
439 
linphone_core_get_current_call_duration(const LinphoneCore * lc)440 int linphone_core_get_current_call_duration(const LinphoneCore *lc){
441 	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
442 	if (call)  return linphone_call_get_duration(call);
443 	return -1;
444 }
445 
linphone_core_get_current_call_remote_address(struct _LinphoneCore * lc)446 const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc){
447 	LinphoneCall *call=linphone_core_get_current_call(lc);
448 	if (call==NULL) return NULL;
449 	return linphone_call_get_remote_address(call);
450 }
451 
452 static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args);
453 
linphone_core_set_log_handler(OrtpLogFunc logfunc)454 void linphone_core_set_log_handler(OrtpLogFunc logfunc) {
455 	if (ortp_get_log_handler() == linphone_core_log_collection_handler) {
456 		ms_message("There is already a log collection handler, keep it");
457 		liblinphone_log_func = logfunc;
458 	} else
459 		ortp_set_log_handler(logfunc);
460 }
461 
linphone_core_set_log_file(FILE * file)462 void linphone_core_set_log_file(FILE *file) {
463 	if (file == NULL) file = stdout;
464 	ortp_set_log_file(file);
465 }
466 
linphone_core_set_log_level(OrtpLogLevel loglevel)467 void linphone_core_set_log_level(OrtpLogLevel loglevel) {
468 	OrtpLogLevel mask = loglevel;
469 	switch (loglevel) {
470 		case ORTP_TRACE:
471 		case ORTP_DEBUG:
472 			mask |= ORTP_DEBUG;
473 			BCTBX_NO_BREAK;
474 		case ORTP_MESSAGE:
475 			mask |= ORTP_MESSAGE;
476 			BCTBX_NO_BREAK;
477 		case ORTP_WARNING:
478 			mask |= ORTP_WARNING;
479 			BCTBX_NO_BREAK;
480 		case ORTP_ERROR:
481 			mask |= ORTP_ERROR;
482 			BCTBX_NO_BREAK;
483 		case ORTP_FATAL:
484 			mask |= ORTP_FATAL;
485 			break;
486 		case ORTP_LOGLEV_END:
487 			break;
488 	}
489 	linphone_core_set_log_level_mask(mask);
490 }
491 
linphone_core_set_log_level_mask(unsigned int loglevel)492 void linphone_core_set_log_level_mask(unsigned int loglevel) {
493 	ortp_set_log_level_mask(NULL, loglevel);
494 	bctbx_set_log_level_mask(NULL, loglevel);
495 	if (loglevel == 0) {
496 		sal_disable_log();
497 	} else {
498 		sal_enable_log();
499 	}
500 }
501 
_open_log_collection_file_with_idx(int idx)502 static int _open_log_collection_file_with_idx(int idx) {
503 	struct stat statbuf;
504 	char *log_filename;
505 
506 	log_filename = ortp_strdup_printf("%s/%s%d.log",
507 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
508 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
509 		idx);
510 	liblinphone_log_collection_file = fopen(log_filename, "a");
511 	ortp_free(log_filename);
512 	if (liblinphone_log_collection_file == NULL) return -1;
513 
514 	fstat(fileno(liblinphone_log_collection_file), &statbuf);
515 	if ((size_t)statbuf.st_size > liblinphone_log_collection_max_file_size) {
516 		fclose(liblinphone_log_collection_file);
517 		return -1;
518 	}
519 
520 	liblinphone_log_collection_file_size = statbuf.st_size;
521 	return 0;
522 }
523 
_rotate_log_collection_files(void)524 static void _rotate_log_collection_files(void) {
525 	char *log_filename1;
526 	char *log_filename2;
527 
528 	log_filename1 = ortp_strdup_printf("%s/%s1.log",
529 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
530 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
531 	log_filename2 = ortp_strdup_printf("%s/%s2.log",
532 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
533 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
534 	unlink(log_filename1);
535 	rename(log_filename2, log_filename1);
536 	ortp_free(log_filename1);
537 	ortp_free(log_filename2);
538 }
539 
_open_log_collection_file(void)540 static void _open_log_collection_file(void) {
541 	if (_open_log_collection_file_with_idx(1) < 0) {
542 		if (_open_log_collection_file_with_idx(2) < 0) {
543 			_rotate_log_collection_files();
544 			_open_log_collection_file_with_idx(2);
545 		}
546 	}
547 }
548 
_close_log_collection_file(void)549 static void _close_log_collection_file(void) {
550 	if (liblinphone_log_collection_file) {
551 		fclose(liblinphone_log_collection_file);
552 		liblinphone_log_collection_file = NULL;
553 		liblinphone_log_collection_file_size = 0;
554 	}
555 }
556 
linphone_core_log_collection_handler(const char * domain,OrtpLogLevel level,const char * fmt,va_list args)557 static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args) {
558 	const char *lname="undef";
559 	char *msg;
560 	struct timeval tp;
561 	struct tm *lt;
562 	time_t tt;
563 	int ret;
564 
565 	if (liblinphone_log_func != NULL && liblinphone_log_func != linphone_core_log_collection_handler) {
566 #ifndef _WIN32
567 		va_list args_copy;
568 		va_copy(args_copy, args);
569 		liblinphone_log_func(domain, level, fmt, args_copy);
570 		va_end(args_copy);
571 #else
572 		/* This works on 32 bits, luckily. */
573 		/* TODO: va_copy is available in Visual Studio 2013. */
574 		liblinphone_log_func(domain, level, fmt, args);
575 #endif
576 	}
577 
578 	ortp_gettimeofday(&tp, NULL);
579 	tt = (time_t)tp.tv_sec;
580 	lt = localtime((const time_t*)&tt);
581 
582 	if ((level & ORTP_DEBUG) != 0) {
583 		lname = "DEBUG";
584 	} else if ((level & ORTP_MESSAGE) != 0) {
585 		lname = "MESSAGE";
586 	} else if ((level & ORTP_WARNING) != 0) {
587 		lname = "WARNING";
588 	} else if ((level & ORTP_ERROR) != 0) {
589 		lname = "ERROR";
590 	} else if ((level & ORTP_FATAL) != 0) {
591 		lname = "FATAL";
592 	} else {
593 		ortp_fatal("Bad level !");
594 	}
595 	msg = ortp_strdup_vprintf(fmt, args);
596 
597 	if (liblinphone_log_collection_file == NULL) {
598 		ortp_mutex_lock(&liblinphone_log_collection_mutex);
599 		_open_log_collection_file();
600 		ortp_mutex_unlock(&liblinphone_log_collection_mutex);
601 	}
602 	if (liblinphone_log_collection_file) {
603 		ortp_mutex_lock(&liblinphone_log_collection_mutex);
604 		ret = fprintf(liblinphone_log_collection_file,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s %s\n",
605 			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);
606 		fflush(liblinphone_log_collection_file);
607 		if (ret > 0) {
608 			liblinphone_log_collection_file_size += ret;
609 			if (liblinphone_log_collection_file_size > liblinphone_log_collection_max_file_size) {
610 				_close_log_collection_file();
611 				_open_log_collection_file();
612 			}
613 		}
614 		ortp_mutex_unlock(&liblinphone_log_collection_mutex);
615 	}
616 
617 	ortp_free(msg);
618 }
619 
linphone_core_get_log_collection_path(void)620 const char * linphone_core_get_log_collection_path(void) {
621 	if (liblinphone_log_collection_path != NULL) {
622 		return liblinphone_log_collection_path;
623 	}
624 	return LOG_COLLECTION_DEFAULT_PATH;
625 }
626 
linphone_core_set_log_collection_path(const char * path)627 void linphone_core_set_log_collection_path(const char *path) {
628 	if (liblinphone_log_collection_path != NULL) {
629 		ms_free(liblinphone_log_collection_path);
630 		liblinphone_log_collection_path = NULL;
631 	}
632 	if (path != NULL) {
633 		liblinphone_log_collection_path = ms_strdup(path);
634 	}
635 }
636 
linphone_core_get_log_collection_prefix(void)637 const char * linphone_core_get_log_collection_prefix(void) {
638 	if (liblinphone_log_collection_prefix != NULL) {
639 		return liblinphone_log_collection_prefix;
640 	}
641 	return LOG_COLLECTION_DEFAULT_PREFIX;
642 }
643 
linphone_core_set_log_collection_prefix(const char * prefix)644 void linphone_core_set_log_collection_prefix(const char *prefix) {
645 	if (liblinphone_log_collection_prefix != NULL) {
646 		ms_free(liblinphone_log_collection_prefix);
647 		liblinphone_log_collection_prefix = NULL;
648 	}
649 	if (prefix != NULL) {
650 		liblinphone_log_collection_prefix = ms_strdup(prefix);
651 	}
652 }
653 
linphone_core_get_log_collection_max_file_size(void)654 size_t linphone_core_get_log_collection_max_file_size(void) {
655 	return liblinphone_log_collection_max_file_size;
656 }
657 
linphone_core_set_log_collection_max_file_size(size_t size)658 void linphone_core_set_log_collection_max_file_size(size_t size) {
659 	liblinphone_log_collection_max_file_size = size;
660 }
661 
linphone_core_get_log_collection_upload_server_url(LinphoneCore * core)662 const char *linphone_core_get_log_collection_upload_server_url(LinphoneCore *core) {
663 	return lp_config_get_string(core->config, "misc", "log_collection_upload_server_url", NULL);
664 }
665 
linphone_core_set_log_collection_upload_server_url(LinphoneCore * core,const char * server_url)666 void linphone_core_set_log_collection_upload_server_url(LinphoneCore *core, const char *server_url) {
667 	lp_config_set_string(core->config, "misc", "log_collection_upload_server_url", server_url);
668 }
669 
linphone_core_log_collection_enabled(void)670 LinphoneLogCollectionState linphone_core_log_collection_enabled(void) {
671 	return liblinphone_log_collection_state;
672 }
673 
linphone_core_enable_log_collection(LinphoneLogCollectionState state)674 void linphone_core_enable_log_collection(LinphoneLogCollectionState state) {
675 	if (liblinphone_log_collection_state == state) return;
676 
677 	/* at first call of this function, set liblinphone_log_func to the current
678 	 * ortp log function */
679 	if( liblinphone_log_func == NULL ){
680 		liblinphone_log_func = ortp_get_log_handler();
681 	}
682 	liblinphone_log_collection_state = state;
683 	if (state != LinphoneLogCollectionDisabled) {
684 		ortp_mutex_init(&liblinphone_log_collection_mutex, NULL);
685 		if (state == LinphoneLogCollectionEnabledWithoutPreviousLogHandler) {
686 			liblinphone_log_func = NULL;
687 		} else {
688 			liblinphone_log_func = ortp_get_log_handler();
689 		}
690 		ortp_set_log_handler(linphone_core_log_collection_handler);
691 	} else {
692 		ortp_set_log_handler(liblinphone_log_func);
693 	}
694 }
695 
clean_log_collection_upload_context(LinphoneCore * lc)696 static void clean_log_collection_upload_context(LinphoneCore *lc) {
697 	char *filename = ms_strdup_printf("%s/%s_log.%s",
698 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
699 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
700 		COMPRESSED_LOG_COLLECTION_EXTENSION);
701 	unlink(filename);
702 	ms_free(filename);
703 	if (lc && lc->log_collection_upload_information) {
704 		linphone_content_unref(lc->log_collection_upload_information);
705 		lc->log_collection_upload_information=NULL;
706 	}
707 }
708 
process_io_error_upload_log_collection(void * data,const belle_sip_io_error_event_t * event)709 static void process_io_error_upload_log_collection(void *data, const belle_sip_io_error_event_t *event) {
710 	LinphoneCore *core = (LinphoneCore *)data;
711 	ms_error("I/O Error during log collection upload to %s", linphone_core_get_log_collection_upload_server_url(core));
712 	linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "I/O Error");
713 	clean_log_collection_upload_context(core);
714 }
715 
process_auth_requested_upload_log_collection(void * data,belle_sip_auth_event_t * event)716 static void process_auth_requested_upload_log_collection(void *data, belle_sip_auth_event_t *event) {
717 	LinphoneCore *core = (LinphoneCore *)data;
718 	ms_error("Error during log collection upload: auth requested to connect %s", linphone_core_get_log_collection_upload_server_url(core));
719 	linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Auth requested");
720 	clean_log_collection_upload_context(core);
721 }
722 
723 /**
724  * Callback called when posting a log collection file to server (following rcs5.1 recommendation)
725  * @param[in] bh The body handler
726  * @param[in] msg The belle sip message
727  * @param[in] data The user data associated with the handler, contains the LinphoneCore object
728  * @param[in] offset The current position in the input buffer
729  * @param[in] buffer The ouput buffer where to copy the data to be uploaded
730  * @param[in,out] size The size in byte of the data requested, as output it will contain the effective copied size
731  */
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)732 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) {
733 	LinphoneCore *core = (LinphoneCore *)data;
734 
735 	/* If we've not reach the end of file yet, fill the buffer with more data */
736 	if (offset < linphone_content_get_size(core->log_collection_upload_information)) {
737 		char *log_filename = ms_strdup_printf("%s/%s_log.%s",
738 			liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
739 			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
740 			COMPRESSED_LOG_COLLECTION_EXTENSION);
741 #ifdef HAVE_ZLIB
742 		FILE *log_file = fopen(log_filename, "rb");
743 #else
744 		FILE *log_file = fopen(log_filename, "r");
745 #endif
746 		if (fseek(log_file, (long)offset, SEEK_SET)) {
747 			ms_error("Cannot seek file [%s] at position [%lu] errno [%s]",log_filename,(unsigned long)offset,strerror(errno));
748 
749 		} else {
750 			*size = fread(buffer, 1, *size, log_file);
751 		}
752 		fclose(log_file);
753 		ms_free(log_filename);
754 		return BELLE_SIP_CONTINUE;
755 	} else {
756 		*size=0;
757 		return BELLE_SIP_STOP;
758 	}
759 }
760 
761 /**
762  * Callback called during upload of a log collection to server.
763  * It is just forwarding the call and some parameters to the vtable defined callback.
764  */
log_collection_upload_on_progress(belle_sip_body_handler_t * bh,belle_sip_message_t * msg,void * data,size_t offset,size_t total)765 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) {
766 	LinphoneCore *core = (LinphoneCore *)data;
767 	linphone_core_notify_log_collection_upload_progress_indication(core, offset, total);
768 }
769 
770 /**
771  * Callback function called when we have a response from server during the upload of the log collection to the server (rcs5.1 recommandation)
772  * 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
773  * to upload the file. The server response to this second post is processed by this same function
774  *
775  * @param[in] data The user-defined pointer associated with the request, it contains the LinphoneCore object
776  * @param[in] event The response from server
777  */
process_response_from_post_file_log_collection(void * data,const belle_http_response_event_t * event)778 static void process_response_from_post_file_log_collection(void *data, const belle_http_response_event_t *event) {
779 	LinphoneCore *core = (LinphoneCore *)data;
780 
781 	/* Check the answer code */
782 	if (event->response) {
783 		int code = belle_http_response_get_status_code(event->response);
784 		if (code == 204) { /* This is the reply to the first post to the server - an empty file */
785 			/* Start uploading the file */
786 			belle_http_request_listener_callbacks_t cbs = { 0 };
787 			belle_http_request_listener_t *l;
788 			belle_generic_uri_t *uri;
789 			belle_http_request_t *req;
790 			belle_sip_multipart_body_handler_t *bh;
791 			char* ua;
792 			char *first_part_header;
793 			belle_sip_user_body_handler_t *first_part_bh;
794 
795 			linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateInProgress, NULL);
796 
797 			/* Temporary storage for the Content-disposition header value */
798 			first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", linphone_content_get_name(core->log_collection_upload_information));
799 
800 			/* Create a user body handler to take care of the file and add the content disposition and content-type headers */
801 			first_part_bh = belle_sip_user_body_handler_new(linphone_content_get_size(core->log_collection_upload_information), NULL, NULL, NULL, log_collection_upload_on_send_body, NULL, core);
802 			belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh, belle_sip_header_create("Content-disposition", first_part_header));
803 			belle_sip_free(first_part_header);
804 			belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh,
805 				(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)));
806 
807 			/* Insert it in a multipart body handler which will manage the boundaries of multipart message */
808 			bh = belle_sip_multipart_body_handler_new(log_collection_upload_on_progress, core, (belle_sip_body_handler_t *)first_part_bh, NULL);
809 			ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(core), linphone_core_get_version());
810 			uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
811 			req = belle_http_request_create("POST", uri, belle_sip_header_create("User-Agent", ua), NULL);
812 			ms_free(ua);
813 			belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh));
814 			cbs.process_response = process_response_from_post_file_log_collection;
815 			cbs.process_io_error = process_io_error_upload_log_collection;
816 			cbs.process_auth_requested = process_auth_requested_upload_log_collection;
817 			l = belle_http_request_listener_create_from_callbacks(&cbs, core);
818 			belle_sip_object_data_set(BELLE_SIP_OBJECT(req), "http_request_listener", l, belle_sip_object_unref); // Ensure the listener object is destroyed when the request is destroyed
819 			belle_http_provider_send_request(core->http_provider, req, l);
820 		} else if (code == 200) { /* The file has been uploaded correctly, get the server reply */
821 			xmlDocPtr xmlMessageBody;
822 			xmlNodePtr cur;
823 			xmlChar *file_url = NULL;
824 			const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
825 			xmlMessageBody = xmlParseDoc((const xmlChar *)body);
826 			cur = xmlDocGetRootElement(xmlMessageBody);
827 			if (cur != NULL) {
828 				cur = cur->xmlChildrenNode;
829 				while (cur != NULL) {
830 					if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */
831 						xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type");
832 						if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */
833 							cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */
834 							while (cur != NULL) {
835 								if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) {
836 									file_url = 	xmlGetProp(cur, (const xmlChar *)"url");
837 								}
838 								cur=cur->next;
839 							}
840 							xmlFree(typeAttribute);
841 							break;
842 						}
843 						xmlFree(typeAttribute);
844 					}
845 					cur = cur->next;
846 				}
847 			}
848 			if (file_url != NULL) {
849 				linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateDelivered, (const char *)file_url);
850 			}
851 			clean_log_collection_upload_context(core);
852 		} else {
853 			ms_error("Unexpected HTTP response code %i during log collection upload to %s", code, linphone_core_get_log_collection_upload_server_url(core));
854 			linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Unexpected HTTP response");
855 			clean_log_collection_upload_context(core);
856 		}
857 	}
858 }
859 
860 #ifdef HAVE_ZLIB
861 #define COMPRESS_FILE_PTR gzFile
862 #define COMPRESS_OPEN gzopen
863 #define COMPRESS_CLOSE gzclose
864 #else
865 #define COMPRESS_FILE_PTR FILE*
866 #define COMPRESS_OPEN fopen
867 #define COMPRESS_CLOSE fclose
868 #endif
869 
870 /**
871  * If zlib is not available the two log files are simply concatenated.
872  */
compress_file(FILE * input_file,COMPRESS_FILE_PTR output_file)873 static int compress_file(FILE *input_file, COMPRESS_FILE_PTR output_file) {
874 	char buffer[131072]; /* 128kB */
875 	size_t bytes;
876 	size_t total_bytes = 0;
877 
878 	while ((bytes = fread(buffer, 1, sizeof(buffer), input_file)) > 0) {
879 #ifdef HAVE_ZLIB
880 		int res = gzwrite(output_file, buffer, (unsigned int)bytes);
881 		if (res < 0) return 0;
882 		total_bytes += (size_t)res;
883 #else
884 		total_bytes += fwrite(buffer, 1, bytes, output_file);
885 #endif
886 	}
887 	return (int)total_bytes;
888 }
889 
prepare_log_collection_file_to_upload(const char * filename)890 static int prepare_log_collection_file_to_upload(const char *filename) {
891 	char *input_filename = NULL;
892 	char *output_filename = NULL;
893 	FILE *input_file = NULL;
894 	COMPRESS_FILE_PTR output_file = NULL;
895 	int ret = 0;
896 
897 	ortp_mutex_lock(&liblinphone_log_collection_mutex);
898 	output_filename = ms_strdup_printf("%s/%s",
899 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
900 	output_file = COMPRESS_OPEN(output_filename, "wb");
901 	if (output_file == NULL) goto error;
902 	input_filename = ms_strdup_printf("%s/%s1.log",
903 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
904 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
905 	input_file = fopen(input_filename, "rb");
906 	if (input_file == NULL) goto error;
907 	ret = compress_file(input_file, output_file);
908 	if (ret <= 0) goto error;
909 	fclose(input_file);
910 	ms_free(input_filename);
911 	input_filename = ms_strdup_printf("%s/%s2.log",
912 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
913 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
914 	input_file = fopen(input_filename, "rb");
915 	if (input_file != NULL) {
916 		ret = compress_file(input_file, output_file);
917 		if (ret <= 0) goto error;
918 	}
919 
920 error:
921 	if (input_file != NULL) fclose(input_file);
922 	if (output_file != NULL) COMPRESS_CLOSE(output_file);
923 	if (input_filename != NULL) ms_free(input_filename);
924 	if (output_filename != NULL) ms_free(output_filename);
925 	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
926 	return ret;
927 }
928 
get_size_of_file_to_upload(const char * filename)929 static size_t get_size_of_file_to_upload(const char *filename) {
930 	struct stat statbuf;
931 	char *output_filename = ms_strdup_printf("%s/%s",
932 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
933 	FILE *output_file = fopen(output_filename, "rb");
934 	fstat(fileno(output_file), &statbuf);
935 	fclose(output_file);
936 	ms_free(output_filename);
937 	return statbuf.st_size;
938 }
939 
linphone_core_upload_log_collection(LinphoneCore * core)940 void linphone_core_upload_log_collection(LinphoneCore *core) {
941 	if ((core->log_collection_upload_information == NULL) && (linphone_core_get_log_collection_upload_server_url(core) != NULL) && (liblinphone_log_collection_state != LinphoneLogCollectionDisabled)) {
942 		/* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */
943 		belle_http_request_listener_callbacks_t cbs = { 0 };
944 		belle_http_request_listener_t *l;
945 		belle_generic_uri_t *uri;
946 		belle_http_request_t *req;
947 		char *name;
948 
949 		core->log_collection_upload_information = linphone_core_create_content(core);
950 #ifdef HAVE_ZLIB
951 		linphone_content_set_type(core->log_collection_upload_information, "application");
952 		linphone_content_set_subtype(core->log_collection_upload_information, "gzip");
953 #else
954 		linphone_content_set_type(core->log_collection_upload_information, "text");
955 		linphone_content_set_subtype(core->log_collection_upload_information,"plain");
956 #endif
957 		name = ms_strdup_printf("%s_log.%s",
958 			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
959 			COMPRESSED_LOG_COLLECTION_EXTENSION);
960 		linphone_content_set_name(core->log_collection_upload_information, name);
961 		if (prepare_log_collection_file_to_upload(name) <= 0) {
962 			linphone_content_unref(core->log_collection_upload_information);
963 			core->log_collection_upload_information = NULL;
964 			ms_error("prepare_log_collection_file_to_upload(): error.");
965 			linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Error while preparing log collection upload");
966 			return;
967 		}
968 		linphone_content_set_size(core->log_collection_upload_information, get_size_of_file_to_upload(name));
969 		uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
970 		req = belle_http_request_create("POST", uri, NULL, NULL, NULL);
971 		cbs.process_response = process_response_from_post_file_log_collection;
972 		cbs.process_io_error = process_io_error_upload_log_collection;
973 		cbs.process_auth_requested = process_auth_requested_upload_log_collection;
974 		l = belle_http_request_listener_create_from_callbacks(&cbs, core);
975 		belle_sip_object_data_set(BELLE_SIP_OBJECT(req), "http_request_listener", l, belle_sip_object_unref); // Ensure the listener object is destroyed when the request is destroyed
976 		belle_http_provider_send_request(core->http_provider, req, l);
977 		ms_free(name);
978 	} else {
979 		const char *msg = NULL;
980 		ms_warning("Could not upload log collection: log_collection_upload_information=%p, server_url=%s, log_collection_state=%d",
981 			core->log_collection_upload_information, linphone_core_get_log_collection_upload_server_url(core), liblinphone_log_collection_state);
982 		if (core->log_collection_upload_information != NULL) {
983 			msg = "Log collection upload already in progress";
984 		} else if (linphone_core_get_log_collection_upload_server_url(core) == NULL) {
985 			msg = "Log collection upload server not set";
986 		} else if (liblinphone_log_collection_state == LinphoneLogCollectionDisabled) {
987 			msg = "Log collection is disabled";
988 		}
989 		linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, msg);
990 	}
991 }
992 
linphone_core_compress_log_collection(void)993 char * linphone_core_compress_log_collection(void) {
994 	char *filename = NULL;
995 	if (liblinphone_log_collection_state == LinphoneLogCollectionDisabled) return NULL;
996 	filename = ms_strdup_printf("%s_log.%s",
997 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
998 		COMPRESSED_LOG_COLLECTION_EXTENSION);
999 	if (prepare_log_collection_file_to_upload(filename) <= 0) {
1000 		ms_free(filename);
1001 		return NULL;
1002 	}
1003 	ms_free(filename);
1004 	return ms_strdup_printf("%s/%s_log.%s",
1005 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
1006 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
1007 		COMPRESSED_LOG_COLLECTION_EXTENSION);
1008 }
1009 
linphone_core_reset_log_collection(void)1010 void linphone_core_reset_log_collection(void) {
1011 	char *filename;
1012 	ortp_mutex_lock(&liblinphone_log_collection_mutex);
1013 	_close_log_collection_file();
1014 	clean_log_collection_upload_context(NULL);
1015 	filename = ms_strdup_printf("%s/%s1.log",
1016 			liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
1017 			liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
1018 	unlink(filename);
1019 	ms_free(filename);
1020 	filename = ms_strdup_printf("%s/%s2.log",
1021 		liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
1022 		liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
1023 	unlink(filename);
1024 	ms_free(filename);
1025 	liblinphone_log_collection_file = NULL;
1026 	liblinphone_log_collection_file_size = 0;
1027 	ortp_mutex_unlock(&liblinphone_log_collection_mutex);
1028 }
1029 
linphone_core_enable_logs(FILE * file)1030 void linphone_core_enable_logs(FILE *file){
1031 	if (file==NULL) file=stdout;
1032 	ortp_set_log_file(file);
1033 	linphone_core_set_log_level(ORTP_MESSAGE);
1034 }
1035 
linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc)1036 void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){
1037 	linphone_core_set_log_level(ORTP_MESSAGE);
1038 	linphone_core_set_log_handler(logfunc);
1039 }
1040 
linphone_core_disable_logs(void)1041 void linphone_core_disable_logs(void){
1042 	linphone_core_set_log_level(ORTP_ERROR);
1043 }
1044 
linphone_core_serialize_logs(void)1045 void linphone_core_serialize_logs(void) {
1046 	liblinphone_serialize_logs = TRUE;
1047 }
1048 
1049 
net_config_read(LinphoneCore * lc)1050 static void net_config_read(LinphoneCore *lc) {
1051 	int tmp;
1052 	const char *tmpstr;
1053 	LpConfig *config=lc->config;
1054 	const char *nat_policy_ref;
1055 
1056 	nat_policy_ref = lp_config_get_string(lc->config, "net", "nat_policy_ref", NULL);
1057 	if (nat_policy_ref != NULL) {
1058 		lc->nat_policy = linphone_core_create_nat_policy_from_config(lc, nat_policy_ref);
1059 	}
1060 	if (lc->nat_policy == NULL){
1061 		/*this will create a default nat policy according to deprecated config keys, or an empty nat policy otherwise*/
1062 		linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc));
1063 	}
1064 
1065 	lc->net_conf.nat_address_ip = NULL;
1066 	tmp=lp_config_get_int(config,"net","download_bw",0);
1067 	linphone_core_set_download_bandwidth(lc,tmp);
1068 	tmp=lp_config_get_int(config,"net","upload_bw",0);
1069 	linphone_core_set_upload_bandwidth(lc,tmp);
1070 	tmp=lp_config_get_int(config, "net", "expected_bw", 0);
1071 	linphone_core_set_expected_bandwidth(lc, tmp);
1072 
1073 	tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL);
1074 	if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL;
1075 	linphone_core_set_nat_address(lc,tmpstr);
1076 	tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0);
1077 	lc->net_conf.nat_sdp_only=tmp;
1078 	tmp=lp_config_get_int(lc->config,"net","mtu",1300);
1079 	linphone_core_set_mtu(lc,tmp);
1080 	tmp=lp_config_get_int(lc->config,"net","download_ptime",-1);
1081 	if (tmp !=-1 && linphone_core_get_download_ptime(lc) !=0) {
1082 		/*legacy parameter*/
1083 		linphone_core_set_download_ptime(lc,tmp);
1084 	}
1085 	tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1);
1086 	linphone_core_enable_dns_srv(lc, tmp);
1087 	tmp = lp_config_get_int(lc->config, "net", "dns_search_enabled", 1);
1088 	linphone_core_enable_dns_search(lc, tmp);
1089 }
1090 
build_sound_devices_table(LinphoneCore * lc)1091 static void build_sound_devices_table(LinphoneCore *lc){
1092 	const char **devices;
1093 	const char **old;
1094 	size_t ndev;
1095 	int i;
1096 	const bctbx_list_t *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(lc->factory));
1097 	ndev=bctbx_list_size(elem);
1098 	devices=ms_malloc((ndev+1)*sizeof(const char *));
1099 	for (i=0;elem!=NULL;elem=elem->next,i++){
1100 		devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data);
1101 	}
1102 	devices[ndev]=NULL;
1103 	old=lc->sound_conf.cards;
1104 	lc->sound_conf.cards=devices;
1105 	if (old!=NULL) ms_free((void *)old);
1106 }
1107 
get_default_local_ring(LinphoneCore * lc)1108 static char *get_default_local_ring(LinphoneCore * lc) {
1109 	LinphoneFactory *factory = linphone_factory_get();
1110 	if (linphone_core_file_format_supported(lc, "mkv")) {
1111 		return bctbx_strdup_printf("%s/%s", linphone_factory_get_ring_resources_dir(factory), LOCAL_RING_MKV);
1112 	}
1113 	return bctbx_strdup_printf("%s/%s", linphone_factory_get_ring_resources_dir(factory), LOCAL_RING_WAV);
1114 }
1115 
get_default_onhold_music(LinphoneCore * lc)1116 static char *get_default_onhold_music(LinphoneCore * lc) {
1117 	LinphoneFactory *factory = linphone_factory_get();
1118 	if (linphone_core_file_format_supported(lc, "mkv")) {
1119 		return bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), HOLD_MUSIC_MKV);
1120 	}
1121 	return bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), HOLD_MUSIC_WAV);
1122 }
1123 
sound_config_read(LinphoneCore * lc)1124 static void sound_config_read(LinphoneCore *lc)
1125 {
1126 	int tmp;
1127 	char *default_remote_ring;
1128 	const char *tmpbuf;
1129 	const char *devid;
1130 	LinphoneFactory *factory = linphone_factory_get();
1131 
1132 #ifdef __linux
1133 	/*alsadev let the user use custom alsa device within linphone*/
1134 	devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
1135 	if (devid){
1136 		MSSndCard* card;
1137 		const char* delim=",";
1138 		size_t l=strlen(devid);
1139 		char* d=malloc(l+1);
1140 		char* i;
1141 		memcpy(d,devid,l+1);
1142 		for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){
1143 			char s=*i;
1144 			*i='\0';
1145 			card=ms_alsa_card_new_custom(d+l,d+l);
1146 			ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
1147 			*i=s;
1148 			l=i-d+1;
1149 		}
1150 		if(d[l]!='\0') {
1151 			card=ms_alsa_card_new_custom(d+l,d+l);
1152 			ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
1153 		}
1154 		free(d);
1155 	}
1156 	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
1157 	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
1158 #endif
1159 	/* retrieve all sound devices */
1160 	build_sound_devices_table(lc);
1161 
1162 	devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
1163 	linphone_core_set_playback_device(lc,devid);
1164 
1165 	devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
1166 	linphone_core_set_ringer_device(lc,devid);
1167 
1168 	devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
1169 	linphone_core_set_capture_device(lc,devid);
1170 
1171 /*
1172 	tmp=lp_config_get_int(lc->config,"sound","play_lev",80);
1173 	linphone_core_set_play_level(lc,tmp);
1174 	tmp=lp_config_get_int(lc->config,"sound","ring_lev",80);
1175 	linphone_core_set_ring_level(lc,tmp);
1176 	tmp=lp_config_get_int(lc->config,"sound","rec_lev",80);
1177 	linphone_core_set_rec_level(lc,tmp);
1178 	tmpbuf=lp_config_get_string(lc->config,"sound","source","m");
1179 	linphone_core_set_sound_source(lc,tmpbuf[0]);
1180 */
1181 
1182 	tmpbuf = lp_config_get_string(lc->config, "sound", "local_ring", NULL);
1183 	if (tmpbuf) {
1184 		if (bctbx_file_exist(tmpbuf) == 0) {
1185 			linphone_core_set_ring(lc, tmpbuf);
1186 		} else {
1187 			ms_warning("'%s' ring file does not exist", tmpbuf);
1188 		}
1189 	} else {
1190 		char *default_local_ring = get_default_local_ring(lc);
1191 		linphone_core_set_ring(lc, default_local_ring);
1192 		bctbx_free(default_local_ring);
1193 	}
1194 
1195 	default_remote_ring = bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), REMOTE_RING_WAV);
1196 	tmpbuf = default_remote_ring;
1197 	tmpbuf = lp_config_get_string(lc->config, "sound", "remote_ring", tmpbuf);
1198 	if (bctbx_file_exist(tmpbuf) == -1){
1199 		tmpbuf = default_remote_ring;
1200 	}
1201 	if (strstr(tmpbuf, ".wav") == NULL) {
1202 		/* It currently uses old sound files, so replace them */
1203 		tmpbuf = default_remote_ring;
1204 	}
1205 	linphone_core_set_ringback(lc, tmpbuf);
1206 	bctbx_free(default_remote_ring);
1207 
1208 	tmpbuf = lp_config_get_string(lc->config, "sound", "hold_music", NULL);
1209 	if (tmpbuf) {
1210 		if (bctbx_file_exist(tmpbuf) == 0) {
1211 			linphone_core_set_play_file(lc, tmpbuf);
1212 		} else {
1213 			ms_warning("'%s' on-hold music file does not exist", tmpbuf);
1214 		}
1215 	} else {
1216 		char *default_onhold_music = get_default_onhold_music(lc);
1217 		linphone_core_set_play_file(lc, default_onhold_music);
1218 		bctbx_free(default_onhold_music);
1219 	}
1220 
1221 	lc->sound_conf.latency=0;
1222 #if !TARGET_OS_IPHONE
1223 	tmp=TRUE;
1224 #else
1225 	tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
1226 #endif
1227 	tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp);
1228 	linphone_core_enable_echo_cancellation(lc,tmp);
1229 	linphone_core_set_echo_canceller_filter_name(lc, linphone_core_get_echo_canceller_filter_name(lc));
1230 	linphone_core_enable_echo_limiter(lc,
1231 		lp_config_get_int(lc->config,"sound","echolimiter",0));
1232 	linphone_core_enable_agc(lc,
1233 		lp_config_get_int(lc->config,"sound","agc",0));
1234 
1235 	linphone_core_set_playback_gain_db (lc,lp_config_get_float(lc->config,"sound","playback_gain_db",0));
1236 	linphone_core_set_mic_gain_db (lc,lp_config_get_float(lc->config,"sound","mic_gain_db",0));
1237 
1238 	linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
1239 
1240 	/*just parse requested stream feature once at start to print out eventual errors*/
1241 	linphone_core_get_audio_features(lc);
1242 
1243 	_linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL);
1244 }
1245 
certificates_config_read(LinphoneCore * lc)1246 static void certificates_config_read(LinphoneCore *lc) {
1247 	LinphoneFactory *factory = linphone_factory_get();
1248 	const char *data_dir = linphone_factory_get_data_resources_dir(factory);
1249 	char *root_ca_path = bctbx_strdup_printf("%s/rootca.pem", data_dir);
1250 	const char *rootca = lp_config_get_string(lc->config,"sip","root_ca", NULL);
1251 	// If rootca is not existing anymore, we reset it to the default value
1252 	if (rootca == NULL || (bctbx_file_exist(rootca) != 0)) {
1253 #ifdef __linux
1254 		struct stat sb;
1255 		if (stat("/etc/ssl/certs", &sb) == 0 && S_ISDIR(sb.st_mode)) {
1256 			rootca = "/etc/ssl/certs";
1257 		} else
1258 #endif
1259 		{
1260 			if (bctbx_file_exist(root_ca_path) == 0) {
1261 				rootca = root_ca_path;
1262 			}
1263 		}
1264 	}
1265 	linphone_core_set_root_ca(lc,rootca);
1266 	linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE));
1267 	linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE));
1268 	bctbx_free(root_ca_path);
1269 }
1270 
sip_config_read(LinphoneCore * lc)1271 static void sip_config_read(LinphoneCore *lc) {
1272 	char *contact;
1273 	const char *tmpstr;
1274 	LinphoneSipTransports tr;
1275 	int i,tmp;
1276 	int ipv6_default = TRUE;
1277 
1278 	if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
1279 		sal_use_session_timers(lc->sal,200);
1280 	}
1281 
1282 	sal_use_no_initial_route(lc->sal,lp_config_get_int(lc->config,"sip","use_no_initial_route",0));
1283 	sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));
1284 
1285 	if (!lp_config_get_int(lc->config,"sip","ipv6_migration_done",FALSE) && lp_config_has_entry(lc->config,"sip","use_ipv6")) {
1286 		lp_config_clean_entry(lc->config,"sip","use_ipv6");
1287 		lp_config_set_int(lc->config, "sip", "ipv6_migration_done", TRUE);
1288 		ms_message("IPV6 settings migration done.");
1289 	}
1290 
1291 	lc->sip_conf.ipv6_enabled=lp_config_get_int(lc->config,"sip","use_ipv6",ipv6_default);
1292 
1293 	memset(&tr,0,sizeof(tr));
1294 
1295 	tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060);
1296 	tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060);
1297 	/*we are not listening inbound connection for tls, port has no meaning*/
1298 	tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM);
1299 
1300 	certificates_config_read(lc);
1301 	/*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/
1302 	sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
1303 	/*start listening on ports*/
1304 	linphone_core_set_sip_transports(lc,&tr);
1305 
1306 	tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL);
1307 	if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) {
1308 		const char *hostname=NULL;
1309 		const char *username=NULL;
1310 #if !defined(LINPHONE_WINDOWS_UNIVERSAL) && !defined(LINPHONE_WINDOWS_PHONE) // Using getenv is forbidden on Windows 10 and Windows Phone
1311 		hostname=getenv("HOST");
1312 		username=getenv("USER");
1313 		if (hostname==NULL) hostname=getenv("HOSTNAME");
1314 #endif
1315 		if (hostname==NULL)
1316 			hostname="unknown-host";
1317 		if (username==NULL){
1318 			username="linphone";
1319 		}
1320 		contact=ortp_strdup_printf("sip:%s@%s",username,hostname);
1321 		linphone_core_set_primary_contact(lc,contact);
1322 		ms_free(contact);
1323 	}
1324 
1325 	tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1);
1326 	linphone_core_set_guess_hostname(lc,tmp);
1327 
1328 	tmp=lp_config_get_int(lc->config,"sip","lime",FALSE);
1329 	linphone_core_enable_lime(lc,tmp);
1330 
1331 	tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30);
1332 	linphone_core_set_inc_timeout(lc,tmp);
1333 
1334 	tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
1335 	linphone_core_set_in_call_timeout(lc,tmp);
1336 
1337 	tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4);
1338 	linphone_core_set_delayed_timeout(lc,tmp);
1339 
1340 	/* get proxies config */
1341 	for(i=0;; i++){
1342 		LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc,i);
1343 		if (cfg!=NULL){
1344 			linphone_core_add_proxy_config(lc,cfg);
1345 			linphone_proxy_config_unref(cfg);
1346 		}else{
1347 			break;
1348 		}
1349 	}
1350 	/* get the default proxy */
1351 	tmp=lp_config_get_int(lc->config,"sip","default_proxy",-1);
1352 	linphone_core_set_default_proxy_index(lc,tmp);
1353 
1354 	/* read authentication information */
1355 	for(i=0;; i++){
1356 		LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i);
1357 		if (ai!=NULL){
1358 			linphone_core_add_auth_info(lc,ai);
1359 			linphone_auth_info_unref(ai);
1360 		}else{
1361 			break;
1362 		}
1363 	}
1364 	/*this is to filter out unsupported encryption schemes*/
1365 	linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
1366 
1367 	/*for tuning or test*/
1368 	lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
1369 	lc->sip_conf.register_only_when_network_is_up=
1370 		lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
1371 	lc->sip_conf.register_only_when_upnp_is_ok=
1372 		lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1);
1373 	lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",0);
1374 	lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1);
1375 	lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000);
1376 	lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0);
1377 	linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
1378 	sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
1379 	sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
1380 	sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1));
1381 	lc->sip_conf.vfu_with_info=lp_config_get_int(lc->config,"sip","vfu_with_info",1);
1382 	linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000));
1383 	sal_set_supported_tags(lc->sal,lp_config_get_string(lc->config,"sip","supported","replaces, outbound"));
1384 	lc->sip_conf.save_auth_info = lp_config_get_int(lc->config, "sip", "save_auth_info", 1);
1385 	linphone_core_create_im_notif_policy(lc);
1386 }
1387 
rtp_config_read(LinphoneCore * lc)1388 static void rtp_config_read(LinphoneCore *lc) {
1389 	int min_port, max_port;
1390 	int jitt_comp;
1391 	int nortp_timeout;
1392 	bool_t rtp_no_xmit_on_audio_mute;
1393 	bool_t adaptive_jitt_comp_enabled;
1394 	const char* tmp;
1395 	int tmp_int;
1396 
1397 	if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
1398 		if (min_port <= 0) min_port = 1;
1399 		if (max_port > 65535) max_port = 65535;
1400 		linphone_core_set_audio_port_range(lc, min_port, max_port);
1401 	} else {
1402 		min_port = lp_config_get_int(lc->config, "rtp", "audio_rtp_port", 7078);
1403 		linphone_core_set_audio_port(lc, min_port);
1404 	}
1405 
1406 	if (lp_config_get_range(lc->config, "rtp", "video_rtp_port", &min_port, &max_port, 9078, 9078) == TRUE) {
1407 		if (min_port <= 0) min_port = 1;
1408 		if (max_port > 65535) max_port = 65535;
1409 		linphone_core_set_video_port_range(lc, min_port, max_port);
1410 	} else {
1411 		min_port = lp_config_get_int(lc->config, "rtp", "video_rtp_port", 9078);
1412 		linphone_core_set_video_port(lc, min_port);
1413 	}
1414 
1415 	if (lp_config_get_range(lc->config, "rtp", "text_rtp_port", &min_port, &max_port, 11078, 11078) == TRUE) {
1416 		if (min_port <= 0) min_port = 1;
1417 		if (max_port > 65535) max_port = 65535;
1418 		linphone_core_set_text_port_range(lc, min_port, max_port);
1419 	} else {
1420 		min_port = lp_config_get_int(lc->config, "rtp", "text_rtp_port", 11078);
1421 		linphone_core_set_text_port(lc, min_port);
1422 	}
1423 
1424 	jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
1425 	linphone_core_set_audio_jittcomp(lc,jitt_comp);
1426 	jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
1427 	if (jitt_comp==0) jitt_comp=60;
1428 	linphone_core_set_video_jittcomp(lc,jitt_comp);
1429 	nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
1430 	linphone_core_set_nortp_timeout(lc,nortp_timeout);
1431 	rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE);
1432 	linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_no_xmit_on_audio_mute);
1433 	adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "audio_adaptive_jitt_comp_enabled", TRUE);
1434 	linphone_core_enable_audio_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
1435 	adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE);
1436 	linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
1437 	lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE);
1438 	linphone_core_set_avpf_mode(lc,lp_config_get_int(lc->config,"rtp","avpf",0));
1439 	if ((tmp=lp_config_get_string(lc->config,"rtp","audio_multicast_addr",NULL)))
1440 		linphone_core_set_audio_multicast_addr(lc,tmp);
1441 	else
1442 		lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3");
1443 	if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1)
1444 		linphone_core_enable_audio_multicast(lc,tmp_int);
1445 	if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0)
1446 			linphone_core_set_audio_multicast_ttl(lc,tmp_int);
1447 	else
1448 		lc->rtp_conf.audio_multicast_ttl=1;/*local network*/
1449 	if ((tmp=lp_config_get_string(lc->config,"rtp","video_multicast_addr",NULL)))
1450 		linphone_core_set_video_multicast_addr(lc,tmp);
1451 	else
1452 		lc->rtp_conf.video_multicast_addr=ms_strdup("224.1.2.3");
1453 	if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_ttl",-1))>-1)
1454 		linphone_core_set_video_multicast_ttl(lc,tmp_int);
1455 	else
1456 		lc->rtp_conf.video_multicast_ttl=1;/*local network*/
1457 	if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_enabled",-1)) >0)
1458 		linphone_core_enable_video_multicast(lc,tmp_int);
1459 }
1460 
find_payload(const bctbx_list_t * default_list,const char * mime_type,int clock_rate,int channels,const char * recv_fmtp)1461 static PayloadType * find_payload(const bctbx_list_t *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
1462 	PayloadType *candidate=NULL;
1463 	PayloadType *it;
1464 	const bctbx_list_t *elem;
1465 
1466 	for(elem=default_list;elem!=NULL;elem=elem->next){
1467 		it=(PayloadType*)elem->data;
1468 		if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
1469 			&& (clock_rate==it->clock_rate || clock_rate<=0)
1470 			&& (channels==it->channels || channels<=0) ){
1471 			if ( (recv_fmtp && it->recv_fmtp && strstr(recv_fmtp,it->recv_fmtp)!=NULL) ||
1472 				(recv_fmtp==NULL && it->recv_fmtp==NULL) ){
1473 				/*exact match*/
1474 				if (recv_fmtp) payload_type_set_recv_fmtp(it,recv_fmtp);
1475 				return it;
1476 			}else {
1477 				if (candidate){
1478 					if (it->recv_fmtp==NULL) candidate=it;
1479 				}else candidate=it;
1480 			}
1481 		}
1482 	}
1483 	if (candidate && recv_fmtp){
1484 		payload_type_set_recv_fmtp(candidate,recv_fmtp);
1485 	}
1486 	return candidate;
1487 }
1488 
find_payload_type_from_list(const char * type,int rate,int channels,const bctbx_list_t * from)1489 static PayloadType* find_payload_type_from_list(const char* type, int rate, int channels, const bctbx_list_t* from) {
1490 	const bctbx_list_t *elem;
1491 	for(elem=from;elem!=NULL;elem=elem->next){
1492 		PayloadType *pt=(PayloadType*)elem->data;
1493 		if ((strcasecmp(type, payload_type_get_mime(pt)) == 0)
1494 			&& (rate == LINPHONE_FIND_PAYLOAD_IGNORE_RATE || rate==pt->clock_rate)
1495 			&& (channels == LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS || channels==pt->channels)) {
1496 			return pt;
1497 		}
1498 	}
1499 	return NULL;
1500 }
1501 
linphone_core_codec_supported(LinphoneCore * lc,SalStreamType type,const char * mime)1502 static bool_t linphone_core_codec_supported(LinphoneCore *lc, SalStreamType type, const char *mime){
1503 	if (type == SalVideo && lp_config_get_int(lc->config, "video", "rtp_io", FALSE)){
1504 		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.*/
1505 	} else if (type == SalAudio && lp_config_get_int(lc->config, "sound", "rtp_io", FALSE)){
1506 		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.*/
1507 	} else if (type == SalText) {
1508 		return TRUE;
1509 	}
1510 	return ms_factory_codec_supported(lc->factory, mime);
1511 }
1512 
1513 
get_codec(LinphoneCore * lc,SalStreamType type,int index,PayloadType ** ret)1514 static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, PayloadType **ret){
1515 	char codeckey[50];
1516 	const char *mime,*fmtp;
1517 	int rate,channels,enabled;
1518 	PayloadType *pt;
1519 	LpConfig *config=lc->config;
1520 
1521 	*ret=NULL;
1522 	snprintf(codeckey,50,"%s_codec_%i",type == SalAudio ? "audio" : type == SalVideo ? "video" : "text", index);
1523 	mime=lp_config_get_string(config,codeckey,"mime",NULL);
1524 	if (mime==NULL || strlen(mime)==0 ) return FALSE;
1525 
1526 	rate=lp_config_get_int(config,codeckey,"rate",8000);
1527 	fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
1528 	channels=lp_config_get_int(config,codeckey,"channels",0);
1529 	enabled=lp_config_get_int(config,codeckey,"enabled",1);
1530 	if (!linphone_core_codec_supported(lc, type, mime)){
1531 		ms_warning("Codec %s/%i read from conf is not supported by mediastreamer2, ignored.",mime,rate);
1532 		return TRUE;
1533 	}
1534 	pt = find_payload(type == SalAudio ? lc->default_audio_codecs : type == SalVideo ? lc->default_video_codecs : lc->default_text_codecs ,mime,rate,channels,fmtp);
1535 	if (!pt){
1536 		bctbx_list_t **default_list = (type==SalAudio) ? &lc->default_audio_codecs : type == SalVideo ? &lc->default_video_codecs : &lc->default_text_codecs;
1537 		if (type == SalAudio)
1538 			ms_warning("Codec %s/%i/%i read from conf is not in the default list.",mime,rate,channels);
1539 		else if (type == SalVideo)
1540 			ms_warning("Codec %s/%i read from conf is not in the default list.",mime,rate);
1541 		else
1542 			ms_warning("Codec %s read from conf is not in the default list.",mime);
1543 		pt=payload_type_new();
1544 		pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : type == SalVideo ? PAYLOAD_VIDEO : PAYLOAD_TEXT;
1545 		pt->mime_type=ortp_strdup(mime);
1546 		pt->clock_rate=rate;
1547 		pt->channels=channels;
1548 		payload_type_set_number(pt,-1); /*dynamic assignment*/
1549 		payload_type_set_recv_fmtp(pt,fmtp);
1550 		*default_list=bctbx_list_append(*default_list, pt);
1551 	}
1552 	if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
1553 	else pt->flags&=~PAYLOAD_TYPE_ENABLED;
1554 	*ret=pt;
1555 	return TRUE;
1556 }
1557 
payload_type_get_stream_type(const PayloadType * pt)1558 static SalStreamType payload_type_get_stream_type(const PayloadType *pt){
1559 	switch(pt->type){
1560 		case PAYLOAD_AUDIO_PACKETIZED:
1561 		case PAYLOAD_AUDIO_CONTINUOUS:
1562 			return SalAudio;
1563 		break;
1564 		case PAYLOAD_VIDEO:
1565 			return SalVideo;
1566 		break;
1567 		case PAYLOAD_TEXT:
1568 			return SalText;
1569 		break;
1570 	}
1571 	return SalOther;
1572 }
1573 
1574 /*this function merges the payload types from the codec default list with the list read from configuration file.
1575  * 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
1576  * automatically. This 'l' list is entirely destroyed and rewritten.*/
add_missing_supported_codecs(LinphoneCore * lc,const bctbx_list_t * default_list,bctbx_list_t * l)1577 static bctbx_list_t *add_missing_supported_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l){
1578 	const bctbx_list_t *elem;
1579 	bctbx_list_t *newlist;
1580 	PayloadType *last_seen = NULL;
1581 
1582 	for(elem=default_list; elem!=NULL; elem=elem->next){
1583 		bctbx_list_t *elem2=bctbx_list_find(l,elem->data);
1584 		if (!elem2){
1585 			PayloadType *pt=(PayloadType*)elem->data;
1586 			/*this codec from default list should be inserted in the list, with respect to the default_list order*/
1587 
1588 			if (!linphone_core_codec_supported(lc, payload_type_get_stream_type(pt), pt->mime_type)) continue;
1589 			if (!last_seen){
1590 				l=bctbx_list_prepend(l,pt);
1591 			}else{
1592 				const bctbx_list_t *after=bctbx_list_find(l,last_seen);
1593 				l=bctbx_list_insert(l, after->next, pt);
1594 			}
1595 			last_seen = pt;
1596 			ms_message("Supported codec %s/%i fmtp=%s automatically added to codec list.", pt->mime_type,
1597 				   pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : "");
1598 		}else{
1599 			last_seen = (PayloadType*)elem2->data;
1600 		}
1601 	}
1602 	newlist=bctbx_list_copy_with_data(l,(void *(*)(void*))payload_type_clone);
1603 	bctbx_list_free(l);
1604 	return newlist;
1605 }
1606 
1607 /*
1608  * This function adds missing codecs, if required by configuration.
1609  * This 'l' list is entirely destroyed and a new list is returned.
1610  */
handle_missing_codecs(LinphoneCore * lc,const bctbx_list_t * default_list,bctbx_list_t * l,MSFormatType ft)1611 static bctbx_list_t *handle_missing_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l, MSFormatType ft){
1612 	const char *name = "unknown";
1613 	int add_missing;
1614 	bctbx_list_t *ret;
1615 
1616 	switch(ft){
1617 		case MSAudio:
1618 			name = "add_missing_audio_codecs";
1619 		break;
1620 		case MSVideo:
1621 			name = "add_missing_video_codecs";
1622 		break;
1623 		case MSText:
1624 			name = "add_missing_text_codecs";
1625 		break;
1626 		case MSUnknownMedia:
1627 		break;
1628 	}
1629 	add_missing = lp_config_get_int(lc->config, "misc", name, 1);
1630 	if (add_missing){
1631 		ret = add_missing_supported_codecs(lc, default_list, l);
1632 	}else{
1633 		ret = bctbx_list_copy_with_data(l,(void *(*)(void*))payload_type_clone);
1634 		bctbx_list_free(l);
1635 	}
1636 	return ret;
1637 }
1638 
codec_append_if_new(bctbx_list_t * l,PayloadType * pt)1639 static bctbx_list_t *codec_append_if_new(bctbx_list_t *l, PayloadType *pt){
1640 	bctbx_list_t *elem;
1641 	for (elem=l;elem!=NULL;elem=elem->next){
1642 		PayloadType *ept=(PayloadType*)elem->data;
1643 		if (pt==ept)
1644 			return l;
1645 	}
1646 	l=bctbx_list_append(l,pt);
1647 	return l;
1648 }
1649 
codecs_config_read(LinphoneCore * lc)1650 static void codecs_config_read(LinphoneCore *lc){
1651 	int i;
1652 	PayloadType *pt;
1653 	bctbx_list_t *audio_codecs=NULL;
1654 	bctbx_list_t *video_codecs=NULL;
1655 	bctbx_list_t *text_codecs=NULL;
1656 
1657 	lc->codecs_conf.dyn_pt=96;
1658 	lc->codecs_conf.telephone_event_pt=lp_config_get_int(lc->config,"misc","telephone_event_pt",101);
1659 
1660 	for (i=0;get_codec(lc,SalAudio,i,&pt);i++){
1661 		if (pt){
1662 			audio_codecs=codec_append_if_new(audio_codecs, pt);
1663 		}
1664 	}
1665 	audio_codecs = handle_missing_codecs(lc, lc->default_audio_codecs,audio_codecs, MSAudio);
1666 
1667 	for (i=0;get_codec(lc,SalVideo,i,&pt);i++){
1668 		if (pt){
1669 			video_codecs=codec_append_if_new(video_codecs, pt);
1670 		}
1671 	}
1672 
1673 	video_codecs = handle_missing_codecs(lc, lc->default_video_codecs, video_codecs, MSVideo);
1674 
1675 	for (i=0;get_codec(lc,SalText,i,&pt);i++){
1676 		if (pt){
1677 			text_codecs=codec_append_if_new(text_codecs, pt);
1678 		}
1679 	}
1680 	text_codecs = add_missing_supported_codecs(lc, lc->default_text_codecs, text_codecs);
1681 
1682 	linphone_core_set_audio_codecs(lc,audio_codecs);
1683 	linphone_core_set_video_codecs(lc,video_codecs);
1684 	linphone_core_set_text_codecs(lc, text_codecs);
1685 	linphone_core_update_allocated_audio_bandwidth(lc);
1686 }
1687 
build_video_devices_table(LinphoneCore * lc)1688 static void build_video_devices_table(LinphoneCore *lc){
1689 	const bctbx_list_t *elem;
1690 	int i;
1691 	size_t ndev;
1692 	const char **devices;
1693 	if (lc->video_conf.cams)
1694 		ms_free((void *)lc->video_conf.cams);
1695 	/* retrieve all video devices */
1696 	elem=ms_web_cam_manager_get_list(ms_factory_get_web_cam_manager(lc->factory));
1697 	ndev=bctbx_list_size(elem);
1698 	devices=ms_malloc((ndev+1)*sizeof(const char *));
1699 	for (i=0;elem!=NULL;elem=elem->next,i++){
1700 		devices[i]=ms_web_cam_get_string_id((MSWebCam *)elem->data);
1701 	}
1702 	devices[ndev]=NULL;
1703 	lc->video_conf.cams=devices;
1704 }
1705 
video_config_read(LinphoneCore * lc)1706 static void video_config_read(LinphoneCore *lc){
1707 #ifdef VIDEO_ENABLED
1708 	int capture, display, self_view, reuse_source;
1709 	int automatic_video=1;
1710 	const char *str;
1711 	LinphoneVideoPolicy vpol;
1712 	memset(&vpol, 0, sizeof(LinphoneVideoPolicy));
1713 	build_video_devices_table(lc);
1714 
1715 	str=lp_config_get_string(lc->config,"video","device",NULL);
1716 	if (str && str[0]==0) str=NULL;
1717 	linphone_core_set_video_device(lc,str);
1718 
1719 	linphone_core_set_preferred_video_size_by_name(lc,
1720 		lp_config_get_string(lc->config,"video","size","vga"));
1721 
1722 	linphone_core_set_preview_video_size_by_name(lc,
1723 		lp_config_get_string(lc->config,"video","preview_size",NULL));
1724 
1725 	linphone_core_set_preferred_framerate(lc,lp_config_get_float(lc->config,"video","framerate",0));
1726 
1727 #if defined(__ANDROID__) || TARGET_OS_IPHONE
1728 	automatic_video=0;
1729 #endif
1730 	capture=lp_config_get_int(lc->config,"video","capture",1);
1731 	display=lp_config_get_int(lc->config,"video","display",1);
1732 	self_view=lp_config_get_int(lc->config,"video","self_view",1);
1733 	reuse_source=lp_config_get_int(lc->config,"video","reuse_source",0);
1734 	vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",automatic_video);
1735 	vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",automatic_video);
1736 	linphone_core_enable_video_capture(lc, capture);
1737 	linphone_core_enable_video_display(lc, display);
1738 	linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0));
1739 	linphone_core_enable_self_view(lc,self_view);
1740 	linphone_core_enable_video_source_reuse(lc, reuse_source);
1741 	linphone_core_set_video_policy(lc,&vpol);
1742 #endif
1743 }
1744 
read_friends_from_rc(LinphoneCore * lc)1745 static void read_friends_from_rc(LinphoneCore *lc)
1746 {
1747 	LinphoneFriend *lf = NULL;
1748 	int i;
1749 	for (i = 0; (lf = linphone_friend_new_from_config_file(lc, i)) != NULL; i++) {
1750 		linphone_core_add_friend(lc, lf);
1751 		linphone_friend_unref(lf);
1752 	}
1753 }
1754 
ui_config_read(LinphoneCore * lc)1755 static void ui_config_read(LinphoneCore *lc)
1756 {
1757 #ifndef SQLITE_STORAGE_ENABLED
1758 	read_friends_from_rc(lc);
1759 	lc->call_logs = call_logs_read_from_config_file(lc);
1760 #else
1761 	if (!lc->friends_db) {
1762 		read_friends_from_rc(lc);
1763 	}
1764 	if (!lc->logs_db) {
1765 		lc->call_logs = call_logs_read_from_config_file(lc);
1766 	}
1767 #endif
1768 }
1769 
1770 /*
1771 static void autoreplier_config_init(LinphoneCore *lc)
1772 {
1773 	autoreplier_config_t *config=&lc->autoreplier_conf;
1774 	config->enabled=lp_config_get_int(lc->config,"autoreplier","enabled",0);
1775 	config->after_seconds=lp_config_get_int(lc->config,"autoreplier","after_seconds",6);
1776 	config->max_users=lp_config_get_int(lc->config,"autoreplier","max_users",1);
1777 	config->max_rec_time=lp_config_get_int(lc->config,"autoreplier","max_rec_time",60);
1778 	config->max_rec_msg=lp_config_get_int(lc->config,"autoreplier","max_rec_msg",10);
1779 	config->message=lp_config_get_string(lc->config,"autoreplier","message",NULL);
1780 }
1781 */
1782 
linphone_core_tunnel_available(void)1783 bool_t linphone_core_tunnel_available(void){
1784 #ifdef TUNNEL_ENABLED
1785 	return TRUE;
1786 #else
1787 	return FALSE;
1788 #endif
1789 }
1790 
linphone_core_enable_adaptive_rate_control(LinphoneCore * lc,bool_t enabled)1791 void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled){
1792 	lp_config_set_int(lc->config,"net","adaptive_rate_control",(int)enabled);
1793 }
1794 
linphone_core_adaptive_rate_control_enabled(const LinphoneCore * lc)1795 bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){
1796 	return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE);
1797 }
1798 
linphone_core_set_adaptive_rate_algorithm(LinphoneCore * lc,const char * algorithm)1799 void linphone_core_set_adaptive_rate_algorithm(LinphoneCore *lc, const char* algorithm){
1800 	if (strcasecmp(algorithm, "basic") != 0 && strcasecmp(algorithm, "advanced") != 0) {
1801 		ms_warning("Unsupported adaptive rate algorithm [%s] on core [%p], using advanced",algorithm,lc);
1802 		linphone_core_set_adaptive_rate_algorithm(lc, "advanced");
1803 		return;
1804 	}
1805 	lp_config_set_string(lc->config,"net","adaptive_rate_algorithm",algorithm);
1806 }
1807 
linphone_core_get_adaptive_rate_algorithm(const LinphoneCore * lc)1808 const char * linphone_core_get_adaptive_rate_algorithm(const LinphoneCore *lc){
1809 	const char* saved_value = lp_config_get_string(lc->config, "net", "adaptive_rate_algorithm", "advanced");
1810 	if (strcasecmp(saved_value, "basic") != 0 && strcasecmp(saved_value, "advanced") != 0) {
1811 		ms_warning("Unsupported adaptive rate algorithm [%s] on core [%p]",saved_value,lc);
1812 	}
1813 	return saved_value;
1814 }
1815 
linphone_core_rtcp_enabled(const LinphoneCore * lc)1816 bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
1817 	return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE);
1818 }
1819 
linphone_core_set_download_bandwidth(LinphoneCore * lc,int bw)1820 void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
1821 	lc->net_conf.download_bw=bw;
1822 	linphone_core_update_allocated_audio_bandwidth(lc);
1823 	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
1824 }
1825 
linphone_core_set_upload_bandwidth(LinphoneCore * lc,int bw)1826 void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
1827 	lc->net_conf.upload_bw=bw;
1828 	linphone_core_update_allocated_audio_bandwidth(lc);
1829 	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
1830 }
1831 
linphone_core_set_expected_bandwidth(LinphoneCore * lc,int bw)1832 void linphone_core_set_expected_bandwidth(LinphoneCore *lc, int bw){
1833 	ms_factory_set_expected_bandwidth(lc->factory, bw * 1000); // In linphone we use kbits/s, in ms2 bits/s
1834 	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","expected_bw",bw);
1835 }
1836 
linphone_core_set_sip_transport_timeout(LinphoneCore * lc,int timeout_ms)1837 void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms) {
1838 	sal_set_transport_timeout(lc->sal, timeout_ms);
1839 	if (linphone_core_ready(lc))
1840 		lp_config_set_int(lc->config, "sip", "transport_timeout", timeout_ms);
1841 }
1842 
linphone_core_get_sip_transport_timeout(LinphoneCore * lc)1843 int linphone_core_get_sip_transport_timeout(LinphoneCore *lc) {
1844 	return sal_get_transport_timeout(lc->sal);
1845 }
1846 
linphone_core_set_dns_servers(LinphoneCore * lc,const bctbx_list_t * servers)1847 void linphone_core_set_dns_servers(LinphoneCore *lc, const bctbx_list_t *servers){
1848 	sal_set_dns_servers(lc->sal, servers);
1849 }
1850 
linphone_core_enable_dns_srv(LinphoneCore * lc,bool_t enable)1851 void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable) {
1852 	sal_enable_dns_srv(lc->sal, enable);
1853 	if (linphone_core_ready(lc))
1854 		lp_config_set_int(lc->config, "net", "dns_srv_enabled", enable ? 1 : 0);
1855 }
1856 
linphone_core_dns_srv_enabled(const LinphoneCore * lc)1857 bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc) {
1858 	return sal_dns_srv_enabled(lc->sal);
1859 }
1860 
linphone_core_enable_dns_search(LinphoneCore * lc,bool_t enable)1861 void linphone_core_enable_dns_search(LinphoneCore *lc, bool_t enable) {
1862 	sal_enable_dns_search(lc->sal, enable);
1863 	if (linphone_core_ready(lc))
1864 		lp_config_set_int(lc->config, "net", "dns_search_enabled", enable ? 1 : 0);
1865 }
1866 
linphone_core_dns_search_enabled(const LinphoneCore * lc)1867 bool_t linphone_core_dns_search_enabled(const LinphoneCore *lc) {
1868 	return sal_dns_search_enabled(lc->sal);
1869 }
1870 
linphone_core_get_download_bandwidth(const LinphoneCore * lc)1871 int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
1872 	return lc->net_conf.download_bw;
1873 }
1874 
linphone_core_get_upload_bandwidth(const LinphoneCore * lc)1875 int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
1876 	return lc->net_conf.upload_bw;
1877 }
1878 
linphone_core_set_download_ptime(LinphoneCore * lc,int ptime)1879 void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
1880 	lp_config_set_int(lc->config,"rtp","download_ptime",ptime);
1881 }
1882 
linphone_core_get_download_ptime(LinphoneCore * lc)1883 int linphone_core_get_download_ptime(LinphoneCore *lc) {
1884 	return lp_config_get_int(lc->config,"rtp","download_ptime",0);
1885 }
1886 
linphone_core_set_upload_ptime(LinphoneCore * lc,int ptime)1887 void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){
1888 	lp_config_set_int(lc->config,"rtp","upload_ptime",ptime);
1889 }
1890 
linphone_core_get_upload_ptime(LinphoneCore * lc)1891 int linphone_core_get_upload_ptime(LinphoneCore *lc){
1892 	return lp_config_get_int(lc->config,"rtp","upload_ptime",0);
1893 }
1894 
linphone_core_get_version(void)1895 const char * linphone_core_get_version(void){
1896 	return liblinphone_version;
1897 }
1898 
linphone_core_register_payload_type(LinphoneCore * lc,const PayloadType * const_pt,const char * recv_fmtp,bool_t enabled)1899 static void linphone_core_register_payload_type(LinphoneCore *lc, const PayloadType *const_pt, const char *recv_fmtp, bool_t enabled){
1900 	bctbx_list_t **codec_list = const_pt->type==PAYLOAD_VIDEO ? &lc->default_video_codecs : const_pt->type==PAYLOAD_TEXT ? &lc->default_text_codecs : &lc->default_audio_codecs;
1901 	PayloadType *pt=payload_type_clone(const_pt);
1902 	int number=-1;
1903 	payload_type_set_enable(pt,enabled);
1904 	if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp);
1905 	/*Set a number to the payload type from the statically defined (RFC3551) profile, if not static, -1 is returned
1906 		and the payload type number will be determined dynamically later, at call time.*/
1907 	payload_type_set_number(pt,
1908 		(number=rtp_profile_find_payload_number(&av_profile, pt->mime_type, pt->clock_rate, pt->channels))
1909 	);
1910 	ms_message("Codec %s/%i fmtp=[%s] number=%i, default enablement: %i) added to the list of possible codecs.", pt->mime_type, pt->clock_rate,
1911 			pt->recv_fmtp ? pt->recv_fmtp : "", number, (int)payload_type_enabled(pt));
1912 	*codec_list=bctbx_list_append(*codec_list,pt);
1913 }
1914 
linphone_core_register_static_payloads(LinphoneCore * lc)1915 static void linphone_core_register_static_payloads(LinphoneCore *lc){
1916 	RtpProfile *prof=&av_profile;
1917 	int i;
1918 	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
1919 		PayloadType *pt=rtp_profile_get_payload(prof,i);
1920 		if (pt){
1921 #ifndef VIDEO_ENABLED
1922 			if (pt->type==PAYLOAD_VIDEO) continue;
1923 #endif
1924 			if (find_payload_type_from_list(
1925 				pt->mime_type, pt->clock_rate, pt->type == PAYLOAD_VIDEO || pt->type == PAYLOAD_TEXT ? LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS : pt->channels,
1926 				pt->type == PAYLOAD_VIDEO ? lc->default_video_codecs : pt->type == PAYLOAD_TEXT ? lc->default_text_codecs : lc->default_audio_codecs)==NULL){
1927 				linphone_core_register_payload_type(lc,pt,NULL,FALSE);
1928 			}
1929 		}
1930 	}
1931 }
1932 
linphone_core_free_payload_types(LinphoneCore * lc)1933 static void linphone_core_free_payload_types(LinphoneCore *lc){
1934 	bctbx_list_free_with_data(lc->default_audio_codecs, (void (*)(void*))payload_type_destroy);
1935 	bctbx_list_free_with_data(lc->default_video_codecs, (void (*)(void*))payload_type_destroy);
1936 	bctbx_list_free_with_data(lc->default_text_codecs, (void (*)(void*))payload_type_destroy);
1937 }
1938 
linphone_core_set_state(LinphoneCore * lc,LinphoneGlobalState gstate,const char * message)1939 void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message){
1940 	lc->state=gstate;
1941 	linphone_core_notify_global_state_changed(lc,gstate,message);
1942 }
1943 
misc_config_read(LinphoneCore * lc)1944 static void misc_config_read(LinphoneCore *lc) {
1945 	LpConfig *config=lc->config;
1946 	const char *uuid;
1947 
1948 	lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",LINPHONE_MAX_CALL_HISTORY_SIZE);
1949 	lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS);
1950 
1951 	uuid=lp_config_get_string(config,"misc","uuid",NULL);
1952 	if (!uuid){
1953 		char tmp[64];
1954 		sal_create_uuid(lc->sal,tmp,sizeof(tmp));
1955 		lp_config_set_string(config,"misc","uuid",tmp);
1956 	}else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/
1957 		sal_set_uuid(lc->sal, uuid);
1958 
1959 	lc->user_certificates_path=ms_strdup(lp_config_get_string(config,"misc","user_certificates_path","."));
1960 }
1961 
linphone_core_reload_ms_plugins(LinphoneCore * lc,const char * path)1962 void linphone_core_reload_ms_plugins(LinphoneCore *lc, const char *path){
1963 	if (path) ms_factory_set_plugins_dir(lc->factory, path);
1964 	ms_factory_init_plugins(lc->factory);
1965 	codecs_config_read(lc);
1966 }
1967 
linphone_core_start(LinphoneCore * lc)1968 static void linphone_core_start(LinphoneCore * lc) {
1969 	LinphoneFriendList *list = linphone_core_create_friend_list(lc);
1970 	linphone_friend_list_set_display_name(list, "_default");
1971 	linphone_core_add_friend_list(lc, list);
1972 	linphone_friend_list_unref(list);
1973 
1974 	sip_setup_register_all(lc->factory);
1975 	sound_config_read(lc);
1976 	net_config_read(lc);
1977 	rtp_config_read(lc);
1978 	codecs_config_read(lc);
1979 	sip_config_read(lc);
1980 	video_config_read(lc);
1981 	//autoreplier_config_init(&lc->autoreplier_conf);
1982 	lc->presence_model=linphone_presence_model_new();
1983 	linphone_presence_model_set_basic_status(lc->presence_model, LinphonePresenceBasicStatusOpen);
1984 	misc_config_read(lc);
1985 	ui_config_read(lc);
1986 #ifdef TUNNEL_ENABLED
1987 	if (lc->tunnel) {
1988 		linphone_tunnel_configure(lc->tunnel);
1989 	}
1990 #endif
1991 
1992 
1993 	linphone_core_notify_display_status(lc,_("Ready"));
1994 	lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
1995 	linphone_core_set_state(lc,LinphoneGlobalOn,"Ready");
1996 }
1997 
linphone_configuring_terminated(LinphoneCore * lc,LinphoneConfiguringState state,const char * message)1998 void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) {
1999 	linphone_core_notify_configuring_status(lc, state, message);
2000 
2001 	if (state == LinphoneConfiguringSuccessful) {
2002 		if (linphone_core_is_provisioning_transient(lc) == TRUE)
2003 			linphone_core_set_provisioning_uri(lc, NULL);
2004 	}
2005 	if (lc->provisioning_http_listener){
2006 		belle_sip_object_unref(lc->provisioning_http_listener);
2007 		lc->provisioning_http_listener = NULL;
2008 	}
2009 	linphone_core_start(lc);
2010 }
2011 
2012 
2013 static int linphone_core_serialization_ref = 0;
2014 
linphone_core_activate_log_serialization_if_needed(void)2015 static void linphone_core_activate_log_serialization_if_needed(void) {
2016 	if (liblinphone_serialize_logs == TRUE) {
2017 		linphone_core_serialization_ref++;
2018 		if (linphone_core_serialization_ref == 1)
2019 			ortp_set_log_thread_id(ortp_thread_self());
2020 	}
2021 }
2022 
linphone_core_deactivate_log_serialization_if_needed(void)2023 static void linphone_core_deactivate_log_serialization_if_needed(void) {
2024 	if (liblinphone_serialize_logs == TRUE) {
2025 		--linphone_core_serialization_ref;
2026 		if (linphone_core_serialization_ref == 0)
2027 			ortp_set_log_thread_id(0);
2028 	}
2029 }
2030 
linphone_core_register_default_codecs(LinphoneCore * lc)2031 static void linphone_core_register_default_codecs(LinphoneCore *lc){
2032 	const char *aac_fmtp162248, *aac_fmtp3244;
2033 	bool_t opus_enabled=TRUE;
2034 	/*default enabled audio codecs, in order of preference*/
2035 #if defined(__arm__) || defined(_M_ARM)
2036 	/*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/
2037 	//if (ms_get_cpu_count()==1) opus_enabled=FALSE;
2038 	if (ms_factory_get_cpu_count(lc->factory)==1) opus_enabled=FALSE;
2039 #endif
2040 	linphone_core_register_payload_type(lc,&payload_type_opus,"useinbandfec=1",opus_enabled);
2041 	linphone_core_register_payload_type(lc,&payload_type_silk_wb,NULL,TRUE);
2042 	linphone_core_register_payload_type(lc,&payload_type_speex_wb,"vbr=on",TRUE);
2043 	linphone_core_register_payload_type(lc,&payload_type_speex_nb,"vbr=on",TRUE);
2044 	linphone_core_register_payload_type(lc,&payload_type_pcmu8000,NULL,TRUE);
2045 	linphone_core_register_payload_type(lc,&payload_type_pcma8000,NULL,TRUE);
2046 
2047 	/* Text codecs in order or preference (RED first (more robust), then T140) */
2048 	linphone_core_register_payload_type(lc, &payload_type_t140_red, NULL, TRUE);
2049 	linphone_core_register_payload_type(lc, &payload_type_t140, NULL, TRUE);
2050 
2051 	/*other audio codecs, not enabled by default, in order of preference*/
2052 	linphone_core_register_payload_type(lc,&payload_type_gsm,NULL,FALSE);
2053 	linphone_core_register_payload_type(lc,&payload_type_g722,NULL,FALSE);
2054 	linphone_core_register_payload_type(lc,&payload_type_ilbc,"mode=30",FALSE);
2055 	linphone_core_register_payload_type(lc,&payload_type_amr,"octet-align=1",FALSE);
2056 	linphone_core_register_payload_type(lc,&payload_type_amrwb,"octet-align=1",FALSE);
2057 	linphone_core_register_payload_type(lc,&payload_type_g729,"annexb=yes",TRUE);
2058 	/* For AAC, we use a config value to determine if we ought to support SBR. Since it is not offically supported
2059 	 * for the mpeg4-generic mime type, setting this flag to 1 will break compatibility with other clients. */
2060 	if( lp_config_get_int(lc->config, "misc", "aac_use_sbr", FALSE) ) {
2061 		ms_message("Using SBR for AAC");
2062 		aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1";
2063 		aac_fmtp3244   = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1";
2064 	} else {
2065 		aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5";
2066 		aac_fmtp3244   = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5";
2067 	}
2068 	linphone_core_register_payload_type(lc,&payload_type_aaceld_16k,aac_fmtp162248,FALSE);
2069 	linphone_core_register_payload_type(lc,&payload_type_aaceld_22k,aac_fmtp162248,FALSE);
2070 	linphone_core_register_payload_type(lc,&payload_type_aaceld_32k,aac_fmtp3244,FALSE);
2071 	linphone_core_register_payload_type(lc,&payload_type_aaceld_44k,aac_fmtp3244,FALSE);
2072 	linphone_core_register_payload_type(lc,&payload_type_aaceld_48k,aac_fmtp162248,FALSE);
2073 	linphone_core_register_payload_type(lc,&payload_type_isac,NULL,FALSE);
2074 	linphone_core_register_payload_type(lc,&payload_type_speex_uwb,"vbr=on",FALSE);
2075 	linphone_core_register_payload_type(lc,&payload_type_silk_nb,NULL,FALSE);
2076 	linphone_core_register_payload_type(lc,&payload_type_silk_mb,NULL,FALSE);
2077 	linphone_core_register_payload_type(lc,&payload_type_silk_swb,NULL,FALSE);
2078 	linphone_core_register_payload_type(lc,&payload_type_g726_16,NULL,FALSE);
2079 	linphone_core_register_payload_type(lc,&payload_type_g726_24,NULL,FALSE);
2080 	linphone_core_register_payload_type(lc,&payload_type_g726_32,NULL,FALSE);
2081 	linphone_core_register_payload_type(lc,&payload_type_g726_40,NULL,FALSE);
2082 	linphone_core_register_payload_type(lc,&payload_type_aal2_g726_16,NULL,FALSE);
2083 	linphone_core_register_payload_type(lc,&payload_type_aal2_g726_24,NULL,FALSE);
2084 	linphone_core_register_payload_type(lc,&payload_type_aal2_g726_32,NULL,FALSE);
2085 	linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE);
2086 	linphone_core_register_payload_type(lc,&payload_type_codec2,NULL,FALSE);
2087 	linphone_core_register_payload_type(lc,&payload_type_bv16,NULL,FALSE);
2088 
2089 
2090 #ifdef VIDEO_ENABLED
2091 	/*default enabled video codecs, in order of preference*/
2092 	linphone_core_register_payload_type(lc,&payload_type_vp8,NULL,TRUE);
2093 	linphone_core_register_payload_type(lc,&payload_type_h264,"profile-level-id=42801F",TRUE);
2094 	linphone_core_register_payload_type(lc,&payload_type_mp4v,"profile-level-id=3",TRUE);
2095 	linphone_core_register_payload_type(lc,&payload_type_h263_1998,"CIF=1;QCIF=1",FALSE);
2096 	linphone_core_register_payload_type(lc,&payload_type_h263,NULL,FALSE);
2097 #endif
2098 	/*register all static payload types declared in av_profile of oRTP, if not already declared above*/
2099 	linphone_core_register_static_payloads(lc);
2100 }
2101 
linphone_core_internal_notify_received(LinphoneCore * lc,LinphoneEvent * lev,const char * notified_event,const LinphoneContent * body)2102 static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body) {
2103 	if (strcmp(notified_event, "Presence") == 0) {
2104 		const bctbx_list_t* friendLists = linphone_core_get_friends_lists(lc);
2105 		while( friendLists != NULL ){
2106 			LinphoneFriendList* list = friendLists->data;
2107 			ms_message("notify presence for list %p", list);
2108 			linphone_friend_list_notify_presence_received(list, lev, body);
2109 			friendLists = friendLists->next;
2110 		}
2111 	}
2112 }
2113 
linphone_core_internal_subscription_state_changed(LinphoneCore * lc,LinphoneEvent * lev,LinphoneSubscriptionState state)2114 static void linphone_core_internal_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) {
2115 	if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) {
2116 		linphone_friend_list_subscription_state_changed(lc, lev, state);
2117 	}
2118 }
2119 
linphone_core_internal_publish_state_changed(LinphoneCore * lc,LinphoneEvent * lev,LinphonePublishState state)2120 static void linphone_core_internal_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state) {
2121 	if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) {
2122 		const bctbx_list_t *cfgs = linphone_core_get_proxy_config_list(lc);
2123 		const bctbx_list_t *item;
2124 		for (item = cfgs; item != NULL; item = bctbx_list_next(item)) {
2125 			LinphoneProxyConfig *cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
2126 			if (cfg->presence_publish_event == lev) {
2127 				linphone_proxy_config_notify_publish_state_changed(cfg, state);
2128 				break;
2129 			}
2130 		}
2131 	}
2132 }
2133 
_linphone_core_init_account_creator_service(LinphoneCore * lc)2134 static void _linphone_core_init_account_creator_service(LinphoneCore *lc) {
2135 	LinphoneAccountCreatorService *service = linphone_account_creator_service_new();
2136 	service->account_creator_service_constructor_cb = linphone_account_creator_constructor_linphone;
2137 	service->account_creator_service_destructor_cb = NULL;
2138 	service->create_account_request_cb = linphone_account_creator_create_account_linphone;
2139 	service->is_account_exist_request_cb = linphone_account_creator_is_account_exist_linphone;
2140 	service->activate_account_request_cb = linphone_account_creator_activate_account_linphone;
2141 	service->is_account_activated_request_cb = linphone_account_creator_is_account_activated_linphone;
2142 	service->link_account_request_cb = linphone_account_creator_link_phone_number_with_account_linphone;
2143 	service->activate_alias_request_cb = linphone_account_creator_activate_phone_number_link_linphone;
2144 	service->is_alias_used_request_cb = linphone_account_creator_is_phone_number_used_linphone;
2145 	service->is_account_linked_request_cb = linphone_account_creator_is_account_linked_linphone;
2146 	service->recover_account_request_cb = linphone_account_creator_recover_phone_account_linphone;
2147 	service->update_account_request_cb = linphone_account_creator_update_password_linphone;
2148 	linphone_core_set_account_creator_service(lc, service);
2149 }
2150 
linphone_core_init(LinphoneCore * lc,LinphoneCoreCbs * cbs,LpConfig * config,void * userdata)2151 static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata){
2152 	const char *remote_provisioning_uri = NULL;
2153 	LinphoneFactory *lfactory = linphone_factory_get();
2154 	LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new();
2155 	const char *msplugins_dir;
2156 	const char *image_resources_dir;
2157 
2158 	ms_message("Initializing LinphoneCore %s", linphone_core_get_version());
2159 
2160 	lc->config=lp_config_ref(config);
2161 	lc->data=userdata;
2162 	lc->ringstream_autorelease=TRUE;
2163 
2164 	linphone_task_list_init(&lc->hooks);
2165 
2166 	_linphone_core_init_account_creator_service(lc);
2167 
2168 	linphone_core_cbs_set_notify_received(internal_cbs, linphone_core_internal_notify_received);
2169 	linphone_core_cbs_set_subscription_state_changed(internal_cbs, linphone_core_internal_subscription_state_changed);
2170 	linphone_core_cbs_set_publish_state_changed(internal_cbs, linphone_core_internal_publish_state_changed);
2171 	_linphone_core_add_callbacks(lc, internal_cbs, TRUE);
2172 	belle_sip_object_unref(internal_cbs);
2173 
2174 
2175 	if (cbs != NULL) {
2176 		_linphone_core_add_callbacks(lc, cbs, FALSE);
2177 	} else {
2178 		LinphoneCoreCbs *fallback_cbs = linphone_factory_create_core_cbs(linphone_factory_get());
2179 		_linphone_core_add_callbacks(lc, fallback_cbs, FALSE);
2180 		belle_sip_object_unref(fallback_cbs);
2181 	}
2182 
2183 
2184 	linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
2185 	ortp_init();
2186 	linphone_core_activate_log_serialization_if_needed();
2187 
2188 	msplugins_dir = linphone_factory_get_msplugins_dir(lfactory);
2189 	image_resources_dir = linphone_factory_get_image_resources_dir(lfactory);
2190 	lc->factory = ms_factory_new_with_voip_and_directories(msplugins_dir, image_resources_dir);
2191 	linphone_core_register_default_codecs(lc);
2192 	linphone_core_register_offer_answer_providers(lc);
2193 	/* Get the mediastreamer2 event queue */
2194 	/* This allows to run event's callback in linphone_core_iterate() */
2195 	lc->msevq=ms_factory_create_event_queue(lc->factory);
2196 
2197 	lc->sal=sal_init(lc->factory);
2198 	sal_set_http_proxy_host(lc->sal, linphone_core_get_http_proxy_host(lc));
2199 	sal_set_http_proxy_port(lc->sal, linphone_core_get_http_proxy_port(lc));
2200 
2201 	sal_set_user_pointer(lc->sal,lc);
2202 	sal_set_callbacks(lc->sal,&linphone_sal_callbacks);
2203 
2204 #ifdef TUNNEL_ENABLED
2205 	lc->tunnel=linphone_core_tunnel_new(lc);
2206 #endif
2207 
2208 	lc->network_last_check = 0;
2209 	lc->network_last_status = FALSE;
2210 
2211 	/* Create the http provider in dual stack mode (ipv4 and ipv6.
2212 	 * If this creates problem, we may need to implement parallel ipv6/ ipv4 http requests in belle-sip.
2213 	 */
2214 	lc->http_provider = belle_sip_stack_create_http_provider(sal_get_stack_impl(lc->sal), "::0");
2215 	lc->http_crypto_config = belle_tls_crypto_config_new();
2216 	belle_http_provider_set_tls_crypto_config(lc->http_provider,lc->http_crypto_config);
2217 
2218 	certificates_config_read(lc);
2219 
2220 	lc->ringtoneplayer = linphone_ringtoneplayer_new();
2221 
2222 #ifdef SQLITE_STORAGE_ENABLED
2223 	sqlite3_bctbx_vfs_register(0);
2224 #endif
2225 
2226 	lc->vcard_context = linphone_vcard_context_new();
2227 	linphone_core_initialize_supported_content_types(lc);
2228 
2229 	remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
2230 	if (remote_provisioning_uri == NULL) {
2231 		linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
2232 	} // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate)
2233 	lc->bw_controller = ms_bandwidth_controller_new();
2234 }
2235 
_linphone_core_new_with_config(LinphoneCoreCbs * cbs,struct _LpConfig * config,void * userdata)2236 LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata) {
2237 	LinphoneCore *core = belle_sip_object_new(LinphoneCore);
2238 	linphone_core_init(core, cbs, config, userdata);
2239 	return core;
2240 }
2241 
linphone_core_new_with_config(const LinphoneCoreVTable * vtable,struct _LpConfig * config,void * userdata)2242 LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata) {
2243 	LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
2244 	LinphoneCoreVTable *local_vtable = linphone_core_v_table_new();
2245 	LinphoneCore *core = NULL;
2246 	if (vtable != NULL) *local_vtable = *vtable;
2247 	_linphone_core_cbs_set_v_table(cbs, local_vtable, TRUE);
2248 	core = _linphone_core_new_with_config(cbs, config, userdata);
2249 	linphone_core_cbs_unref(cbs);
2250 	return core;
2251 }
2252 
_linphone_core_new(const LinphoneCoreVTable * vtable,const char * config_path,const char * factory_config_path,void * userdata)2253 static LinphoneCore *_linphone_core_new(const LinphoneCoreVTable *vtable,
2254 						const char *config_path, const char *factory_config_path, void * userdata) {
2255 	LinphoneCore *lc;
2256 	LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path);
2257 	lc=linphone_core_new_with_config(vtable, config, userdata);
2258 	lp_config_unref(config);
2259 	return lc;
2260 }
2261 
linphone_core_new(const LinphoneCoreVTable * vtable,const char * config_path,const char * factory_config_path,void * userdata)2262 LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
2263 						const char *config_path, const char *factory_config_path, void * userdata) {
2264 	return _linphone_core_new(vtable, config_path, factory_config_path, userdata);
2265 }
2266 
linphone_core_ref(LinphoneCore * lc)2267 LinphoneCore *linphone_core_ref(LinphoneCore *lc) {
2268 	return (LinphoneCore *)belle_sip_object_ref(BELLE_SIP_OBJECT(lc));
2269 }
2270 
linphone_core_unref(LinphoneCore * lc)2271 void linphone_core_unref(LinphoneCore *lc) {
2272 	belle_sip_object_unref(BELLE_SIP_OBJECT(lc));
2273 }
2274 
ortp_payloads_to_linphone_payloads(const bctbx_list_t * ortp_payloads,LinphoneCore * lc)2275 static bctbx_list_t *ortp_payloads_to_linphone_payloads(const bctbx_list_t *ortp_payloads, LinphoneCore *lc) {
2276 	bctbx_list_t *linphone_payloads = NULL;
2277 	for (; ortp_payloads!=NULL; ortp_payloads=bctbx_list_next(ortp_payloads)) {
2278 		LinphonePayloadType *pt = linphone_payload_type_new(lc, (OrtpPayloadType *)ortp_payloads->data);
2279 		linphone_payloads = bctbx_list_append(linphone_payloads, pt);
2280 	}
2281 	return linphone_payloads;
2282 }
2283 
sort_ortp_pt_list(bctbx_list_t ** ortp_pt_list,const bctbx_list_t * linphone_pt_list)2284 static void sort_ortp_pt_list(bctbx_list_t **ortp_pt_list, const bctbx_list_t *linphone_pt_list) {
2285 	bctbx_list_t *new_list = NULL;
2286 	const bctbx_list_t *it;
2287 	for (it=bctbx_list_first_elem(linphone_pt_list); it; it=bctbx_list_next(it)) {
2288 		OrtpPayloadType *ortp_pt = linphone_payload_type_get_ortp_pt((LinphonePayloadType *)it->data);
2289 		bctbx_list_t *elem = bctbx_list_find(*ortp_pt_list, ortp_pt);
2290 		if (elem) {
2291 			*ortp_pt_list = bctbx_list_unlink(*ortp_pt_list, elem);
2292 			new_list = bctbx_list_append_link(new_list, elem);
2293 		}
2294 	}
2295 	*ortp_pt_list = bctbx_list_prepend_link(*ortp_pt_list, new_list);
2296 }
2297 
linphone_core_get_audio_payload_types(LinphoneCore * lc)2298 bctbx_list_t *linphone_core_get_audio_payload_types(LinphoneCore *lc) {
2299 	return ortp_payloads_to_linphone_payloads(lc->codecs_conf.audio_codecs, lc);
2300 }
2301 
linphone_core_set_audio_payload_types(LinphoneCore * lc,const bctbx_list_t * payload_types)2302 void linphone_core_set_audio_payload_types(LinphoneCore *lc, const bctbx_list_t *payload_types) {
2303 	sort_ortp_pt_list(&lc->codecs_conf.audio_codecs, payload_types);
2304 }
2305 
linphone_core_get_video_payload_types(LinphoneCore * lc)2306 bctbx_list_t *linphone_core_get_video_payload_types(LinphoneCore *lc) {
2307 	return ortp_payloads_to_linphone_payloads(lc->codecs_conf.video_codecs, lc);
2308 }
2309 
linphone_core_set_video_payload_types(LinphoneCore * lc,const bctbx_list_t * payload_types)2310 void linphone_core_set_video_payload_types(LinphoneCore *lc, const bctbx_list_t *payload_types) {
2311 	sort_ortp_pt_list(&lc->codecs_conf.video_codecs, payload_types);
2312 }
2313 
linphone_core_get_text_payload_types(LinphoneCore * lc)2314 bctbx_list_t *linphone_core_get_text_payload_types(LinphoneCore *lc) {
2315 	return ortp_payloads_to_linphone_payloads(lc->codecs_conf.text_codecs, lc);
2316 }
2317 
linphone_core_set_text_payload_types(LinphoneCore * lc,const bctbx_list_t * payload_types)2318 void linphone_core_set_text_payload_types(LinphoneCore *lc, const bctbx_list_t *payload_types) {
2319 	sort_ortp_pt_list(&lc->codecs_conf.text_codecs, payload_types);
2320 }
2321 
linphone_core_get_audio_codecs(const LinphoneCore * lc)2322 const bctbx_list_t *linphone_core_get_audio_codecs(const LinphoneCore *lc) {
2323 	return lc->codecs_conf.audio_codecs;
2324 }
2325 
linphone_core_get_video_codecs(const LinphoneCore * lc)2326 const bctbx_list_t *linphone_core_get_video_codecs(const LinphoneCore *lc) {
2327 	return lc->codecs_conf.video_codecs;
2328 }
2329 
linphone_core_get_text_codecs(const LinphoneCore * lc)2330 const bctbx_list_t *linphone_core_get_text_codecs(const LinphoneCore *lc) {
2331 	return lc->codecs_conf.text_codecs;
2332 }
2333 
linphone_core_set_primary_contact(LinphoneCore * lc,const char * contact)2334 LinphoneStatus linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) {
2335 	LinphoneAddress *ctt;
2336 
2337 	if( lc->sip_conf.contact != NULL && strcmp(lc->sip_conf.contact, contact) == 0){
2338 		/* changing for the same contact: no need to do anything */
2339 		return 0;
2340 	}
2341 
2342 	if ((ctt=linphone_address_new(contact))==0) {
2343 		ms_error("Bad contact url: %s",contact);
2344 		return -1;
2345 	}
2346 
2347 	if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact);
2348 	lc->sip_conf.contact=ms_strdup(contact);
2349 	lp_config_set_string(lc->config, "sip", "contact", lc->sip_conf.contact);
2350 
2351 	/* clean the guessed contact, we have to regenerate it */
2352 	if (lc->sip_conf.guessed_contact!=NULL){
2353 		ms_free(lc->sip_conf.guessed_contact);
2354 		lc->sip_conf.guessed_contact=NULL;
2355 	}
2356 	linphone_address_unref(ctt);
2357 	return 0;
2358 }
2359 
2360 
update_primary_contact(LinphoneCore * lc)2361 static void update_primary_contact(LinphoneCore *lc){
2362 	char *guessed=NULL;
2363 	char tmp[LINPHONE_IPADDR_SIZE];
2364 	int port;
2365 
2366 	LinphoneAddress *url;
2367 	if (lc->sip_conf.guessed_contact!=NULL){
2368 		ms_free(lc->sip_conf.guessed_contact);
2369 		lc->sip_conf.guessed_contact=NULL;
2370 	}
2371 	url=linphone_address_new(lc->sip_conf.contact);
2372 	if (!url){
2373 		ms_error("Could not parse identity contact !");
2374 		url=linphone_address_new("sip:unknown@unkwownhost");
2375 	}
2376 	linphone_core_get_local_ip(lc, AF_UNSPEC, NULL, tmp);
2377 	if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){
2378 		ms_warning("Local loopback network only !");
2379 		lc->sip_conf.loopback_only=TRUE;
2380 	}else lc->sip_conf.loopback_only=FALSE;
2381 	linphone_address_set_domain(url,tmp);
2382 	port = linphone_core_get_sip_port(lc);
2383 	if (port > 0) linphone_address_set_port(url, port); /*if there is no listening socket the primary contact is somewhat useless,
2384 		it won't work. But we prefer to return something in all cases. It at least shows username and ip address.*/
2385 	guessed=linphone_address_as_string(url);
2386 	lc->sip_conf.guessed_contact=guessed;
2387 	linphone_address_unref(url);
2388 }
2389 
linphone_core_get_primary_contact(LinphoneCore * lc)2390 const char *linphone_core_get_primary_contact(LinphoneCore *lc){
2391 	char *identity;
2392 
2393 	if (lc->sip_conf.guess_hostname){
2394 		if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){
2395 			update_primary_contact(lc);
2396 		}
2397 		identity=lc->sip_conf.guessed_contact;
2398 	}else{
2399 		identity=lc->sip_conf.contact;
2400 	}
2401 	return identity;
2402 }
2403 
linphone_core_set_guess_hostname(LinphoneCore * lc,bool_t val)2404 void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val){
2405 	lc->sip_conf.guess_hostname=val;
2406 }
2407 
linphone_core_get_guess_hostname(LinphoneCore * lc)2408 bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){
2409 	return lc->sip_conf.guess_hostname;
2410 }
2411 
linphone_core_enable_lime(LinphoneCore * lc,LinphoneLimeState val)2412 void linphone_core_enable_lime(LinphoneCore *lc, LinphoneLimeState val){
2413 	LinphoneImEncryptionEngine *imee = linphone_im_encryption_engine_new();
2414 	LinphoneImEncryptionEngineCbs *cbs = linphone_im_encryption_engine_get_callbacks(imee);
2415 
2416 	if(lime_is_available()){
2417 		if (linphone_core_ready(lc)){
2418 			lp_config_set_int(lc->config,"sip","lime",val);
2419 		}
2420 
2421 		linphone_im_encryption_engine_cbs_set_process_incoming_message(cbs, lime_im_encryption_engine_process_incoming_message_cb);
2422 		linphone_im_encryption_engine_cbs_set_process_downloading_file(cbs, lime_im_encryption_engine_process_downloading_file_cb);
2423 
2424 		if (val != LinphoneLimeDisabled) {
2425 			linphone_im_encryption_engine_cbs_set_process_outgoing_message(cbs, lime_im_encryption_engine_process_outgoing_message_cb);
2426 			linphone_im_encryption_engine_cbs_set_process_uploading_file(cbs, lime_im_encryption_engine_process_uploading_file_cb);
2427 			linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(cbs, lime_im_encryption_engine_is_file_encryption_enabled_cb);
2428 			linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(cbs, lime_im_encryption_engine_generate_file_transfer_key_cb);
2429 		} else {
2430 			linphone_im_encryption_engine_cbs_set_process_outgoing_message(cbs, NULL);
2431 			linphone_im_encryption_engine_cbs_set_process_uploading_file(cbs, NULL);
2432 			linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(cbs, NULL);
2433 			linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(cbs, NULL);
2434 		}
2435 
2436 		linphone_core_set_im_encryption_engine(lc, imee);
2437 	}
2438 	linphone_im_encryption_engine_unref(imee);
2439 }
2440 
linphone_core_lime_available(const LinphoneCore * lc)2441 bool_t linphone_core_lime_available(const LinphoneCore *lc){
2442 	return lime_is_available();
2443 }
2444 
linphone_core_lime_enabled(const LinphoneCore * lc)2445 LinphoneLimeState linphone_core_lime_enabled(const LinphoneCore *lc){
2446 	return linphone_core_lime_available(lc) ? lp_config_get_int(lc->config,"sip", "lime", LinphoneLimeDisabled) : LinphoneLimeDisabled;
2447 }
2448 
linphone_core_lime_for_file_sharing_enabled(const LinphoneCore * lc)2449 LinphoneLimeState linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc){
2450 	LinphoneLimeState s = linphone_core_lime_enabled(lc);
2451 	if (s != LinphoneLimeDisabled) {
2452 		s = lp_config_get_int(lc->config,"sip", "lime_for_file_sharing", 1);
2453 	}
2454 	return s;
2455 }
2456 
linphone_core_get_primary_contact_parsed(LinphoneCore * lc)2457 LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc){
2458 	return linphone_address_new(linphone_core_get_primary_contact(lc));
2459 }
2460 
linphone_core_set_audio_codecs(LinphoneCore * lc,bctbx_list_t * codecs)2461 LinphoneStatus linphone_core_set_audio_codecs(LinphoneCore *lc, bctbx_list_t *codecs){
2462 	if (lc->codecs_conf.audio_codecs!=NULL) bctbx_list_free(lc->codecs_conf.audio_codecs);
2463 	lc->codecs_conf.audio_codecs=codecs;
2464 	_linphone_core_codec_config_write(lc);
2465 	linphone_core_update_allocated_audio_bandwidth(lc);
2466 	return 0;
2467 }
2468 
linphone_core_set_video_codecs(LinphoneCore * lc,bctbx_list_t * codecs)2469 LinphoneStatus linphone_core_set_video_codecs(LinphoneCore *lc, bctbx_list_t *codecs){
2470 	if (lc->codecs_conf.video_codecs!=NULL) bctbx_list_free(lc->codecs_conf.video_codecs);
2471 	lc->codecs_conf.video_codecs=codecs;
2472 	_linphone_core_codec_config_write(lc);
2473 	return 0;
2474 }
2475 
linphone_core_set_text_codecs(LinphoneCore * lc,bctbx_list_t * codecs)2476 LinphoneStatus linphone_core_set_text_codecs(LinphoneCore *lc, bctbx_list_t *codecs) {
2477 	if (lc->codecs_conf.text_codecs != NULL)
2478 		bctbx_list_free(lc->codecs_conf.text_codecs);
2479 
2480 	lc->codecs_conf.text_codecs = codecs;
2481 	_linphone_core_codec_config_write(lc);
2482 	return 0;
2483 }
2484 
linphone_core_enable_generic_comfort_noise(LinphoneCore * lc,bool_t enabled)2485 void linphone_core_enable_generic_comfort_noise(LinphoneCore *lc, bool_t enabled){
2486 	lp_config_set_int(lc->config, "misc", "use_cn", enabled);
2487 }
2488 
linphone_core_generic_comfort_noise_enabled(const LinphoneCore * lc)2489 bool_t linphone_core_generic_comfort_noise_enabled(const LinphoneCore *lc){
2490 	return lp_config_get_int(lc->config, "misc", "use_cn", FALSE);
2491 }
2492 
linphone_core_get_friend_list(const LinphoneCore * lc)2493 const bctbx_list_t* linphone_core_get_friend_list(const LinphoneCore *lc) {
2494 	bctbx_list_t *lists = lc->friends_lists;
2495 	if (lists) {
2496 		LinphoneFriendList *list = (LinphoneFriendList *)lists->data;
2497 		if (list) {
2498 			return list->friends;
2499 		}
2500 	}
2501 	return NULL;
2502 }
2503 
linphone_core_get_friends_lists(const LinphoneCore * lc)2504 const bctbx_list_t* linphone_core_get_friends_lists(const LinphoneCore *lc) {
2505 	return lc->friends_lists;
2506 }
2507 
linphone_core_get_default_friend_list(const LinphoneCore * lc)2508 LinphoneFriendList* linphone_core_get_default_friend_list(const LinphoneCore *lc) {
2509 	if (lc && lc->friends_lists) {
2510 		return (LinphoneFriendList *)lc->friends_lists->data;
2511 	}
2512 	return NULL;
2513 }
2514 
linphone_core_remove_friend_list(LinphoneCore * lc,LinphoneFriendList * list)2515 void linphone_core_remove_friend_list(LinphoneCore *lc, LinphoneFriendList *list) {
2516 	bctbx_list_t *elem = bctbx_list_find(lc->friends_lists, list);
2517 	if (elem == NULL) return;
2518 #ifdef SQLITE_STORAGE_ENABLED
2519 	linphone_core_remove_friends_list_from_db(lc, list);
2520 #endif
2521 	linphone_core_notify_friend_list_removed(lc, list);
2522 	list->lc = NULL;
2523 	linphone_friend_list_unref(list);
2524 	lc->friends_lists = bctbx_list_erase_link(lc->friends_lists, elem);
2525 }
2526 
linphone_core_add_friend_list(LinphoneCore * lc,LinphoneFriendList * list)2527 void linphone_core_add_friend_list(LinphoneCore *lc, LinphoneFriendList *list) {
2528 	if (!list->lc) {
2529 		list->lc = lc;
2530 	}
2531 	lc->friends_lists = bctbx_list_append(lc->friends_lists, linphone_friend_list_ref(list));
2532 #ifdef SQLITE_STORAGE_ENABLED
2533 	linphone_core_store_friends_list_in_db(lc, list);
2534 #endif
2535 	linphone_core_notify_friend_list_created(lc, list);
2536 }
2537 
linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore * lc,bool_t val)2538 void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore* lc, bool_t val) {
2539 	lc->rtp_conf.audio_adaptive_jitt_comp_enabled = val;
2540 }
2541 
linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore * lc)2542 bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore* lc) {
2543 	return lc->rtp_conf.audio_adaptive_jitt_comp_enabled;
2544 }
2545 
linphone_core_get_audio_jittcomp(LinphoneCore * lc)2546 int linphone_core_get_audio_jittcomp(LinphoneCore *lc) {
2547 	return lc->rtp_conf.audio_jitt_comp;
2548 }
2549 
linphone_core_enable_video_adaptive_jittcomp(LinphoneCore * lc,bool_t val)2550 void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore* lc, bool_t val) {
2551 	lc->rtp_conf.video_adaptive_jitt_comp_enabled = val;
2552 }
2553 
linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore * lc)2554 bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore* lc) {
2555 	return lc->rtp_conf.video_adaptive_jitt_comp_enabled;
2556 }
2557 
linphone_core_get_video_jittcomp(LinphoneCore * lc)2558 int linphone_core_get_video_jittcomp(LinphoneCore *lc) {
2559 	return lc->rtp_conf.video_jitt_comp;
2560 }
2561 
linphone_core_get_audio_port(const LinphoneCore * lc)2562 int linphone_core_get_audio_port(const LinphoneCore *lc) {
2563 	return lc->rtp_conf.audio_rtp_min_port;
2564 }
2565 
linphone_core_get_audio_port_range(const LinphoneCore * lc,int * min_port,int * max_port)2566 void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port) {
2567 	*min_port = lc->rtp_conf.audio_rtp_min_port;
2568 	*max_port = lc->rtp_conf.audio_rtp_max_port;
2569 }
2570 
linphone_core_get_audio_ports_range(const LinphoneCore * lc)2571 LinphoneRange *linphone_core_get_audio_ports_range(const LinphoneCore *lc) {
2572 	LinphoneRange *range = linphone_range_new();
2573 	range->min = lc->rtp_conf.audio_rtp_min_port;
2574 	range->max = lc->rtp_conf.audio_rtp_max_port;
2575 	return range;
2576 }
2577 
linphone_core_get_video_port(const LinphoneCore * lc)2578 int linphone_core_get_video_port(const LinphoneCore *lc){
2579 	return lc->rtp_conf.video_rtp_min_port;
2580 }
2581 
linphone_core_get_video_port_range(const LinphoneCore * lc,int * min_port,int * max_port)2582 void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port) {
2583 	*min_port = lc->rtp_conf.video_rtp_min_port;
2584 	*max_port = lc->rtp_conf.video_rtp_max_port;
2585 }
2586 
linphone_core_get_video_ports_range(const LinphoneCore * lc)2587 LinphoneRange *linphone_core_get_video_ports_range(const LinphoneCore *lc) {
2588 	LinphoneRange *range = linphone_range_new();
2589 	range->min = lc->rtp_conf.video_rtp_min_port;
2590 	range->max = lc->rtp_conf.video_rtp_max_port;
2591 	return range;
2592 }
2593 
linphone_core_get_text_port(const LinphoneCore * lc)2594 int linphone_core_get_text_port(const LinphoneCore *lc) {
2595 	return lc->rtp_conf.text_rtp_min_port;
2596 }
2597 
linphone_core_get_text_port_range(const LinphoneCore * lc,int * min_port,int * max_port)2598 void linphone_core_get_text_port_range(const LinphoneCore *lc, int *min_port, int *max_port) {
2599 	*min_port = lc->rtp_conf.text_rtp_min_port;
2600 	*max_port = lc->rtp_conf.text_rtp_max_port;
2601 }
2602 
linphone_core_get_text_ports_range(const LinphoneCore * lc)2603 LinphoneRange *linphone_core_get_text_ports_range(const LinphoneCore *lc) {
2604 	LinphoneRange *range = linphone_range_new();
2605 	range->min = lc->rtp_conf.text_rtp_min_port;
2606 	range->max = lc->rtp_conf.text_rtp_max_port;
2607 	return range;
2608 }
2609 
linphone_core_get_nortp_timeout(const LinphoneCore * lc)2610 int linphone_core_get_nortp_timeout(const LinphoneCore *lc){
2611 	return lc->rtp_conf.nortp_timeout;
2612 }
2613 
linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore * lc)2614 bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc){
2615 	return lc->rtp_conf.rtp_no_xmit_on_audio_mute;
2616 }
2617 
apply_jitter_value(LinphoneCore * lc,int value,MSFormatType stype)2618 static void apply_jitter_value(LinphoneCore *lc, int value, MSFormatType stype){
2619 	LinphoneCall *call;
2620 	bctbx_list_t *it;
2621 	for (it=lc->calls;it!=NULL;it=it->next){
2622 		MediaStream *ms;
2623 		call=(LinphoneCall*)it->data;
2624 		ms = stype==MSAudio ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream;
2625 		if (ms){
2626 			RtpSession *s=ms->sessions.rtp_session;
2627 			if (s){
2628 				if (value>0){
2629 					ms_message("Jitter buffer size set to [%i] ms on call [%p]",value,call);
2630 					rtp_session_set_jitter_compensation(s,value);
2631 					rtp_session_enable_jitter_buffer(s,TRUE);
2632 				}else if (value==0){
2633 					ms_warning("Jitter buffer is disabled per application request on call [%p]",call);
2634 					rtp_session_enable_jitter_buffer(s,FALSE);
2635 				}
2636 			}
2637 		}
2638 	}
2639 }
2640 
linphone_core_set_audio_jittcomp(LinphoneCore * lc,int milliseconds)2641 void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int milliseconds) {
2642 	lc->rtp_conf.audio_jitt_comp=milliseconds;
2643 	apply_jitter_value(lc, milliseconds, MSAudio);
2644 }
2645 
linphone_core_set_video_jittcomp(LinphoneCore * lc,int milliseconds)2646 void linphone_core_set_video_jittcomp(LinphoneCore *lc, int milliseconds) {
2647 	lc->rtp_conf.video_jitt_comp=milliseconds;
2648 	apply_jitter_value(lc, milliseconds, MSVideo);
2649 }
2650 
linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore * lc,bool_t rtp_no_xmit_on_audio_mute)2651 void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_xmit_on_audio_mute){
2652 	lc->rtp_conf.rtp_no_xmit_on_audio_mute=rtp_no_xmit_on_audio_mute;
2653 }
2654 
linphone_core_set_audio_port(LinphoneCore * lc,int port)2655 void linphone_core_set_audio_port(LinphoneCore *lc, int port) {
2656 	lc->rtp_conf.audio_rtp_min_port=lc->rtp_conf.audio_rtp_max_port=port;
2657 }
2658 
linphone_core_set_audio_port_range(LinphoneCore * lc,int min_port,int max_port)2659 void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port) {
2660 	lc->rtp_conf.audio_rtp_min_port=min_port;
2661 	lc->rtp_conf.audio_rtp_max_port=max_port;
2662 }
2663 
linphone_core_set_video_port(LinphoneCore * lc,int port)2664 void linphone_core_set_video_port(LinphoneCore *lc, int port){
2665 	lc->rtp_conf.video_rtp_min_port=lc->rtp_conf.video_rtp_max_port=port;
2666 }
2667 
linphone_core_set_video_port_range(LinphoneCore * lc,int min_port,int max_port)2668 void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port) {
2669 	lc->rtp_conf.video_rtp_min_port=min_port;
2670 	lc->rtp_conf.video_rtp_max_port=max_port;
2671 }
2672 
linphone_core_set_text_port(LinphoneCore * lc,int port)2673 void linphone_core_set_text_port(LinphoneCore *lc, int port) {
2674 	lc->rtp_conf.text_rtp_min_port = lc->rtp_conf.text_rtp_max_port = port;
2675 }
2676 
linphone_core_set_text_port_range(LinphoneCore * lc,int min_port,int max_port)2677 void linphone_core_set_text_port_range(LinphoneCore *lc, int min_port, int max_port) {
2678 	lc->rtp_conf.text_rtp_min_port = min_port;
2679 	lc->rtp_conf.text_rtp_max_port = max_port;
2680 }
2681 
linphone_core_set_nortp_timeout(LinphoneCore * lc,int nortp_timeout)2682 void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){
2683 	lc->rtp_conf.nortp_timeout=nortp_timeout;
2684 }
2685 
linphone_core_get_use_info_for_dtmf(LinphoneCore * lc)2686 bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) {
2687 	return lp_config_get_int(lc->config, "sip", "use_info", 0);
2688 }
2689 
linphone_core_set_use_info_for_dtmf(LinphoneCore * lc,bool_t use_info)2690 void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) {
2691 	if (linphone_core_ready(lc)) {
2692 		lp_config_set_int(lc->config, "sip", "use_info", use_info);
2693 	}
2694 }
2695 
linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore * lc)2696 bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc) {
2697 	return lp_config_get_int(lc->config, "sip", "use_rfc2833", 1);
2698 }
2699 
linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore * lc,bool_t use_rfc2833)2700 void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833) {
2701 	if (linphone_core_ready(lc)) {
2702 		lp_config_set_int(lc->config, "sip", "use_rfc2833", use_rfc2833);
2703 	}
2704 }
2705 
linphone_core_get_sip_port(LinphoneCore * lc)2706 int linphone_core_get_sip_port(LinphoneCore *lc){
2707 	LinphoneSipTransports tr;
2708 	linphone_core_get_sip_transports_used(lc,&tr);
2709 	return tr.udp_port>0 ? tr.udp_port : (tr.tcp_port > 0 ? tr.tcp_port : tr.tls_port);
2710 }
2711 
2712 static char _ua_name[64]="Linphone";
2713 static char _ua_version[64]=LIBLINPHONE_VERSION;
2714 
linphone_core_set_user_agent(LinphoneCore * lc,const char * name,const char * ver)2715 void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char *ver){
2716 	char ua_string[256];
2717 	snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name?name:"", ver?ver:"");
2718 	if (lc->sal) {
2719 		sal_set_user_agent(lc->sal, ua_string);
2720 		sal_append_stack_string_to_user_agent(lc->sal);
2721 	}
2722 }
linphone_core_get_user_agent(LinphoneCore * lc)2723 const char *linphone_core_get_user_agent(LinphoneCore *lc){
2724 	return sal_get_user_agent(lc->sal);
2725 }
2726 
linphone_core_get_user_agent_name(void)2727 const char *linphone_core_get_user_agent_name(void){
2728 	return _ua_name;
2729 }
2730 
linphone_core_get_user_agent_version(void)2731 const char *linphone_core_get_user_agent_version(void){
2732 	return _ua_version;
2733 }
2734 
transport_error(LinphoneCore * lc,const char * transport,int port)2735 static void transport_error(LinphoneCore *lc, const char* transport, int port){
2736 	char *msg=ortp_strdup_printf("Could not start %s transport on port %i, maybe this port is already used.",transport,port);
2737 	ms_warning("%s",msg);
2738 	linphone_core_notify_display_warning(lc,msg);
2739 	ms_free(msg);
2740 }
2741 
transports_unchanged(const LinphoneSipTransports * tr1,const LinphoneSipTransports * tr2)2742 static bool_t transports_unchanged(const LinphoneSipTransports * tr1, const LinphoneSipTransports * tr2){
2743 	return
2744 		tr2->udp_port==tr1->udp_port &&
2745 		tr2->tcp_port==tr1->tcp_port &&
2746 		tr2->dtls_port==tr1->dtls_port &&
2747 		tr2->tls_port==tr1->tls_port;
2748 }
2749 
__linphone_core_invalidate_registers(LinphoneCore * lc)2750 static void __linphone_core_invalidate_registers(LinphoneCore* lc){
2751 	const bctbx_list_t *elem=linphone_core_get_proxy_config_list(lc);
2752 	for(;elem!=NULL;elem=elem->next){
2753 		LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
2754 		if (linphone_proxy_config_register_enabled(cfg)) {
2755 			/*this will force a re-registration at next iterate*/
2756 			cfg->commit = TRUE;
2757 		}
2758 	}
2759 }
2760 
_linphone_core_apply_transports(LinphoneCore * lc)2761 int _linphone_core_apply_transports(LinphoneCore *lc){
2762 	Sal *sal=lc->sal;
2763 	const char *anyaddr;
2764 	LinphoneSipTransports *tr=&lc->sip_conf.transports;
2765 	const char* listening_address;
2766 	/*first of all invalidate all current registrations so that we can register again with new transports*/
2767 	__linphone_core_invalidate_registers(lc);
2768 
2769 	if (lc->sip_conf.ipv6_enabled)
2770 		anyaddr="::0";
2771 	else
2772 		anyaddr="0.0.0.0";
2773 
2774 	sal_unlisten_ports(sal);
2775 
2776 	listening_address = lp_config_get_string(lc->config,"sip","bind_address",anyaddr);
2777 	if (linphone_core_get_http_proxy_host(lc)) {
2778 		sal_set_http_proxy_host(sal, linphone_core_get_http_proxy_host(lc));
2779 		sal_set_http_proxy_port(sal,linphone_core_get_http_proxy_port(lc));
2780 	}
2781 	if (lc->tunnel && linphone_tunnel_sip_enabled(lc->tunnel) && linphone_tunnel_get_activated(lc->tunnel)){
2782 		if (sal_listen_port(sal,anyaddr,tr->udp_port,SalTransportUDP,TRUE)!=0){
2783 			transport_error(lc,"udp+tunnel",tr->udp_port);
2784 		}
2785 	}else{
2786 		if (tr->udp_port!=0){
2787 			if (sal_listen_port(sal,listening_address,tr->udp_port,SalTransportUDP,FALSE)!=0){
2788 				transport_error(lc,"udp",tr->udp_port);
2789 			}
2790 		}
2791 		if (tr->tcp_port!=0){
2792 			if (sal_listen_port (sal,listening_address,tr->tcp_port,SalTransportTCP,FALSE)!=0){
2793 				transport_error(lc,"tcp",tr->tcp_port);
2794 			}
2795 		}
2796 		if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){
2797 			if (tr->tls_port!=0){
2798 				if (sal_listen_port (sal,listening_address,tr->tls_port,SalTransportTLS,FALSE)!=0){
2799 					transport_error(lc,"tls",tr->tls_port);
2800 				}
2801 			}
2802 		}
2803 	}
2804 	return 0;
2805 }
2806 
linphone_core_sip_transport_supported(const LinphoneCore * lc,LinphoneTransportType tp)2807 bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp){
2808 	return sal_transport_available(lc->sal,(SalTransport)tp);
2809 }
2810 
2811 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneTransports);
2812 
2813 BELLE_SIP_INSTANCIATE_VPTR(LinphoneTransports, belle_sip_object_t,
2814 	NULL, // destroy
2815 	NULL, // clone
2816 	NULL, // marshal
2817 	FALSE
2818 );
2819 
linphone_transports_new()2820 LinphoneTransports *linphone_transports_new() {
2821 	LinphoneTransports *transports = belle_sip_object_new(LinphoneTransports);
2822 	transports->udp_port = 0;
2823 	transports->tcp_port = 0;
2824 	transports->tls_port = 0;
2825 	transports->dtls_port = 0;
2826 	return transports;
2827 }
2828 
linphone_transports_ref(LinphoneTransports * transports)2829 LinphoneTransports* linphone_transports_ref(LinphoneTransports* transports) {
2830 	return (LinphoneTransports*) belle_sip_object_ref(transports);
2831 }
2832 
linphone_transports_unref(LinphoneTransports * transports)2833 void linphone_transports_unref (LinphoneTransports* transports) {
2834 	belle_sip_object_unref(transports);
2835 }
2836 
linphone_transports_get_user_data(const LinphoneTransports * transports)2837 void *linphone_transports_get_user_data(const LinphoneTransports *transports) {
2838 	return transports->user_data;
2839 }
2840 
linphone_transports_set_user_data(LinphoneTransports * transports,void * data)2841 void linphone_transports_set_user_data(LinphoneTransports *transports, void *data) {
2842 	transports->user_data = data;
2843 }
2844 
linphone_transports_get_udp_port(const LinphoneTransports * transports)2845 int linphone_transports_get_udp_port(const LinphoneTransports* transports) {
2846 	return transports->udp_port;
2847 }
2848 
linphone_transports_get_tcp_port(const LinphoneTransports * transports)2849 int linphone_transports_get_tcp_port(const LinphoneTransports* transports) {
2850 	return transports->tcp_port;
2851 }
2852 
linphone_transports_get_tls_port(const LinphoneTransports * transports)2853 int linphone_transports_get_tls_port(const LinphoneTransports* transports) {
2854 	return transports->tls_port;
2855 }
2856 
linphone_transports_get_dtls_port(const LinphoneTransports * transports)2857 int linphone_transports_get_dtls_port(const LinphoneTransports* transports) {
2858 	return transports->dtls_port;
2859 }
2860 
linphone_transports_set_udp_port(LinphoneTransports * transports,int port)2861 void linphone_transports_set_udp_port(LinphoneTransports *transports, int port) {
2862 	transports->udp_port = port;
2863 }
2864 
linphone_transports_set_tcp_port(LinphoneTransports * transports,int port)2865 void linphone_transports_set_tcp_port(LinphoneTransports *transports, int port) {
2866 	transports->tcp_port = port;
2867 }
2868 
linphone_transports_set_tls_port(LinphoneTransports * transports,int port)2869 void linphone_transports_set_tls_port(LinphoneTransports *transports, int port) {
2870 	transports->tls_port = port;
2871 }
2872 
linphone_transports_set_dtls_port(LinphoneTransports * transports,int port)2873 void linphone_transports_set_dtls_port(LinphoneTransports *transports, int port) {
2874 	transports->dtls_port = port;
2875 }
2876 
linphone_core_set_sip_transports(LinphoneCore * lc,const LinphoneSipTransports * tr_config)2877 LinphoneStatus linphone_core_set_sip_transports(LinphoneCore *lc, const LinphoneSipTransports * tr_config /*config to be saved*/){
2878 	LinphoneSipTransports tr=*tr_config;
2879 
2880 	if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) {
2881 		/*legacy random mode*/
2882 		if (tr.udp_port>0){
2883 			tr.udp_port=LC_SIP_TRANSPORT_RANDOM;
2884 		}
2885 		if (tr.tcp_port>0){
2886 			tr.tcp_port=LC_SIP_TRANSPORT_RANDOM;
2887 		}
2888 		if (tr.tls_port>0){
2889 			tr.tls_port=LC_SIP_TRANSPORT_RANDOM;
2890 		}
2891 	}
2892 
2893 	if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){
2894 		tr.udp_port=5060;
2895 	}
2896 
2897 	if (transports_unchanged(&tr,&lc->sip_conf.transports))
2898 		return 0;
2899 	memcpy(&lc->sip_conf.transports,&tr,sizeof(tr));
2900 
2901 	if (linphone_core_ready(lc)){
2902 		lp_config_set_int(lc->config,"sip","sip_port",tr_config->udp_port);
2903 		lp_config_set_int(lc->config,"sip","sip_tcp_port",tr_config->tcp_port);
2904 		lp_config_set_int(lc->config,"sip","sip_tls_port",tr_config->tls_port);
2905 	}
2906 
2907 	if (lc->sal==NULL) return 0;
2908 	return _linphone_core_apply_transports(lc);
2909 }
2910 
linphone_core_set_transports(LinphoneCore * lc,const LinphoneTransports * transports)2911 LinphoneStatus linphone_core_set_transports(LinphoneCore *lc, const LinphoneTransports * transports){
2912 	if (transports->udp_port == lc->sip_conf.transports.udp_port &&
2913 		transports->tcp_port == lc->sip_conf.transports.tcp_port &&
2914 		transports->tls_port == lc->sip_conf.transports.tls_port &&
2915 		transports->dtls_port == lc->sip_conf.transports.dtls_port) {
2916 		return 0;
2917 	}
2918 	lc->sip_conf.transports.udp_port = transports->udp_port;
2919 	lc->sip_conf.transports.tcp_port = transports->tcp_port;
2920 	lc->sip_conf.transports.tls_port = transports->tls_port;
2921 	lc->sip_conf.transports.dtls_port = transports->dtls_port;
2922 
2923 	if (linphone_core_ready(lc)) {
2924 		lp_config_set_int(lc->config,"sip", "sip_port", transports->udp_port);
2925 		lp_config_set_int(lc->config,"sip", "sip_tcp_port", transports->tcp_port);
2926 		lp_config_set_int(lc->config,"sip", "sip_tls_port", transports->tls_port);
2927 	}
2928 
2929 	if (lc->sal == NULL) return 0;
2930 	return _linphone_core_apply_transports(lc);
2931 }
2932 
linphone_core_get_sip_transports(LinphoneCore * lc,LinphoneSipTransports * tr)2933 LinphoneStatus linphone_core_get_sip_transports(LinphoneCore *lc, LinphoneSipTransports *tr){
2934 	memcpy(tr,&lc->sip_conf.transports,sizeof(*tr));
2935 	return 0;
2936 }
2937 
linphone_core_get_transports(LinphoneCore * lc)2938 LinphoneTransports *linphone_core_get_transports(LinphoneCore *lc){
2939 	LinphoneTransports *transports = linphone_transports_new();
2940 	transports->udp_port = lc->sip_conf.transports.udp_port;
2941 	transports->tcp_port = lc->sip_conf.transports.tcp_port;
2942 	transports->tls_port = lc->sip_conf.transports.tls_port;
2943 	transports->dtls_port = lc->sip_conf.transports.dtls_port;
2944 	return transports;
2945 }
2946 
linphone_core_get_sip_transports_used(LinphoneCore * lc,LinphoneSipTransports * tr)2947 void linphone_core_get_sip_transports_used(LinphoneCore *lc, LinphoneSipTransports *tr){
2948 	tr->udp_port=sal_get_listening_port(lc->sal,SalTransportUDP);
2949 	tr->tcp_port=sal_get_listening_port(lc->sal,SalTransportTCP);
2950 	tr->tls_port=sal_get_listening_port(lc->sal,SalTransportTLS);
2951 }
2952 
linphone_core_get_transports_used(LinphoneCore * lc)2953 LinphoneTransports *linphone_core_get_transports_used(LinphoneCore *lc){
2954 	LinphoneTransports *transports = linphone_transports_new();
2955 	transports->udp_port = sal_get_listening_port(lc->sal, SalTransportUDP);
2956 	transports->tcp_port = sal_get_listening_port(lc->sal, SalTransportTCP);
2957 	transports->tls_port = sal_get_listening_port(lc->sal, SalTransportTLS);
2958 	transports->dtls_port = sal_get_listening_port(lc->sal, SalTransportDTLS);
2959 	return transports;
2960 }
2961 
linphone_core_set_sip_port(LinphoneCore * lc,int port)2962 void linphone_core_set_sip_port(LinphoneCore *lc,int port) {
2963 	LinphoneSipTransports tr;
2964 	memset(&tr,0,sizeof(tr));
2965 	tr.udp_port=port;
2966 	linphone_core_set_sip_transports (lc,&tr);
2967 }
2968 
linphone_core_ipv6_enabled(LinphoneCore * lc)2969 bool_t linphone_core_ipv6_enabled(LinphoneCore *lc){
2970 	return lc->sip_conf.ipv6_enabled;
2971 }
2972 
linphone_core_enable_ipv6(LinphoneCore * lc,bool_t val)2973 void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){
2974 	if (lc->sip_conf.ipv6_enabled!=val){
2975 		lc->sip_conf.ipv6_enabled=val;
2976 		if (lc->sal){
2977 			/* we need to update the sip stack */
2978 			_linphone_core_apply_transports(lc);
2979 		}
2980 		/*update the localip immediately for the network monitor to avoid to "discover" later that we switched to ipv6*/
2981 		linphone_core_get_local_ip(lc,AF_UNSPEC,NULL,lc->localip);
2982 		if (linphone_core_ready(lc)){
2983 			lp_config_set_int(lc->config,"sip","use_ipv6",(int)val);
2984 		}
2985 	}
2986 }
2987 
linphone_core_content_encoding_supported(const LinphoneCore * lc,const char * content_encoding)2988 bool_t linphone_core_content_encoding_supported(const LinphoneCore *lc, const char *content_encoding) {
2989 	const char *handle_content_encoding = lp_config_get_string(lc->config, "sip", "handle_content_encoding", "deflate");
2990 	return (strcmp(handle_content_encoding, content_encoding) == 0) && sal_content_encoding_available(lc->sal, content_encoding);
2991 }
2992 
monitor_network_state(LinphoneCore * lc,time_t curtime)2993 static void monitor_network_state(LinphoneCore *lc, time_t curtime){
2994 	bool_t new_status=lc->network_last_status;
2995 	char newip[LINPHONE_IPADDR_SIZE];
2996 
2997 	/* only do the network up checking every five seconds */
2998 	if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){
2999 		linphone_core_get_local_ip(lc,AF_UNSPEC,NULL,newip);
3000 		if (strcmp(newip,"::1")!=0 && strcmp(newip,"127.0.0.1")!=0){
3001 			new_status=TRUE;
3002 		}else new_status=FALSE; /*no network*/
3003 
3004 		if (new_status==lc->network_last_status && new_status==TRUE && strcmp(newip,lc->localip)!=0){
3005 			/*IP address change detected*/
3006 			ms_message("IP address change detected.");
3007 			set_network_reachable(lc,FALSE,curtime);
3008 			lc->network_last_status=FALSE;
3009 		}
3010 		strncpy(lc->localip,newip,sizeof(lc->localip));
3011 
3012 		if (new_status!=lc->network_last_status) {
3013 			if (new_status){
3014 				ms_message("New local ip address is %s",lc->localip);
3015 			}
3016 			set_network_reachable(lc,new_status, curtime);
3017 			lc->network_last_status=new_status;
3018 		}
3019 		lc->network_last_check=curtime;
3020 	}
3021 }
3022 
proxy_update(LinphoneCore * lc)3023 static void proxy_update(LinphoneCore *lc){
3024 	bctbx_list_t *elem,*next;
3025 	bctbx_list_for_each(lc->sip_conf.proxies,(void (*)(void*))&linphone_proxy_config_update);
3026 	for(elem=lc->sip_conf.deleted_proxies;elem!=NULL;elem=next){
3027 		LinphoneProxyConfig* cfg = (LinphoneProxyConfig*)elem->data;
3028 		next=elem->next;
3029 		if (ms_time(NULL) - cfg->deletion_date > 32) {
3030 			lc->sip_conf.deleted_proxies =bctbx_list_erase_link(lc->sip_conf.deleted_proxies,elem);
3031 			ms_message("Proxy config for [%s] is definitely removed from core.",linphone_proxy_config_get_addr(cfg));
3032 			_linphone_proxy_config_release_ops(cfg);
3033 			linphone_proxy_config_unref(cfg);
3034 		}
3035 	}
3036 }
3037 
assign_buddy_info(LinphoneCore * lc,BuddyInfo * info)3038 static void assign_buddy_info(LinphoneCore *lc, BuddyInfo *info){
3039 	LinphoneFriend *lf=linphone_core_get_friend_by_address(lc,info->sip_uri);
3040 	if (lf!=NULL){
3041 		lf->info=info;
3042 		ms_message("%s has a BuddyInfo assigned with image %p",info->sip_uri, info->image_data);
3043 		linphone_core_notify_buddy_info_updated(lc,lf);
3044 	}else{
3045 		ms_warning("Could not any friend with uri %s",info->sip_uri);
3046 	}
3047 }
3048 
analyze_buddy_lookup_results(LinphoneCore * lc,LinphoneProxyConfig * cfg)3049 static void analyze_buddy_lookup_results(LinphoneCore *lc, LinphoneProxyConfig *cfg){
3050 	bctbx_list_t *elem;
3051 	SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
3052 	for (elem=lc->bl_reqs;elem!=NULL;elem=bctbx_list_next(elem)){
3053 		BuddyLookupRequest *req=(BuddyLookupRequest *)elem->data;
3054 		if (req->status==BuddyLookupDone || req->status==BuddyLookupFailure){
3055 			if (req->results!=NULL){
3056 				BuddyInfo *i=(BuddyInfo*)req->results->data;
3057 				bctbx_list_free(req->results);
3058 				req->results=NULL;
3059 				assign_buddy_info(lc,i);
3060 			}
3061 			sip_setup_context_buddy_lookup_free(ctx,req);
3062 			elem->data=NULL;
3063 		}
3064 	}
3065 	/*purge completed requests */
3066 	while((elem=bctbx_list_find(lc->bl_reqs,NULL))!=NULL){
3067 		lc->bl_reqs=bctbx_list_erase_link(lc->bl_reqs,elem);
3068 	}
3069 }
3070 
linphone_core_grab_buddy_infos(LinphoneCore * lc,LinphoneProxyConfig * cfg)3071 static void linphone_core_grab_buddy_infos(LinphoneCore *lc, LinphoneProxyConfig *cfg){
3072 	const bctbx_list_t *elem;
3073 	SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
3074 	for(elem=linphone_core_get_friend_list(lc);elem!=NULL;elem=elem->next){
3075 		LinphoneFriend *lf=(LinphoneFriend*)elem->data;
3076 		if (lf->info==NULL){
3077 			if (linphone_core_lookup_known_proxy(lc,lf->uri)==cfg){
3078 				if (linphone_address_get_username(lf->uri)!=NULL){
3079 					BuddyLookupRequest *req;
3080 					char *tmp=linphone_address_as_string_uri_only(lf->uri);
3081 					req=sip_setup_context_create_buddy_lookup_request(ctx);
3082 					buddy_lookup_request_set_key(req,tmp);
3083 					buddy_lookup_request_set_max_results(req,1);
3084 					sip_setup_context_buddy_lookup_submit(ctx,req);
3085 					lc->bl_reqs=bctbx_list_append(lc->bl_reqs,req);
3086 					ms_free(tmp);
3087 				}
3088 			}
3089 		}
3090 	}
3091 }
3092 
linphone_core_do_plugin_tasks(LinphoneCore * lc)3093 static void linphone_core_do_plugin_tasks(LinphoneCore *lc){
3094 	LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(lc);
3095 	if (cfg){
3096 		if (lc->bl_refresh){
3097 			SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
3098 			if (ctx && (sip_setup_context_get_capabilities(ctx) & SIP_SETUP_CAP_BUDDY_LOOKUP)){
3099 				linphone_core_grab_buddy_infos(lc,cfg);
3100 				lc->bl_refresh=FALSE;
3101 			}
3102 		}
3103 		if (lc->bl_reqs) analyze_buddy_lookup_results(lc,cfg);
3104 	}
3105 }
3106 
linphone_core_iterate(LinphoneCore * lc)3107 void linphone_core_iterate(LinphoneCore *lc){
3108 	bctbx_list_t *calls;
3109 	LinphoneCall *call;
3110 	uint64_t curtime_ms = ms_get_cur_time_ms(); /*monotonic time*/
3111 	int elapsed;
3112 	time_t current_real_time = ms_time(NULL);
3113 	int64_t diff_time;
3114 	bool_t one_second_elapsed=FALSE;
3115 	const char *remote_provisioning_uri = NULL;
3116 
3117 	if (lc->network_reachable_to_be_notified) {
3118 		lc->network_reachable_to_be_notified=FALSE;
3119 		linphone_core_notify_network_reachable(lc,lc->sip_network_reachable);
3120 		if (lc->sip_network_reachable) {
3121 			linphone_core_resolve_stun_server(lc);
3122 		}
3123 	}
3124 	if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) {
3125 		if (sal_get_root_ca(lc->sal)) {
3126 			belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, sal_get_root_ca(lc->sal));
3127 			belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config);
3128 		}
3129 
3130 		linphone_core_notify_display_status(lc, _("Configuring"));
3131 		linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring");
3132 
3133 		remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
3134 		if (remote_provisioning_uri) {
3135 			int err = linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri);
3136 			if (err == -1) {
3137 				linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI");
3138 			}
3139 		} // else linphone_configuring_terminated has already been called in linphone_core_init
3140 	}
3141 	if (lc->prevtime_ms == 0){
3142 		lc->prevtime_ms = curtime_ms;
3143 	}
3144 	if ((diff_time=curtime_ms-lc->prevtime_ms) >= 1000){
3145 		one_second_elapsed=TRUE;
3146 		if (diff_time>3000){
3147 			/*since monotonic time doesn't increment while machine is sleeping, we don't want to catchup too much*/
3148 			lc->prevtime_ms = curtime_ms;
3149 		}else{
3150 			lc->prevtime_ms += 1000;
3151 
3152 		}
3153 	}
3154 
3155 	if (lc->ecc!=NULL){
3156 		LinphoneEcCalibratorStatus ecs=ec_calibrator_get_status(lc->ecc);
3157 		if (ecs!=LinphoneEcCalibratorInProgress){
3158 			if (lc->ecc->cb)
3159 				lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data);
3160 			if (ecs==LinphoneEcCalibratorDone){
3161 				int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
3162 				int margin=len/2;
3163 
3164 				lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0));
3165 			} else if (ecs == LinphoneEcCalibratorFailed) {
3166 				lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/
3167 			} else if (ecs == LinphoneEcCalibratorDoneNoEcho) {
3168 				linphone_core_enable_echo_cancellation(lc, FALSE);
3169 			}
3170 			ec_calibrator_destroy(lc->ecc);
3171 			lc->ecc=NULL;
3172 		}
3173 	}
3174 
3175 	if (lc->preview_finished){
3176 		lc->preview_finished=0;
3177 		linphone_ringtoneplayer_stop(lc->ringtoneplayer);
3178 		lc_callback_obj_invoke(&lc->preview_finished_cb,lc);
3179 	}
3180 
3181 	if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0
3182 		&& (curtime_ms/1000 - lc->dmfs_playing_start_time)>5){
3183 		MSPlayerState state;
3184 		bool_t stop=TRUE;
3185 		if (lc->ringstream->source && ms_filter_call_method(lc->ringstream->source,MS_PLAYER_GET_STATE,&state)==0){
3186 			if (state==MSPlayerPlaying) stop=FALSE;
3187 		}
3188 		if (stop) {
3189 			ms_message("Releasing inactive tone player.");
3190 			linphone_core_stop_dtmf_stream(lc);
3191 		}
3192 	}
3193 
3194 	sal_iterate(lc->sal);
3195 	if (lc->msevq) ms_event_queue_pump(lc->msevq);
3196 	if (lc->auto_net_state_mon) monitor_network_state(lc, current_real_time);
3197 
3198 	proxy_update(lc);
3199 
3200 	//we have to iterate for each call
3201 	calls = lc->calls;
3202 	while(calls!= NULL){
3203 		call = (LinphoneCall *)calls->data;
3204 		elapsed = (int)(current_real_time - call->log->start_date_time);
3205 		 /* get immediately a reference to next one in case the one
3206 		 we are going to examine is destroy and removed during
3207 		 linphone_call_start_invite() */
3208 		calls=calls->next;
3209 		linphone_call_background_tasks(call,one_second_elapsed);
3210 		if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){
3211 			/*start the call even if the OPTIONS reply did not arrive*/
3212 			if (call->ice_session != NULL) {
3213 				ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway."
3214 						,linphone_nat_policy_get_stun_server(call->nat_policy));
3215 				linphone_call_delete_ice_session(call);
3216 				linphone_call_stop_media_streams_for_ice_gathering(call);
3217 			}
3218 #ifdef BUILD_UPNP
3219 			if (call->upnp_session != NULL) {
3220 				ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway.");
3221 				linphone_call_delete_upnp_session(call);
3222 			}
3223 #endif //BUILD_UPNP
3224 			linphone_call_start_invite(call, NULL);
3225 		}
3226 		if (call->state==LinphoneCallIncomingReceived || call->state==LinphoneCallIncomingEarlyMedia){
3227 			if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed);
3228 			if (elapsed>lc->sip_conf.inc_timeout){
3229 				LinphoneReason decline_reason;
3230 				ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout);
3231 				decline_reason = (lc->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined;
3232 				call->log->status=LinphoneCallMissed;
3233 				call->non_op_error = TRUE;
3234 				linphone_error_info_set(call->ei, NULL, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL);
3235 				linphone_call_decline(call, decline_reason);
3236 			}
3237 		}
3238 		if ( (lc->sip_conf.in_call_timeout > 0)
3239 			 && (call->log->connected_date_time != 0)
3240 			 && ((current_real_time - call->log->connected_date_time) > lc->sip_conf.in_call_timeout))
3241 		{
3242 			ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout);
3243 			linphone_call_terminate(call);
3244 		}
3245 	}
3246 
3247 	if (linphone_core_video_preview_enabled(lc)){
3248 		if (lc->previewstream==NULL && lc->calls==NULL)
3249 			toggle_video_preview(lc,TRUE);
3250 #ifdef VIDEO_ENABLED
3251 		if (lc->previewstream) video_stream_iterate(lc->previewstream);
3252 #endif
3253 	}else{
3254 		if (lc->previewstream!=NULL)
3255 			toggle_video_preview(lc,FALSE);
3256 	}
3257 
3258 	linphone_core_run_hooks(lc);
3259 	linphone_core_do_plugin_tasks(lc);
3260 
3261 	if (lc->sip_network_reachable && lc->netup_time!=0 && (current_real_time-lc->netup_time)>=2){
3262 		/*not do that immediately, take your time.*/
3263 		linphone_core_send_initial_subscribes(lc);
3264 	}
3265 
3266 	if (one_second_elapsed) {
3267 		bctbx_list_t *elem = NULL;
3268 		if (lp_config_needs_commit(lc->config)) {
3269 			lp_config_sync(lc->config);
3270 		}
3271 		for (elem = lc->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) {
3272 			LinphoneFriendList *list = (LinphoneFriendList *)elem->data;
3273 			if (list->dirty_friends_to_update) {
3274 				linphone_friend_list_update_dirty_friends(list);
3275 			}
3276 		}
3277 	}
3278 
3279 	if (liblinphone_serialize_logs == TRUE) {
3280 		ortp_logv_flush();
3281 	}
3282 }
3283 
linphone_core_interpret_url(LinphoneCore * lc,const char * url)3284 LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url){
3285 	LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(lc);
3286 	LinphoneAddress *result=NULL;
3287 
3288 	if (linphone_proxy_config_is_phone_number(proxy,url)) {
3289 		char *normalized_number = linphone_proxy_config_normalize_phone_number(proxy, url);
3290 		result = linphone_proxy_config_normalize_sip_uri(proxy, normalized_number);
3291 		ms_free(normalized_number);
3292 	} else {
3293 		result = linphone_proxy_config_normalize_sip_uri(proxy, url);
3294 	}
3295 	return result;
3296 }
3297 
linphone_core_get_identity(LinphoneCore * lc)3298 const char * linphone_core_get_identity(LinphoneCore *lc){
3299 	LinphoneProxyConfig *proxy=linphone_core_get_default_proxy_config(lc);
3300 	const char *from;
3301 	if (proxy!=NULL) {
3302 		from=linphone_proxy_config_get_identity(proxy);
3303 	}else from=linphone_core_get_primary_contact(lc);
3304 	return from;
3305 }
3306 
linphone_core_get_route(LinphoneCore * lc)3307 const char * linphone_core_get_route(LinphoneCore *lc){
3308 	LinphoneProxyConfig *proxy=linphone_core_get_default_proxy_config(lc);
3309 	const char *route=NULL;
3310 	if (proxy!=NULL) {
3311 		route=linphone_proxy_config_get_route(proxy);
3312 	}
3313 	return route;
3314 }
3315 
linphone_core_start_refered_call(LinphoneCore * lc,LinphoneCall * call,const LinphoneCallParams * params)3316 LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
3317 	LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_call_params(lc, NULL);
3318 	LinphoneCall *newcall;
3319 
3320 	if (call->state!=LinphoneCallPaused){
3321 		ms_message("Automatically pausing current call to accept transfer.");
3322 		_linphone_call_pause(call);
3323 		call->was_automatically_paused=TRUE;
3324 	}
3325 
3326 	if (!params){
3327 		cp->has_audio = call->current_params->has_audio;
3328 		cp->has_video = call->current_params->has_video; /*start the call to refer-target with video enabled if original call had video*/
3329 	}
3330 	cp->referer=call;
3331 	ms_message("Starting new call to refered address %s",call->refer_to);
3332 	call->refer_pending=FALSE;
3333 	newcall=linphone_core_invite_with_params(lc,call->refer_to,cp);
3334 	linphone_call_params_unref(cp);
3335 	if (newcall) {
3336 		call->transfer_target=linphone_call_ref(newcall);
3337 		linphone_core_notify_refer_state(lc,call,newcall);
3338 	}
3339 	return newcall;
3340 }
3341 
linphone_core_notify_refer_state(LinphoneCore * lc,LinphoneCall * referer,LinphoneCall * newcall)3342 void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){
3343 	if (referer->op!=NULL){
3344 		sal_call_notify_refer_state(referer->op,newcall ? newcall->op : NULL);
3345 	}
3346 }
3347 
3348 /*
3349    returns the ideal route set for making an operation through this proxy.
3350    The list must be freed as well as the SalAddress content
3351 
3352    rfc3608
3353    6.1.  Procedures at the UA
3354 
3355    /.../
3356    For example, some devices will use locally-configured
3357    explicit loose routing to reach a next-hop proxy, and others will use
3358    a default outbound-proxy routing rule.  However, for the result to
3359    function, the combination MUST provide valid routing in the local
3360    environment.  In general, the service route set is appended to any
3361    locally configured route needed to egress the access proxy chain.
3362    Systems designers must match the service routing policy of their
3363    nodes with the basic SIP routing policy in order to get a workable
3364    system.
3365 */
make_routes_for_proxy(LinphoneProxyConfig * proxy,const LinphoneAddress * dest)3366 static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){
3367 	bctbx_list_t *ret=NULL;
3368 	const char *local_route=linphone_proxy_config_get_route(proxy);
3369 	const LinphoneAddress *srv_route=linphone_proxy_config_get_service_route(proxy);
3370 	if (local_route){
3371 		ret=bctbx_list_append(ret,sal_address_new(local_route));
3372 	}
3373 	if (srv_route){
3374 		ret=bctbx_list_append(ret,sal_address_clone((SalAddress*)srv_route));
3375 	}
3376 	if (ret==NULL){
3377 		/*if the proxy address matches the domain part of the destination, then use the same transport
3378 		 * as the one used for registration. This is done by forcing a route to this proxy.*/
3379 		SalAddress *proxy_addr=sal_address_new(linphone_proxy_config_get_addr(proxy));
3380 		if (strcmp(sal_address_get_domain(proxy_addr),linphone_address_get_domain(dest))==0){
3381 			ret=bctbx_list_append(ret,proxy_addr);
3382 		}else sal_address_destroy(proxy_addr);
3383 	}
3384 	return ret;
3385 }
3386 
linphone_core_lookup_known_proxy(LinphoneCore * lc,const LinphoneAddress * uri)3387 LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){
3388 	const bctbx_list_t *elem;
3389 	LinphoneProxyConfig *found_cfg=NULL;
3390 	LinphoneProxyConfig *found_reg_cfg=NULL;
3391 	LinphoneProxyConfig *found_noreg_cfg=NULL;
3392 	LinphoneProxyConfig *default_cfg=lc->default_proxy;
3393 
3394 	if (linphone_address_get_domain(uri) == NULL) {
3395 		ms_message("cannot seach for proxy for uri [%p] if no domain set. returning default",uri);
3396 		return default_cfg;
3397 	}
3398 	/*return default proxy if it is matching the destination uri*/
3399 	if (default_cfg){
3400 		const char *domain=linphone_proxy_config_get_domain(default_cfg);
3401 		if (strcmp(domain,linphone_address_get_domain(uri))==0){
3402 			found_cfg=default_cfg;
3403 			goto end;
3404 		}
3405 	}
3406 
3407 	/*otherwise return first registered, then first registering matching, otherwise first matching */
3408 	for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
3409 		LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
3410 		const char *domain=linphone_proxy_config_get_domain(cfg);
3411 		if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){
3412 			if (linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk ){
3413 				found_cfg=cfg;
3414 				break;
3415 			} else if (!found_reg_cfg && linphone_proxy_config_register_enabled(cfg)) {
3416 				found_reg_cfg=cfg;
3417 			} else if (!found_noreg_cfg){
3418 				found_noreg_cfg=cfg;
3419 			}
3420 		}
3421 	}
3422 end:
3423 	if     ( !found_cfg && found_reg_cfg)    found_cfg = found_reg_cfg;
3424 	else if( !found_cfg && found_noreg_cfg ) found_cfg = found_noreg_cfg;
3425 
3426 	if (found_cfg && found_cfg!=default_cfg){
3427 		ms_debug("Overriding default proxy setting for this call/message/subscribe operation.");
3428 	}else if (!found_cfg) found_cfg=default_cfg; /*when no matching proxy config is found, use the default proxy config*/
3429 	return found_cfg;
3430 }
3431 
linphone_core_find_best_identity(LinphoneCore * lc,const LinphoneAddress * to)3432 const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to){
3433 	LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to);
3434 	if (cfg!=NULL){
3435 		return linphone_proxy_config_get_identity (cfg);
3436 	}
3437 	return linphone_core_get_primary_contact(lc);
3438 }
3439 
linphone_core_invite(LinphoneCore * lc,const char * url)3440 LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){
3441 	LinphoneCall *call;
3442 	LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL);
3443 	p->has_video &= !!lc->video_policy.automatically_initiate;
3444 	call=linphone_core_invite_with_params(lc,url,p);
3445 	linphone_call_params_unref(p);
3446 	return call;
3447 }
3448 
linphone_core_invite_with_params(LinphoneCore * lc,const char * url,const LinphoneCallParams * p)3449 LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *p){
3450 	LinphoneAddress *addr=linphone_core_interpret_url(lc,url);
3451 	if (addr){
3452 		LinphoneCall *call;
3453 		call=linphone_core_invite_address_with_params(lc,addr,p);
3454 		linphone_address_unref(addr);
3455 		return call;
3456 	}
3457 	return NULL;
3458 }
3459 
linphone_core_invite_address(LinphoneCore * lc,const LinphoneAddress * addr)3460 LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr){
3461 	LinphoneCall *call;
3462 	LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL);
3463 	p->has_video &= !!lc->video_policy.automatically_initiate;
3464 	call=linphone_core_invite_address_with_params (lc,addr,p);
3465 	linphone_call_params_unref(p);
3466 	return call;
3467 }
3468 
linphone_transfer_routes_to_op(bctbx_list_t * routes,SalOp * op)3469 static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){
3470 	bctbx_list_t *it;
3471 	for(it=routes;it!=NULL;it=it->next){
3472 		SalAddress *addr=(SalAddress*)it->data;
3473 		sal_op_add_route_address(op,addr);
3474 		sal_address_destroy(addr);
3475 	}
3476 	bctbx_list_free(routes);
3477 }
3478 
linphone_configure_op_with_proxy(LinphoneCore * lc,SalOp * op,const LinphoneAddress * dest,SalCustomHeader * headers,bool_t with_contact,LinphoneProxyConfig * proxy)3479 void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy){
3480 	bctbx_list_t *routes=NULL;
3481 	const char *identity;
3482 	if (proxy){
3483 		identity=linphone_proxy_config_get_identity(proxy);
3484 		if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) {
3485 			sal_op_set_privacy(op,linphone_proxy_config_get_privacy(proxy));
3486 		}
3487 	}else identity=linphone_core_get_primary_contact(lc);
3488 	/*sending out of calls*/
3489 	if (proxy){
3490 		routes=make_routes_for_proxy(proxy,dest);
3491 		linphone_transfer_routes_to_op(routes,op);
3492 	}
3493 	sal_op_set_to_address(op,dest);
3494 	sal_op_set_from(op,identity);
3495 	sal_op_set_sent_custom_header(op,headers);
3496 	sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy));
3497 	if (with_contact && proxy && proxy->op){
3498 		const SalAddress *contact;
3499 		if ((contact=sal_op_get_contact_address(proxy->op))){
3500 			SalTransport tport=sal_address_get_transport((SalAddress*)contact);
3501 			SalAddress *new_contact=sal_address_clone(contact);
3502 			sal_address_clean(new_contact); /* clean out contact_params that come from proxy config*/
3503 			sal_address_set_transport(new_contact,tport);
3504 			sal_op_set_contact_address(op,new_contact);
3505 			sal_address_destroy(new_contact);
3506 		}
3507 	}
3508 	sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/
3509 }
linphone_configure_op(LinphoneCore * lc,SalOp * op,const LinphoneAddress * dest,SalCustomHeader * headers,bool_t with_contact)3510 void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact) {
3511 	linphone_configure_op_with_proxy(lc, op, dest, headers,with_contact,linphone_core_lookup_known_proxy(lc,dest));
3512 }
3513 
linphone_core_invite_address_with_params(LinphoneCore * lc,const LinphoneAddress * addr,const LinphoneCallParams * params)3514 LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params){
3515 	const char *from=NULL;
3516 	LinphoneProxyConfig *proxy=NULL;
3517 	LinphoneAddress *parsed_url2=NULL;
3518 	char *real_url=NULL;
3519 	LinphoneCall *call;
3520 	bool_t defer = FALSE;
3521 	LinphoneCallParams *cp;
3522 
3523 	if (!(!linphone_call_params_audio_enabled(params) ||
3524 		linphone_call_params_get_audio_direction(params) == LinphoneMediaDirectionInactive ||
3525 		linphone_call_params_get_local_conference_mode(params) == TRUE
3526 		)
3527 		&& linphone_core_preempt_sound_resources(lc) == -1) {
3528 		ms_error("linphone_core_invite_address_with_params(): sound is required for this call but another call is already locking the sound resource. Call attempt is rejected.");
3529 		return NULL;
3530 	}
3531 
3532 	if(!linphone_core_can_we_add_call(lc)){
3533 		linphone_core_notify_display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls"));
3534 		return NULL;
3535 	}
3536 
3537 	cp = linphone_call_params_copy(params);
3538 
3539 	real_url=linphone_address_as_string(addr);
3540 	proxy=linphone_core_lookup_known_proxy(lc,addr);
3541 
3542 	if (proxy!=NULL) {
3543 		from=linphone_proxy_config_get_identity(proxy);
3544 		cp->avpf_enabled = linphone_proxy_config_avpf_enabled(proxy);
3545 		cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000;
3546 	}else{
3547 		cp->avpf_enabled=linphone_core_get_avpf_mode(lc)==LinphoneAVPFEnabled;
3548 		if (cp->avpf_enabled) cp->avpf_rr_interval=linphone_core_get_avpf_rr_interval(lc) * 1000;
3549 	}
3550 
3551 	/* if no proxy or no identity defined for this proxy, default to primary contact*/
3552 	if (from==NULL) from=linphone_core_get_primary_contact(lc);
3553 
3554 	parsed_url2=linphone_address_new(from);
3555 
3556 	call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy);
3557 
3558 	if(linphone_core_add_call(lc,call)!= 0)
3559 	{
3560 		ms_warning("we had a problem in adding the call into the invite ... weird");
3561 		linphone_call_unref(call);
3562 		linphone_call_params_unref(cp);
3563 		return NULL;
3564 	}
3565 
3566 	/* Unless this call is for a conference, it becomes now the current one*/
3567 	if (linphone_call_params_get_local_conference_mode(params) ==  FALSE) lc->current_call=call;
3568 	linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call");
3569 	call->log->start_date_time=ms_time(NULL);
3570 	linphone_call_init_media_streams(call);
3571 
3572 	if (linphone_nat_policy_ice_enabled(call->nat_policy)) {
3573 		if (lc->sip_conf.sdp_200_ack){
3574 			ms_warning("ICE is not supported when sending INVITE without SDP");
3575 		}else{
3576 			/* Defer the start of the call after the ICE gathering process. */
3577 			if (linphone_call_prepare_ice(call,FALSE)==1)
3578 				defer=TRUE;
3579 		}
3580 	}
3581 	else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
3582 #ifdef BUILD_UPNP
3583 		if (linphone_call_update_upnp(call) < 0) {
3584 			/* uPnP port mappings failed, proceed with the call anyway. */
3585 			linphone_call_delete_upnp_session(call);
3586 		} else {
3587 			defer = TRUE;
3588 		}
3589 #endif // BUILD_UPNP
3590 	}
3591 
3592 	if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
3593 #ifdef BUILD_UPNP
3594 		if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
3595 			linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
3596 #else //BUILD_UPNP
3597 		{
3598 #endif //BUILD_UPNP
3599 			/*defer the start of the call after the OPTIONS ping*/
3600 			call->ping_replied=FALSE;
3601 			call->ping_op=sal_op_new(lc->sal);
3602 			sal_ping(call->ping_op,from,real_url);
3603 			sal_op_set_user_pointer(call->ping_op,call);
3604 			defer = TRUE;
3605 		}
3606 	}
3607 
3608 	if (defer==FALSE) {
3609 		if (linphone_call_start_invite(call,NULL) != 0){
3610 			/*the call has already gone to error and released state, so do not return it*/
3611 			call = NULL;
3612 		}
3613 	}
3614 
3615 	if (real_url!=NULL) ms_free(real_url);
3616 	linphone_call_params_unref(cp);
3617 	return call;
3618 }
3619 
3620 LinphoneStatus linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) {
3621 	if (call == NULL) {
3622 		ms_warning("No established call to refer.");
3623 		return -1;
3624 	}
3625 	return linphone_call_transfer(call, url);
3626 }
3627 
3628 LinphoneStatus linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest) {
3629 	return linphone_call_transfer_to_another(call, dest);
3630 }
3631 
3632 bool_t linphone_core_is_incoming_invite_pending(LinphoneCore*lc){
3633 	LinphoneCall *call = linphone_core_get_current_call(lc);
3634 	if(call != NULL)
3635 	{
3636 		if(call->dir==LinphoneCallIncoming
3637 			&& (call->state == LinphoneCallIncomingReceived || call->state ==  LinphoneCallIncomingEarlyMedia))
3638 			return TRUE;
3639 	}
3640 	return FALSE;
3641 }
3642 
3643 bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){
3644 	return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !sal_media_description_has_srtp(md);
3645 }
3646 
3647 void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
3648 	char *barmesg;
3649 	char *tmp;
3650 	LinphoneAddress *from_parsed;
3651 	bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
3652 
3653 	from_parsed=linphone_address_new(sal_op_get_from(call->op));
3654 	linphone_address_clean(from_parsed);
3655 	tmp=linphone_address_as_string(from_parsed);
3656 	linphone_address_unref(from_parsed);
3657 	barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
3658 		(sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):".");
3659 	linphone_core_notify_show_interface(lc);
3660 	linphone_core_notify_display_status(lc,barmesg);
3661 
3662 	/* play the ring if this is the only call*/
3663 	if (bctbx_list_size(lc->calls)==1){
3664 		MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
3665 		lc->current_call=call;
3666 		if (lc->ringstream && lc->dmfs_playing_start_time!=0){
3667 			linphone_core_stop_dtmf_stream(lc);
3668 		}
3669 		linphone_ringtoneplayer_start(lc->factory, lc->ringtoneplayer, ringcard, lc->sound_conf.local_ring, 2000);
3670 	}else{
3671 		/* else play a tone within the context of the current call */
3672 		call->ringing_beep=TRUE;
3673 		linphone_core_play_named_tone(lc,LinphoneToneCallWaiting);
3674 	}
3675 
3676 	linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
3677 	/*from now on, the application is aware of the call and supposed to take background task or already submitted notification to the user.
3678 	We can then drop our background task.*/
3679 	if (call->bg_task_id!=0) {
3680 		sal_end_background_task(call->bg_task_id);
3681 		call->bg_task_id=0;
3682 	}
3683 
3684 	if (call->state==LinphoneCallIncomingReceived){
3685 		/*try to be best-effort in giving real local or routable contact address for 100Rel case*/
3686 		linphone_call_set_contact_op(call);
3687 
3688 		if (propose_early_media){
3689 			linphone_call_accept_early_media(call);
3690 		}else sal_call_notify_ringing(call->op,FALSE);
3691 
3692 		if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){
3693 			linphone_call_accept(call);
3694 		}
3695 	}
3696 	linphone_call_unref(call);
3697 
3698 	ms_free(barmesg);
3699 	ms_free(tmp);
3700 }
3701 
3702 LinphoneStatus linphone_core_accept_early_media_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3703 	return linphone_call_accept_early_media_with_params(call, params);
3704 }
3705 
3706 LinphoneStatus linphone_core_accept_early_media(LinphoneCore *lc, LinphoneCall *call) {
3707 	return linphone_call_accept_early_media(call);
3708 }
3709 
3710 LinphoneStatus linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3711 	return linphone_call_update(call, params);
3712 }
3713 
3714 LinphoneStatus linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call) {
3715 	return linphone_call_defer_update(call);
3716 }
3717 
3718 LinphoneStatus linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3719 	return linphone_call_accept_update(call, params);
3720 }
3721 
3722 static LinphoneCall * get_unique_call(LinphoneCore *lc) {
3723 	LinphoneCall *call = linphone_core_get_current_call(lc);
3724 	if ((call == NULL) && (linphone_core_get_calls_nb(lc) == 1)) {
3725 		call = (LinphoneCall *)bctbx_list_get_data(linphone_core_get_calls(lc));
3726 	}
3727 	return call;
3728 }
3729 
3730 LinphoneStatus linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) {
3731 	return linphone_call_accept_with_params(call, NULL);
3732 }
3733 
3734 LinphoneStatus linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3735 	if (call == NULL) {
3736 		call = get_unique_call(lc);
3737 		if (call == NULL) {
3738 			ms_warning("No unique call to accept!");
3739 			return -1;
3740 		}
3741 	}
3742 	return linphone_call_accept_with_params(call, params);
3743 }
3744 
3745 LinphoneStatus linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri) {
3746 	return linphone_call_redirect(call, redirect_uri);
3747 }
3748 
3749 LinphoneStatus linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call) {
3750 	if (call == NULL) {
3751 		call = get_unique_call(lc);
3752 		if (call == NULL) {
3753 			ms_warning("No unique call to terminate!");
3754 			return -1;
3755 		}
3756 	}
3757 	return linphone_call_terminate(call);
3758 }
3759 
3760 LinphoneStatus linphone_core_terminate_all_calls(LinphoneCore *lc) {
3761 	bctbx_list_t *calls=lc->calls;
3762 	while(calls) {
3763 		LinphoneCall *c=(LinphoneCall*)calls->data;
3764 		calls=calls->next;
3765 		linphone_call_terminate(c);
3766 	}
3767 	return 0;
3768 }
3769 
3770 LinphoneStatus linphone_core_decline_call(LinphoneCore *lc, LinphoneCall *call, LinphoneReason reason) {
3771 	return linphone_call_decline(call, reason);
3772 }
3773 
3774 const bctbx_list_t *linphone_core_get_calls(LinphoneCore *lc) {
3775 	return lc->calls;
3776 }
3777 
3778 bool_t linphone_core_in_call(const LinphoneCore *lc){
3779 	return linphone_core_get_current_call((LinphoneCore *)lc)!=NULL || linphone_core_is_in_conference(lc);
3780 }
3781 
3782 LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc){
3783 	return lc->current_call;
3784 }
3785 
3786 LinphoneStatus linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) {
3787 	return linphone_call_pause(call);
3788 }
3789 
3790 LinphoneStatus linphone_core_pause_all_calls(LinphoneCore *lc){
3791 	const bctbx_list_t *elem;
3792 	for(elem=lc->calls;elem!=NULL;elem=elem->next){
3793 		LinphoneCall *call=(LinphoneCall *)elem->data;
3794 		LinphoneCallState cs=linphone_call_get_state(call);
3795 		if (cs==LinphoneCallStreamsRunning || cs==LinphoneCallPausedByRemote){
3796 			_linphone_call_pause(call);
3797 		}
3798 	}
3799 	return 0;
3800 }
3801 
3802 int linphone_core_preempt_sound_resources(LinphoneCore *lc){
3803 	LinphoneCall *current_call;
3804 	int err = 0;
3805 
3806 	if (linphone_core_is_in_conference(lc)){
3807 		linphone_core_leave_conference(lc);
3808 		return 0;
3809 	}
3810 
3811 	current_call=linphone_core_get_current_call(lc);
3812 	if(current_call != NULL){
3813 		ms_message("Pausing automatically the current call.");
3814 		err = _linphone_call_pause(current_call);
3815 	}
3816 	if (lc->ringstream){
3817 		linphone_core_stop_ringing(lc);
3818 	}
3819 	return err;
3820 }
3821 
3822 LinphoneStatus linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call) {
3823 	return linphone_call_resume(call);
3824 }
3825 
3826 static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *raddr){
3827 	const LinphoneAddress *addr=linphone_call_get_remote_address (call);
3828 	return !linphone_address_weak_equal (addr,raddr);
3829 }
3830 
3831 LinphoneCall *linphone_core_get_call_by_remote_address(const LinphoneCore *lc, const char *remote_address){
3832 	LinphoneCall *call=NULL;
3833 	LinphoneAddress *raddr=linphone_address_new(remote_address);
3834 	if (raddr) {
3835 		call=linphone_core_get_call_by_remote_address2(lc, raddr);
3836 		linphone_address_unref(raddr);
3837 	}
3838 	return call;
3839 }
3840 
3841 LinphoneCall *linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *remote_address){
3842 	return linphone_core_get_call_by_remote_address(lc, remote_address);
3843 }
3844 
3845 LinphoneCall *linphone_core_get_call_by_remote_address2(const LinphoneCore *lc, const LinphoneAddress *raddr){
3846 	const bctbx_list_t *elem=bctbx_list_find_custom(lc->calls,(int (*)(const void*,const void *))remote_address_compare,raddr);
3847 
3848 	if (elem) return (LinphoneCall*) elem->data;
3849 	return NULL;
3850 }
3851 
3852 int linphone_core_send_publish(LinphoneCore *lc, LinphonePresenceModel *presence) {
3853 	const bctbx_list_t *elem;
3854 	for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=bctbx_list_next(elem)){
3855 		LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
3856 		if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence);
3857 	}
3858 	return 0;
3859 }
3860 
3861 void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds){
3862 	lc->sip_conf.inc_timeout=seconds;
3863 	if (linphone_core_ready(lc)){
3864 		lp_config_set_int(lc->config,"sip","inc_timeout",seconds);
3865 	}
3866 }
3867 
3868 int linphone_core_get_inc_timeout(LinphoneCore *lc){
3869 	return lc->sip_conf.inc_timeout;
3870 }
3871 
3872 void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds){
3873 	lc->sip_conf.in_call_timeout=seconds;
3874 	if( linphone_core_ready(lc)){
3875 		lp_config_set_int(lc->config, "sip", "in_call_timeout", seconds);
3876 	}
3877 }
3878 
3879 int linphone_core_get_in_call_timeout(LinphoneCore *lc){
3880 	return lc->sip_conf.in_call_timeout;
3881 }
3882 
3883 int linphone_core_get_delayed_timeout(LinphoneCore *lc){
3884 	return lc->sip_conf.delayed_timeout;
3885 }
3886 
3887 void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){
3888 	lc->sip_conf.delayed_timeout=seconds;
3889 }
3890 
3891 void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const char *contact, LinphoneOnlineStatus os) {
3892 	LinphonePresenceModel *presence = NULL;
3893 	LinphonePresenceActivity *activity = NULL;
3894 	char *description = NULL;
3895 	LinphonePresenceActivityType acttype = LinphonePresenceActivityUnknown;
3896 
3897 	if (minutes_away>0) lc->minutes_away=minutes_away;
3898 
3899 	presence = linphone_presence_model_new();
3900 	linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusOpen);
3901 	switch (os) {
3902 		case LinphoneStatusOffline:
3903 			linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
3904 			goto end;
3905 		case LinphoneStatusOnline:
3906 			goto end;
3907 		case LinphoneStatusBusy:
3908 			acttype = LinphonePresenceActivityBusy;
3909 			break;
3910 		case LinphoneStatusBeRightBack:
3911 			acttype = LinphonePresenceActivityInTransit;
3912 			break;
3913 		case LinphoneStatusAway:
3914 			acttype = LinphonePresenceActivityAway;
3915 			break;
3916 		case LinphoneStatusOnThePhone:
3917 			acttype = LinphonePresenceActivityOnThePhone;
3918 			break;
3919 		case LinphoneStatusOutToLunch:
3920 			acttype = LinphonePresenceActivityLunch;
3921 			break;
3922 		case LinphoneStatusDoNotDisturb:
3923 			acttype = LinphonePresenceActivityBusy;
3924 			description = "Do not disturb";
3925 			linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
3926 			break;
3927 		case LinphoneStatusMoved:
3928 			acttype = LinphonePresenceActivityPermanentAbsence;
3929 			break;
3930 		case LinphoneStatusAltService:
3931 			acttype = LinphonePresenceActivityBusy;
3932 			description = "Using another messaging service";
3933 			break;
3934 		case LinphoneStatusPending:
3935 			acttype = LinphonePresenceActivityOther;
3936 			description = "Waiting for user acceptance";
3937 			break;
3938 		case LinphoneStatusVacation:
3939 			acttype = LinphonePresenceActivityVacation;
3940 			break;
3941 		case LinphoneStatusEnd:
3942 			ms_warning("Invalid status LinphoneStatusEnd");
3943 			return;
3944 	}
3945 	activity = linphone_presence_activity_new(acttype, description);
3946 	linphone_presence_model_add_activity(presence, activity);
3947 	linphone_presence_activity_unref(activity);
3948 
3949 end:
3950 	linphone_presence_model_set_contact(presence, contact);
3951 	linphone_core_set_presence_model(lc, presence);
3952 	linphone_presence_model_unref(presence);
3953 }
3954 
3955 void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence){
3956 	linphone_core_notify_all_friends(lc,presence);
3957 	linphone_core_send_publish(lc,presence);
3958 }
3959 
3960 void linphone_core_set_presence_model(LinphoneCore *lc, LinphonePresenceModel *presence) {
3961 	linphone_presence_model_ref(presence);
3962 	linphone_core_send_presence(lc, presence);
3963 	if (lc->presence_model != NULL) linphone_presence_model_unref(lc->presence_model);
3964 	lc->presence_model = presence;
3965 }
3966 
3967 LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){
3968 	LinphonePresenceActivity *activity = NULL;
3969 	const char *description = NULL;
3970 
3971 	activity = linphone_presence_model_get_activity(lc->presence_model);
3972 	if (activity) {
3973 		description = linphone_presence_activity_get_description(activity);
3974 		switch (linphone_presence_activity_get_type(activity)) {
3975 			case LinphonePresenceActivityBusy:
3976 				if (description != NULL) {
3977 					if (strcmp(description, "Do not disturb") == 0)
3978 						return LinphoneStatusDoNotDisturb;
3979 					else if (strcmp(description, "Using another messaging service") == 0)
3980 						return LinphoneStatusAltService;
3981 				}
3982 				return LinphoneStatusBusy;
3983 			case LinphonePresenceActivityInTransit:
3984 			case LinphonePresenceActivitySteering:
3985 				return LinphoneStatusBeRightBack;
3986 			case LinphonePresenceActivityAway:
3987 				return LinphoneStatusAway;
3988 			case LinphonePresenceActivityOnThePhone:
3989 				return LinphoneStatusOnThePhone;
3990 			case LinphonePresenceActivityBreakfast:
3991 			case LinphonePresenceActivityDinner:
3992 			case LinphonePresenceActivityLunch:
3993 			case LinphonePresenceActivityMeal:
3994 				return LinphoneStatusOutToLunch;
3995 			case LinphonePresenceActivityPermanentAbsence:
3996 				return LinphoneStatusMoved;
3997 			case LinphonePresenceActivityOther:
3998 				if (description != NULL) {
3999 					if (strcmp(description, "Waiting for user acceptance") == 0)
4000 						return LinphoneStatusPending;
4001 				}
4002 				return LinphoneStatusBusy;
4003 			case LinphonePresenceActivityVacation:
4004 				return LinphoneStatusVacation;
4005 			case LinphonePresenceActivityAppointment:
4006 			case LinphonePresenceActivityMeeting:
4007 			case LinphonePresenceActivityWorship:
4008 				return LinphoneStatusDoNotDisturb;
4009 			default:
4010 				return LinphoneStatusBusy;
4011 		}
4012 	} else {
4013 		if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusOpen)
4014 			return LinphoneStatusOnline;
4015 		else
4016 			return LinphoneStatusOffline;
4017 	}
4018 }
4019 
4020 LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc) {
4021 	return lc->presence_model;
4022 }
4023 
4024 LinphoneConsolidatedPresence linphone_core_get_consolidated_presence(const LinphoneCore *lc) {
4025 	LinphoneProxyConfig *cfg = lc->default_proxy;
4026 	LinphonePresenceModel *model = linphone_core_get_presence_model(lc);
4027 
4028 	return ((cfg && !linphone_proxy_config_publish_enabled(cfg)) || !model)
4029 		? LinphoneConsolidatedPresenceOffline
4030 		: linphone_presence_model_get_consolidated_presence(model);
4031 }
4032 
4033 void linphone_core_set_consolidated_presence(LinphoneCore *lc, LinphoneConsolidatedPresence presence) {
4034 	const bctbx_list_t *cfg_list;
4035 	const bctbx_list_t *item;
4036 	LinphoneProxyConfig *cfg;
4037 	LinphonePresenceModel *model;
4038 	LinphonePresenceActivity *activity = NULL;
4039 
4040 	cfg_list = linphone_core_get_proxy_config_list(lc);
4041 	for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
4042 		cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
4043 		if ((cfg != NULL) && (presence == LinphoneConsolidatedPresenceOffline) && linphone_proxy_config_publish_enabled(cfg)) {
4044 			/* Unpublish when going offline before changing the presence model. */
4045 			linphone_proxy_config_edit(cfg);
4046 			linphone_proxy_config_enable_publish(cfg, FALSE);
4047 			linphone_proxy_config_done(cfg);
4048 		}
4049 	}
4050 	model = linphone_presence_model_new();
4051 	switch (presence) {
4052 		case LinphoneConsolidatedPresenceOnline:
4053 			linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusOpen);
4054 			break;
4055 		case LinphoneConsolidatedPresenceBusy:
4056 			linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusOpen);
4057 			activity = linphone_presence_activity_new(LinphonePresenceActivityAway, NULL);
4058 			break;
4059 		case LinphoneConsolidatedPresenceDoNotDisturb:
4060 			linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusClosed);
4061 			activity = linphone_presence_activity_new(LinphonePresenceActivityAway, NULL);
4062 			break;
4063 		case LinphoneConsolidatedPresenceOffline:
4064 		default:
4065 			linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusClosed);
4066 			break;
4067 	}
4068 	if (activity != NULL) linphone_presence_model_add_activity(model, activity);
4069 	linphone_core_set_presence_model(lc, model);
4070 	linphone_presence_model_unref(model);
4071 	for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
4072 		cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
4073 		if ((cfg != NULL) && (presence != LinphoneConsolidatedPresenceOffline) && !linphone_proxy_config_publish_enabled(cfg)) {
4074 			/* When going online or busy, publish after changing the presence model. */
4075 			linphone_proxy_config_edit(cfg);
4076 			linphone_proxy_config_enable_publish(cfg, TRUE);
4077 			linphone_proxy_config_done(cfg);
4078 		}
4079 	}
4080 }
4081 
4082 int linphone_core_get_play_level(LinphoneCore *lc) {
4083 	return lc->sound_conf.play_lev;
4084 }
4085 
4086 int linphone_core_get_ring_level(LinphoneCore *lc) {
4087 	return lc->sound_conf.ring_lev;
4088 }
4089 
4090 int linphone_core_get_rec_level(LinphoneCore *lc) {
4091 	return lc->sound_conf.rec_lev;
4092 }
4093 
4094 void linphone_core_set_ring_level(LinphoneCore *lc, int level){
4095 	MSSndCard *sndcard;
4096 	lc->sound_conf.ring_lev=level;
4097 	sndcard=lc->sound_conf.ring_sndcard;
4098 	if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
4099 }
4100 
4101 void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){
4102 	float gain=gaindb;
4103 	LinphoneCall *call=linphone_core_get_current_call (lc);
4104 	AudioStream *st;
4105 
4106 	lc->sound_conf.soft_mic_lev=gaindb;
4107 
4108 	if (linphone_core_ready(lc)){
4109 		lp_config_set_float(lc->config,"sound","mic_gain_db",lc->sound_conf.soft_mic_lev);
4110 	}
4111 
4112 	if (call==NULL || (st=call->audiostream)==NULL){
4113 		ms_message("linphone_core_set_mic_gain_db(): no active call.");
4114 		return;
4115 	}
4116 	set_mic_gain_db(st,gain);
4117 }
4118 
4119 float linphone_core_get_mic_gain_db(LinphoneCore *lc) {
4120 	return lc->sound_conf.soft_mic_lev;
4121 }
4122 
4123 void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){
4124 	float gain=gaindb;
4125 	LinphoneCall *call=linphone_core_get_current_call (lc);
4126 	AudioStream *st;
4127 
4128 	lc->sound_conf.soft_play_lev=gaindb;
4129 	if (linphone_core_ready(lc)){
4130 		lp_config_set_float(lc->config,"sound","playback_gain_db",lc->sound_conf.soft_play_lev);
4131 	}
4132 
4133 	if (call==NULL || (st=call->audiostream)==NULL){
4134 		ms_message("linphone_core_set_playback_gain_db(): no active call.");
4135 		return;
4136 	}
4137 	set_playback_gain_db(st,gain);
4138 }
4139 
4140 float linphone_core_get_playback_gain_db(LinphoneCore *lc) {
4141 	return lc->sound_conf.soft_play_lev;
4142 }
4143 
4144 void linphone_core_set_play_level(LinphoneCore *lc, int level){
4145 	MSSndCard *sndcard;
4146 	lc->sound_conf.play_lev=level;
4147 	sndcard=lc->sound_conf.play_sndcard;
4148 	if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
4149 }
4150 
4151 void linphone_core_set_rec_level(LinphoneCore *lc, int level) {
4152 	MSSndCard *sndcard;
4153 	lc->sound_conf.rec_lev=level;
4154 	sndcard=lc->sound_conf.capt_sndcard;
4155 	if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_CAPTURE,level);
4156 }
4157 
4158 static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap, MSFactory *f){
4159 	MSSndCard *sndcard=NULL;
4160 	if (devid!=NULL){
4161 		sndcard=ms_snd_card_manager_get_card(ms_factory_get_snd_card_manager(f),devid);
4162 		if (sndcard!=NULL &&
4163 			(ms_snd_card_get_capabilities(sndcard) & cap)==0 ){
4164 			ms_warning("%s card does not have the %s capability, ignoring.",
4165 				devid,
4166 				cap==MS_SND_CARD_CAP_CAPTURE ? "capture" : "playback");
4167 			sndcard=NULL;
4168 		}
4169 	}
4170 	if (sndcard==NULL) {
4171 		if ((cap & MS_SND_CARD_CAP_CAPTURE) && (cap & MS_SND_CARD_CAP_PLAYBACK)){
4172 			sndcard=ms_snd_card_manager_get_default_card(ms_factory_get_snd_card_manager(f));
4173 		}else if (cap & MS_SND_CARD_CAP_CAPTURE){
4174 			sndcard=ms_snd_card_manager_get_default_capture_card(ms_factory_get_snd_card_manager(f));
4175 		}
4176 		else if (cap & MS_SND_CARD_CAP_PLAYBACK){
4177 			sndcard=ms_snd_card_manager_get_default_playback_card(ms_factory_get_snd_card_manager(f));
4178 		}
4179 		if (sndcard==NULL){/*looks like a bug! take the first one !*/
4180 			const bctbx_list_t *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(f));
4181 			if (elem) sndcard=(MSSndCard*)elem->data;
4182 		}
4183 	}
4184 	if (sndcard==NULL) ms_error("Could not find a suitable soundcard !");
4185 	return sndcard;
4186 }
4187 
4188 bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *devid){
4189 	return ms_snd_card_manager_get_capture_card(ms_factory_get_snd_card_manager(lc->factory),devid) != NULL;
4190 }
4191 
4192 bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *devid){
4193 	return ms_snd_card_manager_get_playback_card(ms_factory_get_snd_card_manager(lc->factory),devid) != NULL;
4194 }
4195 
4196 LinphoneStatus linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){
4197 	MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK, lc->factory);
4198 	lc->sound_conf.ring_sndcard=card;
4199 	if (card && linphone_core_ready(lc))
4200 		lp_config_set_string(lc->config,"sound","ringer_dev_id",ms_snd_card_get_string_id(card));
4201 	return 0;
4202 }
4203 
4204 LinphoneStatus linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){
4205 	MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK, lc->factory);
4206 	lc->sound_conf.play_sndcard=card;
4207 	if (card &&  linphone_core_ready(lc))
4208 		lp_config_set_string(lc->config,"sound","playback_dev_id",ms_snd_card_get_string_id(card));
4209 	return 0;
4210 }
4211 
4212 LinphoneStatus linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){
4213 	MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_CAPTURE, lc->factory);
4214 	lc->sound_conf.capt_sndcard=card;
4215 	if (card &&  linphone_core_ready(lc))
4216 		lp_config_set_string(lc->config,"sound","capture_dev_id",ms_snd_card_get_string_id(card));
4217 	return 0;
4218 }
4219 
4220 const char * linphone_core_get_ringer_device(LinphoneCore *lc) {
4221 	if (lc->sound_conf.ring_sndcard) return ms_snd_card_get_string_id(lc->sound_conf.ring_sndcard);
4222 	return NULL;
4223 }
4224 
4225 const char * linphone_core_get_playback_device(LinphoneCore *lc) {
4226 	return lc->sound_conf.play_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.play_sndcard) : NULL;
4227 }
4228 
4229 const char * linphone_core_get_capture_device(LinphoneCore *lc) {
4230 	return lc->sound_conf.capt_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.capt_sndcard) : NULL;
4231 }
4232 
4233 const char**  linphone_core_get_sound_devices(LinphoneCore *lc){
4234 	return lc->sound_conf.cards;
4235 }
4236 
4237 const char**  linphone_core_get_video_devices(const LinphoneCore *lc){
4238 	return lc->video_conf.cams;
4239 }
4240 
4241 void linphone_core_set_default_sound_devices(LinphoneCore *lc){
4242     linphone_core_set_ringer_device(lc, NULL);
4243     linphone_core_set_playback_device(lc, NULL);
4244     linphone_core_set_capture_device(lc, NULL);
4245 }
4246 
4247 void linphone_core_reload_sound_devices(LinphoneCore *lc){
4248 	const char *ringer;
4249 	const char *playback;
4250 	const char *capture;
4251 	char *ringer_copy = NULL;
4252 	char *playback_copy = NULL;
4253 	char *capture_copy = NULL;
4254 
4255 	ringer = linphone_core_get_ringer_device(lc);
4256 	if (ringer != NULL) {
4257 		ringer_copy = ms_strdup(ringer);
4258 	}
4259 	playback = linphone_core_get_playback_device(lc);
4260 	if (playback != NULL) {
4261 		playback_copy = ms_strdup(playback);
4262 	}
4263 	capture = linphone_core_get_capture_device(lc);
4264 	if (capture != NULL) {
4265 		capture_copy = ms_strdup(capture);
4266 	}
4267 	ms_snd_card_manager_reload(ms_factory_get_snd_card_manager(lc->factory));
4268 	build_sound_devices_table(lc);
4269 	if (ringer_copy != NULL) {
4270 		linphone_core_set_ringer_device(lc, ringer_copy);
4271 		ms_free(ringer_copy);
4272 	}
4273 	if (playback_copy != NULL) {
4274 		linphone_core_set_playback_device(lc, playback_copy);
4275 		ms_free(playback_copy);
4276 	}
4277 	if (capture_copy != NULL) {
4278 		linphone_core_set_capture_device(lc, capture_copy);
4279 		ms_free(capture_copy);
4280 	}
4281 }
4282 
4283 void linphone_core_reload_video_devices(LinphoneCore *lc){
4284 	char *devid_copy = NULL;
4285 	const char *devid = linphone_core_get_video_device(lc);
4286 	if (devid != NULL) {
4287 		devid_copy = ms_strdup(devid);
4288 	}
4289 	ms_web_cam_manager_reload(ms_factory_get_web_cam_manager(lc->factory));
4290 	build_video_devices_table(lc);
4291 	if (devid_copy != NULL) {
4292 		linphone_core_set_video_device(lc, devid_copy);
4293 		ms_free(devid_copy);
4294 	}
4295 }
4296 
4297 char linphone_core_get_sound_source(LinphoneCore *lc) {
4298 	return lc->sound_conf.source;
4299 }
4300 
4301 void linphone_core_set_sound_source(LinphoneCore *lc, char source) {
4302 	MSSndCard *sndcard=lc->sound_conf.capt_sndcard;
4303 	lc->sound_conf.source=source;
4304 	if (!sndcard) return;
4305 	switch(source){
4306 		case 'm':
4307 			ms_snd_card_set_capture(sndcard,MS_SND_CARD_MIC);
4308 			break;
4309 		case 'l':
4310 			ms_snd_card_set_capture(sndcard,MS_SND_CARD_LINE);
4311 			break;
4312 	}
4313 
4314 }
4315 
4316 
4317 void linphone_core_set_ring(LinphoneCore *lc,const char *path){
4318 	if (lc->sound_conf.local_ring!=0){
4319 		ms_free(lc->sound_conf.local_ring);
4320 		lc->sound_conf.local_ring=NULL;
4321 	}
4322 	if (path)
4323 		lc->sound_conf.local_ring=ms_strdup(path);
4324 	if ( linphone_core_ready(lc) && lc->sound_conf.local_ring)
4325 		lp_config_set_string(lc->config,"sound","local_ring",lc->sound_conf.local_ring);
4326 }
4327 
4328 const char *linphone_core_get_ring(const LinphoneCore *lc){
4329 	return lc->sound_conf.local_ring;
4330 }
4331 
4332 void linphone_core_set_root_ca(LinphoneCore *lc, const char *path) {
4333 	sal_set_root_ca(lc->sal, path);
4334 	if (lc->http_crypto_config) {
4335 		belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, path);
4336 	}
4337 	lp_config_set_string(lc->config,"sip", "root_ca", path);
4338 }
4339 
4340 void linphone_core_set_root_ca_data(LinphoneCore *lc, const char *data) {
4341 	sal_set_root_ca(lc->sal, NULL);
4342 	sal_set_root_ca_data(lc->sal, data);
4343 	if (lc->http_crypto_config) {
4344 		belle_tls_crypto_config_set_root_ca_data(lc->http_crypto_config, data);
4345 	}
4346 }
4347 
4348 const char *linphone_core_get_root_ca(LinphoneCore *lc){
4349 	return lp_config_get_string(lc->config,"sip","root_ca",NULL);
4350 }
4351 
4352 void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){
4353 	sal_verify_server_certificates(lc->sal,yesno);
4354 	if (lc->http_crypto_config){
4355 		belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_ANY_REASON);
4356 	}
4357 	lp_config_set_int(lc->config,"sip","verify_server_certs",yesno);
4358 }
4359 
4360 void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){
4361 	sal_verify_server_cn(lc->sal,yesno);
4362 	if (lc->http_crypto_config){
4363 		belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_CN_MISMATCH);
4364 	}
4365 	lp_config_set_int(lc->config,"sip","verify_server_cn",yesno);
4366 }
4367 
4368 void linphone_core_set_ssl_config(LinphoneCore *lc, void *ssl_config) {
4369 	sal_set_ssl_config(lc->sal, ssl_config);
4370 	if (lc->http_crypto_config) {
4371 		belle_tls_crypto_config_set_ssl_config(lc->http_crypto_config, ssl_config);
4372 	}
4373 }
4374 
4375 static void notify_end_of_ringtone( LinphoneRingtonePlayer* rp, void* user_data, int status) {
4376 	LinphoneCore *lc=(LinphoneCore*)user_data;
4377 	lc->preview_finished=1;
4378 }
4379 
4380 LinphoneStatus linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc end_of_ringtone,void * userdata)
4381 {
4382 	int err;
4383 	MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
4384 	if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)){
4385 		ms_warning("Cannot start ring now,there's already a ring being played");
4386 		return -1;
4387 	}
4388 	lc_callback_obj_init(&lc->preview_finished_cb,end_of_ringtone,userdata);
4389 	lc->preview_finished=0;
4390 	err = linphone_ringtoneplayer_start_with_cb(lc->factory, lc->ringtoneplayer, ringcard, ring, -1, notify_end_of_ringtone,(void *)lc);
4391 	if (err) {
4392 		lc->preview_finished=1;
4393 	}
4394 	return err;
4395 }
4396 
4397 MSFactory *linphone_core_get_ms_factory(LinphoneCore *lc){
4398 	return lc->factory;
4399 }
4400 
4401 void linphone_core_set_ringback(LinphoneCore *lc, const char *path){
4402 	if (lc->sound_conf.remote_ring!=0){
4403 		ms_free(lc->sound_conf.remote_ring);
4404 	}
4405 	lc->sound_conf.remote_ring=path?ms_strdup(path):NULL;
4406 }
4407 
4408 const char * linphone_core_get_ringback(const LinphoneCore *lc){
4409 	return lc->sound_conf.remote_ring;
4410 }
4411 
4412 void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val){
4413 	lc->sound_conf.ec=val;
4414 	if ( linphone_core_ready(lc))
4415 		lp_config_set_int(lc->config,"sound","echocancellation",val);
4416 }
4417 
4418 bool_t linphone_core_echo_cancellation_enabled(const LinphoneCore *lc){
4419 	return lc->sound_conf.ec;
4420 }
4421 
4422 void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val){
4423 	lc->sound_conf.ea=val;
4424 }
4425 
4426 bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){
4427 	return lc->sound_conf.ea;
4428 }
4429 
4430 static void linphone_core_mute_audio_stream(LinphoneCore *lc, AudioStream *st, bool_t val) {
4431 	if (val) {
4432 		audio_stream_set_mic_gain(st, 0);
4433 	} else {
4434 		audio_stream_set_mic_gain_db(st, lc->sound_conf.soft_mic_lev);
4435 	}
4436 
4437 	if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){
4438 		audio_stream_mute_rtp(st,val);
4439 	}
4440 }
4441 
4442 void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){
4443 	linphone_core_enable_mic(lc, !val);
4444 }
4445 
4446 bool_t linphone_core_is_mic_muted(LinphoneCore *lc) {
4447 	return !linphone_core_mic_enabled(lc);
4448 }
4449 
4450 void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable) {
4451 	LinphoneCall *call;
4452 	const bctbx_list_t *list;
4453 	const bctbx_list_t *elem;
4454 
4455 	if (linphone_core_is_in_conference(lc)){
4456 		linphone_conference_mute_microphone(lc->conf_ctx, !enable);
4457 	}
4458 	list = linphone_core_get_calls(lc);
4459 	for (elem = list; elem != NULL; elem = elem->next) {
4460 		call = (LinphoneCall *)elem->data;
4461 		call->audio_muted = !enable;
4462 		if (call->audiostream)
4463 			linphone_core_mute_audio_stream(lc, call->audiostream, call->audio_muted);
4464 	}
4465 }
4466 
4467 bool_t linphone_core_mic_enabled(LinphoneCore *lc) {
4468 	LinphoneCall *call=linphone_core_get_current_call(lc);
4469 	if (linphone_core_is_in_conference(lc)){
4470 		return !linphone_conference_microphone_is_muted(lc->conf_ctx);
4471 	}else if (call==NULL){
4472 		ms_warning("%s(): No current call!", __FUNCTION__);
4473 		return TRUE;
4474 	}
4475 	return !call->audio_muted;
4476 }
4477 
4478 bool_t linphone_core_is_rtp_muted(LinphoneCore *lc){
4479 	LinphoneCall *call=linphone_core_get_current_call(lc);
4480 	if (call==NULL){
4481 		ms_warning("linphone_core_is_rtp_muted(): No current call !");
4482 		return FALSE;
4483 	}
4484 	if( linphone_core_get_rtp_no_xmit_on_audio_mute(lc)){
4485 		return call->audio_muted;
4486 	}
4487 	return FALSE;
4488 }
4489 
4490 void linphone_core_enable_agc(LinphoneCore *lc, bool_t val){
4491 	lc->sound_conf.agc=val;
4492 }
4493 
4494 bool_t linphone_core_agc_enabled(const LinphoneCore *lc){
4495 	return lc->sound_conf.agc;
4496 }
4497 
4498 void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf) {
4499 	LinphoneCall *call=linphone_core_get_current_call(lc);
4500 	linphone_call_send_dtmf(call, dtmf);
4501 }
4502 
4503 void linphone_core_set_stun_server(LinphoneCore *lc, const char *server) {
4504 	if (lc->nat_policy != NULL) {
4505 		linphone_nat_policy_set_stun_server(lc->nat_policy, server);
4506 		linphone_nat_policy_save_to_config(lc->nat_policy);
4507 	} else {
4508 		lp_config_set_string(lc->config, "net", "stun_server", server);
4509 	}
4510 }
4511 
4512 const char * linphone_core_get_stun_server(const LinphoneCore *lc){
4513 	if (lc->nat_policy != NULL)
4514 		return linphone_nat_policy_get_stun_server(lc->nat_policy);
4515 	else
4516 		return lp_config_get_string(lc->config, "net", "stun_server", NULL);
4517 }
4518 
4519 
4520 bool_t linphone_core_upnp_available(){
4521 #ifdef BUILD_UPNP
4522 	return TRUE;
4523 #else
4524 	return FALSE;
4525 #endif //BUILD_UPNP
4526 }
4527 
4528 LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc){
4529 #ifdef BUILD_UPNP
4530 	return linphone_upnp_context_get_state(lc->upnp);
4531 #else
4532 	return LinphoneUpnpStateNotAvailable;
4533 #endif //BUILD_UPNP
4534 }
4535 
4536 const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc){
4537 #ifdef BUILD_UPNP
4538 	return linphone_upnp_context_get_external_ipaddress(lc->upnp);
4539 #else
4540 	return NULL;
4541 #endif //BUILD_UPNP
4542 }
4543 
4544 void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr) {
4545 	if (lc->net_conf.nat_address!=NULL){
4546 		ms_free(lc->net_conf.nat_address);
4547 	}
4548 	if (addr!=NULL) lc->net_conf.nat_address=ms_strdup(addr);
4549 	else lc->net_conf.nat_address=NULL;
4550 	if (lc->sip_conf.contact) update_primary_contact(lc);
4551 }
4552 
4553 const char *linphone_core_get_nat_address(const LinphoneCore *lc) {
4554 	return lc->net_conf.nat_address;
4555 }
4556 
4557 const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) {
4558 	struct sockaddr_storage ss;
4559 	socklen_t ss_len;
4560 	int error;
4561 	char ipstring [INET6_ADDRSTRLEN];
4562 
4563 	if (lc->net_conf.nat_address==NULL) return NULL;
4564 
4565 	if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len, 5060)<0) {
4566 		return lc->net_conf.nat_address;
4567 	}
4568 
4569 	error = bctbx_getnameinfo((struct sockaddr *)&ss, ss_len,
4570 		ipstring, sizeof(ipstring), NULL, 0, NI_NUMERICHOST);
4571 	if (error) {
4572 		return lc->net_conf.nat_address;
4573 	}
4574 
4575 	if (lc->net_conf.nat_address_ip!=NULL){
4576 		ms_free(lc->net_conf.nat_address_ip);
4577 	}
4578 	lc->net_conf.nat_address_ip = ms_strdup (ipstring);
4579 	return lc->net_conf.nat_address_ip;
4580 }
4581 
4582 void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol) {
4583 	LinphoneNatPolicy *nat_policy;
4584 	char *stun_server = NULL;
4585 	char *stun_server_username = NULL;
4586 
4587 	if (lc->nat_policy != NULL) {
4588 		nat_policy = linphone_nat_policy_ref(lc->nat_policy);
4589 		stun_server = ms_strdup(linphone_nat_policy_get_stun_server(nat_policy));
4590 		stun_server_username = ms_strdup(linphone_nat_policy_get_stun_server_username(nat_policy));
4591 		linphone_nat_policy_clear(nat_policy);
4592 	} else {
4593 		nat_policy = linphone_core_create_nat_policy(lc);
4594 		stun_server = ms_strdup(linphone_core_get_stun_server(lc));
4595 	}
4596 
4597 	switch (pol) {
4598 		default:
4599 		case LinphonePolicyNoFirewall:
4600 		case LinphonePolicyUseNatAddress:
4601 			break;
4602 		case LinphonePolicyUseStun:
4603 			linphone_nat_policy_enable_stun(nat_policy, TRUE);
4604 			break;
4605 		case LinphonePolicyUseIce:
4606 			linphone_nat_policy_enable_ice(nat_policy, TRUE);
4607 			linphone_nat_policy_enable_stun(nat_policy, TRUE);
4608 			break;
4609 		case LinphonePolicyUseUpnp:
4610 #ifdef BUILD_UPNP
4611 			linphone_nat_policy_enable_upnp(nat_policy, TRUE);
4612 #else
4613 			ms_warning("UPNP is not available, reset firewall policy to no firewall");
4614 #endif //BUILD_UPNP
4615 			break;
4616 	}
4617 
4618 	if (stun_server_username != NULL) {
4619 		linphone_nat_policy_set_stun_server_username(nat_policy, stun_server_username);
4620 		ms_free(stun_server_username);
4621 	}
4622 	if (stun_server != NULL) {
4623 		linphone_nat_policy_set_stun_server(nat_policy, stun_server);
4624 		ms_free(stun_server);
4625 	}
4626 	linphone_core_set_nat_policy(lc, nat_policy);
4627 	linphone_nat_policy_unref(nat_policy);
4628 
4629 	/* Ensure that the firewall policy is cleared in the config because it has been replaced by the nat_policy. */
4630 	lp_config_set_string(lc->config, "net", "firewall_policy", NULL);
4631 }
4632 
4633 LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc) {
4634 	const char *policy;
4635 
4636 	policy = lp_config_get_string(lc->config, "net", "firewall_policy", NULL);
4637 	if (policy == NULL) {
4638 		LinphoneNatPolicy *nat_policy = linphone_core_get_nat_policy(lc);
4639 		if (nat_policy == NULL) {
4640 			return LinphonePolicyNoFirewall;
4641 		} else if (linphone_nat_policy_upnp_enabled(nat_policy))
4642 			return LinphonePolicyUseUpnp;
4643 		else if (linphone_nat_policy_ice_enabled(nat_policy))
4644 			return LinphonePolicyUseIce;
4645 		else if (linphone_nat_policy_stun_enabled(nat_policy))
4646 			return LinphonePolicyUseStun;
4647 		else
4648 			return LinphonePolicyNoFirewall;
4649 	} else if (strcmp(policy, "0") == 0)
4650 		return LinphonePolicyNoFirewall;
4651 	else if ((strcmp(policy, "nat_address") == 0) || (strcmp(policy, "1") == 0))
4652 		return LinphonePolicyUseNatAddress;
4653 	else if ((strcmp(policy, "stun") == 0) || (strcmp(policy, "2") == 0))
4654 		return LinphonePolicyUseStun;
4655 	else if ((strcmp(policy, "ice") == 0) || (strcmp(policy, "3") == 0))
4656 		return LinphonePolicyUseIce;
4657 	else if ((strcmp(policy, "upnp") == 0) || (strcmp(policy, "4") == 0))
4658 		return LinphonePolicyUseUpnp;
4659 	else
4660 		return LinphonePolicyNoFirewall;
4661 }
4662 
4663 void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy) {
4664 	if (policy != NULL) policy = linphone_nat_policy_ref(policy); /* Prevent object destruction if the same policy is used */
4665 	else{
4666 		ms_error("linphone_core_set_nat_policy() setting to NULL is not allowed");
4667 		return ;
4668 	}
4669 	if (lc->nat_policy != NULL) {
4670 		linphone_nat_policy_unref(lc->nat_policy);
4671 		lc->nat_policy = NULL;
4672 	}
4673 	if (policy != NULL){
4674 		lc->nat_policy = policy;
4675 		/*start an immediate (but asynchronous) resolution.*/
4676 		linphone_nat_policy_resolve_stun_server(policy);
4677 		lp_config_set_string(lc->config, "net", "nat_policy_ref", lc->nat_policy->ref);
4678 		linphone_nat_policy_save_to_config(lc->nat_policy);
4679 	}
4680 
4681 #ifdef BUILD_UPNP
4682 	linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
4683 	if (linphone_nat_policy_upnp_enabled(policy)) {
4684 		if (lc->upnp == NULL) {
4685 			lc->upnp = linphone_upnp_context_new(lc);
4686 		}
4687 		sal_nat_helper_enable(lc->sal, FALSE);
4688 		sal_enable_auto_contacts(lc->sal, FALSE);
4689 		sal_use_rport(lc->sal, FALSE);
4690 	} else {
4691 		if (lc->upnp != NULL) {
4692 			linphone_upnp_context_destroy(lc->upnp);
4693 			lc->upnp = NULL;
4694 		}
4695 #endif
4696 		sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config, "net", "enable_nat_helper", 1));
4697 		sal_enable_auto_contacts(lc->sal, TRUE);
4698 		sal_use_rport(lc->sal, lp_config_get_int(lc->config, "sip", "use_rport", 1));
4699 		if (lc->sip_conf.contact) update_primary_contact(lc);
4700 #ifdef BUILD_UPNP
4701 	}
4702 #endif
4703 }
4704 
4705 LinphoneNatPolicy * linphone_core_get_nat_policy(const LinphoneCore *lc) {
4706 	return lc->nat_policy;
4707 }
4708 
4709 
4710 /*******************************************************************************
4711  * Call log related functions                                                  *
4712  ******************************************************************************/
4713 
4714 void linphone_core_set_call_logs_database_path(LinphoneCore *lc, const char *path) {
4715 	if (lc->logs_db_file){
4716 		ms_free(lc->logs_db_file);
4717 		lc->logs_db_file = NULL;
4718 	}
4719 	if (path) {
4720 		lc->logs_db_file = ms_strdup(path);
4721 		linphone_core_call_log_storage_init(lc);
4722 
4723 		linphone_core_migrate_logs_from_rc_to_db(lc);
4724 	}
4725 }
4726 
4727 const char * linphone_core_get_call_logs_database_path(LinphoneCore *lc) {
4728 	return lc->logs_db_file;
4729 }
4730 
4731 const bctbx_list_t* linphone_core_get_call_logs(LinphoneCore *lc) {
4732 #ifdef SQLITE_STORAGE_ENABLED
4733 	if (lc->logs_db) {
4734 		linphone_core_get_call_history(lc);
4735 	}
4736 #endif
4737 	return lc->call_logs;
4738 }
4739 
4740 void linphone_core_clear_call_logs(LinphoneCore *lc) {
4741 	bool_t call_logs_sqlite_db_found = FALSE;
4742 	lc->missed_calls=0;
4743 #ifdef SQLITE_STORAGE_ENABLED
4744 	if (lc->logs_db) {
4745 		call_logs_sqlite_db_found = TRUE;
4746 		linphone_core_delete_call_history(lc);
4747 	}
4748 #endif
4749 	if (!call_logs_sqlite_db_found) {
4750 		bctbx_list_for_each(lc->call_logs, (void (*)(void*))linphone_call_log_unref);
4751 		lc->call_logs = bctbx_list_free(lc->call_logs);
4752 		call_logs_write_to_config_file(lc);
4753 	}
4754 }
4755 
4756 int linphone_core_get_missed_calls_count(LinphoneCore *lc) {
4757 	return lc->missed_calls;
4758 }
4759 
4760 void linphone_core_reset_missed_calls_count(LinphoneCore *lc) {
4761 	lc->missed_calls=0;
4762 }
4763 
4764 void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *cl) {
4765 	bool_t call_logs_sqlite_db_found = FALSE;
4766 #ifdef SQLITE_STORAGE_ENABLED
4767 	if (lc->logs_db) {
4768 		call_logs_sqlite_db_found = TRUE;
4769 		linphone_core_delete_call_log(lc, cl);
4770 	}
4771 #endif
4772 	lc->call_logs = bctbx_list_remove(lc->call_logs, cl);
4773 	if (!call_logs_sqlite_db_found) {
4774 		call_logs_write_to_config_file(lc);
4775 		linphone_call_log_unref(cl);
4776 	}
4777 }
4778 
4779 void linphone_core_migrate_logs_from_rc_to_db(LinphoneCore *lc) {
4780 	bctbx_list_t *logs_to_migrate = NULL;
4781 	LpConfig *lpc = NULL;
4782 	size_t original_logs_count, migrated_logs_count;
4783 	int i;
4784 
4785 #ifndef SQLITE_STORAGE_ENABLED
4786 	ms_warning("linphone has been compiled without sqlite, can't migrate call logs");
4787 	return;
4788 #endif
4789 	if (!lc) {
4790 		return;
4791 	}
4792 
4793 	lpc = linphone_core_get_config(lc);
4794 	if (!lpc) {
4795 		ms_warning("this core has been started without a rc file, nothing to migrate");
4796 		return;
4797 	}
4798 	if (lp_config_get_int(lpc, "misc", "call_logs_migration_done", 0) == 1) {
4799 		ms_warning("the call logs migration has already been done, skipping...");
4800 		return;
4801 	}
4802 
4803 	logs_to_migrate = call_logs_read_from_config_file(lc);
4804 	if (!logs_to_migrate) {
4805 		ms_warning("nothing to migrate, skipping...");
4806 		return;
4807 	}
4808 
4809 	// This is because there must have been a call previously to linphone_core_call_log_storage_init
4810 	lc->call_logs = bctbx_list_free_with_data(lc->call_logs, (void (*)(void*))linphone_call_log_unref);
4811 	lc->call_logs = NULL;
4812 
4813 	// We can't use bctbx_list_for_each because logs_to_migrate are listed in the wrong order (latest first), and we want to store the logs latest last
4814 	for (i = (int)bctbx_list_size(logs_to_migrate) - 1; i >= 0; i--) {
4815 		LinphoneCallLog *log = (LinphoneCallLog *) bctbx_list_nth_data(logs_to_migrate, i);
4816 		linphone_core_store_call_log(lc, log);
4817 	}
4818 
4819 	original_logs_count = bctbx_list_size(logs_to_migrate);
4820 	migrated_logs_count = bctbx_list_size(lc->call_logs);
4821 	if (original_logs_count == migrated_logs_count) {
4822 		size_t i = 0;
4823 		ms_debug("call logs migration successful: %u logs migrated", (unsigned int)bctbx_list_size(lc->call_logs));
4824 		lp_config_set_int(lpc, "misc", "call_logs_migration_done", 1);
4825 
4826 		for (; i < original_logs_count; i++) {
4827 			char logsection[32];
4828 			snprintf(logsection, sizeof(logsection), "call_log_%u", (unsigned int)i);
4829 			lp_config_clean_section(lpc, logsection);
4830 		}
4831 	} else {
4832 		ms_error("not as many logs saved in db has logs read from rc ("FORMAT_SIZE_T" in rc against "FORMAT_SIZE_T" in db)!", original_logs_count, migrated_logs_count);
4833 	}
4834 
4835 	bctbx_list_free_with_data(logs_to_migrate, (void (*)(void*))linphone_call_log_unref);
4836 }
4837 
4838 
4839 /*******************************************************************************
4840  * Video related functions                                                  *
4841  ******************************************************************************/
4842 
4843 #ifdef VIDEO_ENABLED
4844 static void snapshot_taken(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) {
4845 	if (id == MS_JPEG_WRITER_SNAPSHOT_TAKEN) {
4846 		LinphoneCore *lc = (LinphoneCore *)userdata;
4847 		linphone_core_enable_video_preview(lc, FALSE);
4848 	}
4849 }
4850 #endif
4851 
4852 LinphoneStatus linphone_core_take_preview_snapshot(LinphoneCore *lc, const char *file) {
4853 	LinphoneCall *call = linphone_core_get_current_call(lc);
4854 
4855 	if (!file) return -1;
4856 	if (call) {
4857 		return linphone_call_take_preview_snapshot(call, file);
4858 	} else {
4859 #ifdef VIDEO_ENABLED
4860 		if (lc->previewstream == NULL) {
4861 			MSVideoSize vsize=lc->video_conf.preview_vsize.width != 0 ? lc->video_conf.preview_vsize : lc->video_conf.vsize;
4862 			lc->previewstream = video_preview_new(lc->factory);
4863 			video_preview_set_size(lc->previewstream, vsize);
4864 			video_preview_set_display_filter_name(lc->previewstream, NULL);
4865 			video_preview_set_fps(lc->previewstream,linphone_core_get_preferred_framerate(lc));
4866 			video_preview_start(lc->previewstream, lc->video_conf.device);
4867 			lc->previewstream->ms.factory = lc->factory;
4868 			linphone_core_enable_video_preview(lc, TRUE);
4869 
4870 			ms_filter_add_notify_callback(lc->previewstream->local_jpegwriter, snapshot_taken, lc, TRUE);
4871 			ms_filter_call_method(lc->previewstream->local_jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void*)file);
4872 		} else {
4873 			ms_filter_call_method(lc->previewstream->local_jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void*)file);
4874 		}
4875 		return 0;
4876 #endif
4877 	}
4878 	return -1;
4879 }
4880 
4881 static void toggle_video_preview(LinphoneCore *lc, bool_t val){
4882 #ifdef VIDEO_ENABLED
4883 	if (val){
4884 		if (lc->previewstream==NULL){
4885 			const char *display_filter=linphone_core_get_video_display_filter(lc);
4886 			MSVideoSize vsize = { 0 };
4887 			const LinphoneVideoDefinition *vdef = linphone_core_get_preview_video_definition(lc);
4888 			if (!vdef || linphone_video_definition_is_undefined(vdef)) {
4889 				vdef = linphone_core_get_preferred_video_definition(lc);
4890 			}
4891 			vsize.width = linphone_video_definition_get_width(vdef);
4892 			vsize.height = linphone_video_definition_get_height(vdef);
4893 			lc->previewstream=video_preview_new(lc->factory);
4894 			video_preview_set_size(lc->previewstream,vsize);
4895 			if (display_filter)
4896 				video_preview_set_display_filter_name(lc->previewstream,display_filter);
4897 			if (lc->preview_window_id != NULL)
4898 				video_preview_set_native_window_id(lc->previewstream,lc->preview_window_id);
4899 			video_preview_set_fps(lc->previewstream,linphone_core_get_preferred_framerate(lc));
4900 			video_preview_start(lc->previewstream,lc->video_conf.device);
4901 		}
4902 	}else{
4903 		if (lc->previewstream!=NULL){
4904 			video_preview_stop(lc->previewstream);
4905 			lc->previewstream=NULL;
4906 		}
4907 	}
4908 #endif
4909 }
4910 
4911 static void relaunch_video_preview(LinphoneCore *lc){
4912 	if (lc->previewstream){
4913 		toggle_video_preview(lc,FALSE);
4914 	}
4915 	/* And nothing else, because linphone_core_iterate() will restart the preview stream if necessary.
4916 	 * This code will need to be revisited when linphone_core_iterate() will no longer be required*/
4917 }
4918 
4919 bool_t linphone_core_video_supported(LinphoneCore *lc){
4920 #ifdef VIDEO_ENABLED
4921 	return TRUE;
4922 #else
4923 	return FALSE;
4924 #endif
4925 }
4926 
4927 void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled) {
4928 	linphone_core_enable_video_capture(lc, vcap_enabled);
4929 	linphone_core_enable_video_display(lc, display_enabled);
4930 }
4931 
4932 bool_t linphone_core_video_enabled(LinphoneCore *lc){
4933 	return (lc->video_conf.display || lc->video_conf.capture);
4934 }
4935 
4936 static void reapply_network_bandwidth_settings(LinphoneCore *lc) {
4937 	linphone_core_set_download_bandwidth(lc, linphone_core_get_download_bandwidth(lc));
4938 	linphone_core_set_upload_bandwidth(lc, linphone_core_get_upload_bandwidth(lc));
4939 }
4940 
4941 void linphone_core_enable_video_capture(LinphoneCore *lc, bool_t enable) {
4942 #ifndef VIDEO_ENABLED
4943 	if (enable == TRUE) {
4944 		ms_warning("Cannot enable video capture, this version of linphone was built without video support.");
4945 	}
4946 #endif
4947 	lc->video_conf.capture = enable;
4948 	if (linphone_core_ready(lc)) {
4949 		lp_config_set_int(lc->config, "video", "capture", lc->video_conf.capture);
4950 	}
4951 	/* Need to re-apply network bandwidth settings. */
4952 	reapply_network_bandwidth_settings(lc);
4953 }
4954 
4955 void linphone_core_enable_video_display(LinphoneCore *lc, bool_t enable) {
4956 #ifndef VIDEO_ENABLED
4957 	if (enable == TRUE) {
4958 		ms_warning("Cannot enable video display, this version of linphone was built without video support.");
4959 	}
4960 #endif
4961 	lc->video_conf.display = enable;
4962 	if (linphone_core_ready(lc)) {
4963 		lp_config_set_int(lc->config, "video", "display", lc->video_conf.display);
4964 	}
4965 	/* Need to re-apply network bandwidth settings. */
4966 	reapply_network_bandwidth_settings(lc);
4967 }
4968 
4969 void linphone_core_enable_video_source_reuse(LinphoneCore* lc, bool_t enable){
4970 #ifndef VIDEO_ENABLED
4971 	if (enable == TRUE) {
4972 		ms_warning("Cannot enable video display, this version of linphone was built without video support.");
4973 	}
4974 #endif
4975 	lc->video_conf.reuse_preview_source = enable;
4976 	if( linphone_core_ready(lc) ){
4977 		lp_config_set_int(lc->config, "video", "reuse_source", lc->video_conf.reuse_preview_source);
4978 	}
4979 }
4980 
4981 bool_t linphone_core_video_capture_enabled(LinphoneCore *lc) {
4982 	return lc->video_conf.capture;
4983 }
4984 
4985 bool_t linphone_core_video_display_enabled(LinphoneCore *lc) {
4986 	return lc->video_conf.display;
4987 }
4988 
4989 void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy){
4990 	lc->video_policy=*policy;
4991 	if (linphone_core_ready(lc)){
4992 		lp_config_set_int(lc->config,"video","automatically_initiate",policy->automatically_initiate);
4993 		lp_config_set_int(lc->config,"video","automatically_accept",policy->automatically_accept);
4994 	}
4995 }
4996 
4997 const LinphoneVideoPolicy *linphone_core_get_video_policy(const LinphoneCore *lc){
4998 	return &lc->video_policy;
4999 }
5000 
5001 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneVideoActivationPolicy);
5002 
5003 BELLE_SIP_INSTANCIATE_VPTR(LinphoneVideoActivationPolicy, belle_sip_object_t,
5004 	NULL, // destroy
5005 	NULL, // clone
5006 	NULL, // marshal
5007 	FALSE
5008 );
5009 
5010 LinphoneVideoActivationPolicy *linphone_video_activation_policy_new() {
5011 	LinphoneVideoActivationPolicy *policy = belle_sip_object_new(LinphoneVideoActivationPolicy);
5012 	policy->automatically_accept = FALSE;
5013 	policy->automatically_initiate = FALSE;
5014 	return policy;
5015 }
5016 
5017 LinphoneVideoActivationPolicy* linphone_video_activation_policy_ref(LinphoneVideoActivationPolicy* policy) {
5018 	return (LinphoneVideoActivationPolicy*) belle_sip_object_ref(policy);
5019 }
5020 
5021 void linphone_video_activation_policy_unref(LinphoneVideoActivationPolicy* policy) {
5022 	belle_sip_object_unref(policy);
5023 }
5024 
5025 void *linphone_video_activation_policy_get_user_data(const LinphoneVideoActivationPolicy *policy) {
5026 	return policy->user_data;
5027 }
5028 
5029 void linphone_video_activation_policy_set_user_data(LinphoneVideoActivationPolicy *policy, void *data) {
5030 	policy->user_data = data;
5031 }
5032 
5033 bool_t linphone_video_activation_policy_get_automatically_accept(const LinphoneVideoActivationPolicy *policy) {
5034 	return policy->automatically_accept;
5035 }
5036 
5037 bool_t linphone_video_activation_policy_get_automatically_initiate(const LinphoneVideoActivationPolicy *policy) {
5038 	return policy->automatically_initiate;
5039 }
5040 
5041 void linphone_video_activation_policy_set_automatically_accept(LinphoneVideoActivationPolicy *policy, bool_t enable) {
5042 	policy->automatically_accept = enable;
5043 }
5044 
5045 void linphone_video_activation_policy_set_automatically_initiate(LinphoneVideoActivationPolicy *policy, bool_t enable) {
5046 	policy->automatically_initiate = enable;
5047 }
5048 
5049 void linphone_core_set_video_activation_policy(LinphoneCore *lc, const LinphoneVideoActivationPolicy *policy) {
5050 	lc->video_policy.automatically_accept = policy->automatically_accept;
5051 	lc->video_policy.automatically_initiate = policy->automatically_initiate;
5052 	if (linphone_core_ready(lc)) {
5053 		lp_config_set_int(lc->config, "video", "automatically_initiate", policy->automatically_initiate);
5054 		lp_config_set_int(lc->config, "video", "automatically_accept", policy->automatically_accept);
5055 	}
5056 }
5057 
5058 LinphoneVideoActivationPolicy *linphone_core_get_video_activation_policy(const LinphoneCore *lc){
5059 	LinphoneVideoActivationPolicy *policy = linphone_video_activation_policy_new();
5060 	policy->automatically_accept = lc->video_policy.automatically_accept;
5061 	policy->automatically_initiate = lc->video_policy.automatically_initiate;
5062 	return policy;
5063 }
5064 
5065 void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){
5066 	lc->video_conf.show_local=val;
5067 	if (linphone_core_ready(lc))
5068 		lp_config_set_int(lc->config,"video","show_local",val);
5069 }
5070 
5071 bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc){
5072 	return lc->video_conf.show_local;
5073 }
5074 
5075 void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){
5076 #ifdef VIDEO_ENABLED
5077 	LinphoneCall *call=linphone_core_get_current_call (lc);
5078 	lc->video_conf.selfview=val;
5079 	if (linphone_core_ready(lc)) {
5080 		lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc));
5081 	}
5082 	if (call && call->videostream){
5083 		video_stream_enable_self_view(call->videostream,val);
5084 	}
5085 	if (linphone_core_ready(lc)){
5086 		lp_config_set_int(lc->config,"video","self_view",val);
5087 	}
5088 #endif
5089 }
5090 
5091 bool_t linphone_core_self_view_enabled(const LinphoneCore *lc){
5092 	return lc->video_conf.selfview;
5093 }
5094 
5095 LinphoneStatus linphone_core_set_video_device(LinphoneCore *lc, const char *id){
5096 	MSWebCam *olddev=lc->video_conf.device;
5097 	const char *vd;
5098 	if (id!=NULL){
5099 		lc->video_conf.device=ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(lc->factory),id);
5100 		if (lc->video_conf.device==NULL){
5101 			ms_warning("Could not find video device %s",id);
5102 		}
5103 	}
5104 	if (lc->video_conf.device==NULL)
5105 		lc->video_conf.device=ms_web_cam_manager_get_default_cam(ms_factory_get_web_cam_manager(lc->factory));
5106 	if (olddev!=NULL && olddev!=lc->video_conf.device){
5107 		relaunch_video_preview(lc);
5108 	}
5109 	if ( linphone_core_ready(lc) && lc->video_conf.device){
5110 		vd=ms_web_cam_get_string_id(lc->video_conf.device);
5111 		if (vd && strstr(vd,"Static picture")!=NULL){
5112 			vd=NULL;
5113 		}
5114 		lp_config_set_string(lc->config,"video","device",vd);
5115 	}
5116 	return 0;
5117 }
5118 
5119 const char *linphone_core_get_video_device(const LinphoneCore *lc){
5120 	if (lc->video_conf.device) return ms_web_cam_get_string_id(lc->video_conf.device);
5121 	return NULL;
5122 }
5123 
5124 #ifdef VIDEO_ENABLED
5125 static VideoStream * get_active_video_stream(LinphoneCore *lc){
5126 	VideoStream *vs = NULL;
5127 	LinphoneCall *call=linphone_core_get_current_call (lc);
5128 	/* Select the video stream from the call in the first place */
5129 	if (call && call->videostream) {
5130 		vs = call->videostream;
5131 	}
5132 	/* If not in call, select the video stream from the preview */
5133 	if (vs == NULL && lc->previewstream) {
5134 		vs = lc->previewstream;
5135 	}
5136 	return vs;
5137 }
5138 #endif
5139 
5140 LinphoneStatus linphone_core_set_static_picture(LinphoneCore *lc, const char *path) {
5141 #ifdef VIDEO_ENABLED
5142 	VideoStream *vs=get_active_video_stream(lc);
5143 	/* If we have a video stream (either preview, either from call), we
5144 		 have a source and it is using the static picture filter, then
5145 		 force the filter to use that picture. */
5146 	if (vs && vs->source) {
5147 		if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) {
5148 			ms_filter_call_method(vs->source, MS_STATIC_IMAGE_SET_IMAGE,
5149 														(void *)path);
5150 		}
5151 	}
5152 	/* Tell the static image filter to use that image from now on so
5153 		 that the image will be used next time it has to be read */
5154 	ms_static_image_set_default_image(path);
5155 #else
5156 	ms_warning("Video support not compiled.");
5157 #endif
5158 	return 0;
5159 }
5160 
5161 const char *linphone_core_get_static_picture(LinphoneCore *lc) {
5162 	const char *path=NULL;
5163 #ifdef VIDEO_ENABLED
5164 	path=ms_static_image_get_default_image();
5165 #else
5166 	ms_warning("Video support not compiled.");
5167 #endif
5168 	return path;
5169 }
5170 
5171 LinphoneStatus linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps) {
5172 #ifdef VIDEO_ENABLED
5173 	VideoStream *vs = NULL;
5174 
5175 	vs=get_active_video_stream(lc);
5176 
5177 	/* If we have a video stream (either preview, either from call), we
5178 		 have a source and it is using the static picture filter, then
5179 		 force the filter to use that picture. */
5180 	if (vs && vs->source) {
5181 		if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) {
5182 			ms_filter_call_method(vs->source, MS_FILTER_SET_FPS,(void *)&fps);
5183 		}
5184 	}
5185 #else
5186 	ms_warning("Video support not compiled.");
5187 #endif
5188 	return 0;
5189 }
5190 
5191 float linphone_core_get_static_picture_fps(LinphoneCore *lc) {
5192 #ifdef VIDEO_ENABLED
5193 	VideoStream *vs = NULL;
5194 	vs=get_active_video_stream(lc);
5195 	/* If we have a video stream (either preview, either from call), we
5196 		 have a source and it is using the static picture filter, then
5197 		 force the filter to use that picture. */
5198 	if (vs && vs->source) {
5199 		if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) {
5200 
5201 				float fps;
5202 
5203 			ms_filter_call_method(vs->source, MS_FILTER_GET_FPS,(void *)&fps);
5204 			return fps;
5205 		}
5206 	}
5207 #else
5208 	ms_warning("Video support not compiled.");
5209 #endif
5210 	return 0;
5211 }
5212 
5213 void * linphone_core_get_native_video_window_id(const LinphoneCore *lc){
5214 	if (lc->video_window_id) {
5215 		/* case where the video id was previously set by the app*/
5216 		return lc->video_window_id;
5217 	}else{
5218 #ifdef VIDEO_ENABLED
5219 		/*case where it was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only)*/
5220 		LinphoneCall *call=linphone_core_get_current_call (lc);
5221 		if (call && call->videostream)
5222 			return video_stream_get_native_window_id(call->videostream);
5223 #endif
5224 	}
5225 	return 0;
5226 }
5227 
5228 /* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/
5229 static void unset_video_window_id(LinphoneCore *lc, bool_t preview, void *id){
5230 #ifdef VIDEO_ENABLED
5231 	LinphoneCall *call;
5232 	bctbx_list_t *elem;
5233 #endif
5234 
5235 	if ((id != NULL)
5236 #ifndef _WIN32
5237 		&& ((unsigned long)id != (unsigned long)-1)
5238 #endif
5239 	){
5240 		ms_error("Invalid use of unset_video_window_id()");
5241 		return;
5242 	}
5243 #ifdef VIDEO_ENABLED
5244 	for(elem=lc->calls;elem!=NULL;elem=elem->next){
5245 		call=(LinphoneCall *) elem->data;
5246 		if (call->videostream){
5247 			if (preview)
5248 				video_stream_set_native_preview_window_id(call->videostream,id);
5249 			else
5250 				video_stream_set_native_window_id(call->videostream,id);
5251 		}
5252 	}
5253 #endif
5254 }
5255 
5256 void linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id){
5257 	if ((id == NULL)
5258 #ifndef _WIN32
5259 		|| ((unsigned long)id == (unsigned long)-1)
5260 #endif
5261 	){
5262 		unset_video_window_id(lc,FALSE,id);
5263 	}
5264 	lc->video_window_id=id;
5265 #ifdef VIDEO_ENABLED
5266 	{
5267 		LinphoneCall *call=linphone_core_get_current_call(lc);
5268 		if (call!=NULL && call->videostream){
5269 			video_stream_set_native_window_id(call->videostream,id);
5270 		}
5271 	}
5272 #endif
5273 }
5274 
5275 void * linphone_core_get_native_preview_window_id(const LinphoneCore *lc){
5276 	if (lc->preview_window_id){
5277 		/*case where the id was set by the app previously*/
5278 		return lc->preview_window_id;
5279 	}else{
5280 		/*case where we want the id automatically created by mediastreamer2 (desktop versions only)*/
5281 #ifdef VIDEO_ENABLED
5282 		LinphoneCall *call=linphone_core_get_current_call(lc);
5283 		if (call && call->videostream)
5284 			return video_stream_get_native_preview_window_id(call->videostream);
5285 		if (lc->previewstream)
5286 			return video_preview_get_native_window_id(lc->previewstream);
5287 #endif
5288 	}
5289 	return 0;
5290 }
5291 
5292 void linphone_core_set_native_preview_window_id(LinphoneCore *lc, void *id){
5293 	if ((id == NULL)
5294 #ifndef _WIN32
5295 		|| ((unsigned long)id == (unsigned long)-1)
5296 #endif
5297 	) {
5298 		unset_video_window_id(lc,TRUE,id);
5299 	}
5300 	lc->preview_window_id=id;
5301 #ifdef VIDEO_ENABLED
5302 	{
5303 		LinphoneCall *call=linphone_core_get_current_call(lc);
5304 		if (call!=NULL && call->videostream){
5305 			video_stream_set_native_preview_window_id(call->videostream,id);
5306 		}else if (lc->previewstream){
5307 			video_preview_set_native_window_id(lc->previewstream,id);
5308 		}
5309 	}
5310 #endif
5311 }
5312 
5313 void linphone_core_show_video(LinphoneCore *lc, bool_t show){
5314 #ifdef VIDEO_ENABLED
5315 	LinphoneCall *call=linphone_core_get_current_call(lc);
5316 	ms_error("linphone_core_show_video %d", show);
5317 	if (call!=NULL && call->videostream){
5318 		video_stream_show_video(call->videostream,show);
5319 	}
5320 #endif
5321 }
5322 
5323 void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno){
5324 	lc->use_preview_window=yesno;
5325 }
5326 
5327 int linphone_core_get_device_rotation(LinphoneCore *lc ) {
5328 	return lc->device_rotation;
5329 }
5330 
5331 void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) {
5332 	if (rotation!=lc->device_rotation) ms_message("%s : rotation=%d\n", __FUNCTION__, rotation);
5333 	lc->device_rotation = rotation;
5334 #ifdef VIDEO_ENABLED
5335 	{
5336 		LinphoneCall *call=linphone_core_get_current_call(lc);
5337 		if (call!=NULL && call->videostream){
5338 			video_stream_set_device_rotation(call->videostream,rotation);
5339 		}
5340 	}
5341 #endif
5342 }
5343 
5344 int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) {
5345 #ifdef VIDEO_ENABLED
5346 	LinphoneCall *call = linphone_core_get_current_call(lc);
5347 	if ((call != NULL) && (call->videostream != NULL)) {
5348 		return video_stream_get_camera_sensor_rotation(call->videostream);
5349 	}
5350 #endif
5351 	return -1;
5352 }
5353 
5354 static MSVideoSizeDef supported_resolutions[] = {
5355 #if !defined(__ANDROID__) && !TARGET_OS_IPHONE
5356 	{ { MS_VIDEO_SIZE_1080P_W, MS_VIDEO_SIZE_1080P_H }, "1080p" },
5357 #endif
5358 #if !defined(__ANDROID__) && !TARGET_OS_MAC /*limit to most common sizes because mac video API cannot list supported resolutions*/
5359 	{ { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H }, "uxga" },
5360 	{ { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H }, "sxga-" },
5361 #endif
5362 	{ { MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H }, "720p" },
5363 #if !defined(__ANDROID__) && !TARGET_OS_MAC
5364 	{ { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H }, "xga" },
5365 #endif
5366 #if !defined(__ANDROID__) && !TARGET_OS_IPHONE
5367 	{ { MS_VIDEO_SIZE_SVGA_W, MS_VIDEO_SIZE_SVGA_H }, "svga" },
5368 	{ { MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H }, "4cif" },
5369 #endif
5370 	{ { MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H }, "vga" },
5371 #if TARGET_OS_IPHONE
5372 	{ { MS_VIDEO_SIZE_IOS_MEDIUM_H, MS_VIDEO_SIZE_IOS_MEDIUM_W }, "ios-medium" },
5373 #endif
5374 	{ { MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H }, "cif" },
5375 #if !TARGET_OS_MAC || TARGET_OS_IPHONE /* OS_MAC is 1 for iPhone, but we need QVGA */
5376 	{ { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" },
5377 #endif
5378 	{ { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H }, "qcif" },
5379 	{ { 0, 0 }, NULL }
5380 };
5381 
5382 const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc){
5383 	return supported_resolutions;
5384 }
5385 
5386 static MSVideoSize video_size_get_by_name(const char *name){
5387 	MSVideoSizeDef *pdef=supported_resolutions;
5388 	MSVideoSize null_vsize={0,0};
5389 	MSVideoSize parsed;
5390 	if (!name) return null_vsize;
5391 	for(;pdef->name!=NULL;pdef++){
5392 		if (strcasecmp(name,pdef->name)==0){
5393 			return pdef->vsize;
5394 		}
5395 	}
5396 	if (sscanf(name,"%ix%i",&parsed.width,&parsed.height)==2){
5397 		return parsed;
5398 	}
5399 	ms_warning("Video resolution %s is not supported in linphone.",name);
5400 	return null_vsize;
5401 }
5402 
5403 static bool_t video_definition_supported(const LinphoneVideoDefinition *vdef) {
5404 	const bctbx_list_t *item;
5405 	const bctbx_list_t *supported_definitions = linphone_factory_get_supported_video_definitions(linphone_factory_get());
5406 	for (item = supported_definitions; item != NULL; item = bctbx_list_next(item)) {
5407 		LinphoneVideoDefinition *supported_vdef = (LinphoneVideoDefinition *)bctbx_list_get_data(item);
5408 		if (linphone_video_definition_equals(vdef, supported_vdef)) return TRUE;
5409 	}
5410 	ms_warning("Video definition %ix%i is not supported", linphone_video_definition_get_width(vdef), linphone_video_definition_get_height(vdef));
5411 	return FALSE;
5412 }
5413 
5414 void linphone_core_set_preferred_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef) {
5415 	if (video_definition_supported(vdef)) {
5416 		LinphoneVideoDefinition *oldvdef = lc->video_conf.vdef;
5417 		lc->video_conf.vdef = linphone_video_definition_ref(vdef);
5418 
5419 		if ((lc->previewstream != NULL) && (lc->video_conf.preview_vdef == NULL)
5420 			&& (oldvdef != NULL) && !linphone_video_definition_equals(oldvdef, vdef)) {
5421 			relaunch_video_preview(lc);
5422 		}
5423 
5424 		if (oldvdef != NULL) linphone_video_definition_unref(oldvdef);
5425 		if (linphone_core_ready(lc)) {
5426 			lp_config_set_string(lc->config, "video", "size", linphone_video_definition_get_name(vdef));
5427 		}
5428 	}
5429 }
5430 
5431 void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize) {
5432 	linphone_core_set_preferred_video_definition(lc,
5433 		linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height));
5434 }
5435 
5436 void linphone_core_set_preview_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef) {
5437 	if (!vdef || linphone_video_definition_is_undefined(vdef)) {
5438 		/* Reset the forced preview video definition mode */
5439 		if (lc->video_conf.preview_vdef != NULL) linphone_video_definition_unref(lc->video_conf.preview_vdef);
5440 		lc->video_conf.preview_vdef = NULL;
5441 		if (linphone_core_ready(lc)) {
5442 			lp_config_set_string(lc->config, "video", "preview_size", NULL);
5443 		}
5444 		return;
5445 	}
5446 
5447 	if (!linphone_video_definition_equals(lc->video_conf.preview_vdef, vdef)) {
5448 		LinphoneVideoDefinition *oldvdef = lc->video_conf.preview_vdef;
5449 		lc->video_conf.preview_vdef = linphone_video_definition_ref(vdef);
5450 		if (oldvdef != NULL) linphone_video_definition_unref(oldvdef);
5451 		if (lc->previewstream != NULL) {
5452 			relaunch_video_preview(lc);
5453 		}
5454 	}
5455 	if (linphone_core_ready(lc)) {
5456 		lp_config_set_string(lc->config, "video", "preview_size", linphone_video_definition_get_name(vdef));
5457 	}
5458 }
5459 
5460 void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize) {
5461 	linphone_core_set_preview_video_definition(lc,
5462 		linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height));
5463 }
5464 
5465 const LinphoneVideoDefinition * linphone_core_get_preview_video_definition(const LinphoneCore *lc) {
5466 	return lc->video_conf.preview_vdef;
5467 }
5468 
5469 MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc) {
5470 	MSVideoSize vsize = { 0 };
5471 	vsize.width = linphone_video_definition_get_width(lc->video_conf.preview_vdef);
5472 	vsize.height = linphone_video_definition_get_height(lc->video_conf.preview_vdef);
5473 	return vsize;
5474 }
5475 
5476 MSVideoSize linphone_core_get_current_preview_video_size(const LinphoneCore *lc){
5477 	MSVideoSize ret={0};
5478 #ifndef VIDEO_ENABLED
5479 	ms_error("linphone_core_get_current_preview_video_size() fail. Support for video is disabled");
5480 #else
5481 	if (lc->previewstream){
5482 		ret=video_preview_get_current_size(lc->previewstream);
5483 	}
5484 #endif
5485 	return ret;
5486 }
5487 
5488 LinphoneVideoDefinition * linphone_core_get_current_preview_video_definition(const LinphoneCore *lc) {
5489 #ifdef VIDEO_ENABLED
5490 	MSVideoSize vsize;
5491 	if (lc->previewstream) {
5492 		vsize = video_preview_get_current_size(lc->previewstream);
5493 	}
5494 	return linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height);
5495 #else
5496 	ms_error("Video support is disabled");
5497 	return NULL;
5498 #endif
5499 }
5500 
5501 void linphone_core_set_preview_video_size_by_name(LinphoneCore *lc, const char *name){
5502 	MSVideoSize vsize=video_size_get_by_name(name);
5503 	linphone_core_set_preview_video_size(lc,vsize);
5504 }
5505 
5506 void linphone_core_set_preview_video_definition_by_name(LinphoneCore *lc, const char *name) {
5507 	LinphoneVideoDefinition *vdef = linphone_factory_find_supported_video_definition_by_name(linphone_factory_get(), name);
5508 	if (vdef == NULL) {
5509 		ms_error("Video definition '%s' is not supported", name);
5510 	} else {
5511 		linphone_core_set_preview_video_definition(lc, vdef);
5512 	}
5513 }
5514 
5515 void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name){
5516 	MSVideoSize vsize=video_size_get_by_name(name);
5517 	MSVideoSize default_vsize={MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H};
5518 	if (vsize.width!=0)	linphone_core_set_preferred_video_size(lc,vsize);
5519 	else linphone_core_set_preferred_video_size(lc,default_vsize);
5520 }
5521 
5522 void linphone_core_set_preferred_video_definition_by_name(LinphoneCore *lc, const char *name) {
5523 	LinphoneVideoDefinition *vdef = linphone_factory_find_supported_video_definition_by_name(linphone_factory_get(), name);
5524 	if (vdef == NULL) {
5525 		ms_error("Video definition '%s' is not supported", name);
5526 	} else {
5527 		linphone_core_set_preferred_video_definition(lc, vdef);
5528 	}
5529 }
5530 
5531 const LinphoneVideoDefinition * linphone_core_get_preferred_video_definition(const LinphoneCore *lc) {
5532 	return lc->video_conf.vdef;
5533 }
5534 
5535 MSVideoSize linphone_core_get_preferred_video_size(const LinphoneCore *lc) {
5536 	MSVideoSize vsize = { 0 };
5537 	vsize.width = linphone_video_definition_get_width(lc->video_conf.vdef);
5538 	vsize.height = linphone_video_definition_get_height(lc->video_conf.vdef);
5539 	return vsize;
5540 }
5541 
5542 char * linphone_core_get_preferred_video_size_name(const LinphoneCore *lc) {
5543 	return ms_strdup(linphone_video_definition_get_name(lc->video_conf.vdef));
5544 }
5545 
5546 void linphone_core_set_preferred_framerate(LinphoneCore *lc, float fps){
5547 	lc->video_conf.fps=fps;
5548 	if (linphone_core_ready(lc))
5549 		lp_config_set_float(lc->config,"video","framerate",fps);
5550 }
5551 
5552 float linphone_core_get_preferred_framerate(LinphoneCore *lc){
5553 	return lc->video_conf.fps;
5554 }
5555 
5556 void linphone_core_preview_ogl_render(const LinphoneCore *lc) {
5557 	#ifdef VIDEO_ENABLED
5558 
5559 	LinphoneCall *call = linphone_core_get_current_call(lc);
5560 	VideoStream *stream = call ? call->videostream : lc->previewstream;
5561 
5562 	if (stream && stream->output2 && ms_filter_get_id(stream->output2) == MS_OGL_ID) {
5563 		int mirroring = TRUE;
5564 		ms_filter_call_method(stream->output2, MS_VIDEO_DISPLAY_ENABLE_MIRRORING, &mirroring);
5565 		ms_filter_call_method(stream->output2, MS_OGL_RENDER, NULL);
5566 	}
5567 
5568 	#endif
5569 }
5570 
5571 void linphone_core_set_use_files(LinphoneCore *lc, bool_t yesno){
5572 	lc->use_files=yesno;
5573 }
5574 
5575 bool_t linphone_core_get_use_files(LinphoneCore *lc) {
5576 	return lc->use_files;
5577 }
5578 
5579 const char * linphone_core_get_play_file(const LinphoneCore *lc) {
5580 	return lc->play_file;
5581 }
5582 
5583 void linphone_core_set_play_file(LinphoneCore *lc, const char *file){
5584 	LinphoneCall *call=linphone_core_get_current_call(lc);
5585 	if (lc->play_file!=NULL){
5586 		ms_free(lc->play_file);
5587 		lc->play_file=NULL;
5588 	}
5589 	if (file!=NULL) {
5590 		lc->play_file=ms_strdup(file);
5591 		if (call && call->audiostream && call->audiostream->ms.state==MSStreamStarted)
5592 			audio_stream_play(call->audiostream,file);
5593 	}
5594 }
5595 
5596 const char * linphone_core_get_record_file(const LinphoneCore *lc) {
5597 	return lc->rec_file;
5598 }
5599 
5600 void linphone_core_set_record_file(LinphoneCore *lc, const char *file){
5601 	LinphoneCall *call=linphone_core_get_current_call(lc);
5602 	if (lc->rec_file!=NULL){
5603 		ms_free(lc->rec_file);
5604 		lc->rec_file=NULL;
5605 	}
5606 	if (file!=NULL) {
5607 		lc->rec_file=ms_strdup(file);
5608 		if (call && call->audiostream)
5609 			audio_stream_record(call->audiostream,file);
5610 	}
5611 }
5612 
5613 typedef enum{
5614 	LinphoneToneGenerator,
5615 	LinphoneLocalPlayer
5616 }LinphoneAudioResourceType;
5617 
5618 static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType rtype){
5619 	LinphoneCall *call=linphone_core_get_current_call(lc);
5620 	AudioStream *stream=NULL;
5621 	RingStream *ringstream;
5622 	if (call){
5623 		stream=call->audiostream;
5624 	}else if (linphone_core_is_in_conference(lc)){
5625 		stream=linphone_conference_get_audio_stream(lc->conf_ctx);
5626 	}
5627 	if (stream){
5628 		if (rtype==LinphoneToneGenerator) return stream->dtmfgen;
5629 		if (rtype==LinphoneLocalPlayer) return stream->local_player;
5630 		return NULL;
5631 	}
5632 	if (lc->ringstream==NULL){
5633 		float amp=lp_config_get_float(lc->config,"sound","dtmf_player_amp",0.1f);
5634 		MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
5635 		if (ringcard == NULL)
5636 			return NULL;
5637 
5638 		ringstream=lc->ringstream=ring_start(lc->factory, NULL,0,ringcard);
5639 		ms_filter_call_method(lc->ringstream->gendtmf,MS_DTMF_GEN_SET_DEFAULT_AMPLITUDE,&amp);
5640 		lc->dmfs_playing_start_time = ms_get_cur_time_ms()/1000;
5641 	}else{
5642 		ringstream=lc->ringstream;
5643 		if (lc->dmfs_playing_start_time!=0)
5644 			lc->dmfs_playing_start_time = ms_get_cur_time_ms()/1000;
5645 	}
5646 	if (rtype==LinphoneToneGenerator) return ringstream->gendtmf;
5647 	if (rtype==LinphoneLocalPlayer) return ringstream->source;
5648 	return NULL;
5649 }
5650 
5651 static MSFilter *get_dtmf_gen(LinphoneCore *lc){
5652 	return get_audio_resource(lc,LinphoneToneGenerator);
5653 }
5654 
5655 void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){
5656 	MSFilter *f=get_dtmf_gen(lc);
5657 	if (f==NULL){
5658 		ms_error("No dtmf generator at this time !");
5659 		return;
5660 	}
5661 
5662 	if (duration_ms > 0)
5663 		ms_filter_call_method(f, MS_DTMF_GEN_PLAY, &dtmf);
5664 	else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf);
5665 }
5666 
5667 LinphoneStatus linphone_core_play_local(LinphoneCore *lc, const char *audiofile){
5668 	MSFilter *f=get_audio_resource(lc,LinphoneLocalPlayer);
5669 	int loopms=-1;
5670 	if (!f) return -1;
5671 	ms_filter_call_method(f,MS_PLAYER_SET_LOOP,&loopms);
5672 	if (ms_filter_call_method(f,MS_PLAYER_OPEN,(void*)audiofile)!=0){
5673 		return -1;
5674 	}
5675 	ms_filter_call_method_noarg(f,MS_PLAYER_START);
5676 	return 0;
5677 }
5678 
5679 void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){
5680 	if (linphone_core_tone_indications_enabled(lc)){
5681 		const char *audiofile=linphone_core_get_tone_file(lc,toneid);
5682 		if (!audiofile){
5683 			MSFilter *f=get_dtmf_gen(lc);
5684 			MSDtmfGenCustomTone def;
5685 			if (f==NULL){
5686 				ms_error("No dtmf generator at this time !");
5687 				return;
5688 			}
5689 			memset(&def,0,sizeof(def));
5690 			def.amplitude=1;
5691 			/*these are french tones, excepted the failed one, which is USA congestion tone (does not exist in France)*/
5692 			switch(toneid){
5693 				case LinphoneToneCallOnHold:
5694 				case LinphoneToneCallWaiting:
5695 					def.duration=300;
5696 					def.frequencies[0]=440;
5697 					def.interval=2000;
5698 				break;
5699 				case LinphoneToneBusy:
5700 					def.duration=500;
5701 					def.frequencies[0]=440;
5702 					def.interval=500;
5703 					def.repeat_count=3;
5704 				break;
5705 				case LinphoneToneCallLost:
5706 					def.duration=250;
5707 					def.frequencies[0]=480;
5708 					def.frequencies[0]=620;
5709 					def.interval=250;
5710 					def.repeat_count=3;
5711 
5712 				break;
5713 				default:
5714 					ms_warning("Unhandled tone id.");
5715 			}
5716 			if (def.duration>0)
5717 				ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def);
5718 		}else{
5719 			linphone_core_play_local(lc,audiofile);
5720 		}
5721 	}
5722 }
5723 
5724 void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason){
5725 	if (linphone_core_tone_indications_enabled(lc)){
5726 		LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason);
5727 		if (tone){
5728 			if (tone->audiofile){
5729 				linphone_core_play_local(lc,tone->audiofile);
5730 			}else if (tone->toneid != LinphoneToneUndefined){
5731 				linphone_core_play_named_tone(lc,tone->toneid);
5732 			}
5733 		}
5734 	}
5735 }
5736 
5737 void linphone_core_stop_dtmf(LinphoneCore *lc){
5738 	MSFilter *f=get_dtmf_gen(lc);
5739 	if (f!=NULL)
5740 		ms_filter_call_method_noarg (f, MS_DTMF_GEN_STOP);
5741 }
5742 
5743 void *linphone_core_get_user_data(const LinphoneCore *lc){
5744 	return lc->data;
5745 }
5746 
5747 void linphone_core_set_user_data(LinphoneCore *lc, void *userdata){
5748 	lc->data=userdata;
5749 }
5750 
5751 int linphone_core_get_mtu(const LinphoneCore *lc){
5752 	return lc->net_conf.mtu;
5753 }
5754 
5755 void linphone_core_set_mtu(LinphoneCore *lc, int mtu){
5756 	lc->net_conf.mtu=mtu;
5757 	if (mtu>0){
5758 		if (mtu<500){
5759 			ms_error("MTU too small !");
5760 			mtu=500;
5761 		}
5762 		ms_factory_set_mtu(lc->factory, mtu);
5763 		ms_message("MTU is supposed to be %i, rtp payload max size will be %i",mtu, ms_factory_get_payload_max_size(lc->factory));
5764 	}else ms_factory_set_mtu(lc->factory, 0);//use mediastreamer2 default value
5765 }
5766 
5767 void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneCoreWaitingCallback cb, void *user_context){
5768 	lc->wait_cb=cb;
5769 	lc->wait_ctx=user_context;
5770 }
5771 
5772 void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose){
5773 	if (lc->wait_cb){
5774 		lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingStart,purpose,0);
5775 	}
5776 }
5777 
5778 void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progress){
5779 	if (lc->wait_cb){
5780 		lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingProgress,purpose,progress);
5781 	}else{
5782 		ms_usleep(50000);
5783 	}
5784 }
5785 
5786 void linphone_core_stop_waiting(LinphoneCore *lc){
5787 	if (lc->wait_cb){
5788 		lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingFinished,NULL,0);
5789 	}
5790 }
5791 
5792 void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTransportFactories *factories){
5793 	lc->rtptf=factories;
5794 }
5795 
5796 int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote){
5797 	LinphoneCall *call=linphone_core_get_current_call (lc);
5798 	if (call!=NULL){
5799 		if (call->audiostream!=NULL){
5800 			memset(remote,0,sizeof(*remote));
5801 			audio_stream_get_local_rtp_stats (call->audiostream,local);
5802 			return 0;
5803 		}
5804 	}
5805 	return -1;
5806 }
5807 
5808 void net_config_uninit(LinphoneCore *lc)
5809 {
5810 	net_config_t *config=&lc->net_conf;
5811 
5812 	if (config->nat_address!=NULL){
5813 		lp_config_set_string(lc->config,"net","nat_address",config->nat_address);
5814 		ms_free(lc->net_conf.nat_address);
5815 	}
5816 	if (lc->net_conf.nat_address_ip !=NULL){
5817 		ms_free(lc->net_conf.nat_address_ip);
5818 	}
5819 	lp_config_set_int(lc->config,"net","mtu",config->mtu);
5820 	if (lc->nat_policy != NULL) {
5821 		linphone_nat_policy_unref(lc->nat_policy);
5822 		lc->nat_policy = NULL;
5823 	}
5824 }
5825 
5826 void sip_config_uninit(LinphoneCore *lc)
5827 {
5828 	bctbx_list_t *elem;
5829 	int i;
5830 	sip_config_t *config=&lc->sip_conf;
5831 	bool_t still_registered=TRUE;
5832 
5833 	lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname);
5834 	lp_config_set_string(lc->config,"sip","contact",config->contact);
5835 	lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout);
5836 	lp_config_set_int(lc->config,"sip","in_call_timeout",config->in_call_timeout);
5837 	lp_config_set_int(lc->config,"sip","delayed_timeout",config->delayed_timeout);
5838 	lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up);
5839 	lp_config_set_int(lc->config,"sip","register_only_when_upnp_is_ok",config->register_only_when_upnp_is_ok);
5840 
5841 	if (lc->sip_network_reachable) {
5842 		for(elem=config->proxies;elem!=NULL;elem=bctbx_list_next(elem)){
5843 			LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
5844 			_linphone_proxy_config_unpublish(cfg);	/* to unpublish without changing the stored flag enable_publish */
5845 			_linphone_proxy_config_unregister(cfg);	/* to unregister without changing the stored flag enable_register */
5846 		}
5847 
5848 		ms_message("Unregistration started.");
5849 
5850 		for (i=0;i<20&&still_registered;i++){
5851 			still_registered=FALSE;
5852 			sal_iterate(lc->sal);
5853 			for(elem=config->proxies;elem!=NULL;elem=bctbx_list_next(elem)){
5854 				LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
5855 				LinphoneRegistrationState state = linphone_proxy_config_get_state(cfg);
5856 				still_registered|=(state==LinphoneRegistrationOk||state==LinphoneRegistrationProgress);
5857 			}
5858 			ms_usleep(100000);
5859 		}
5860 		if (i>=20) ms_warning("Cannot complete unregistration, giving up");
5861 	}
5862 	elem = config->proxies;
5863 	config->proxies=NULL; /*to make sure proxies cannot be refferenced during deletion*/
5864 	bctbx_list_free_with_data(elem,(void (*)(void*)) _linphone_proxy_config_release);
5865 
5866 	config->deleted_proxies=bctbx_list_free_with_data(config->deleted_proxies,(void (*)(void*)) _linphone_proxy_config_release);
5867 
5868 	/*no longuer need to write proxy config if not changedlinphone_proxy_config_write_to_config_file(lc->config,NULL,i);*/	/*mark the end */
5869 
5870 	lc->auth_info=bctbx_list_free_with_data(lc->auth_info,(void (*)(void*))linphone_auth_info_unref);
5871 
5872 	if (lc->vcard_context) {
5873 		linphone_vcard_context_destroy(lc->vcard_context);
5874 	}
5875 
5876 	sal_reset_transports(lc->sal);
5877 	sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/
5878 	if (lc->http_provider) {
5879 		belle_sip_object_unref(lc->http_provider);
5880 		lc->http_provider=NULL;
5881 	}
5882 	if (lc->http_crypto_config){
5883 		belle_sip_object_unref(lc->http_crypto_config);
5884 		lc->http_crypto_config=NULL;
5885 	}
5886 
5887 	/*now that we are unregisted, there is no more channel using tunnel socket we no longer need the tunnel.*/
5888 #ifdef TUNNEL_ENABLED
5889 	if (lc->tunnel) {
5890 		linphone_tunnel_unref(lc->tunnel);
5891 		lc->tunnel=NULL;
5892 		ms_message("Tunnel destroyed.");
5893 	}
5894 #endif
5895 
5896 	sal_iterate(lc->sal); /*make sure event are purged*/
5897 	sal_uninit(lc->sal);
5898 	lc->sal=NULL;
5899 
5900 	if (lc->sip_conf.guessed_contact)
5901 		ms_free(lc->sip_conf.guessed_contact);
5902 	if (config->contact)
5903 		ms_free(config->contact);
5904 	if (lc->default_rls_addr)
5905 		linphone_address_unref(lc->default_rls_addr);
5906 
5907 	linphone_im_notif_policy_unref(lc->im_notif_policy);
5908 }
5909 
5910 void rtp_config_uninit(LinphoneCore *lc)
5911 {
5912 	rtp_config_t *config=&lc->rtp_conf;
5913 	if (config->audio_rtp_min_port == config->audio_rtp_max_port) {
5914 		lp_config_set_int(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port);
5915 	} else {
5916 		lp_config_set_range(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port, config->audio_rtp_max_port);
5917 	}
5918 	if (config->video_rtp_min_port == config->video_rtp_max_port) {
5919 		lp_config_set_int(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port);
5920 	} else {
5921 		lp_config_set_range(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port, config->video_rtp_max_port);
5922 	}
5923 	if (config->text_rtp_min_port == config->text_rtp_max_port) {
5924 		lp_config_set_int(lc->config, "rtp", "text_rtp_port", config->text_rtp_min_port);
5925 	} else {
5926 		lp_config_set_range(lc->config, "rtp", "text_rtp_port", config->text_rtp_min_port, config->text_rtp_max_port);
5927 	}
5928 	lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp);
5929 	lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp);
5930 	lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
5931 	lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled);
5932 	lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled);
5933 	ms_free(lc->rtp_conf.audio_multicast_addr);
5934 	ms_free(lc->rtp_conf.video_multicast_addr);
5935 	ms_free(config->srtp_suites);
5936 }
5937 
5938 static void sound_config_uninit(LinphoneCore *lc)
5939 {
5940 	sound_config_t *config=&lc->sound_conf;
5941 	ms_free((void *)config->cards);
5942 
5943 	lp_config_set_string(lc->config,"sound","remote_ring",config->remote_ring);
5944 	lp_config_set_float(lc->config,"sound","playback_gain_db",config->soft_play_lev);
5945 	lp_config_set_float(lc->config,"sound","mic_gain_db",config->soft_mic_lev);
5946 
5947 	if (config->local_ring) ms_free(config->local_ring);
5948 	if (config->remote_ring) ms_free(config->remote_ring);
5949 	lc->tones=bctbx_list_free_with_data(lc->tones, (void (*)(void*))linphone_tone_description_destroy);
5950 }
5951 
5952 static void video_config_uninit(LinphoneCore *lc)
5953 {
5954 	const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(lc);
5955 	lp_config_set_string(lc->config,"video","size",vdef ? linphone_video_definition_get_name(vdef) : NULL);
5956 	lp_config_set_int(lc->config,"video","display",lc->video_conf.display);
5957 	lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture);
5958 	if (lc->video_conf.cams)
5959 		ms_free((void *)lc->video_conf.cams);
5960 	if (lc->video_conf.vdef) linphone_video_definition_unref(lc->video_conf.vdef);
5961 	if (lc->video_conf.preview_vdef) linphone_video_definition_unref(lc->video_conf.preview_vdef);
5962 }
5963 
5964 void _linphone_core_codec_config_write(LinphoneCore *lc){
5965 	if (linphone_core_ready(lc)){
5966 		PayloadType *pt;
5967 		codecs_config_t *config=&lc->codecs_conf;
5968 		bctbx_list_t *node;
5969 		char key[50];
5970 		int index;
5971 		index=0;
5972 		for(node=config->audio_codecs;node!=NULL;node=bctbx_list_next(node)){
5973 			pt=(PayloadType*)(node->data);
5974 			sprintf(key,"audio_codec_%i",index);
5975 			lp_config_set_string(lc->config,key,"mime",pt->mime_type);
5976 			lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
5977 			lp_config_set_int(lc->config,key,"channels",pt->channels);
5978 			lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt));
5979 			index++;
5980 		}
5981 		sprintf(key,"audio_codec_%i",index);
5982 		lp_config_clean_section (lc->config,key);
5983 
5984 		index=0;
5985 		for(node=config->video_codecs;node!=NULL;node=bctbx_list_next(node)){
5986 			pt=(PayloadType*)(node->data);
5987 			sprintf(key,"video_codec_%i",index);
5988 			lp_config_set_string(lc->config,key,"mime",pt->mime_type);
5989 			lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
5990 			lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt));
5991 			lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp);
5992 			index++;
5993 		}
5994 		sprintf(key,"video_codec_%i",index);
5995 		lp_config_clean_section (lc->config,key);
5996 	}
5997 }
5998 
5999 static void codecs_config_uninit(LinphoneCore *lc)
6000 {
6001 	_linphone_core_codec_config_write(lc);
6002 	bctbx_list_free_with_data(lc->codecs_conf.audio_codecs, (void (*)(void*))payload_type_destroy);
6003 	bctbx_list_free_with_data(lc->codecs_conf.video_codecs, (void (*)(void*))payload_type_destroy);
6004 	bctbx_list_free_with_data(lc->codecs_conf.text_codecs, (void (*)(void*))payload_type_destroy);
6005 }
6006 
6007 void friends_config_uninit(LinphoneCore* lc)
6008 {
6009 	ms_message("Destroying friends.");
6010 	lc->friends_lists = bctbx_list_free_with_data(lc->friends_lists, (void (*)(void*))_linphone_friend_list_release);
6011 	if (lc->subscribers) {
6012 		lc->subscribers = bctbx_list_free_with_data(lc->subscribers, (void (*)(void *))_linphone_friend_release);
6013 	}
6014 	if (lc->presence_model) {
6015 		linphone_presence_model_unref(lc->presence_model);
6016 		lc->presence_model = NULL;
6017 	}
6018 	ms_message("Destroying friends done.");
6019 }
6020 
6021 LpConfig * linphone_core_get_config(LinphoneCore *lc){
6022 	return lc->config;
6023 }
6024 
6025 LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename) {
6026 	return lp_config_new(filename);
6027 }
6028 
6029 LinphoneConfig * linphone_core_create_config(LinphoneCore *lc, const char *filename) {
6030 	return lp_config_new(filename);
6031 }
6032 
6033 static void linphone_core_uninit(LinphoneCore *lc)
6034 {
6035 	bctbx_list_t *elem = NULL;
6036 	int i=0;
6037 	bool_t wait_until_unsubscribe = FALSE;
6038 	linphone_task_list_free(&lc->hooks);
6039 	lc->video_conf.show_local = FALSE;
6040 
6041 	while(lc->calls) {
6042 		LinphoneCall *the_call = lc->calls->data;
6043 		linphone_call_terminate(the_call);
6044 		linphone_core_iterate(lc);
6045 		ms_usleep(10000);
6046 	}
6047 
6048 	for (elem = lc->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) {
6049 		LinphoneFriendList *list = (LinphoneFriendList *)elem->data;
6050 		linphone_friend_list_enable_subscriptions(list,FALSE);
6051 		if (list->event)
6052 			wait_until_unsubscribe =  TRUE;
6053 	}
6054 	/*give a chance to unsubscribe, might be optimized*/
6055 	for (i=0; wait_until_unsubscribe && i<50; i++) {
6056 		linphone_core_iterate(lc);
6057 		ms_usleep(10000);
6058 	}
6059 
6060 	lc->chatrooms = bctbx_list_free_with_data(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release);
6061 
6062 	linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down");
6063 #ifdef VIDEO_ENABLED
6064 	if (lc->previewstream!=NULL){
6065 		video_preview_stop(lc->previewstream);
6066 		lc->previewstream=NULL;
6067 	}
6068 #endif
6069 
6070 	lc->msevq=NULL;
6071 
6072 	/* save all config */
6073 	friends_config_uninit(lc);
6074 	sip_config_uninit(lc);
6075 	net_config_uninit(lc);
6076 	rtp_config_uninit(lc);
6077 	linphone_core_stop_ringing(lc);
6078 	sound_config_uninit(lc);
6079 	video_config_uninit(lc);
6080 	codecs_config_uninit(lc);
6081 
6082 	sip_setup_unregister_all();
6083 
6084 #ifdef BUILD_UPNP
6085 	if(lc->upnp != NULL) {
6086 		linphone_upnp_context_destroy(lc->upnp);
6087 		lc->upnp = NULL;
6088 	}
6089 #endif //BUILD_UPNP
6090 
6091 	if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
6092 	lp_config_destroy(lc->config);
6093 	lc->config = NULL; /* Mark the config as NULL to block further calls */
6094 
6095 	bctbx_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_unref);
6096 	lc->call_logs=bctbx_list_free(lc->call_logs);
6097 
6098 	if(lc->zrtp_secrets_cache != NULL) {
6099 		ms_free(lc->zrtp_secrets_cache);
6100 	}
6101 
6102 	if(lc->user_certificates_path != NULL) {
6103 		ms_free(lc->user_certificates_path);
6104 	}
6105 	if(lc->play_file!=NULL){
6106 		ms_free(lc->play_file);
6107 	}
6108 	if(lc->rec_file!=NULL){
6109 		ms_free(lc->rec_file);
6110 	}
6111 	if (lc->chat_db_file){
6112 		ms_free(lc->chat_db_file);
6113 	}
6114 	if (lc->logs_db_file) {
6115 		ms_free(lc->logs_db_file);
6116 	}
6117 	if (lc->friends_db_file) {
6118 		ms_free(lc->friends_db_file);
6119 	}
6120 	if (lc->ringtoneplayer) {
6121 		linphone_ringtoneplayer_destroy(lc->ringtoneplayer);
6122 	}
6123 	if (lc->im_encryption_engine) {
6124 		linphone_im_encryption_engine_unref(lc->im_encryption_engine);
6125 	}
6126 	if (lc->default_ac_service) {
6127 		linphone_account_creator_service_unref(lc->default_ac_service);
6128 	}
6129 
6130 	linphone_core_free_payload_types(lc);
6131 	if (lc->supported_formats) ms_free((void *)lc->supported_formats);
6132 	linphone_core_message_storage_close(lc);
6133 	linphone_core_call_log_storage_close(lc);
6134 	linphone_core_friends_storage_close(lc);
6135 	linphone_core_zrtp_cache_close(lc);
6136 
6137 	linphone_core_set_state(lc,LinphoneGlobalOff,"Off");
6138 	linphone_core_deactivate_log_serialization_if_needed();
6139 	bctbx_list_free_with_data(lc->vtable_refs,(void (*)(void *))v_table_reference_destroy);
6140 	ms_bandwidth_controller_destroy(lc->bw_controller);
6141 	ms_factory_destroy(lc->factory);
6142 }
6143 
6144 static void stop_refreshing_proxy_config(bool_t is_sip_reachable, LinphoneProxyConfig* cfg) {
6145 	if (linphone_proxy_config_register_enabled(cfg) ) {
6146 		if (!is_sip_reachable) {
6147 			linphone_proxy_config_stop_refreshing(cfg);
6148 			linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone,"Registration impossible (network down)");
6149 		}else{
6150 			cfg->commit=TRUE;
6151 		}
6152 	}
6153 }
6154 
6155 static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, time_t curtime){
6156 	// second get the list of available proxies
6157 	const bctbx_list_t *elem = NULL;
6158 
6159 	if (lc->sip_network_reachable==is_sip_reachable) return; // no change, ignore.
6160 	lc->network_reachable_to_be_notified=TRUE;
6161 	ms_message("SIP network reachability state is now [%s]",is_sip_reachable?"UP":"DOWN");
6162 	for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
6163 		LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
6164 		stop_refreshing_proxy_config(is_sip_reachable, cfg);
6165 	}
6166 	for(elem=lc->sip_conf.deleted_proxies;elem!=NULL;elem=elem->next){
6167 		LinphoneProxyConfig *deleted_cfg=(LinphoneProxyConfig*)elem->data;
6168 		stop_refreshing_proxy_config(is_sip_reachable, deleted_cfg);
6169 	}
6170 
6171 	lc->netup_time=curtime;
6172 	lc->sip_network_reachable=is_sip_reachable;
6173 
6174 	if (!lc->sip_network_reachable){
6175 		linphone_core_invalidate_friend_subscriptions(lc);
6176 		sal_reset_transports(lc->sal);
6177 		/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
6178 		bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
6179 	}
6180 #ifdef BUILD_UPNP
6181 	if(lc->upnp == NULL) {
6182 		if(is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
6183 			lc->upnp = linphone_upnp_context_new(lc);
6184 		}
6185 	} else {
6186 		if(!is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
6187 			linphone_upnp_context_destroy(lc->upnp);
6188 			lc->upnp = NULL;
6189 		}
6190 	}
6191 #endif
6192 }
6193 
6194 void linphone_core_repair_calls(LinphoneCore *lc){
6195 	if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1) && lc->media_network_reachable){
6196 		/*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
6197 		bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
6198 	}
6199 }
6200 
6201 static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reachable){
6202 	if (lc->media_network_reachable==is_media_reachable) return; // no change, ignore.
6203 	ms_message("Media network reachability state is now [%s]",is_media_reachable?"UP":"DOWN");
6204 	lc->media_network_reachable=is_media_reachable;
6205 
6206 	if (!lc->media_network_reachable){
6207 		/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
6208 		bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
6209 	}else{
6210 		if (lp_config_get_int(lc->config, "net", "recreate_sockets_when_network_is_up", 0)){
6211 			bctbx_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets);
6212 		}
6213 		linphone_core_repair_calls(lc);
6214 	}
6215 }
6216 
6217 static void set_network_reachable(LinphoneCore *lc, bool_t is_network_reachable, time_t curtime){
6218 	set_sip_network_reachable(lc, is_network_reachable, curtime);
6219 	set_media_network_reachable(lc, is_network_reachable);
6220 }
6221 
6222 void linphone_core_refresh_registers(LinphoneCore* lc) {
6223 	const bctbx_list_t *elem;
6224 	if (!lc->sip_network_reachable) {
6225 		ms_warning("Refresh register operation not available (network unreachable)");
6226 		return;
6227 	}
6228 	elem=linphone_core_get_proxy_config_list(lc);
6229 	for(;elem!=NULL;elem=elem->next){
6230 		LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
6231 		if (linphone_proxy_config_register_enabled(cfg) && linphone_proxy_config_get_expires(cfg)>0) {
6232 			linphone_proxy_config_refresh_register(cfg);
6233 		}
6234 	}
6235 }
6236 
6237 static void disable_internal_network_reachability_detection(LinphoneCore *lc){
6238 	if (lc->auto_net_state_mon) {
6239 		ms_message("Disabling automatic network state monitoring");
6240 		lc->auto_net_state_mon=FALSE;
6241 	}
6242 }
6243 
6244 void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) {
6245 	disable_internal_network_reachability_detection(lc);
6246 	set_network_reachable(lc, isReachable, ms_time(NULL));
6247 }
6248 
6249 void linphone_core_set_media_network_reachable(LinphoneCore *lc, bool_t is_reachable){
6250 	disable_internal_network_reachability_detection(lc);
6251 	set_media_network_reachable(lc, is_reachable);
6252 }
6253 
6254 void linphone_core_set_sip_network_reachable(LinphoneCore *lc, bool_t is_reachable){
6255 	disable_internal_network_reachability_detection(lc);
6256 	set_sip_network_reachable(lc, is_reachable, ms_time(NULL));
6257 }
6258 
6259 bool_t linphone_core_is_network_reachable(LinphoneCore* lc) {
6260 	return lc->sip_network_reachable;
6261 }
6262 
6263 ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc){
6264 	return sal_get_socket(lc->sal);
6265 }
6266 
6267 void linphone_core_destroy(LinphoneCore *lc){
6268 	linphone_core_unref(lc);
6269 }
6270 
6271 int linphone_core_get_calls_nb(const LinphoneCore *lc){
6272 	return (int)bctbx_list_size(lc->calls);
6273 }
6274 
6275 /**
6276  * Check if we do not have exceed the number of simultaneous call
6277  * @ingroup call_control
6278 **/
6279 bool_t linphone_core_can_we_add_call(LinphoneCore *lc)
6280 {
6281 	if(linphone_core_get_calls_nb(lc) < lc->max_calls)
6282 		return TRUE;
6283 	ms_message("Maximum amount of simultaneous calls reached !");
6284 	return FALSE;
6285 }
6286 
6287 static void notify_soundcard_usage(LinphoneCore *lc, bool_t used){
6288 	MSSndCard *card=lc->sound_conf.capt_sndcard;
6289 	if (card && ms_snd_card_get_capabilities(card) & MS_SND_CARD_CAP_IS_SLOW){
6290 		ms_snd_card_set_usage_hint(card,used);
6291 	}
6292 }
6293 
6294 void linphone_core_soundcard_hint_check( LinphoneCore* lc){
6295 	bctbx_list_t* the_calls = lc->calls;
6296 	LinphoneCall* call = NULL;
6297 	bool_t dont_need_sound = TRUE;
6298 	bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE);
6299 	bool_t use_rtp_io_enable_local_output = lp_config_get_int(lc->config, "sound", "rtp_io_enable_local_output", FALSE);
6300 
6301 	/* check if the remaining calls are paused */
6302 	while( the_calls ){
6303 		call = the_calls->data;
6304 		if( call->state != LinphoneCallPausing && call->state != LinphoneCallPaused && call->state != LinphoneCallEnd && call->state != LinphoneCallError){
6305 			dont_need_sound = FALSE;
6306 			break;
6307 		}
6308 		the_calls = the_calls->next;
6309 	}
6310 	/* if no more calls or all calls are paused, we can free the soundcard */
6311 	if ( (lc->calls==NULL || dont_need_sound) && !lc->use_files && (!use_rtp_io || (use_rtp_io && use_rtp_io_enable_local_output))){
6312 		ms_message("Notifying soundcard that we don't need it anymore for calls.");
6313 		notify_soundcard_usage(lc,FALSE);
6314 	}
6315 }
6316 
6317 int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) {
6318 	if (linphone_core_can_we_add_call(lc)){
6319 		if (lc->calls==NULL) notify_soundcard_usage(lc,TRUE);
6320 		lc->calls = bctbx_list_append(lc->calls,call);
6321 		linphone_core_notify_call_created(lc, call);
6322 		return 0;
6323 	}
6324 	return -1;
6325 }
6326 
6327 int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) {
6328 	bctbx_list_t *it;
6329 	bctbx_list_t *the_calls = lc->calls;
6330 
6331 	it=bctbx_list_find(the_calls,call);
6332 	if (it)
6333 	{
6334 		the_calls = bctbx_list_erase_link(the_calls,it);
6335 	}
6336 	else
6337 	{
6338 		ms_warning("could not find the call into the list\n");
6339 		return -1;
6340 	}
6341 	lc->calls = the_calls;
6342 
6343 	return 0;
6344 }
6345 
6346 void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *file){
6347 	if (lc->sound_conf.ringback_tone){
6348 		ms_free(lc->sound_conf.ringback_tone);
6349 		lc->sound_conf.ringback_tone=NULL;
6350 	}
6351 	if (file)
6352 		lc->sound_conf.ringback_tone=ms_strdup(file);
6353 }
6354 
6355 const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc){
6356 	return lc->sound_conf.ringback_tone;
6357 }
6358 
6359 void linphone_core_set_ring_during_incoming_early_media(LinphoneCore *lc, bool_t enable) {
6360 	lp_config_set_int(lc->config, "sound", "ring_during_incoming_early_media", (int)enable);
6361 }
6362 
6363 bool_t linphone_core_get_ring_during_incoming_early_media(const LinphoneCore *lc) {
6364 	return (bool_t)lp_config_get_int(lc->config, "sound", "ring_during_incoming_early_media", 0);
6365 }
6366 
6367 static OrtpPayloadType* _linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) {
6368 	OrtpPayloadType* result = find_payload_type_from_list(type, rate, channels, lc->codecs_conf.audio_codecs);
6369 	if (result)  {
6370 		return result;
6371 	} else {
6372 		result = find_payload_type_from_list(type, rate, 0, lc->codecs_conf.video_codecs);
6373 		if (result) {
6374 			return result;
6375 		} else {
6376 			result = find_payload_type_from_list(type, rate, 0, lc->codecs_conf.text_codecs);
6377 			if (result) {
6378 				return result;
6379 			}
6380 		}
6381 	}
6382 	/*not found*/
6383 	return NULL;
6384 }
6385 
6386 OrtpPayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) {
6387 	return _linphone_core_find_payload_type(lc, type, rate, channels);
6388 }
6389 
6390 LinphonePayloadType *linphone_core_get_payload_type(LinphoneCore *lc, const char *type, int rate, int channels) {
6391 	OrtpPayloadType *pt = _linphone_core_find_payload_type(lc, type, rate, channels);
6392 	return pt ? linphone_payload_type_new(lc, pt) : NULL;
6393 }
6394 
6395 const char* linphone_configuring_state_to_string(LinphoneConfiguringState cs){
6396 	switch(cs){
6397 		case LinphoneConfiguringSuccessful:
6398 			return "LinphoneConfiguringSuccessful";
6399 		break;
6400 		case LinphoneConfiguringFailed:
6401 			return "LinphoneConfiguringFailed";
6402 		break;
6403 		case LinphoneConfiguringSkipped:
6404 			return "LinphoneConfiguringSkipped";
6405 		break;
6406 	}
6407 	return NULL;
6408 }
6409 
6410 const char *linphone_global_state_to_string(LinphoneGlobalState gs){
6411 	switch(gs){
6412 		case LinphoneGlobalOff:
6413 			return "LinphoneGlobalOff";
6414 		break;
6415 		case LinphoneGlobalOn:
6416 			return "LinphoneGlobalOn";
6417 		break;
6418 		case LinphoneGlobalStartup:
6419 			return "LinphoneGlobalStartup";
6420 		break;
6421 		case LinphoneGlobalShutdown:
6422 			return "LinphoneGlobalShutdown";
6423 		case LinphoneGlobalConfiguring:
6424 			return "LinphoneGlobalConfiguring";
6425 		break;
6426 	}
6427 	return NULL;
6428 }
6429 
6430 LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc){
6431 	return lc->state;
6432 }
6433 
6434 
6435 static LinphoneCallParams *_create_call_params(LinphoneCore *lc){
6436 	LinphoneCallParams *p=linphone_call_params_new();
6437 	linphone_core_init_default_params(lc, p);
6438 	return p;
6439 }
6440 
6441 LinphoneCallParams *linphone_core_create_call_params(LinphoneCore *lc, LinphoneCall *call){
6442 	if (!call) return _create_call_params(lc);
6443 	if (call->params){
6444 		return linphone_call_params_copy(call->params);
6445 	}
6446 	ms_error("linphone_core_create_call_params(): call [%p] is not in a state where call params can be created or used.", call);
6447 	return NULL;
6448 }
6449 
6450 const char *linphone_error_to_string(LinphoneReason err){
6451 	return linphone_reason_to_string(err);
6452 }
6453 
6454 void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) {
6455 #ifdef BUILD_UPNP
6456 	if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp) {
6457 		enable = FALSE;
6458 	}
6459 #endif //BUILD_UPNP
6460 	if (enable > 0) {
6461 		sal_use_tcp_tls_keepalive(lc->sal,lc->sip_conf.tcp_tls_keepalive);
6462 		sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period);
6463 	} else {
6464 		sal_set_keepalive_period(lc->sal,0);
6465 	}
6466 }
6467 
6468 bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc) {
6469 	return sal_get_keepalive_period(lc->sal) > 0;
6470 }
6471 
6472 void linphone_core_start_dtmf_stream(LinphoneCore* lc) {
6473 	get_dtmf_gen(lc); /*make sure ring stream is started*/
6474 	lc->ringstream_autorelease=FALSE; /*disable autorelease mode*/
6475 }
6476 
6477 void linphone_core_stop_ringing(LinphoneCore* lc) {
6478 	LinphoneCall *call=linphone_core_get_current_call(lc);
6479 	if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) {
6480 		linphone_ringtoneplayer_stop(lc->ringtoneplayer);
6481 	}
6482 	if (lc->ringstream) {
6483 		ring_stop(lc->ringstream);
6484 		lc->ringstream=NULL;
6485 		lc->dmfs_playing_start_time=0;
6486 		lc->ringstream_autorelease=TRUE;
6487 	}
6488 	if (call && call->ringing_beep){
6489 		linphone_core_stop_dtmf(lc);
6490 		call->ringing_beep=FALSE;
6491 	}
6492 }
6493 
6494 void linphone_core_stop_dtmf_stream(LinphoneCore* lc) {
6495 	if (lc->dmfs_playing_start_time!=0) {
6496 		linphone_core_stop_ringing(lc);
6497 	}
6498 }
6499 
6500 int linphone_core_get_max_calls(LinphoneCore *lc) {
6501 	return lc->max_calls;
6502 }
6503 
6504 void linphone_core_set_max_calls(LinphoneCore *lc, int max) {
6505 	lc->max_calls=max;
6506 }
6507 
6508 void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
6509 	linphone_task_list_add(&lc->hooks, hook, hook_data);
6510 }
6511 
6512 static void linphone_core_run_hooks(LinphoneCore *lc){
6513 	linphone_task_list_run(&lc->hooks);
6514 }
6515 
6516 void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
6517 	linphone_task_list_remove(&lc->hooks, hook, hook_data);
6518 
6519 }
6520 
6521 void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){
6522 	if (lc->zrtp_secrets_cache != NULL) {
6523 		ms_free(lc->zrtp_secrets_cache);
6524 	}
6525 
6526 	lc->zrtp_secrets_cache=file ? ms_strdup(file) : NULL;
6527 
6528 	/* shall we perform cache migration ? */
6529 	if (!lp_config_get_int(lc->config,"sip","zrtp_cache_migration_done",FALSE)) {
6530 		char *tmpFile = bctbx_malloc(strlen(file)+6);
6531 		/* check we have a valid xml cache file given in path */
6532 		FILE *CACHEFD = NULL;
6533 		/* load the xml cache */
6534 		if (file != NULL) {
6535 			int ret=0;
6536 			CACHEFD = fopen(file, "rb+");
6537 			xmlDocPtr cacheXml = NULL;
6538 			if (CACHEFD) {
6539 				size_t cacheSize;
6540 				char *cacheString = ms_load_file_content(CACHEFD, &cacheSize);
6541 				if (!cacheString) {
6542 					ms_warning("Unable to load content of ZRTP ZID cache");
6543 					bctbx_free(tmpFile);
6544 					return;
6545 				}
6546 				cacheString[cacheSize] = '\0';
6547 				cacheSize += 1;
6548 				fclose(CACHEFD);
6549 				cacheXml = xmlParseDoc((xmlChar*)cacheString);
6550 				ms_free(cacheString);
6551 			}
6552 
6553 			/* create a temporary file for the sqlite base and initialise it */
6554 			sprintf(tmpFile,"%s.tmp", file);
6555 			linphone_core_zrtp_cache_db_init(lc, tmpFile);
6556 
6557 			/* migrate */
6558 			char *bkpFile = bctbx_malloc(strlen(file)+6);
6559 			sprintf(bkpFile,"%s.bkp", file);
6560 
6561 			if ((ret = ms_zrtp_cache_migration((void *)cacheXml, linphone_core_get_zrtp_cache_db(lc), linphone_core_get_identity(lc))) == 0) {
6562 				ms_message("LIME/ZRTP cache migration successfull, obsolete xml file kept as backup in %s", bkpFile);
6563 			} else {
6564 				ms_error("LIME/ZRTP cache migration failed(returned -%x), start with a fresh cache, old one kept as backup in %s", -ret, bkpFile);
6565 			}
6566 
6567 			/* rename the newly created sqlite3 file in to the given file name */
6568 			rename(file, bkpFile);
6569 			if (rename(tmpFile, file)==0) { /* set the flag if we were able to set the sqlite file in the correct place (even if migration failed) */
6570 				lp_config_set_int(lc->config, "sip", "zrtp_cache_migration_done", TRUE);
6571 			}
6572 
6573 			/* clean up */
6574 			bctbx_free(bkpFile);
6575 			xmlFree(cacheXml);
6576 		}
6577 		bctbx_free(tmpFile);
6578 	} else {
6579 		linphone_core_zrtp_cache_db_init(lc, file);
6580 	}
6581 }
6582 
6583 const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){
6584 	return lc->zrtp_secrets_cache;
6585 }
6586 
6587 void *linphone_core_get_zrtp_cache_db(LinphoneCore *lc){
6588 #ifdef SQLITE_STORAGE_ENABLED
6589 	return (void *)lc->zrtp_cache_db;
6590 #else /* SQLITE_STORAGE_ENABLED */
6591 	return NULL;
6592 #endif /* SQLITE_STORAGE_ENABLED */
6593 }
6594 
6595 static void linphone_core_zrtp_cache_close(LinphoneCore *lc) {
6596 #ifdef SQLITE_STORAGE_ENABLED
6597 	if (lc->zrtp_cache_db) {
6598 		sqlite3_close(lc->zrtp_cache_db);
6599 		lc->zrtp_cache_db = NULL;
6600 	}
6601 #endif /* SQLITE_STORAGE_ENABLED */
6602 }
6603 
6604 
6605 void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName) {
6606 #ifdef SQLITE_STORAGE_ENABLED
6607 	int ret;
6608 	const char *errmsg;
6609 	const char *backupExtension = "_backup";
6610 	char *backupName = malloc(snprintf(NULL, 0, "%s%s", fileName, backupExtension) + 1);
6611 	sprintf(backupName, "%s%s", fileName, backupExtension);
6612 	sqlite3 *db;
6613 
6614 	linphone_core_zrtp_cache_close(lc);
6615 
6616 	ret = _linphone_sqlite3_open(fileName, &db);
6617 	if (ret != SQLITE_OK) {
6618 		errmsg = sqlite3_errmsg(db);
6619 		ms_error("Error in the opening zrtp_cache_db_file(%s): %s.\n", fileName, errmsg);
6620 		sqlite3_close(db);
6621 		unlink(backupName);
6622 		rename(fileName, backupName);
6623 		lc->zrtp_cache_db=NULL;
6624 		return;
6625 	}
6626 
6627 	ret = ms_zrtp_initCache((void *)db); /* this may perform an update, check return value */
6628 
6629 	if (ret == MSZRTP_CACHE_SETUP || ret == MSZRTP_CACHE_UPDATE) {
6630 		/* After updating schema, database need to be closed/reopenned */
6631 		sqlite3_close(db);
6632 		_linphone_sqlite3_open(fileName, &db);
6633 	} else if(ret != 0) { /* something went wrong */
6634 		ms_error("Zrtp cache failed to initialise(returned -%x), run cacheless", -ret);
6635 		sqlite3_close(db);
6636 		unlink(backupName);
6637 		rename(fileName, backupName);
6638 		lc->zrtp_cache_db = NULL;
6639 		return;
6640 	}
6641 
6642 	/* everything ok, set the db pointer into core */
6643 	lc->zrtp_cache_db = db;
6644 #endif /* SQLITE_STORAGE_ENABLED */
6645 }
6646 
6647 void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path){
6648 	char* new_value;
6649 	new_value = path?ms_strdup(path):NULL;
6650 	if (lc->user_certificates_path) ms_free(lc->user_certificates_path);
6651 	lp_config_set_string(lc->config,"misc","user_certificates_path",lc->user_certificates_path=new_value);
6652 	return ;
6653 }
6654 
6655 const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){
6656 	return lc->user_certificates_path;
6657 }
6658 
6659 bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){
6660 	bctbx_list_t *elem;
6661 	for(elem=lc->calls;elem!=NULL;elem=elem->next) {
6662 		LinphoneCall *c=(LinphoneCall*)elem->data;
6663 
6664 		if (linphone_call_media_in_progress(c)) {
6665 			return TRUE;
6666 		}
6667 
6668 		switch (c->state) {
6669 			case LinphoneCallOutgoingInit:
6670 			case LinphoneCallOutgoingProgress:
6671 			case LinphoneCallOutgoingRinging:
6672 			case LinphoneCallOutgoingEarlyMedia:
6673 			case LinphoneCallConnected:
6674 			case LinphoneCallRefered:
6675 			case LinphoneCallIncomingEarlyMedia:
6676 			case LinphoneCallUpdating:
6677 				ms_message("Call %p is locking sound resources.",c);
6678 				return TRUE;
6679 			default:
6680 				break;
6681 		}
6682 	}
6683 	return FALSE;
6684 }
6685 
6686 void linphone_core_set_srtp_enabled(LinphoneCore *lc, bool_t enabled) {
6687 	lp_config_set_int(lc->config,"sip","srtp",(int)enabled);
6688 }
6689 
6690 const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){
6691 	switch(menc){
6692 		case LinphoneMediaEncryptionSRTP:
6693 			return "LinphoneMediaEncryptionSRTP";
6694 		case LinphoneMediaEncryptionDTLS:
6695 			return "LinphoneMediaEncryptionDTLS";
6696 		case LinphoneMediaEncryptionZRTP:
6697 			return "LinphoneMediaEncryptionZRTP";
6698 		case LinphoneMediaEncryptionNone:
6699 			return "LinphoneMediaEncryptionNone";
6700 	}
6701 	ms_error("Invalid LinphoneMediaEncryption value %i",(int)menc);
6702 	return "INVALID";
6703 }
6704 
6705 
6706 bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc){
6707 	switch(menc){
6708 		case LinphoneMediaEncryptionSRTP:
6709 			return ms_srtp_supported();
6710 		case LinphoneMediaEncryptionDTLS:
6711 			return ms_dtls_srtp_available();
6712 		case LinphoneMediaEncryptionZRTP:
6713 			return ms_zrtp_available() && !lc->zrtp_not_available_simulation;
6714 		case LinphoneMediaEncryptionNone:
6715 			return TRUE;
6716 	}
6717 	return FALSE;
6718 }
6719 
6720 LinphoneStatus linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption menc) {
6721 	const char *type="none";
6722 	int ret=-1;
6723 
6724 	switch(menc){
6725 		case LinphoneMediaEncryptionSRTP:
6726 			if (!ms_srtp_supported()){
6727 				ms_warning("SRTP not supported by library.");
6728 				type="none";
6729 				ret=-1;
6730 			}else{
6731 				type="srtp";
6732 				ret = 0;
6733 			}
6734 		break;
6735 		case LinphoneMediaEncryptionZRTP:
6736 			if (!linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)){
6737 				ms_warning("ZRTP not supported by library.");
6738 				type="none";
6739 				ret=-1;
6740 			}else {
6741 				type="zrtp";
6742 				ret = 0;
6743 			}
6744 		break;
6745 		case LinphoneMediaEncryptionDTLS:
6746 			if (!ms_dtls_srtp_available()){
6747 				ms_warning("DTLS not supported by library.");
6748 				type="none";
6749 				ret=-1;
6750 			}else {
6751 				type="dtls";
6752 				ret = 0;
6753 			}
6754 		break;
6755 		case LinphoneMediaEncryptionNone:
6756 			type = "none";
6757 			ret = 0;
6758 		break;
6759 	}
6760 	lp_config_set_string(lc->config,"sip","media_encryption",type);
6761 	return ret;
6762 }
6763 
6764 LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) {
6765 	const char* menc = lp_config_get_string(lc->config, "sip", "media_encryption", NULL);
6766 
6767 	if (menc == NULL)
6768 		return LinphoneMediaEncryptionNone;
6769 	else if (strcmp(menc, "srtp")==0)
6770 		return LinphoneMediaEncryptionSRTP;
6771 	else if (strcmp(menc, "dtls")==0)
6772 		return LinphoneMediaEncryptionDTLS;
6773 	else if (strcmp(menc, "zrtp")==0)
6774 		return LinphoneMediaEncryptionZRTP;
6775 	else
6776 		return LinphoneMediaEncryptionNone;
6777 }
6778 
6779 bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc) {
6780 	return (bool_t)lp_config_get_int(lc->config, "sip", "media_encryption_mandatory", 0);
6781 }
6782 
6783 void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) {
6784 	lp_config_set_int(lc->config, "sip", "media_encryption_mandatory", (int)m);
6785 }
6786 
6787 void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) {
6788 	params->has_audio = TRUE;
6789 	params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate;
6790 	if (!linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate){
6791 		ms_error("LinphoneCore has video disabled for both capture and display, but video policy is to start the call with video. "
6792 			"This is a possible mis-use of the API. In this case, video is disabled in default LinphoneCallParams");
6793 	}
6794 	params->media_encryption=linphone_core_get_media_encryption(lc);
6795 	params->in_conference=FALSE;
6796 	params->realtimetext_enabled = linphone_core_realtime_text_enabled(lc);
6797 	params->privacy=LinphonePrivacyDefault;
6798 	params->avpf_enabled=linphone_core_get_avpf_mode(lc);
6799 	params->implicit_rtcp_fb = lp_config_get_int(lc->config,"rtp","rtcp_fb_implicit_rtcp_fb",TRUE);
6800 	params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(lc);
6801 	params->audio_dir=LinphoneMediaDirectionSendRecv;
6802 	params->video_dir=LinphoneMediaDirectionSendRecv;
6803 	params->real_early_media=lp_config_get_int(lc->config,"misc","real_early_media",FALSE);
6804 	params->audio_multicast_enabled=linphone_core_audio_multicast_enabled(lc);
6805 	params->video_multicast_enabled=linphone_core_video_multicast_enabled(lc);
6806 	params->update_call_when_ice_completed = lp_config_get_int(lc->config, "sip", "update_call_when_ice_completed", TRUE);
6807 	params->encryption_mandatory = linphone_core_is_media_encryption_mandatory(lc);
6808 }
6809 
6810 void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
6811 	if (lc->device_id) ms_free(lc->device_id);
6812 	lc->device_id=ms_strdup(device_id);
6813 }
6814 
6815 const char*  linphone_core_get_device_identifier(const LinphoneCore *lc) {
6816 	return lc->device_id;
6817 }
6818 
6819 void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){
6820 	sal_set_dscp(lc->sal,dscp);
6821 	if (linphone_core_ready(lc)){
6822 		lp_config_set_int_hex(lc->config,"sip","dscp",dscp);
6823 		_linphone_core_apply_transports(lc);
6824 	}
6825 }
6826 
6827 int linphone_core_get_sip_dscp(const LinphoneCore *lc){
6828 	return lp_config_get_int(lc->config,"sip","dscp",0x1a);
6829 }
6830 
6831 void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){
6832 	if (linphone_core_ready(lc))
6833 		lp_config_set_int_hex(lc->config,"rtp","audio_dscp",dscp);
6834 }
6835 
6836 int linphone_core_get_audio_dscp(const LinphoneCore *lc){
6837 	return lp_config_get_int(lc->config,"rtp","audio_dscp",0x2e);
6838 }
6839 
6840 void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){
6841 	if (linphone_core_ready(lc))
6842 		lp_config_set_int_hex(lc->config,"rtp","video_dscp",dscp);
6843 
6844 }
6845 
6846 int linphone_core_get_video_dscp(const LinphoneCore *lc){
6847 	return lp_config_get_int(lc->config,"rtp","video_dscp",0);
6848 }
6849 
6850 void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){
6851 	if (lc->chat_db_file){
6852 		ms_free(lc->chat_db_file);
6853 		lc->chat_db_file=NULL;
6854 	}
6855 	if (path) {
6856 		lc->chat_db_file=ms_strdup(path);
6857 		linphone_core_message_storage_init(lc);
6858 	}
6859 }
6860 
6861 const char* linphone_core_get_chat_database_path(const LinphoneCore *lc) {
6862 	return lc->chat_db_file;
6863 }
6864 
6865 void linphone_core_enable_sdp_200_ack(LinphoneCore *lc, bool_t enable) {
6866 	lp_config_set_int(lc->config,"sip","sdp_200_ack",lc->sip_conf.sdp_200_ack=enable);
6867 }
6868 
6869 bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc) {
6870 	return lc->sip_conf.sdp_200_ack!=0;
6871 }
6872 
6873 void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url) {
6874 	lp_config_set_string(core->config, "misc", "file_transfer_server_url", server_url);
6875 }
6876 
6877 const char * linphone_core_get_file_transfer_server(LinphoneCore *core) {
6878 	return lp_config_get_string(core->config, "misc", "file_transfer_server_url", NULL);
6879 }
6880 
6881 void linphone_core_add_supported_tag(LinphoneCore *lc, const char *tag){
6882 	sal_add_supported_tag(lc->sal,tag);
6883 	lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal));
6884 }
6885 
6886 void linphone_core_remove_supported_tag(LinphoneCore *lc, const char *tag){
6887 	sal_remove_supported_tag(lc->sal,tag);
6888 	lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal));
6889 }
6890 
6891 void linphone_core_set_avpf_mode(LinphoneCore *lc, LinphoneAVPFMode mode){
6892 	if (mode==LinphoneAVPFDefault) mode=LinphoneAVPFDisabled;
6893 	lc->rtp_conf.avpf_mode=mode;
6894 	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"rtp","avpf",mode);
6895 }
6896 
6897 LinphoneAVPFMode linphone_core_get_avpf_mode(const LinphoneCore *lc){
6898 	return lc->rtp_conf.avpf_mode;
6899 }
6900 
6901 int linphone_core_get_avpf_rr_interval(const LinphoneCore *lc){
6902 	return lp_config_get_int(lc->config,"rtp","avpf_rr_interval",5);
6903 }
6904 
6905 void linphone_core_set_avpf_rr_interval(LinphoneCore *lc, int interval){
6906 	lp_config_set_int(lc->config,"rtp","avpf_rr_interval",interval);
6907 }
6908 
6909 LinphoneStatus linphone_core_set_audio_multicast_addr(LinphoneCore *lc, const char* ip) {
6910 	char* new_value;
6911 	if (ip && !ms_is_multicast(ip)) {
6912 		ms_error("Cannot set multicast audio addr to core [%p] because [%s] is not multicast",lc,ip);
6913 		return -1;
6914 	}
6915 	new_value = ip?ms_strdup(ip):NULL;
6916 	if (lc->rtp_conf.audio_multicast_addr) ms_free(lc->rtp_conf.audio_multicast_addr);
6917 	lp_config_set_string(lc->config,"rtp","audio_multicast_addr",lc->rtp_conf.audio_multicast_addr=new_value);
6918 	return 0;
6919 }
6920 
6921 LinphoneStatus linphone_core_set_video_multicast_addr(LinphoneCore *lc, const char* ip) {
6922 	char* new_value;
6923 	if (ip && !ms_is_multicast(ip)) {
6924 		ms_error("Cannot set multicast video addr to core [%p] because [%s] is not multicast",lc,ip);
6925 		return -1;
6926 	}
6927 	new_value = ip?ms_strdup(ip):NULL;
6928 	if (lc->rtp_conf.video_multicast_addr) ms_free(lc->rtp_conf.video_multicast_addr);
6929 	lp_config_set_string(lc->config,"rtp","video_multicast_addr",lc->rtp_conf.video_multicast_addr=new_value);
6930 	return 0;
6931 }
6932 
6933 const char* linphone_core_get_audio_multicast_addr(const LinphoneCore *lc) {
6934 	return lc->rtp_conf.audio_multicast_addr;
6935 }
6936 
6937 const char* linphone_core_get_video_multicast_addr(const LinphoneCore *lc){
6938 	return lc->rtp_conf.video_multicast_addr;
6939 }
6940 
6941 LinphoneStatus linphone_core_set_audio_multicast_ttl(LinphoneCore *lc, int ttl) {
6942 	if (ttl>255) {
6943 		ms_error("Cannot set multicast audio ttl to core [%p] to [%i] value must be <256",lc,ttl);
6944 		return -1;
6945 	}
6946 
6947 	lp_config_set_int(lc->config,"rtp","audio_multicast_ttl",lc->rtp_conf.audio_multicast_ttl=ttl);
6948 	return 0;
6949 }
6950 
6951 LinphoneStatus linphone_core_set_video_multicast_ttl(LinphoneCore *lc, int ttl) {
6952 	if (ttl>255) {
6953 		ms_error("Cannot set multicast video ttl to core [%p] to [%i] value must be <256",lc,ttl);
6954 		return -1;
6955 	}
6956 
6957 	lp_config_set_int(lc->config,"rtp","video_multicast_ttl",lc->rtp_conf.video_multicast_ttl=ttl);
6958 	return 0;
6959 }
6960 
6961 int linphone_core_get_audio_multicast_ttl(const LinphoneCore *lc) {
6962 	return lc->rtp_conf.audio_multicast_ttl;
6963 }
6964 
6965 
6966 int linphone_core_get_video_multicast_ttl(const LinphoneCore *lc){
6967 	return lc->rtp_conf.video_multicast_ttl;
6968 }
6969 
6970 void linphone_core_enable_audio_multicast(LinphoneCore *lc, bool_t yesno) {
6971 	lp_config_set_int(lc->config,"rtp","audio_multicast_enabled",lc->rtp_conf.audio_multicast_enabled=yesno);
6972 }
6973 
6974  bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *lc) {
6975 	return lc->rtp_conf.audio_multicast_enabled;
6976 }
6977 
6978 void linphone_core_enable_video_multicast(LinphoneCore *lc, bool_t yesno) {
6979 	lp_config_set_int(lc->config,"rtp","video_multicast_enabled",lc->rtp_conf.video_multicast_enabled=yesno);
6980 }
6981 
6982 bool_t linphone_core_video_multicast_enabled(const LinphoneCore *lc) {
6983 	return lc->rtp_conf.video_multicast_enabled;
6984 }
6985 
6986 void linphone_core_set_video_preset(LinphoneCore *lc, const char *preset) {
6987 	lp_config_set_string(lc->config, "video", "preset", preset);
6988 }
6989 
6990 const char * linphone_core_get_video_preset(const LinphoneCore *lc) {
6991 	return lp_config_get_string(lc->config, "video", "preset", NULL);
6992 }
6993 
6994 #ifdef __ANDROID__
6995 static int linphone_core_call_void_method(jobject obj, jmethodID id) {
6996 	JNIEnv *env=ms_get_jni_env();
6997 	if (env && obj) {
6998 		(*env)->CallVoidMethod(env,obj,id);
6999 		if ((*env)->ExceptionCheck(env)) {
7000 			(*env)->ExceptionClear(env);
7001 			return -1;
7002 		} else
7003 			return 0;
7004 	} else
7005 		return -1;
7006 }
7007 
7008 void linphone_core_wifi_lock_acquire(LinphoneCore *lc) {
7009 	if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_acquire_id))
7010 		ms_warning("No wifi lock configured or not usable for core [%p]",lc);
7011 }
7012 
7013 void linphone_core_wifi_lock_release(LinphoneCore *lc) {
7014 	if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_release_id))
7015 		ms_warning("No wifi lock configured or not usable for core [%p]",lc);
7016 }
7017 
7018 void linphone_core_multicast_lock_acquire(LinphoneCore *lc) {
7019 	if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_acquire_id))
7020 			ms_warning("No multicast lock configured or not usable for core [%p]",lc);
7021 }
7022 
7023 void linphone_core_multicast_lock_release(LinphoneCore *lc) {
7024 	if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_release_id))
7025 			ms_warning("No wifi lock configured or not usable for core [%p]",lc);
7026 }
7027 #endif
7028 
7029 
7030 LINPHONE_PUBLIC const char *linphone_core_log_collection_upload_state_to_string(const LinphoneCoreLogCollectionUploadState lcus) {
7031 	switch (lcus) {
7032 	case LinphoneCoreLogCollectionUploadStateInProgress : return "LinphoneCoreLogCollectionUploadStateInProgress";
7033 	case LinphoneCoreLogCollectionUploadStateDelivered : return "LinphoneCoreLogCollectionUploadStateDelivered";
7034 	case LinphoneCoreLogCollectionUploadStateNotDelivered : return "LinphoneCoreLogCollectionUploadStateNotDelivered";
7035 	}
7036 	return "UNKNOWN";
7037 }
7038 
7039 bool_t linphone_core_realtime_text_enabled(LinphoneCore *lc) {
7040 	return lc->text_conf.enabled;
7041 }
7042 
7043 void linphone_core_set_http_proxy_host(LinphoneCore *lc, const char *host) {
7044 	lp_config_set_string(lc->config,"sip","http_proxy_host",host);
7045 	if (lc->sal) {
7046 		sal_set_http_proxy_host(lc->sal,host);
7047 		sal_set_http_proxy_port(lc->sal,linphone_core_get_http_proxy_port(lc)); /*to make sure default value is set*/
7048 	}
7049 }
7050 
7051 void linphone_core_set_http_proxy_port(LinphoneCore *lc, int port) {
7052 	lp_config_set_int(lc->config,"sip","http_proxy_port",port);
7053 	if (lc->sal)
7054 		sal_set_http_proxy_port(lc->sal,port);
7055 }
7056 
7057 const char *linphone_core_get_http_proxy_host(const LinphoneCore *lc) {
7058 	return lp_config_get_string(lc->config,"sip","http_proxy_host",NULL);
7059 }
7060 
7061 int linphone_core_get_http_proxy_port(const LinphoneCore *lc) {
7062 	return lp_config_get_int(lc->config,"sip","http_proxy_port",3128);
7063 }
7064 
7065 const char* linphone_transport_to_string(LinphoneTransportType transport) {
7066 	return sal_transport_to_string((SalTransport)transport);
7067 }
7068 
7069 LinphoneTransportType linphone_transport_parse(const char* transport) {
7070 	return (LinphoneTransportType)sal_transport_parse(transport);
7071 }
7072 
7073 const char *linphone_stream_type_to_string(const LinphoneStreamType type) {
7074 	switch (type) {
7075 		case LinphoneStreamTypeAudio: return "LinphoneStreamTypeAudio";
7076 		case LinphoneStreamTypeVideo: return "LinphoneStreamTypeVideo";
7077 		case LinphoneStreamTypeText: return "LinphoneStreamTypeText";
7078 		case LinphoneStreamTypeUnknown: return "LinphoneStreamTypeUnknown";
7079 	}
7080 	return "INVALID";
7081 }
7082 
7083 LinphoneRingtonePlayer *linphone_core_get_ringtoneplayer(LinphoneCore *lc) {
7084 	return lc->ringtoneplayer;
7085 }
7086 
7087 static int _linphone_core_delayed_conference_destruction_cb(void *user_data, unsigned int event) {
7088 	LinphoneConference *conf = (LinphoneConference *)user_data;
7089 	linphone_conference_unref(conf);
7090 	return 0;
7091 }
7092 
7093 static void _linphone_core_conference_state_changed(LinphoneConference *conf, LinphoneConferenceState cstate, void *user_data) {
7094 	LinphoneCore *lc = (LinphoneCore *)user_data;
7095 	if(cstate == LinphoneConferenceStartingFailed || cstate == LinphoneConferenceStopped) {
7096 		linphone_core_queue_task(lc, _linphone_core_delayed_conference_destruction_cb, conf, "Conference destruction task");
7097 		lc->conf_ctx = NULL;
7098 	}
7099 }
7100 
7101 /*This function sets the "unique" conference object for the LinphoneCore - which is necessary as long as
7102  * liblinphone is used in a client app. When liblinphone will be used in a server app, this shall not be done anymore.*/
7103 static void linphone_core_set_conference(LinphoneCore *lc, LinphoneConference *conf){
7104 	lc->conf_ctx = linphone_conference_ref(conf);
7105 }
7106 
7107 LinphoneConference *linphone_core_create_conference_with_params(LinphoneCore *lc, const LinphoneConferenceParams *params) {
7108 	const char *conf_method_name;
7109 	LinphoneConference *conf;
7110 	if(lc->conf_ctx == NULL) {
7111 		LinphoneConferenceParams *params2 = linphone_conference_params_clone(params);
7112 		linphone_conference_params_set_state_changed_callback(params2, _linphone_core_conference_state_changed, lc);
7113 		conf_method_name = lp_config_get_string(lc->config, "misc", "conference_type", "local");
7114 		if(strcasecmp(conf_method_name, "local") == 0) {
7115 			conf = linphone_local_conference_new_with_params(lc, params2);
7116 		} else if(strcasecmp(conf_method_name, "remote") == 0) {
7117 			conf = linphone_remote_conference_new_with_params(lc, params2);
7118 		} else {
7119 			ms_error("'%s' is not a valid conference method", conf_method_name);
7120 			linphone_conference_params_unref(params2);
7121 			return NULL;
7122 		}
7123 		linphone_conference_params_unref(params2);
7124 		linphone_core_set_conference(lc, conf);
7125 	} else {
7126 		ms_error("Could not create a conference: a conference instance already exists");
7127 		return NULL;
7128 	}
7129 	return lc->conf_ctx;
7130 }
7131 
7132 LinphoneConferenceParams * linphone_core_create_conference_params(LinphoneCore *lc){
7133 	return linphone_conference_params_new(lc);
7134 }
7135 
7136 LinphoneStatus linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call) {
7137 	LinphoneConference *conference = linphone_core_get_conference(lc);
7138 	if(conference == NULL) {
7139 		LinphoneConferenceParams *params = linphone_conference_params_new(lc);
7140 		conference = linphone_core_create_conference_with_params(lc, params);
7141 		linphone_conference_params_unref(params);
7142 		linphone_conference_unref(conference); /*actually linphone_core_create_conference_with_params() takes a ref for lc->conf_ctx */
7143 	}
7144 	if(conference) return linphone_conference_add_participant(lc->conf_ctx, call);
7145 	else return -1;
7146 }
7147 
7148 LinphoneStatus linphone_core_add_all_to_conference(LinphoneCore *lc) {
7149 	bctbx_list_t *calls=lc->calls;
7150 	while (calls) {
7151 		LinphoneCall *call=(LinphoneCall*)calls->data;
7152 		calls=calls->next;
7153 		if(linphone_call_get_conference(call) == NULL) { // Prevent the call to the conference server from being added to the conference
7154 			linphone_core_add_to_conference(lc, call);
7155 		}
7156 	}
7157 	if(lc->conf_ctx && linphone_conference_check_class(lc->conf_ctx, LinphoneConferenceClassLocal)) {
7158 		linphone_core_enter_conference(lc);
7159 	}
7160 	return 0;
7161 }
7162 
7163 LinphoneStatus linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call) {
7164 	if(lc->conf_ctx) return linphone_conference_remove_participant_with_call(lc->conf_ctx, call);
7165 	else return -1;
7166 }
7167 
7168 int linphone_core_terminate_conference(LinphoneCore *lc) {
7169 	if(lc->conf_ctx == NULL) {
7170 		ms_error("Could not terminate conference: no conference context");
7171 		return -1;
7172 	}
7173 	linphone_conference_terminate(lc->conf_ctx);
7174 	lc->conf_ctx = NULL;
7175 	return 0;
7176 }
7177 
7178 LinphoneStatus linphone_core_enter_conference(LinphoneCore *lc) {
7179 	if(lc->conf_ctx) return linphone_conference_enter(lc->conf_ctx);
7180 	else return -1;
7181 }
7182 
7183 LinphoneStatus linphone_core_leave_conference(LinphoneCore *lc) {
7184 	if(lc->conf_ctx) return linphone_conference_leave(lc->conf_ctx);
7185 	else return -1;
7186 }
7187 
7188 bool_t linphone_core_is_in_conference(const LinphoneCore *lc) {
7189 	if(lc->conf_ctx) return linphone_conference_is_in(lc->conf_ctx);
7190 	else return FALSE;
7191 }
7192 
7193 int linphone_core_get_conference_size(LinphoneCore *lc) {
7194 	if(lc->conf_ctx) return linphone_conference_get_size(lc->conf_ctx);
7195 	return 0;
7196 }
7197 
7198 float linphone_core_get_conference_local_input_volume(LinphoneCore *lc) {
7199 	if(lc->conf_ctx) return linphone_conference_get_input_volume(lc->conf_ctx);
7200 	else return -1.0;
7201 }
7202 
7203 LinphoneStatus linphone_core_start_conference_recording(LinphoneCore *lc, const char *path) {
7204 	if(lc->conf_ctx) return linphone_conference_start_recording(lc->conf_ctx, path);
7205 	return -1;
7206 }
7207 
7208 LinphoneStatus linphone_core_stop_conference_recording(LinphoneCore *lc) {
7209 	if(lc->conf_ctx) return linphone_conference_stop_recording(lc->conf_ctx);
7210 	return -1;
7211 }
7212 
7213 LinphoneConference *linphone_core_get_conference(LinphoneCore *lc) {
7214 	return lc->conf_ctx;
7215 }
7216 
7217 void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) {
7218 	if (lc->tls_cert) {
7219 		ms_free(lc->tls_cert);
7220 		lc->tls_cert = NULL;
7221 	}
7222 	if (tls_cert && strlen(tls_cert) > 0) lc->tls_cert = ms_strdup(tls_cert);
7223 }
7224 
7225 void linphone_core_set_tls_key(LinphoneCore *lc, const char *tls_key) {
7226 	if (lc->tls_key) {
7227 		ms_free(lc->tls_key);
7228 		lc->tls_key = NULL;
7229 	}
7230 	if (tls_key && strlen(tls_key) > 0) lc->tls_key = ms_strdup(tls_key);
7231 }
7232 
7233 void linphone_core_set_tls_cert_path(LinphoneCore *lc, const char *tls_cert_path) {
7234 	lp_config_set_string(lc->config, "sip", "client_cert_chain", tls_cert_path);
7235 }
7236 
7237 void linphone_core_set_tls_key_path(LinphoneCore *lc, const char *tls_key_path) {
7238 	lp_config_set_string(lc->config, "sip", "client_cert_key", tls_key_path);
7239 }
7240 
7241 const char *linphone_core_get_tls_cert(const LinphoneCore *lc) {
7242 	return lc->tls_cert;
7243 }
7244 
7245 const char *linphone_core_get_tls_key(const LinphoneCore *lc) {
7246 	return lc->tls_key;
7247 }
7248 
7249 const char *linphone_core_get_tls_cert_path(const LinphoneCore *lc) {
7250 	const char *tls_cert_path = lp_config_get_string(lc->config, "sip", "client_cert_chain", NULL);
7251 	return tls_cert_path;
7252 }
7253 
7254 const char *linphone_core_get_tls_key_path(const LinphoneCore *lc) {
7255 	const char *tls_key_path = lp_config_get_string(lc->config, "sip", "client_cert_key", NULL);
7256 	return tls_key_path;
7257 }
7258 
7259 void linphone_core_set_im_encryption_engine(LinphoneCore *lc, LinphoneImEncryptionEngine *imee) {
7260 	if (lc->im_encryption_engine) {
7261 		linphone_im_encryption_engine_unref(lc->im_encryption_engine);
7262 		lc->im_encryption_engine = NULL;
7263 	}
7264 	if (imee) {
7265 		imee->lc = lc;
7266 		lc->im_encryption_engine = linphone_im_encryption_engine_ref(imee);
7267 	}
7268 }
7269 
7270 LinphoneImEncryptionEngine *linphone_core_get_im_encryption_engine(const LinphoneCore *lc) {
7271 	return lc->im_encryption_engine;
7272 }
7273 
7274 void linphone_core_initialize_supported_content_types(LinphoneCore *lc) {
7275 	sal_add_content_type_support(lc->sal, "text/plain");
7276 	sal_add_content_type_support(lc->sal, "message/external-body");
7277 	sal_add_content_type_support(lc->sal, "application/vnd.gsma.rcs-ft-http+xml");
7278 	sal_add_content_type_support(lc->sal, "application/im-iscomposing+xml");
7279 	sal_add_content_type_support(lc->sal, "message/imdn+xml");
7280 }
7281 
7282 bool_t linphone_core_is_content_type_supported(const LinphoneCore *lc, const char *content_type) {
7283 	return sal_is_content_type_supported(lc->sal, content_type);
7284 }
7285 
7286 void linphone_core_add_content_type_support(LinphoneCore *lc, const char *content_type) {
7287 	sal_add_content_type_support(lc->sal, content_type);
7288 }
7289 
7290 #ifdef ENABLE_UPDATE_CHECK
7291 static void update_check_process_terminated(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url) {
7292 	linphone_core_notify_version_update_check_result_received(lc, result, version, url);
7293 	if (lc->update_check_http_listener) {
7294 		belle_sip_object_unref(lc->update_check_http_listener);
7295 		lc->update_check_http_listener = NULL;
7296 	}
7297 	bctbx_free(lc->update_check_current_version);
7298 	lc->update_check_current_version = NULL;
7299 }
7300 
7301 typedef struct _parsed_version_st {
7302 	int major;
7303 	int minor;
7304 	int patch;
7305 } parsed_version_t;
7306 
7307 static int compare_parsed_versions(parsed_version_t current_version, parsed_version_t last_version) {
7308 	if (last_version.major > current_version.major) return 1;
7309 	if (last_version.minor > current_version.minor) return 1;
7310 	if (last_version.patch > current_version.patch) return 1;
7311 	return -1;
7312 }
7313 
7314 static void parse_version(const char *version, parsed_version_t *parsed_version) {
7315 	char *copy = bctbx_strdup(version);
7316 	char *ptr = copy;
7317 	char *next;
7318 	memset(parsed_version, 0, sizeof(parsed_version_t));
7319 	next = strchr(ptr, '.');
7320 	parsed_version->major = atoi(ptr);
7321 	ptr = next + 1;
7322 	next = strchr(ptr, '.');
7323 	parsed_version->minor = atoi(ptr);
7324 	if (next != NULL) {
7325 		ptr = next + 1;
7326 		parsed_version->patch = atoi(ptr);
7327 	}
7328 	bctbx_free(copy);
7329 }
7330 
7331 static bool_t update_is_available(const char *current_version, const char *last_version) {
7332 	parsed_version_t current_parsed_version;
7333 	parsed_version_t last_parsed_version;
7334 	parse_version(current_version, &current_parsed_version);
7335 	parse_version(last_version, &last_parsed_version);
7336 	return (compare_parsed_versions(current_parsed_version, last_parsed_version) > 0) ? TRUE : FALSE;
7337 }
7338 
7339 static void update_check_process_response_event(void *ctx, const belle_http_response_event_t *event) {
7340 	LinphoneCore *lc = (LinphoneCore *)ctx;
7341 
7342 	if (belle_http_response_get_status_code(event->response) == 200) {
7343 		belle_sip_message_t *message = BELLE_SIP_MESSAGE(event->response);
7344 		char *body = bctbx_strdup(belle_sip_message_get_body(message));
7345 		char *last_version = body;
7346 		char *url = strchr(body, '\t');
7347 		char *ptr;
7348 		if (url == NULL) {
7349 			update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7350 			bctbx_free(body);
7351 			return;
7352 		}
7353 		*url = '\0';
7354 		url++;
7355 		ptr = strrchr(url, '\r');
7356 		if (ptr != NULL) *ptr = '\0';
7357 		ptr = strrchr(url, '\n');
7358 		if (ptr != NULL) *ptr = '\0';
7359 		if (update_is_available(lc->update_check_current_version, last_version)) {
7360 			update_check_process_terminated(lc, LinphoneVersionUpdateCheckNewVersionAvailable, last_version, url);
7361 		} else {
7362 			update_check_process_terminated(lc, LinphoneVersionUpdateCheckUpToDate, NULL, NULL);
7363 		}
7364 		bctbx_free(body);
7365 	} else {
7366 		update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7367 	}
7368 }
7369 
7370 static void update_check_process_io_error(void *ctx, const belle_sip_io_error_event_t *event) {
7371 	LinphoneCore *lc = (LinphoneCore *)ctx;
7372 	update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7373 }
7374 
7375 static void update_check_process_timeout(void *ctx, const belle_sip_timeout_event_t *event) {
7376 	LinphoneCore *lc = (LinphoneCore *)ctx;
7377 	update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7378 }
7379 
7380 static void update_check_process_auth_requested(void *ctx, belle_sip_auth_event_t *event) {
7381 	LinphoneCore *lc = (LinphoneCore *)ctx;
7382 	update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7383 }
7384 #endif /* ENABLE_UPDATE_CHECK */
7385 
7386 void linphone_core_check_for_update(LinphoneCore *lc, const char *current_version) {
7387 #ifdef ENABLE_UPDATE_CHECK
7388 	int err;
7389 	bool_t is_desktop = FALSE;
7390 	const char *platform = NULL;
7391 	const char *version_check_url_root = lp_config_get_string(lc->config, "misc", "version_check_url_root", NULL);
7392 
7393 	if (version_check_url_root != NULL) {
7394 		belle_http_request_listener_callbacks_t belle_request_listener = { 0 };
7395 		belle_http_request_t *request;
7396 		belle_generic_uri_t *uri;
7397 		char *version_check_url;
7398 		MSList *item;
7399 		MSList *platform_tags = ms_factory_get_platform_tags(linphone_core_get_ms_factory(lc));
7400 
7401 		for (item = platform_tags; item != NULL; item = ms_list_next(item)) {
7402 			const char *tag = (const char *)item->data;
7403 			if (strcmp(tag, "win32") == 0) platform = "windows";
7404 			else if (strcmp(tag, "apple") == 0) platform = "macosx";
7405 			else if (strcmp(tag, "linux") == 0) platform = "linux";
7406 			else if (strcmp(tag, "desktop") == 0) is_desktop = TRUE;
7407 		}
7408 		if ((is_desktop == FALSE) || (platform == NULL)) {
7409 			ms_warning("Update checking is not supported on this platform");
7410 			return;
7411 		}
7412 		version_check_url = bctbx_strdup_printf("%s/%s/RELEASE", version_check_url_root, platform);
7413 		uri = belle_generic_uri_parse(version_check_url);
7414 		ms_message("Checking for new version at: %s", version_check_url);
7415 		bctbx_free(version_check_url);
7416 
7417 		belle_request_listener.process_response = update_check_process_response_event;
7418 		belle_request_listener.process_auth_requested = update_check_process_auth_requested;
7419 		belle_request_listener.process_io_error = update_check_process_io_error;
7420 		belle_request_listener.process_timeout = update_check_process_timeout;
7421 
7422 		lc->update_check_current_version = bctbx_strdup(current_version);
7423 		lc->update_check_http_listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc);
7424 		request = belle_http_request_create("GET", uri, belle_sip_header_create("User-Agent", linphone_core_get_user_agent(lc)), NULL);
7425 		err = belle_http_provider_send_request(lc->http_provider, request, lc->update_check_http_listener);
7426 	}
7427 #endif
7428 }
7429