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