1 /*
2 linphone
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19 
20 
21 #include "sal/sal.h"
22 
23 #include "linphone/core.h"
24 #include "private.h"
25 #include "mediastreamer2/mediastream.h"
26 #include "linphone/lpconfig.h"
27 #include <bctoolbox/defs.h>
28 
29 // stat
30 #ifndef _WIN32
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #endif
35 
36 static void register_failure(SalOp *op);
37 
media_parameters_changed(LinphoneCall * call,SalMediaDescription * oldmd,SalMediaDescription * newmd)38 static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) {
39 	int result=0;
40 	int otherdesc_changed;
41 	char *tmp1=NULL;
42 	char *tmp2=NULL;
43 	if (call->params->in_conference != call->current_params->in_conference) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION;
44 	if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION;
45 	if (call->localdesc_changed) ms_message("Local description has changed: %s", tmp1 = sal_media_description_print_differences(call->localdesc_changed));
46 	otherdesc_changed = sal_media_description_equals(oldmd, newmd);
47 	if (otherdesc_changed) ms_message("Other description has changed: %s", tmp2 = sal_media_description_print_differences(otherdesc_changed));
48 	result = call->localdesc_changed | otherdesc_changed;
49 	if (tmp1) ms_free(tmp1);
50 	if (tmp2) ms_free(tmp2);
51 	return result;
52 }
53 
linphone_core_update_streams_destinations(LinphoneCall * call,SalMediaDescription * old_md,SalMediaDescription * new_md)54 void linphone_core_update_streams_destinations(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
55 	SalStreamDescription *new_audiodesc = NULL;
56 	SalStreamDescription *new_videodesc = NULL;
57 	char *rtp_addr, *rtcp_addr;
58 	int i;
59 
60 	for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
61 		if (!sal_stream_description_active(&new_md->streams[i])) continue;
62 		if (new_md->streams[i].type == SalAudio) {
63 			new_audiodesc = &new_md->streams[i];
64 		} else if (new_md->streams[i].type == SalVideo) {
65 			new_videodesc = &new_md->streams[i];
66 		}
67 	}
68 	if (call->audiostream && new_audiodesc) {
69 		rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr;
70 		rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr;
71 		ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
72 		rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
73 	}
74 #ifdef VIDEO_ENABLED
75 	if (call->videostream && new_videodesc) {
76 		rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr;
77 		rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr;
78 		ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
79 		rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
80 	}
81 #else
82 	(void)new_videodesc;
83 #endif
84 }
85 
_clear_early_media_destinations(LinphoneCall * call,MediaStream * ms)86 static void _clear_early_media_destinations(LinphoneCall *call, MediaStream *ms){
87 	RtpSession *session=ms->sessions.rtp_session;
88 	rtp_session_clear_aux_remote_addr(session);
89 	if (!call->ice_session) rtp_session_set_symmetric_rtp(session,linphone_core_symmetric_rtp_enabled(call->core));/*restore symmetric rtp if ICE is not used*/
90 }
91 
clear_early_media_destinations(LinphoneCall * call)92 static void clear_early_media_destinations(LinphoneCall *call){
93 	if (call->audiostream){
94 		_clear_early_media_destinations(call,(MediaStream*)call->audiostream);
95 	}
96 	if (call->videostream){
97 		_clear_early_media_destinations(call,(MediaStream*)call->videostream);
98 	}
99 }
100 
prepare_early_media_forking(LinphoneCall * call)101 static void prepare_early_media_forking(LinphoneCall *call){
102 	/*we need to disable symmetric rtp otherwise our outgoing streams will be switching permanently between the multiple destinations*/
103 	if (call->audiostream){
104 		rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session,FALSE);
105 	}
106 	if (call->videostream){
107 		rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,FALSE);
108 	}
109 }
110 
linphone_call_update_frozen_payloads(LinphoneCall * call,SalMediaDescription * result_desc)111 void linphone_call_update_frozen_payloads(LinphoneCall *call, SalMediaDescription *result_desc){
112 	SalMediaDescription *local=call->localdesc;
113 	int i;
114 	for(i=0;i<result_desc->nb_streams;++i){
115 		bctbx_list_t *elem;
116 		for (elem=result_desc->streams[i].payloads;elem!=NULL;elem=elem->next){
117 			PayloadType *pt=(PayloadType*)elem->data;
118 			if (is_payload_type_number_available(local->streams[i].already_assigned_payloads, payload_type_get_number(pt), NULL)){
119 				/*new codec, needs to be added to the list*/
120 				local->streams[i].already_assigned_payloads=bctbx_list_append(local->streams[i].already_assigned_payloads, payload_type_clone(pt));
121 				ms_message("LinphoneCall[%p] : payload type %i %s/%i fmtp=%s added to frozen list.",
122 					   call, payload_type_get_number(pt), pt->mime_type, pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : "");
123 			}
124 		}
125 	}
126 }
127 
linphone_call_update_streams(LinphoneCall * call,SalMediaDescription * new_md,LinphoneCallState target_state)128 void linphone_call_update_streams(LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state) {
129 	LinphoneCore *lc = linphone_call_get_core(call);
130 	SalMediaDescription *oldmd = call->resultdesc;
131 	int md_changed = 0;
132 
133 	if (!((call->state == LinphoneCallIncomingEarlyMedia) && (linphone_core_get_ring_during_incoming_early_media(lc)))) {
134 		linphone_core_stop_ringing(lc);
135 	}
136 	if (!new_md) {
137 		ms_error("linphone_call_update_streams() called with null media description");
138 		return;
139 	}
140 	linphone_call_update_biggest_desc(call, call->localdesc);
141 	sal_media_description_ref(new_md);
142 	call->resultdesc = new_md;
143 	if ((call->audiostream && (call->audiostream->ms.state == MSStreamStarted)) || (call->videostream && (call->videostream->ms.state == MSStreamStarted))) {
144 		clear_early_media_destinations(call);
145 
146 		/* We already started media: check if we really need to restart it */
147 		if (oldmd) {
148 			md_changed = media_parameters_changed(call, oldmd, new_md);
149 			/*might not be mandatory to restart stream for each ice restart as it leads bad user experience, specially in video. See 0002495 for better background on this*/
150 			if ((md_changed & (	SAL_MEDIA_DESCRIPTION_CODEC_CHANGED
151 								|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED
152 								|SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED
153 								|SAL_MEDIA_DESCRIPTION_ICE_RESTART_DETECTED
154 								|SAL_MEDIA_DESCRIPTION_FORCE_STREAM_RECONSTRUCTION ))) {
155 				ms_message("Media descriptions are different, need to restart the streams.");
156 			} else if (call->playing_ringbacktone) {
157 				ms_message("Playing ringback tone, will restart the streams.");
158 			} else {
159 				if (call->all_muted && target_state == LinphoneCallStreamsRunning) {
160 					ms_message("Early media finished, unmuting inputs...");
161 					/* We were in early media, now we want to enable real media */
162 					call->all_muted = FALSE;
163 					if (call->audiostream) linphone_core_enable_mic(lc, linphone_core_mic_enabled(lc));
164 #ifdef VIDEO_ENABLED
165 					if (call->videostream && call->camera_enabled) {
166 						linphone_call_enable_camera(call, linphone_call_camera_enabled(call));
167 					}
168 #endif
169 				}
170 				if (md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) {
171 					/*FIXME ZRTP, might be restarted in any cases ? */
172 					ms_message("No need to restart streams, SDP is unchanged.");
173 					goto end;
174 				} else {
175 					if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) {
176 						ms_message("Network parameters have changed, update them.");
177 						linphone_core_update_streams_destinations(call, oldmd, new_md);
178 					}
179 					if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) {
180 						ms_message("Crypto parameters have changed, update them.");
181 						linphone_call_update_crypto_parameters(call, oldmd, new_md);
182 					}
183 					goto end;
184 				}
185 			}
186 		}
187 		linphone_call_stop_media_streams(call);
188 		if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED) {
189 			ms_message("Media ip type has changed, destroying sessions context on call [%p]", call);
190 			ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]);
191 			ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]);
192 			ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
193 		}
194 		linphone_call_init_media_streams(call);
195 	}
196 
197 	if (call->audiostream == NULL) {
198 		/* This happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them */
199 		linphone_call_init_media_streams(call);
200 	}
201 
202 	if (call->params->real_early_media && (call->state == LinphoneCallOutgoingEarlyMedia)) {
203 		prepare_early_media_forking(call);
204 	}
205 	linphone_call_start_media_streams(call, target_state);
206 	if ((call->state == LinphoneCallPausing) && call->paused_by_app && (bctbx_list_size(lc->calls) == 1)) {
207 		linphone_core_play_named_tone(lc, LinphoneToneCallOnHold);
208 	}
209 	linphone_call_update_frozen_payloads(call, new_md);
210 
211 end:
212 	if (oldmd) sal_media_description_unref(oldmd);
213 
214 }
215 
216 #if 0
217 static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){
218 	bctbx_list_t *elem;
219 	for(elem=lc->calls;elem!=NULL;elem=elem->next){
220 		LinphoneCall *call=(LinphoneCall*)elem->data;
221 		if (linphone_address_weak_equal(call->log->from,from) &&
222 			linphone_address_weak_equal(call->log->to, to)){
223 			return TRUE;
224 		}
225 	}
226 	return FALSE;
227 }
228 #endif
229 
already_a_call_with_remote_address(const LinphoneCore * lc,const LinphoneAddress * remote)230 static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const LinphoneAddress *remote) {
231 	bctbx_list_t *elem;
232 	ms_message("Searching for already_a_call_with_remote_address.");
233 
234 	for(elem=lc->calls;elem!=NULL;elem=elem->next){
235 		const LinphoneCall *call=(LinphoneCall*)elem->data;
236 		const LinphoneAddress *cRemote=linphone_call_get_remote_address(call);
237 		if (linphone_address_weak_equal(cRemote,remote)) {
238 			ms_warning("already_a_call_with_remote_address found.");
239 			return TRUE;
240 		}
241 	}
242 	return FALSE;
243 }
244 
245 
look_for_broken_call_to_replace(SalOp * h,LinphoneCore * lc)246 static LinphoneCall * look_for_broken_call_to_replace(SalOp *h, LinphoneCore *lc) {
247 	const bctbx_list_t *calls = linphone_core_get_calls(lc);
248 	const bctbx_list_t *it = calls;
249 	while (it != NULL) {
250 		LinphoneCall *replaced_call = NULL;
251 		LinphoneCall *call = (LinphoneCall *)bctbx_list_get_data(it);
252 		SalOp *replaced_op = sal_call_get_replaces(h);
253 		if (replaced_op) replaced_call = (LinphoneCall*)sal_op_get_user_pointer(replaced_op);
254 		if ((call->broken && sal_call_compare_op(h, call->op))
255 			|| ((replaced_call == call) && (strcmp(sal_op_get_from(h), sal_op_get_from(replaced_op)) == 0) && (strcmp(sal_op_get_to(h), sal_op_get_to(replaced_op)) == 0))) {
256 			return call;
257 		}
258 		it = bctbx_list_next(it);
259 	}
260 
261 	return NULL;
262 }
263 
call_received(SalOp * h)264 static void call_received(SalOp *h){
265 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
266 	LinphoneCall *call;
267 	LinphoneCall *replaced_call;
268 	char *alt_contact;
269 	LinphoneAddress *from_addr=NULL;
270 	LinphoneAddress  *to_addr=NULL;
271 	LinphoneAddress *from_address_to_search_if_me=NULL; /*address used to know if I'm the caller*/
272 	SalMediaDescription *md;
273 	const char * p_asserted_id;
274 	LinphoneErrorInfo *ei = NULL;
275 	LinphonePresenceActivity *activity = NULL;
276 
277 	/* Look if this INVITE is for a call that has already been notified but broken because of network failure */
278 	replaced_call = look_for_broken_call_to_replace(h, lc);
279 	if (replaced_call != NULL) {
280 		linphone_call_replace_op(replaced_call, h);
281 		return;
282 	}
283 
284 	p_asserted_id = sal_custom_header_find(sal_op_get_recv_custom_header(h),"P-Asserted-Identity");
285 	/*in some situation, better to trust the network rather than the UAC*/
286 	if (lp_config_get_int(lc->config,"sip","call_logs_use_asserted_id_instead_of_from",0)) {
287 		LinphoneAddress *p_asserted_id_addr;
288 		if (!p_asserted_id) {
289 			ms_warning("No P-Asserted-Identity header found so cannot use it for op [%p] instead of from",h);
290 		} else {
291 			p_asserted_id_addr = linphone_address_new(p_asserted_id);
292 			if (!p_asserted_id_addr) {
293 				ms_warning("Unsupported P-Asserted-Identity header for op [%p] ",h);
294 			} else {
295 				ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]",p_asserted_id,sal_op_get_from(h),h);
296 				from_addr=p_asserted_id_addr;
297 			}
298 		}
299 	}
300 
301 	if (!from_addr)
302 		from_addr=linphone_address_new(sal_op_get_from(h));
303 	to_addr=linphone_address_new(sal_op_get_to(h));
304 
305 	/* first check if we can answer successfully to this invite */
306 	if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed
307 		&& (activity = linphone_presence_model_get_activity(lc->presence_model))) {
308 		switch (linphone_presence_activity_get_type(activity)) {
309 			case LinphonePresenceActivityPermanentAbsence:
310 				alt_contact = linphone_presence_model_get_contact(lc->presence_model);
311 				if (alt_contact != NULL) {
312 					SalErrorInfo sei = { 0 };
313 					sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL);
314 					sal_call_decline_with_error_info(h, &sei,alt_contact);
315 					ms_free(alt_contact);
316 					ei = linphone_error_info_new();
317 					linphone_error_info_set(ei, NULL, LinphoneReasonMovedPermanently, 302, "Moved permanently", NULL);
318 					linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei);
319 					sal_op_release(h);
320 					sal_error_info_reset(&sei);
321 					return;
322 				}
323 				break;
324 			default:
325 				/*nothing special to be done*/
326 				break;
327 		}
328 	}
329 
330 	if (!linphone_core_can_we_add_call(lc)){/*busy*/
331 		sal_call_decline(h,SalReasonBusy,NULL);
332 		ei = linphone_error_info_new();
333 		linphone_error_info_set(ei, NULL, LinphoneReasonBusy, 486, "Busy - too many calls", NULL);
334 		linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei);
335 		sal_op_release(h);
336 		return;
337 	}
338 
339 
340 	if (sal_op_get_privacy(h) == SalPrivacyNone) {
341 		from_address_to_search_if_me=linphone_address_clone(from_addr);
342 	} else if (p_asserted_id) {
343 		from_address_to_search_if_me  = linphone_address_new(p_asserted_id);
344 	} else {
345 		ms_warning ("Hidden from identity, don't know if it's me");
346 	}
347 
348 	if (from_address_to_search_if_me && already_a_call_with_remote_address(lc,from_address_to_search_if_me)){
349 		char *addr = linphone_address_as_string(from_addr);
350 		ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message.",addr);
351 		sal_call_decline(h,SalReasonBusy,NULL);
352 		ei = linphone_error_info_new();
353 		linphone_error_info_set(ei, NULL, LinphoneReasonBusy, 486, "Busy - duplicated call", NULL);
354 		linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei);
355 		sal_op_release(h);
356 		linphone_address_unref(from_address_to_search_if_me);
357 		ms_free(addr);
358 		return;
359 	} else if (from_address_to_search_if_me) {
360 		linphone_address_unref(from_address_to_search_if_me);
361 	}
362 
363 	call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
364 
365 	linphone_call_make_local_media_description(call);
366 	sal_call_set_local_media_description(call->op,call->localdesc);
367 	md=sal_call_get_final_media_description(call->op);
368 	if (md){
369 		if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){
370 			ei = linphone_error_info_new();
371 			linphone_error_info_set(ei, NULL, LinphoneReasonNotAcceptable, 488, "Not acceptable here", NULL);
372 			linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_ref(from_addr), linphone_address_ref(to_addr), ei);
373 			sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
374 			linphone_call_unref(call);
375 			return;
376 		}
377 	}
378 
379 	/* the call is acceptable so we can now add it to our list */
380 	linphone_core_add_call(lc,call);
381 	linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */
382 
383 	call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL);
384 
385 	if (call->defer_notify_incoming) {
386 		/* Defer ringing until the end of the ICE candidates gathering process. */
387 		ms_message("Defer ringing to gather ICE candidates");
388 		return;
389 	}
390 #ifdef BUILD_UPNP
391 	if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) && (call->upnp_session != NULL)) {
392 		/* Defer ringing until the end of the ICE candidates gathering process. */
393 		ms_message("Defer ringing to gather uPnP candidates");
394 		return;
395 	}
396 #endif //BUILD_UPNP
397 
398 	linphone_core_notify_incoming_call(lc,call);
399 }
400 
call_rejected(SalOp * h)401 static void call_rejected(SalOp *h){
402 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
403 	LinphoneErrorInfo *ei = linphone_error_info_new();
404 	linphone_error_info_from_sal_op(ei, h);
405 	linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_new(sal_op_get_from(h)), linphone_address_new(sal_op_get_to(h)), ei);
406 }
407 
try_early_media_forking(LinphoneCall * call,SalMediaDescription * md)408 static void try_early_media_forking(LinphoneCall *call, SalMediaDescription *md){
409 	SalMediaDescription *cur_md=call->resultdesc;
410 	int i;
411 	SalStreamDescription *ref_stream,*new_stream;
412 	ms_message("Early media response received from another branch, checking if media can be forked to this new destination.");
413 
414 	for (i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
415 		if (!sal_stream_description_active(&cur_md->streams[i])) continue;
416 		ref_stream=&cur_md->streams[i];
417 		new_stream=&md->streams[i];
418 		if (ref_stream->type==new_stream->type && ref_stream->payloads && new_stream->payloads){
419 			PayloadType *refpt, *newpt;
420 			refpt=(PayloadType*)ref_stream->payloads->data;
421 			newpt=(PayloadType*)new_stream->payloads->data;
422 			if (strcmp(refpt->mime_type,newpt->mime_type)==0 && refpt->clock_rate==newpt->clock_rate
423 				&& payload_type_get_number(refpt)==payload_type_get_number(newpt)){
424 				MediaStream *ms=NULL;
425 				if (ref_stream->type==SalAudio){
426 					ms=(MediaStream*)call->audiostream;
427 				}else if (ref_stream->type==SalVideo){
428 					ms=(MediaStream*)call->videostream;
429 				}
430 				if (ms){
431 					RtpSession *session=ms->sessions.rtp_session;
432 					const char *rtp_addr=new_stream->rtp_addr[0]!='\0' ? new_stream->rtp_addr : md->addr;
433 					const char *rtcp_addr=new_stream->rtcp_addr[0]!='\0' ? new_stream->rtcp_addr : md->addr;
434 					if (ms_is_multicast(rtp_addr))
435 						ms_message("Multicast addr [%s/%i] does not need auxiliary rtp's destination for call [%p]",
436 							   rtp_addr,new_stream->rtp_port,call);
437 					else
438 						rtp_session_add_aux_remote_addr_full(session,rtp_addr,new_stream->rtp_port,rtcp_addr,new_stream->rtcp_port);
439 				}
440 			}
441 		}
442 	}
443 }
444 
start_remote_ring(LinphoneCore * lc,LinphoneCall * call)445 static void start_remote_ring(LinphoneCore *lc, LinphoneCall *call) {
446 	if (lc->sound_conf.play_sndcard!=NULL){
447 		MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
448 		if (call->localdesc->streams[0].max_rate>0) ms_snd_card_set_preferred_sample_rate(ringcard, call->localdesc->streams[0].max_rate);
449 		/*we release sound before playing ringback tone*/
450 		if (call->audiostream)
451 			audio_stream_unprepare_sound(call->audiostream);
452 		if( lc->sound_conf.remote_ring ){
453 			lc->ringstream=ring_start(lc->factory, lc->sound_conf.remote_ring,2000,ringcard);
454 		}
455 	}
456 }
457 
call_ringing(SalOp * h)458 static void call_ringing(SalOp *h){
459 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
460 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
461 	SalMediaDescription *md;
462 
463 	if (call==NULL) return;
464 
465 	/*set privacy*/
466 	call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
467 
468 	linphone_core_notify_display_status(lc,_("Remote ringing."));
469 
470 	md=sal_call_get_final_media_description(h);
471 	if (md==NULL){
472 		linphone_core_stop_dtmf_stream(lc);
473 		if (call->state==LinphoneCallOutgoingEarlyMedia){
474 			/*already doing early media */
475 			return;
476 		}
477 		if (lc->ringstream == NULL) start_remote_ring(lc, call);
478 		ms_message("Remote ringing...");
479 		linphone_core_notify_display_status(lc,_("Remote ringing..."));
480 		linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
481 	}else{
482 		/*initialize the remote call params by invoking linphone_call_get_remote_params(). This is useful as the SDP may not be present in the 200Ok*/
483 		linphone_call_get_remote_params(call);
484 		/*accept early media */
485 		if ((call->audiostream && audio_stream_started(call->audiostream))
486 #ifdef VIDEO_ENABLED
487 			|| (call->videostream && video_stream_started(call->videostream))
488 #endif
489 			) {
490 			/*streams already started */
491 			try_early_media_forking(call,md);
492 			#ifdef VIDEO_ENABLED
493 			if (call->videostream){
494 				/*just request for iframe*/
495 				video_stream_send_vfu(call->videostream);
496 			}
497 			#endif
498 		return;
499 		}
500 
501 		linphone_core_notify_show_interface(lc);
502 		linphone_core_notify_display_status(lc,_("Early media."));
503 		linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
504 		linphone_core_stop_ringing(lc);
505 		ms_message("Doing early media...");
506 		linphone_call_update_streams(call, md, call->state);
507 		if ((linphone_call_params_get_audio_direction(linphone_call_get_current_params(call)) == LinphoneMediaDirectionInactive) && call->audiostream) {
508 			if (lc->ringstream != NULL) return; /* Already ringing! */
509 			start_remote_ring(lc, call);
510 		}
511 	}
512 }
513 
start_pending_refer(LinphoneCall * call)514 static void start_pending_refer(LinphoneCall *call){
515 	linphone_core_start_refered_call(call->core, call,NULL);
516 }
517 
process_call_accepted(LinphoneCore * lc,LinphoneCall * call,SalOp * op)518 static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *op){
519 	SalMediaDescription *md, *rmd;
520 	LinphoneCallState next_state = LinphoneCallIdle;
521 	const char *next_state_str = NULL;
522 	LinphoneTaskList tl;
523 
524 	switch (call->state){/*immediately notify the connected state, even if errors occur after*/
525 		case LinphoneCallOutgoingProgress:
526 		case LinphoneCallOutgoingRinging:
527 		case LinphoneCallOutgoingEarlyMedia:
528 			/*immediately notify the connected state*/
529 			linphone_call_set_state(call,LinphoneCallConnected,"Connected");
530 			{
531 				char *tmp=linphone_call_get_remote_address_as_string (call);
532 				char *msg=ms_strdup_printf(_("Call answered by %s"),tmp);
533 				linphone_core_notify_display_status(lc,msg);
534 				ms_free(tmp);
535 				ms_free(msg);
536 			}
537 		break;
538 		default:
539 		break;
540 	}
541 
542 	linphone_task_list_init(&tl);
543 	rmd=sal_call_get_remote_media_description(op);
544 	/*set privacy*/
545 	call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
546 	/*reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs*/
547 	if (call->params->internal_call_update)
548 		call->params->internal_call_update = FALSE;
549 
550 
551 #ifdef BUILD_UPNP
552 	if (call->upnp_session != NULL && rmd) {
553 		linphone_call_update_upnp_from_remote_media_description(call, rmd);
554 	}
555 #endif //BUILD_UPNP
556 
557 	md=sal_call_get_final_media_description(op);
558 	if (md == NULL && call->prevstate == LinphoneCallOutgoingEarlyMedia && call->resultdesc != NULL){
559 		ms_message("Using early media SDP since none was received with the 200 OK");
560 		md = call->resultdesc;
561 	}
562 	if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
563 		md = NULL;
564 	}
565 	if (md){ /*there is a valid SDP in the response, either offer or answer, and we're able to start/update the streams*/
566 
567 		/* Handle remote ICE attributes if any. */
568 		if (call->ice_session != NULL && rmd) {
569 			linphone_call_update_ice_from_remote_media_description(call, rmd, !sal_call_is_offerer(op));
570 		}
571 
572 		switch (call->state){
573 			case LinphoneCallResuming:
574 				linphone_core_notify_display_status(lc,_("Call resumed."));
575 				BCTBX_NO_BREAK; /*intentionally no break*/
576 			case LinphoneCallConnected:
577 				if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
578 				BCTBX_NO_BREAK; /*intentionally no break*/
579 			case LinphoneCallUpdating:
580 			case LinphoneCallUpdatedByRemote:
581 				if (!sal_media_description_has_dir(call->localdesc, SalStreamInactive) &&
582 					(sal_media_description_has_dir(md,SalStreamRecvOnly) ||
583 					sal_media_description_has_dir(md,SalStreamInactive))){
584 					next_state = LinphoneCallPausedByRemote;
585 					next_state_str = "Call paused by remote";
586 				}else{
587 					if (!call->params->in_conference)
588 						lc->current_call=call;
589 					next_state = LinphoneCallStreamsRunning;
590 					next_state_str = "Streams running";
591 				}
592 			break;
593 			case LinphoneCallEarlyUpdating:
594 				next_state_str = "Early update accepted";
595 				next_state = call->prevstate;
596 			break;
597 			case LinphoneCallPausing:
598 				/*when we entered the pausing state, we always reach the paused state whatever the content of the remote SDP is.
599 					Our streams are all send-only (with music), soundcard and camera are never used*/
600 				next_state = LinphoneCallPaused;
601 				next_state_str = "Call paused";
602 				if (call->refer_pending)
603 					linphone_task_list_add(&tl, (LinphoneCoreIterateHook)start_pending_refer, call);
604 			break;
605 			default:
606 				ms_error("call_accepted(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
607 			break;
608 		}
609 
610 		if (next_state != LinphoneCallIdle){
611 			linphone_call_update_remote_session_id_and_ver(call);
612 			linphone_call_update_ice_state_in_call_stats(call);
613 			linphone_call_update_streams(call, md, next_state);
614 			linphone_call_fix_call_parameters(call, rmd);
615 			linphone_call_set_state(call, next_state, next_state_str);
616 		}else{
617 			ms_error("BUG: next_state is not set in call_accepted(), current state is %s", linphone_call_state_to_string(call->state));
618 		}
619 	}else{ /*invalid or no SDP*/
620 		switch (call->prevstate){
621 			/*send a bye only in case of early states*/
622 			case LinphoneCallOutgoingInit:
623 			case LinphoneCallOutgoingProgress:
624 			case LinphoneCallOutgoingRinging:
625 			case LinphoneCallOutgoingEarlyMedia:
626 			case LinphoneCallIncomingReceived:
627 			case LinphoneCallIncomingEarlyMedia:
628 				ms_error("Incompatible SDP answer received, need to abort the call");
629 				linphone_call_abort(call, _("Incompatible, check codecs or security settings..."));
630 				break;
631 			/*otherwise we are able to resume previous state*/
632 			default:
633 				ms_error("Incompatible SDP answer received");
634 				switch(call->state) {
635 					case LinphoneCallPausedByRemote:
636 						break;
637 					case LinphoneCallPaused:
638 						break;
639 					case LinphoneCallStreamsRunning:
640 						break;
641 					default:
642 						ms_message("Incompatible SDP answer received, restoring previous state [%s]",linphone_call_state_to_string(call->prevstate));
643 						linphone_call_set_state(call,call->prevstate,_("Incompatible media parameters."));
644 						break;
645 				}
646 				break;
647 		}
648 	}
649 	linphone_task_list_run(&tl);
650 	linphone_task_list_free(&tl);
651 }
652 
653 /*
654  * could be reach :
655  *  - when the call is accepted
656  *  - when a request is accepted (pause, resume)
657  */
call_accepted(SalOp * op)658 static void call_accepted(SalOp *op){
659 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
660 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
661 
662 	if (call == NULL){
663 		ms_warning("call_accepted: call does no longer exist.");
664 		return ;
665 	}
666 	process_call_accepted(lc, call, op);
667 }
668 
call_resumed(LinphoneCore * lc,LinphoneCall * call)669 static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
670 	linphone_core_notify_display_status(lc,_("We have been resumed."));
671 	_linphone_call_accept_update(call,NULL,LinphoneCallStreamsRunning,"Connected (streams running)");
672 }
673 
call_paused_by_remote(LinphoneCore * lc,LinphoneCall * call)674 static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
675 	LinphoneCallParams *params;
676 
677 	/* we are being paused */
678 	linphone_core_notify_display_status(lc,_("We are paused by other party."));
679 	params = linphone_call_params_copy(call->params);
680 	if (lp_config_get_int(lc->config, "sip", "inactive_video_on_pause", 0)) {
681 		linphone_call_params_set_video_direction(params, LinphoneMediaDirectionInactive);
682 	}
683 	_linphone_call_accept_update(call,params,LinphoneCallPausedByRemote,"Call paused by remote");
684 	linphone_call_params_unref(params);
685 }
686 
call_updated_by_remote(LinphoneCore * lc,LinphoneCall * call)687 static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){
688 	linphone_core_notify_display_status(lc,_("Call is updated by remote."));
689 	linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
690 	if (call->defer_update == FALSE){
691 		if (call->state == LinphoneCallUpdatedByRemote){
692 			linphone_call_accept_update(call, NULL);
693 		}else{
694 			/*otherwise it means that the app responded by linphone_core_accept_call_update
695 			 * within the callback, so job is already done.*/
696 		}
697 	}else{
698 		if (call->state == LinphoneCallUpdatedByRemote){
699 			ms_message("LinphoneCall [%p]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call "
700 				"linphone_core_accept_call_update() later.", call);
701 		}
702 	}
703 }
704 
705 /* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
call_updated(LinphoneCore * lc,LinphoneCall * call,SalOp * op,bool_t is_update)706 static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t is_update){
707 	SalErrorInfo sei = { 0 };
708 	SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
709 
710 	call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE);
711 
712 	switch(call->state){
713 		case LinphoneCallPausedByRemote:
714 			if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){
715 				call_resumed(lc,call);
716 			}else{
717 				call_updated_by_remote(lc, call);
718 			}
719 		break;
720 		/*SIP UPDATE CASE*/
721 		case LinphoneCallOutgoingRinging:
722 		case LinphoneCallOutgoingEarlyMedia:
723 		case LinphoneCallIncomingEarlyMedia:
724 			if (is_update) {
725 				linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
726 				_linphone_call_accept_update(call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));
727 			}
728 			break;
729 		case LinphoneCallStreamsRunning:
730 		case LinphoneCallConnected:
731 		case LinphoneCallUpdatedByRemote: // Can happen on UAC connectivity loss
732 			if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
733 				call_paused_by_remote(lc,call);
734 			}else{
735 				call_updated_by_remote(lc, call);
736 			}
737 		break;
738 		case LinphoneCallPaused:
739 			/*we'll remain in pause state but accept the offer anyway according to default parameters*/
740 			_linphone_call_accept_update(call,NULL,call->state,linphone_call_state_to_string(call->state));
741 		break;
742 		case LinphoneCallUpdating:
743 		case LinphoneCallPausing:
744 		case LinphoneCallResuming:
745 			sal_error_info_set(&sei,SalReasonInternalError, "SIP", 0, NULL, NULL);
746 			sal_call_decline_with_error_info(call->op, &sei,NULL);
747 			BCTBX_NO_BREAK; /*no break*/
748 		case LinphoneCallIdle:
749 		case LinphoneCallOutgoingInit:
750 		case LinphoneCallEnd:
751 		case LinphoneCallIncomingReceived:
752 		case LinphoneCallOutgoingProgress:
753 		case LinphoneCallRefered:
754 		case LinphoneCallError:
755 		case LinphoneCallReleased:
756 		case LinphoneCallEarlyUpdatedByRemote:
757 		case LinphoneCallEarlyUpdating:
758 			ms_warning("Receiving reINVITE or UPDATE while in state [%s], should not happen.",linphone_call_state_to_string(call->state));
759 		break;
760 	}
761 	sal_error_info_reset(&sei);
762 }
763 
764 /* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
call_updating(SalOp * op,bool_t is_update)765 static void call_updating(SalOp *op, bool_t is_update){
766 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
767 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
768 	SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
769 	SalErrorInfo sei = {0};
770 
771 	if (!call) {
772 		ms_error("call_updating(): call doesn't exist anymore");
773 		return ;
774 	}
775 	linphone_call_fix_call_parameters(call, rmd);
776 	if (call->state!=LinphoneCallPaused){
777 		/*Refresh the local description, but in paused state, we don't change anything.*/
778 		if (rmd == NULL && lp_config_get_int(call->core->config,"sip","sdp_200_ack_follow_video_policy",0)) {
779 			LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL);
780 			ms_message("Applying default policy for offering SDP on call [%p]",call);
781 			_linphone_call_set_new_params(call, p);
782 			linphone_call_params_unref(p);
783 		}
784 		linphone_call_make_local_media_description(call);
785 		sal_call_set_local_media_description(call->op,call->localdesc);
786 	}
787 	if (rmd == NULL){
788 		/* case of a reINVITE or UPDATE without SDP */
789 		call->expect_media_in_ack = TRUE;
790 		sal_call_accept(op); /*respond with an offer*/
791 		/*don't do anything else in this case, wait for the ACK to receive to notify the app*/
792 	}else {
793 		SalMediaDescription *md;
794 		SalMediaDescription *prev_result_desc=call->resultdesc;
795 
796 		call->expect_media_in_ack = FALSE;
797 
798 		md=sal_call_get_final_media_description(call->op);
799 		if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
800 			sal_error_info_set(&sei,SalReasonNotAcceptable, "SIP", 0, NULL, NULL);
801 			sal_call_decline_with_error_info(call->op, &sei,NULL);
802 			sal_error_info_reset(&sei);
803 			return;
804 		}
805 		if (is_update && prev_result_desc && md){
806 			int diff=sal_media_description_equals(prev_result_desc,md);
807 			if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){
808 				ms_warning("Cannot accept this update, it is changing parameters that require user approval");
809 				sal_error_info_set(&sei,SalReasonUnknown, "SIP", 504, "Cannot change the session parameters without prompting the user", NULL);
810 				sal_call_decline_with_error_info(call->op, &sei,NULL);
811 				sal_error_info_reset(&sei);
812 				return;
813 			}
814 		}
815 		call_updated(lc, call, op, is_update);
816 	}
817 }
818 
819 
call_ack_received(SalOp * op,SalCustomHeader * ack)820 static void call_ack_received(SalOp *op, SalCustomHeader *ack){
821 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
822 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
823 
824 	if (call == NULL){
825 		ms_warning("call_ack(): no call for which an ack is expected");
826 		return;
827 	}
828 	linphone_call_notify_ack_processing(call, ack, TRUE);
829 	if (call->expect_media_in_ack){
830 		switch(call->state){
831 			case LinphoneCallStreamsRunning:
832 			case LinphoneCallPausedByRemote:
833 				linphone_call_set_state(call, LinphoneCallUpdatedByRemote, "UpdatedByRemote");
834 			break;
835 			default:
836 			break;
837 		}
838 		process_call_accepted(lc, call, op);
839 	}
840 }
841 
842 
call_ack_being_sent(SalOp * op,SalCustomHeader * ack)843 static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack){
844 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
845 
846 	if (call == NULL){
847 		ms_warning("call_ack(): no call for which an ack is supposed to be sent");
848 		return;
849 	}
850 	linphone_call_notify_ack_processing(call, ack, FALSE);
851 }
852 
call_terminated(SalOp * op,const char * from)853 static void call_terminated(SalOp *op, const char *from){
854 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
855 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
856 
857 	if (call==NULL) return;
858 
859 	switch(linphone_call_get_state(call)){
860 		case LinphoneCallEnd:
861 		case LinphoneCallError:
862 			ms_warning("call_terminated: already terminated, ignoring.");
863 			return;
864 		break;
865 		case LinphoneCallIncomingReceived:
866 		case LinphoneCallIncomingEarlyMedia:
867 			if(!sal_op_get_reason_error_info(op)->protocol || strcmp(sal_op_get_reason_error_info(op)->protocol, "") == 0) {
868 				linphone_error_info_set(call->ei,NULL, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", NULL);
869 				call->non_op_error = TRUE;
870 			}
871 			break;
872 		default:
873 		break;
874 	}
875 	ms_message("Current call terminated...");
876 	if (call->refer_pending){
877 		linphone_core_start_refered_call(lc,call,NULL);
878 	}
879 	//we stop the call only if we have this current call or if we are in call
880 	if ((bctbx_list_size(lc->calls)  == 1) || linphone_core_in_call(lc)) {
881 		linphone_core_stop_ringing(lc);
882 	}
883 	linphone_call_stop_media_streams(call);
884 	linphone_core_notify_show_interface(lc);
885 	linphone_core_notify_display_status(lc,_("Call terminated."));
886 
887 #ifdef BUILD_UPNP
888 	linphone_call_delete_upnp_session(call);
889 #endif //BUILD_UPNP
890 
891 	linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
892 }
893 
resume_call_after_failed_transfer(LinphoneCall * call)894 static int resume_call_after_failed_transfer(LinphoneCall *call){
895 	if (call->was_automatically_paused && call->state==LinphoneCallPausing)
896 		return BELLE_SIP_CONTINUE; /*was still in pausing state*/
897 
898 	if (call->was_automatically_paused && call->state==LinphoneCallPaused){
899 		if (sal_op_is_idle(call->op)){
900 			linphone_call_resume(call);
901 		}else {
902 			ms_message("resume_call_after_failed_transfer(), salop was busy");
903 			return BELLE_SIP_CONTINUE;
904 		}
905 	}
906 	linphone_call_unref(call);
907 	return BELLE_SIP_STOP;
908 }
909 
call_failure(SalOp * op)910 static void call_failure(SalOp *op){
911 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
912 	const SalErrorInfo *ei=sal_op_get_error_info(op);
913 	char *msg486=_("User is busy.");
914 	char *msg480=_("User is temporarily unavailable.");
915 	/*char *retrymsg=_("%s. Retry after %i minute(s).");*/
916 	char *msg600=_("User does not want to be disturbed.");
917 	char *msg603=_("Call declined.");
918 	const char *msg=ei->full_string;
919 	LinphoneCall *referer;
920 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
921 	bool_t stop_ringing = TRUE;
922 	bctbx_list_t *calls = lc->calls;
923 
924 	if (call==NULL){
925 		ms_warning("Call faillure reported on already terminated call.");
926 		return ;
927 	}
928 
929 	referer=call->referer;
930 
931 	linphone_core_notify_show_interface(lc);
932 	switch(ei->reason){
933 		case SalReasonNone:
934 		break;
935 		case SalReasonRequestTimeout:
936 			msg=_("Request timeout.");
937 			linphone_core_notify_display_status(lc,msg);
938 		break;
939 		case SalReasonDeclined:
940 			msg=msg603;
941 			linphone_core_notify_display_status(lc,msg603);
942 		break;
943 		case SalReasonBusy:
944 			msg=msg486;
945 			linphone_core_notify_display_status(lc,msg486);
946 		break;
947 		case SalReasonRedirect:
948 		{
949 			linphone_call_stop_media_streams(call);
950 			if (	call->state==LinphoneCallOutgoingInit
951 					|| call->state==LinphoneCallOutgoingProgress
952 					|| call->state==LinphoneCallOutgoingRinging /*push case*/
953 					|| call->state==LinphoneCallOutgoingEarlyMedia){
954 				LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op);
955 				if( redirection_to ){
956 					char* url = linphone_address_as_string(redirection_to);
957 					ms_warning("Redirecting call [%p] to %s",call, url);
958 					ms_free(url);
959 					if( call->log->to != NULL ) {
960 						linphone_address_unref(call->log->to);
961 					}
962 					call->log->to = linphone_address_ref(redirection_to);
963 					linphone_call_restart_invite(call);
964 					return;
965 				}
966 			}
967 			msg=_("Redirected");
968 			linphone_core_notify_display_status(lc,msg);
969 		}
970 		break;
971 		case SalReasonTemporarilyUnavailable:
972 			msg=msg480;
973 			linphone_core_notify_display_status(lc,msg480);
974 		break;
975 		case SalReasonNotFound:
976 			linphone_core_notify_display_status(lc,msg);
977 		break;
978 		case SalReasonDoNotDisturb:
979 			msg=msg600;
980 			linphone_core_notify_display_status(lc,msg600);
981 		break;
982 		case SalReasonUnsupportedContent: /*<this is for compatibility: linphone sent 415 because of SDP offer answer failure*/
983 		case SalReasonNotAcceptable:
984 			ms_message("Outgoing call [%p] failed with SRTP and/or AVPF enabled", call);
985 			if ((call->state == LinphoneCallOutgoingInit)
986 				|| (call->state == LinphoneCallOutgoingProgress)
987 				|| (call->state == LinphoneCallOutgoingRinging) /* Push notification case */
988 				|| (call->state == LinphoneCallOutgoingEarlyMedia)) {
989 				int i;
990 				for (i = 0; i < call->localdesc->nb_streams; i++) {
991 					if (!sal_stream_description_active(&call->localdesc->streams[i])) continue;
992 					if (call->params->media_encryption == LinphoneMediaEncryptionSRTP) {
993 						if (call->params->avpf_enabled == TRUE) {
994 							if (i == 0) ms_message("Retrying call [%p] with SAVP", call);
995 							call->params->avpf_enabled = FALSE;
996 							linphone_call_restart_invite(call);
997 							return;
998 						} else if (!linphone_core_is_media_encryption_mandatory(lc)) {
999 							if (i == 0) ms_message("Retrying call [%p] with AVP", call);
1000 							call->params->media_encryption = LinphoneMediaEncryptionNone;
1001 							memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
1002 							linphone_call_restart_invite(call);
1003 							return;
1004 						}
1005 					} else if (call->params->avpf_enabled == TRUE) {
1006 						if (i == 0) ms_message("Retrying call [%p] with AVP", call);
1007 						call->params->avpf_enabled = FALSE;
1008 						linphone_call_restart_invite(call);
1009 						return;
1010 					}
1011 				}
1012 			}
1013 			msg=_("Incompatible media parameters.");
1014 			linphone_core_notify_display_status(lc,msg);
1015 		break;
1016 		default:
1017 			linphone_core_notify_display_status(lc,_("Call failed."));
1018 	}
1019 
1020 	/*some call errors are not fatal*/
1021 	switch (call->state) {
1022 	case LinphoneCallUpdating:
1023 	case LinphoneCallPausing:
1024 	case LinphoneCallResuming:
1025 		if (ei->reason != SalReasonNoMatch){
1026 			ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate));
1027 			linphone_call_set_state(call, call->prevstate,ei->full_string);
1028 			return;
1029 		}
1030 	default:
1031 		break; /*nothing to do*/
1032 	}
1033 
1034 	/* Stop ringing */
1035 	bool_t ring_during_early_media = linphone_core_get_ring_during_incoming_early_media(lc);
1036 	while(calls) {
1037 		if (((LinphoneCall *)calls->data)->state == LinphoneCallIncomingReceived || (ring_during_early_media && ((LinphoneCall *)calls->data)->state == LinphoneCallIncomingEarlyMedia)) {
1038 			stop_ringing = FALSE;
1039 			break;
1040 		}
1041 		calls = calls->next;
1042 	}
1043 	if(stop_ringing) {
1044 		linphone_core_stop_ringing(lc);
1045 	}
1046 	linphone_call_stop_media_streams(call);
1047 
1048 #ifdef BUILD_UPNP
1049 	linphone_call_delete_upnp_session(call);
1050 #endif //BUILD_UPNP
1051 
1052 	if (call->state!=LinphoneCallEnd && call->state!=LinphoneCallError){
1053 		if (ei->reason==SalReasonDeclined){
1054 			linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
1055 		}else{
1056 			if (linphone_call_state_is_early(call->state)){
1057 				linphone_call_set_state(call,LinphoneCallError,ei->full_string);
1058 			}else{
1059 				linphone_call_set_state(call, LinphoneCallEnd, ei->full_string);
1060 			}
1061 		}
1062 		if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason));
1063 	}
1064 
1065 	if (referer){
1066 		/*notify referer of the failure*/
1067 		linphone_core_notify_refer_state(lc,referer,call);
1068 		/*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/
1069 		linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer");
1070 	}
1071 }
1072 
call_released(SalOp * op)1073 static void call_released(SalOp *op){
1074 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
1075 	if (call!=NULL){
1076 		linphone_call_set_state(call,LinphoneCallReleased,"Call released");
1077 	}else{
1078 		/*we can arrive here when the core manages call at Sal level without creating a LinphoneCall object. Typicially:
1079 		 * - when declining an incoming call with busy because maximum number of calls is reached.
1080 		 */
1081 	}
1082 }
1083 
call_cancel_done(SalOp * op)1084 static void call_cancel_done(SalOp *op) {
1085 	LinphoneCall *call = (LinphoneCall *)sal_op_get_user_pointer(op);
1086 	if (call->reinvite_on_cancel_response_requested == TRUE) {
1087 		call->reinvite_on_cancel_response_requested = FALSE;
1088 		linphone_call_reinvite_to_recover_from_connection_loss(call);
1089 	}
1090 }
1091 
auth_failure(SalOp * op,SalAuthInfo * info)1092 static void auth_failure(SalOp *op, SalAuthInfo* info) {
1093 	LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1094 	LinphoneAuthInfo *ai = NULL;
1095 
1096 	if (info != NULL) {
1097 		ai = (LinphoneAuthInfo*)_linphone_core_find_auth_info(lc, info->realm, info->username, info->domain, TRUE);
1098 		if (ai){
1099 			LinphoneAuthMethod method = info->mode == SalAuthModeHttpDigest ? LinphoneAuthHttpDigest : LinphoneAuthTls;
1100 			LinphoneAuthInfo *auth_info = linphone_core_create_auth_info(lc, info->username, NULL, NULL, NULL, info->realm, info->domain);
1101 			ms_message("%s/%s/%s/%s authentication fails.", info->realm, info->username, info->domain, info->mode == SalAuthModeHttpDigest ? "HttpDigest" : "Tls");
1102 			/*ask again for password if auth info was already supplied but apparently not working*/
1103 			linphone_core_notify_authentication_requested(lc, auth_info, method);
1104 			linphone_auth_info_unref(auth_info);
1105 			// Deprecated
1106 			linphone_core_notify_auth_info_requested(lc, info->realm, info->username, info->domain);
1107 		}
1108 	}
1109 }
1110 
register_success(SalOp * op,bool_t registered)1111 static void register_success(SalOp *op, bool_t registered){
1112 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1113 	LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
1114 	char *msg;
1115 
1116 	if (!cfg){
1117 		ms_message("Registration success for deleted proxy config, ignored");
1118 		return;
1119 	}
1120 	linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared ,
1121 									registered ? "Registration successful" : "Unregistration done");
1122 	{
1123 		if (registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
1124 		else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
1125 		linphone_core_notify_display_status(lc,msg);
1126 		ms_free(msg);
1127 	}
1128 
1129 }
1130 
register_failure(SalOp * op)1131 static void register_failure(SalOp *op){
1132 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1133 	LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
1134 	const SalErrorInfo *ei=sal_op_get_error_info(op);
1135 	const char *details=ei->full_string;
1136 
1137 	if (cfg==NULL){
1138 		ms_warning("Registration failed for unknown proxy config.");
1139 		return ;
1140 	}
1141 	if (details==NULL)
1142 		details=_("no response timeout");
1143 
1144 	{
1145 		char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op), details);
1146 		linphone_core_notify_display_status(lc,msg);
1147 		ms_free(msg);
1148 	}
1149 
1150 	if ((ei->reason == SalReasonServiceUnavailable || ei->reason == SalReasonIOError)
1151 			&& linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) {
1152 		linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying"));
1153 	} else {
1154 		linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details);
1155 	}
1156 	if (cfg->presence_publish_event){
1157 		/*prevent publish to be sent now until registration gets successful*/
1158 		linphone_event_terminate(cfg->presence_publish_event);
1159 		cfg->presence_publish_event=NULL;
1160 		cfg->send_publish=cfg->publish;
1161 	}
1162 }
1163 
vfu_request(SalOp * op)1164 static void vfu_request(SalOp *op){
1165 #ifdef VIDEO_ENABLED
1166 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
1167 	if (call==NULL){
1168 		ms_warning("VFU request but no call !");
1169 		return ;
1170 	}
1171 	if (call->videostream)
1172 		video_stream_send_vfu(call->videostream);
1173 #endif
1174 }
1175 
dtmf_received(SalOp * op,char dtmf)1176 static void dtmf_received(SalOp *op, char dtmf){
1177 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
1178 	if (!call) return;
1179 	linphone_call_notify_dtmf_received(call, dtmf);
1180 }
1181 
refer_received(Sal * sal,SalOp * op,const char * referto)1182 static void refer_received(Sal *sal, SalOp *op, const char *referto){
1183 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
1184 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
1185 	LinphoneAddress *refer_to_addr = linphone_address_new(referto);
1186 	char method[20] = "";
1187 
1188 	if(refer_to_addr) {
1189 		const char *tmp = linphone_address_get_method_param(refer_to_addr);
1190 		if(tmp) strncpy(method, tmp, sizeof(method));
1191 		linphone_address_unref(refer_to_addr);
1192 	}
1193 	if (call && (strlen(method) == 0 || strcmp(method, "INVITE") == 0)) {
1194 		if (call->refer_to!=NULL){
1195 			ms_free(call->refer_to);
1196 		}
1197 		call->refer_to=ms_strdup(referto);
1198 		call->refer_pending=TRUE;
1199 		linphone_call_set_state(call,LinphoneCallRefered,"Refered");
1200 		{
1201 			char *msg=ms_strdup_printf(_("We are transferred to %s"),referto);
1202 			linphone_core_notify_display_status(lc,msg);
1203 			ms_free(msg);
1204 		}
1205 		if (call->refer_pending) linphone_core_start_refered_call(lc,call,NULL);
1206 	}else {
1207 		linphone_core_notify_refer_received(lc,referto);
1208 	}
1209 }
1210 
message_received(SalOp * op,const SalMessage * msg)1211 static void message_received(SalOp *op, const SalMessage *msg){
1212 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1213 	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
1214 	LinphoneReason reason = lc->chat_deny_code;
1215 	if (reason == LinphoneReasonNone) {
1216 		linphone_core_message_received(lc, op, msg);
1217 	}
1218 	sal_message_reply(op, linphone_reason_to_sal(reason));
1219 	if (!call) sal_op_release(op);
1220 }
1221 
parse_presence_requested(SalOp * op,const char * content_type,const char * content_subtype,const char * body,SalPresenceModel ** result)1222 static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
1223 	linphone_notify_parse_presence(content_type, content_subtype, body, result);
1224 }
1225 
convert_presence_to_xml_requested(SalOp * op,SalPresenceModel * presence,const char * contact,char ** content)1226 static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) {
1227 	/*for backward compatibility because still used by notify. No loguer used for publish*/
1228 
1229 	if(linphone_presence_model_get_presentity((LinphonePresenceModel*)presence) == NULL) {
1230 		LinphoneAddress * presentity = linphone_address_new(contact);
1231 		linphone_presence_model_set_presentity((LinphonePresenceModel*)presence, presentity);
1232 		linphone_address_unref(presentity);
1233 	}
1234 	*content = linphone_presence_model_to_xml((LinphonePresenceModel*)presence);
1235 }
1236 
notify_presence(SalOp * op,SalSubscribeStatus ss,SalPresenceModel * model,const char * msg)1237 static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg){
1238 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1239 	linphone_notify_recv(lc,op,ss,model);
1240 }
1241 
subscribe_presence_received(SalOp * op,const char * from)1242 static void subscribe_presence_received(SalOp *op, const char *from){
1243 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1244 	linphone_subscription_new(lc,op,from);
1245 }
1246 
subscribe_presence_closed(SalOp * op,const char * from)1247 static void subscribe_presence_closed(SalOp *op, const char *from){
1248 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1249 	linphone_subscription_closed(lc,op);
1250 }
1251 
ping_reply(SalOp * op)1252 static void ping_reply(SalOp *op){
1253 	LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
1254 	ms_message("ping reply !");
1255 	if (call){
1256 		if (call->state==LinphoneCallOutgoingInit){
1257 			call->ping_replied=TRUE;
1258 			linphone_call_proceed_with_invite_if_ready(call, NULL);
1259 		}
1260 	}
1261 	else
1262 	{
1263 		ms_warning("ping reply without call attached...");
1264 	}
1265 }
1266 
fill_auth_info_with_client_certificate(LinphoneCore * lc,SalAuthInfo * sai)1267 static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) {
1268 	const char *chain_file = linphone_core_get_tls_cert_path(lc);
1269 	const char *key_file = linphone_core_get_tls_key_path(lc);
1270 
1271 	if (key_file && chain_file) {
1272 #ifndef _WIN32
1273 		// optinal check for files
1274 		struct stat st;
1275 		if (stat(key_file, &st)) {
1276 			ms_warning("No client certificate key found in %s", key_file);
1277 			return FALSE;
1278 		}
1279 		if (stat(chain_file, &st)) {
1280 			ms_warning("No client certificate chain found in %s", chain_file);
1281 			return FALSE;
1282 		}
1283 #endif
1284 		sal_certificates_chain_parse_file(sai, chain_file, SAL_CERTIFICATE_RAW_FORMAT_PEM);
1285 		sal_signing_key_parse_file(sai, key_file, "");
1286 	} else if (lc->tls_cert && lc->tls_key) {
1287 		sal_certificates_chain_parse(sai, lc->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM);
1288 		sal_signing_key_parse(sai, lc->tls_key, "");
1289 	}
1290 	return sai->certificates && sai->key;
1291 }
1292 
fill_auth_info(LinphoneCore * lc,SalAuthInfo * sai)1293 static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) {
1294 	LinphoneAuthInfo *ai = NULL;
1295 	if (sai->mode == SalAuthModeTls) {
1296 		ai = (LinphoneAuthInfo*)_linphone_core_find_tls_auth_info(lc);
1297 	} else {
1298 		ai = (LinphoneAuthInfo*)_linphone_core_find_auth_info(lc,sai->realm,sai->username,sai->domain, FALSE);
1299 	}
1300 	if (ai) {
1301 		if (sai->mode == SalAuthModeHttpDigest) {
1302 			sai->userid = ms_strdup(ai->userid ? ai->userid : ai->username);
1303 			sai->password = ai->passwd?ms_strdup(ai->passwd) : NULL;
1304 			sai->ha1 = ai->ha1 ? ms_strdup(ai->ha1) : NULL;
1305 		} else if (sai->mode == SalAuthModeTls) {
1306 			if (ai->tls_cert && ai->tls_key) {
1307 				sal_certificates_chain_parse(sai, ai->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM);
1308 				sal_signing_key_parse(sai, ai->tls_key, "");
1309 			} else if (ai->tls_cert_path && ai->tls_key_path) {
1310 				sal_certificates_chain_parse_file(sai, ai->tls_cert_path, SAL_CERTIFICATE_RAW_FORMAT_PEM);
1311 				sal_signing_key_parse_file(sai, ai->tls_key_path, "");
1312 			} else {
1313 				fill_auth_info_with_client_certificate(lc, sai);
1314 			}
1315 		}
1316 
1317 		if (sai->realm && !ai->realm){
1318 			/*if realm was not known, then set it so that ha1 may eventually be calculated and clear text password dropped*/
1319 			linphone_auth_info_set_realm(ai, sai->realm);
1320 			linphone_core_write_auth_info(lc, ai);
1321 		}
1322 		return TRUE;
1323 	} else {
1324 		if (sai->mode == SalAuthModeTls) {
1325 			return fill_auth_info_with_client_certificate(lc, sai);
1326 		}
1327 		return FALSE;
1328 	}
1329 }
auth_requested(Sal * sal,SalAuthInfo * sai)1330 static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) {
1331 	LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal);
1332 	if (fill_auth_info(lc,sai)) {
1333 		return TRUE;
1334 	} else {
1335 		LinphoneAuthMethod method = sai->mode == SalAuthModeHttpDigest ? LinphoneAuthHttpDigest : LinphoneAuthTls;
1336 		LinphoneAuthInfo *ai = linphone_core_create_auth_info(lc, sai->username, NULL, NULL, NULL, sai->realm, sai->domain);
1337 		linphone_core_notify_authentication_requested(lc, ai, method);
1338 		linphone_auth_info_unref(ai);
1339 		// Deprecated
1340 		linphone_core_notify_auth_info_requested(lc, sai->realm, sai->username, sai->domain);
1341 		if (fill_auth_info(lc, sai)) {
1342 			return TRUE;
1343 		}
1344 		return FALSE;
1345 	}
1346 }
1347 
notify_refer(SalOp * op,SalReferStatus status)1348 static void notify_refer(SalOp *op, SalReferStatus status){
1349 	LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
1350 	LinphoneCallState cstate;
1351 	if (call==NULL) {
1352 		ms_warning("Receiving notify_refer for unknown call.");
1353 		return ;
1354 	}
1355 	switch(status){
1356 		case SalReferTrying:
1357 			cstate=LinphoneCallOutgoingProgress;
1358 		break;
1359 		case SalReferSuccess:
1360 			cstate=LinphoneCallConnected;
1361 		break;
1362 		case SalReferFailed:
1363 			cstate=LinphoneCallError;
1364 		break;
1365 		default:
1366 			cstate=LinphoneCallError;
1367 	}
1368 	linphone_call_set_transfer_state(call, cstate);
1369 	if (cstate==LinphoneCallConnected){
1370 		/*automatically terminate the call as the transfer is complete.*/
1371 		linphone_call_terminate(call);
1372 	}
1373 }
1374 
chatStatusSal2Linphone(SalMessageDeliveryStatus status)1375 static LinphoneChatMessageState chatStatusSal2Linphone(SalMessageDeliveryStatus status){
1376 	switch(status){
1377 		case SalMessageDeliveryInProgress:
1378 			return LinphoneChatMessageStateInProgress;
1379 		case SalMessageDeliveryDone:
1380 			return LinphoneChatMessageStateDelivered;
1381 		case SalMessageDeliveryFailed:
1382 			return LinphoneChatMessageStateNotDelivered;
1383 	}
1384 	return LinphoneChatMessageStateIdle;
1385 }
1386 
message_delivery_update(SalOp * op,SalMessageDeliveryStatus status)1387 static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status){
1388 	LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
1389 
1390 	if (chat_msg == NULL) {
1391 		// Do not handle delivery status for isComposing messages.
1392 		return;
1393 	}
1394 	// check that the message does not belong to an already destroyed chat room - if so, do not invoke callbacks
1395 	if (chat_msg->chat_room != NULL) {
1396 		linphone_chat_message_update_state(chat_msg, chatStatusSal2Linphone(status));
1397 	}
1398 	if (status != SalMessageDeliveryInProgress) { /*only release op if not in progress*/
1399 		linphone_chat_message_destroy(chat_msg);
1400 	}
1401 }
1402 
info_received(SalOp * op,SalBodyHandler * body_handler)1403 static void info_received(SalOp *op, SalBodyHandler *body_handler){
1404 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1405 	linphone_core_notify_info_message(lc,op,body_handler);
1406 }
1407 
subscribe_response(SalOp * op,SalSubscribeStatus status,int will_retry)1408 static void subscribe_response(SalOp *op, SalSubscribeStatus status, int will_retry){
1409 	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
1410 
1411 	if (lev==NULL) return;
1412 
1413 	if (status==SalSubscribeActive){
1414 		linphone_event_set_state(lev,LinphoneSubscriptionActive);
1415 	}else if (status==SalSubscribePending){
1416 		linphone_event_set_state(lev,LinphoneSubscriptionPending);
1417 	}else{
1418 		if (will_retry){
1419 			linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress);
1420 		}
1421 		else linphone_event_set_state(lev,LinphoneSubscriptionError);
1422 	}
1423 }
1424 
notify(SalOp * op,SalSubscribeStatus st,const char * eventname,SalBodyHandler * body_handler)1425 static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, SalBodyHandler *body_handler){
1426 	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
1427 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1428 	bool_t out_of_dialog = (lev==NULL);
1429 	if (out_of_dialog) {
1430 		/*out of dialog notify */
1431 		lev = linphone_event_new_with_out_of_dialog_op(lc,op,LinphoneSubscriptionOutgoing,eventname);
1432 	}
1433 	{
1434 		LinphoneContent *ct=linphone_content_from_sal_body_handler(body_handler);
1435 		if (ct) {
1436 			linphone_core_notify_notify_received(lc,lev,eventname,ct);
1437 			linphone_content_unref(ct);
1438 		}
1439 	}
1440 	if (out_of_dialog){
1441 		/*out of dialog NOTIFY do not create an implicit subscription*/
1442 		linphone_event_set_state(lev, LinphoneSubscriptionTerminated);
1443 	}else if (st!=SalSubscribeNone){
1444 		linphone_event_set_state(lev,linphone_subscription_state_from_sal(st));
1445 	}
1446 }
1447 
subscribe_received(SalOp * op,const char * eventname,const SalBodyHandler * body_handler)1448 static void subscribe_received(SalOp *op, const char *eventname, const SalBodyHandler *body_handler){
1449 	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
1450 	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
1451 
1452 	if (lev==NULL) {
1453 		lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionIncoming,eventname);
1454 		linphone_event_set_state(lev,LinphoneSubscriptionIncomingReceived);
1455 	}else{
1456 		/*subscribe refresh, unhandled*/
1457 	}
1458 
1459 }
1460 
incoming_subscribe_closed(SalOp * op)1461 static void incoming_subscribe_closed(SalOp *op){
1462 	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
1463 
1464 	linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
1465 }
1466 
on_publish_response(SalOp * op)1467 static void on_publish_response(SalOp* op){
1468 	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
1469 	const SalErrorInfo *ei=sal_op_get_error_info(op);
1470 
1471 	if (lev==NULL) return;
1472 	if (ei->reason==SalReasonNone){
1473 		if (!lev->terminating)
1474 			linphone_event_set_publish_state(lev,LinphonePublishOk);
1475 		else
1476 			linphone_event_set_publish_state(lev,LinphonePublishCleared);
1477 	}else{
1478 		if (lev->publish_state==LinphonePublishOk){
1479 			linphone_event_set_publish_state(lev,LinphonePublishProgress);
1480 		}else{
1481 			linphone_event_set_publish_state(lev,LinphonePublishError);
1482 		}
1483 	}
1484 }
1485 
1486 
on_expire(SalOp * op)1487 static void on_expire(SalOp *op){
1488 	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
1489 
1490 	if (lev==NULL) return;
1491 
1492 	if (linphone_event_get_publish_state(lev)==LinphonePublishOk){
1493 		linphone_event_set_publish_state(lev,LinphonePublishExpiring);
1494 	}else if (linphone_event_get_subscription_state(lev)==LinphoneSubscriptionActive){
1495 		linphone_event_set_state(lev,LinphoneSubscriptionExpiring);
1496 	}
1497 }
1498 
on_notify_response(SalOp * op)1499 static void on_notify_response(SalOp *op){
1500 	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
1501 
1502 	if (lev==NULL) return;
1503 	/*this is actually handling out of dialogs notify - for the moment*/
1504 	if (!lev->is_out_of_dialog_op) return;
1505 	switch (linphone_event_get_subscription_state(lev)){
1506 		case LinphoneSubscriptionIncomingReceived:
1507 			if (sal_op_get_error_info(op)->reason == SalReasonNone){
1508 				linphone_event_set_state(lev, LinphoneSubscriptionTerminated);
1509 			}else{
1510 				linphone_event_set_state(lev, LinphoneSubscriptionError);
1511 			}
1512 		break;
1513 		default:
1514 			ms_warning("Unhandled on_notify_response() case %s", linphone_subscription_state_to_string(linphone_event_get_subscription_state(lev)));
1515 	}
1516 }
1517 
1518 SalCallbacks linphone_sal_callbacks={
1519 	call_received,
1520 	call_rejected,
1521 	call_ringing,
1522 	call_accepted,
1523 	call_ack_received,
1524 	call_ack_being_sent,
1525 	call_updating,
1526 	call_terminated,
1527 	call_failure,
1528 	call_released,
1529 	call_cancel_done,
1530 	auth_failure,
1531 	register_success,
1532 	register_failure,
1533 	vfu_request,
1534 	dtmf_received,
1535 	refer_received,
1536 	message_received,
1537 	message_delivery_update,
1538 	notify_refer,
1539 	subscribe_received,
1540 	incoming_subscribe_closed,
1541 	subscribe_response,
1542 	notify,
1543 	subscribe_presence_received,
1544 	subscribe_presence_closed,
1545 	parse_presence_requested,
1546 	convert_presence_to_xml_requested,
1547 	notify_presence,
1548 	ping_reply,
1549 	auth_requested,
1550 	info_received,
1551 	on_publish_response,
1552 	on_expire,
1553 	on_notify_response
1554 };
1555