diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 825c01642..7b347d503 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -511,6 +511,7 @@ static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { belle_sdp_session_description_t* sdp; int err=0; SalReason reason; + SalErrorInfo sei; if (extract_sdp(op,BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { if (sdp){ @@ -527,6 +528,7 @@ static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { }else err=-1; if (err==-1){ + sal_error_info_set(&sei, reason,"SIP", 0, NULL, NULL); sal_call_decline(op,reason,NULL); } return err; @@ -942,6 +944,17 @@ int sal_call_accept(SalOp*h){ return 0; } +static belle_sip_header_reason_t *sal_call_make_reason_header( const SalErrorInfo *info){ + if (info != NULL){ + belle_sip_header_reason_t* reason = BELLE_SIP_HEADER_REASON(belle_sip_header_reason_new()); + belle_sip_header_reason_set_text(reason, info->status_string); + belle_sip_header_reason_set_protocol(reason,info->protocol); + belle_sip_header_reason_set_cause(reason,info->protocol_code); + return reason; + } + return NULL; +} + int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){ belle_sip_response_t* response; belle_sip_header_contact_t* contact=NULL; @@ -970,6 +983,41 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti return 0; } +int sal_call_decline_with_error_info(SalOp *op, const SalErrorInfo *info, const char *redirection /*optional*/){ + belle_sip_response_t* response; + belle_sip_header_contact_t* contact=NULL; + int status = info->protocol_code; + belle_sip_transaction_t *trans; + + if (info->reason==SalReasonRedirect){ + if (redirection!=NULL) { + if (strstr(redirection,"sip:")!=0) status=302; + else status=380; + contact= belle_sip_header_contact_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); + } else { + ms_error("Cannot redirect to null"); + } + } + trans=(belle_sip_transaction_t*)op->pending_server_trans; + if (!trans) trans=(belle_sip_transaction_t*)op->pending_update_server_trans; + if (!trans){ + ms_error("sal_call_decline(): no pending transaction to decline."); + return -1; + } + response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(trans),status); + belle_sip_header_reason_t* reason_header = sal_call_make_reason_header(info->sub_sei); + if (reason_header) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(reason_header)); + } + + if (contact) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); + } + belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); + return 0; +} + int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ belle_sip_request_t *update; belle_sip_dialog_state_t state; @@ -1041,6 +1089,7 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){ int sal_call_terminate_with_error(SalOp *op, const SalErrorInfo *info){ +// SalErrorInfo sei; belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; if (op->state==SalOpStateTerminating || op->state==SalOpStateTerminated) { ms_error("Cannot terminate op [%p] in state [%s]",op,sal_op_state_to_string(op->state)); @@ -1050,10 +1099,7 @@ int sal_call_terminate_with_error(SalOp *op, const SalErrorInfo *info){ case BELLE_SIP_DIALOG_CONFIRMED: { belle_sip_request_t * req = belle_sip_dialog_create_request(op->dialog,"BYE"); if (info != NULL){ - belle_sip_header_reason_t* reason = BELLE_SIP_HEADER_REASON(belle_sip_header_reason_new()); - belle_sip_header_reason_set_text(reason, info->status_string); - belle_sip_header_reason_set_protocol(reason,info->protocol); - belle_sip_header_reason_set_cause(reason,info->protocol_code); + belle_sip_header_reason_t* reason = sal_call_make_reason_header(info); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(reason)); } sal_op_send_request(op,req); @@ -1063,6 +1109,7 @@ int sal_call_terminate_with_error(SalOp *op, const SalErrorInfo *info){ case BELLE_SIP_DIALOG_NULL: { if (op->dir == SalOpDirIncoming) { + //sal_error_info_set(&sei, SalReasonDeclined,"SIP", 0, NULL, NULL); sal_call_decline(op, SalReasonDeclined,NULL); op->state=SalOpStateTerminated; } else if (op->pending_client_trans){ @@ -1080,6 +1127,7 @@ int sal_call_terminate_with_error(SalOp *op, const SalErrorInfo *info){ } case BELLE_SIP_DIALOG_EARLY: { if (op->dir == SalOpDirIncoming) { + //sal_error_info_set(&sei, SalReasonDeclined,"SIP", 0, NULL, NULL); sal_call_decline(op, SalReasonDeclined,NULL); op->state=SalOpStateTerminated; } else { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a8e263d37..a9c9c8ca1 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -561,11 +561,22 @@ const SalErrorInfo *sal_error_info_none(void){ "Ok", 200, NULL, - NULL + NULL, + }; return &none; } +void sal_error_info_init_to_null(SalErrorInfo *sei){ + sei->status_string = NULL; + sei->full_string = NULL; + sei->protocol = NULL; + sei->sub_sei = NULL; + sei->warnings = NULL; + sei->protocol_code=0; + sei->reason=SalReasonNone; +} + void sal_error_info_reset(SalErrorInfo *ei){ if (ei->status_string){ ms_free(ei->status_string); @@ -584,6 +595,10 @@ void sal_error_info_reset(SalErrorInfo *ei){ ms_free(ei->protocol); ei->protocol = NULL; } + if (ei->sub_sei){ + ms_free(ei->sub_sei); + ei->sub_sei = NULL; + } ei->protocol_code=0; ei->reason=SalReasonNone; } @@ -591,7 +606,12 @@ void sal_error_info_reset(SalErrorInfo *ei){ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol, int code, const char *status_string, const char *warning){ sal_error_info_reset(ei); if (reason==SalReasonUnknown && strcmp(protocol, "SIP") == 0) ei->reason=_sal_reason_from_sip_code(code); - else ei->reason=reason; + else{ + ei->reason=reason; + if (code == 0) { + code = sal_reason_to_sip_code(reason); + } + } ei->protocol_code=code; ei->status_string=status_string ? ms_strdup(status_string) : NULL; ei->warnings=warning ? ms_strdup(warning) : NULL; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1d46cd3a0..81618bab6 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -269,6 +269,7 @@ static void call_received(SalOp *h){ LinphoneAddress *from_address_to_search_if_me=NULL; /*address used to know if I'm the caller*/ SalMediaDescription *md; const char * p_asserted_id; + SalErrorInfo sei; /* Look if this INVITE is for a call that has already been notified but broken because of network failure */ replaced_call = look_for_broken_call_to_replace(h, lc); @@ -284,6 +285,8 @@ static void call_received(SalOp *h){ case LinphonePresenceActivityPermanentAbsence: alt_contact = linphone_presence_model_get_contact(lc->presence_model); if (alt_contact != NULL) { + sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL); + sal_call_decline_with_error_info(h, SalReasonRedirect,alt_contact); sal_call_decline(h,SalReasonRedirect,alt_contact); ms_free(alt_contact); sal_op_release(h); @@ -297,6 +300,7 @@ static void call_received(SalOp *h){ } if (!linphone_core_can_we_add_call(lc)){/*busy*/ + sal_error_info_set(&sei,SalReasonBusy, "SIP", 0, NULL, NULL); sal_call_decline(h,SalReasonBusy,NULL); sal_op_release(h); return; @@ -333,6 +337,7 @@ static void call_received(SalOp *h){ if (from_address_to_search_if_me && already_a_call_with_remote_address(lc,from_address_to_search_if_me)){ char *addr = linphone_address_as_string(from_addr); ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message.",addr); + sal_error_info_set(&sei,SalReasonBusy, "SIP", 0, NULL, NULL); sal_call_decline(h,SalReasonBusy,NULL); sal_op_release(h); linphone_address_unref(from_addr); @@ -351,6 +356,7 @@ static void call_received(SalOp *h){ md=sal_call_get_final_media_description(call->op); if (md){ if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ + sal_error_info_set(&sei,SalReasonNotAcceptable, "SIP", 0, NULL, NULL); sal_call_decline(call->op,SalReasonNotAcceptable,NULL); linphone_call_unref(call); return; @@ -678,6 +684,7 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){ /* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t is_update){ + SalErrorInfo sei; SalMediaDescription *rmd=sal_call_get_remote_media_description(op); call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE); @@ -715,6 +722,7 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t case LinphoneCallUpdating: case LinphoneCallPausing: case LinphoneCallResuming: + sal_error_info_set(&sei,SalReasonInternalError, "SIP", 0, NULL, NULL); sal_call_decline(call->op,SalReasonInternalError,NULL); /*no break*/ case LinphoneCallIdle: @@ -737,7 +745,8 @@ static void call_updating(SalOp *op, bool_t is_update){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); SalMediaDescription *rmd=sal_call_get_remote_media_description(op); - + SalErrorInfo sei; + if (!call) { ms_error("call_updating(): call doesn't exist anymore"); return ; @@ -767,6 +776,7 @@ static void call_updating(SalOp *op, bool_t is_update){ md=sal_call_get_final_media_description(call->op); if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){ + sal_error_info_set(&sei,SalReasonNotAcceptable, "SIP", 0, NULL, NULL); sal_call_decline(call->op,SalReasonNotAcceptable,NULL); return; } @@ -774,6 +784,7 @@ static void call_updating(SalOp *op, bool_t is_update){ int diff=sal_media_description_equals(prev_result_desc,md); if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){ ms_warning("Cannot accept this update, it is changing parameters that require user approval"); + sal_error_info_set(&sei,SalReasonNotAcceptable, "SIP", 0, NULL, NULL); sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/ return; } diff --git a/coreapi/error_info.c b/coreapi/error_info.c index 832a8361d..8f9e9cbb4 100644 --- a/coreapi/error_info.c +++ b/coreapi/error_info.c @@ -31,6 +31,7 @@ static void error_info_destroy(LinphoneErrorInfo *ei){ } static void error_info_clone(LinphoneErrorInfo *ei, const LinphoneErrorInfo *other){ + linphone_error_info_set_reason(ei, linphone_error_info_get_reason(other)); ei->protocol = bctbx_strdup(other->protocol); ei->phrase = bctbx_strdup(other->phrase); ei->warnings = bctbx_strdup(other->warnings); @@ -213,6 +214,12 @@ void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op){ } } +void linphone_error_info_set_sub_error_info(LinphoneErrorInfo *ei, LinphoneErrorInfo *appended_ei){ + if (appended_ei != NULL){ + ei->sub_ei = appended_ei; + } +} + void linphone_error_info_set(LinphoneErrorInfo *ei, const char *protocol, LinphoneReason reason, int code, const char *status_string, const char *warning){ linphone_error_info_reset(ei); ei->reason = reason; diff --git a/coreapi/factory.c b/coreapi/factory.c index 05d8ad4ce..738dc9db4 100644 --- a/coreapi/factory.c +++ b/coreapi/factory.c @@ -53,6 +53,7 @@ struct _LinphoneFactory { char *cached_ring_resources_dir; char *cached_image_resources_dir; char *cached_msplugins_dir; + LinphoneErrorInfo* ei; }; static void linphone_factory_uninit(LinphoneFactory *obj){ @@ -207,7 +208,7 @@ void linphone_factory_set_msplugins_dir(LinphoneFactory *factory, const char *pa STRING_SET(factory->msplugins_dir, path); } -LinphoneErrorInfo *linphone_factory_create_error_info(void){ +LinphoneErrorInfo *linphone_factory_create_error_info(LinphoneFactory *factory){ return linphone_error_info_new(); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 504e549f0..02b508247 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -5100,18 +5100,29 @@ int linphone_call_terminate(LinphoneCall *call) { return 0; } -static void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){ - +static void linphone_error_info_fields_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){ + sei->reason = linphone_error_info_get_reason(ei); sei->status_string = bctbx_strdup(ei->phrase); sei->full_string = bctbx_strdup(ei->full_string); sei->warnings = bctbx_strdup(ei->warnings); sei->protocol_code = ei->protocol_code; sei->protocol = bctbx_strdup(ei->protocol); + +} + +static void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){ + + linphone_error_info_fields_to_sal(ei, sei); + if (ei->sub_ei !=NULL) { + + linphone_error_info_to_sal(ei->sub_ei, sei->sub_sei); + } } int linphone_call_terminate_with_error_info(LinphoneCall *call , const LinphoneErrorInfo *ei){ - SalErrorInfo sei; + SalErrorInfo sei ; + sal_error_info_init_to_null(&sei); ms_message("Terminate call [%p] which is currently in state %s", call, linphone_call_state_to_string(call->state)); switch (call->state) { @@ -5150,6 +5161,7 @@ int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) { char *real_url = NULL; LinphoneCore *lc; LinphoneAddress *real_parsed_url; + SalErrorInfo sei; if (call->state != LinphoneCallIncomingReceived) { ms_error("Bad state for call redirection."); @@ -5165,6 +5177,7 @@ int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) { } real_url = linphone_address_as_string(real_parsed_url); + sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL); sal_call_decline(call->op, SalReasonRedirect, real_url); ms_free(real_url); linphone_error_info_set(call->ei, NULL, LinphoneReasonMovedPermanently, 302, "Call redirected", NULL); @@ -5175,16 +5188,43 @@ int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) { } int linphone_call_decline(LinphoneCall * call, LinphoneReason reason) { + SalErrorInfo sei; if ((call->state != LinphoneCallIncomingReceived) && (call->state != LinphoneCallIncomingEarlyMedia)) { ms_error("Cannot decline a call that is in state %s", linphone_call_state_to_string(call->state)); return -1; } - + sal_error_info_set(&sei, linphone_reason_to_sal(reason),"SIP", 0, NULL, NULL); sal_call_decline(call->op, linphone_reason_to_sal(reason), NULL); terminate_call(call); return 0; } + +static const LinphoneErrorInfo* linphone_error_info_get_sub(const LinphoneErrorInfo *ei){ + + return ei->sub_ei; +} + +int linphone_call_decline_with_error(LinphoneCall * call, const LinphoneErrorInfo *ei) { + SalErrorInfo sei; + sal_error_info_init_to_null(&sei); + SalErrorInfo sub_sei; + sal_error_info_init_to_null(&sub_sei); + sei.sub_sei = &sub_sei; + + if ((call->state != LinphoneCallIncomingReceived) && (call->state != LinphoneCallIncomingEarlyMedia)) { + ms_error("Cannot decline a call that is in state %s", linphone_call_state_to_string(call->state)); + return -1; + } + linphone_error_info_to_sal(ei, &sei); + //linphone_error_info_to_sal(ei->sub_ei, &sub_sei); + //sei.sub_sei = &sub_sei; + // check if sub reason exists + + sal_call_decline_with_error_info(call->op, &sei , NULL); + terminate_call(call); + return 0; +} int linphone_call_accept(LinphoneCall *call) { return linphone_call_accept_with_params(call, NULL); } @@ -5779,6 +5819,7 @@ void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) } void linphone_call_repair_if_broken(LinphoneCall *call){ + SalErrorInfo sei; if (!call->broken) return; if (!call->core->media_network_reachable) return; @@ -5808,6 +5849,7 @@ void linphone_call_repair_if_broken(LinphoneCall *call){ break; case LinphoneCallUpdatedByRemote: if (sal_call_dialog_request_pending(call->op)) { + sal_error_info_set(&sei, SalReasonServiceUnavailable,"SIP", 0, NULL, NULL); sal_call_decline(call->op, SalReasonServiceUnavailable, NULL); } linphone_call_reinvite_to_recover_from_connection_loss(call); diff --git a/include/linphone/call.h b/include/linphone/call.h index d23c10867..0afd289ca 100644 --- a/include/linphone/call.h +++ b/include/linphone/call.h @@ -401,6 +401,8 @@ LINPHONE_PUBLIC int linphone_call_redirect(LinphoneCall *call, const char *redir * @return 0 on success, -1 on failure **/ LINPHONE_PUBLIC int linphone_call_decline(LinphoneCall * call, LinphoneReason reason); + +LINPHONE_PUBLIC int linphone_call_decline_with_error(LinphoneCall * call, const LinphoneErrorInfo *ei); /** * Accept an incoming call. diff --git a/include/linphone/error_info.h b/include/linphone/error_info.h index 49980608c..61ea9b6e6 100644 --- a/include/linphone/error_info.h +++ b/include/linphone/error_info.h @@ -103,6 +103,8 @@ LINPHONE_PUBLIC int linphone_error_info_get_protocol_code(const LinphoneErrorInf * @param[in] warning warning message */ LINPHONE_PUBLIC void linphone_error_info_set(LinphoneErrorInfo *ei, const char *protocol, LinphoneReason reason, int code, const char *status_string, const char *warning); + +LINPHONE_PUBLIC void linphone_error_info_set_sub_error_info(LinphoneErrorInfo *ei, LinphoneErrorInfo *appended_ei); /** * Assign reason LinphoneReason to a LinphoneErrorUnfo object. diff --git a/include/linphone/factory.h b/include/linphone/factory.h index b4f785ad4..ef26ea7d3 100644 --- a/include/linphone/factory.h +++ b/include/linphone/factory.h @@ -205,9 +205,10 @@ LINPHONE_PUBLIC void linphone_factory_set_msplugins_dir(LinphoneFactory *factory /** * Creates an object LinphoneErrorInfo. + * @param[in] factory LinphoneFactory object * @return LinphoneErrorInfo object. */ -LINPHONE_PUBLIC LinphoneErrorInfo *linphone_factory_create_error_info(void); +LINPHONE_PUBLIC LinphoneErrorInfo *linphone_factory_create_error_info(LinphoneFactory *factory); /** * @} */ diff --git a/include/sal/sal.h b/include/sal/sal.h index 09df18d47..d5eb9d91c 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -412,6 +412,7 @@ typedef struct SalErrorInfo{ char *warnings; char *protocol; char *full_string; /*concatenation of status_string + warnings*/ + struct SalErrorInfo *sub_sei; }SalErrorInfo; typedef enum SalPresenceStatus{ @@ -729,6 +730,7 @@ const SalErrorInfo *sal_error_info_none(void); LINPHONE_PUBLIC const SalErrorInfo *sal_op_get_error_info(const SalOp *op); const SalErrorInfo *sal_op_get_reason_error_info(const SalOp *op); void sal_error_info_reset(SalErrorInfo *ei); +void sal_error_info_init_to_null(SalErrorInfo *sei); void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol, int code, const char *status_string, const char *warning); /*entity tag used for publish (see RFC 3903)*/ @@ -744,6 +746,7 @@ int sal_call_notify_ringing(SalOp *h, bool_t early_media); /*accept an incoming call or, during a call accept a reINVITE*/ int sal_call_accept(SalOp*h); int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/); +int sal_call_decline_with_error_info(SalOp *h, const SalErrorInfo* info, const char *redirection /*optional*/); int sal_call_update(SalOp *h, const char *subject, bool_t no_user_consent); void sal_call_cancel_invite(SalOp *op); SalMediaDescription * sal_call_get_remote_media_description(SalOp *h); diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 9c56c968a..c00065237 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -1189,6 +1189,48 @@ static void call_busy_when_calling_self(void) { linphone_core_manager_destroy(marie); } +static void call_declined_with_error(void) { + LinphoneCoreManager* callee_mgr = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* caller_mgr = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + LinphoneCall* in_call; + LinphoneCall* out_call = linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity); + LinphoneFactory* factory = linphone_factory_get(); + + LinphoneErrorInfo *ei = linphone_factory_create_error_info(factory); + LinphoneErrorInfo *reason_ei = linphone_factory_create_error_info(factory); + + linphone_error_info_set(ei, "SIP", LinphoneReasonUnknown, 603, "Decline", NULL); //ordre des arguments à vérifier + linphone_error_info_set(reason_ei, "hardware", LinphoneReasonUnknown, 66, "J'ai plus de batterie", NULL); + + linphone_error_info_set_sub_error_info(ei, reason_ei); + + linphone_call_ref(out_call); + BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); + BC_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(callee_mgr->lc)); + if (in_call) { + linphone_call_ref(in_call); + linphone_call_decline_with_error(in_call, ei); + // linphone_call_terminate(in_call); + BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallReleased,1)); + BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallReleased,1)); + BC_ASSERT_EQUAL(callee_mgr->stat.number_of_LinphoneCallEnd,1, int, "%d"); + BC_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallEnd,1, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_log_get_status(linphone_call_get_call_log(in_call)),LinphoneCallDeclined, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined, int, "%d"); + BC_ASSERT_EQUAL(linphone_call_log_get_status(linphone_call_get_call_log(out_call)),LinphoneCallDeclined, int, "%d"); + + + linphone_call_unref(in_call); + } + linphone_call_unref(out_call); + //linphone_error_info_unref(reason_ei); + linphone_error_info_unref(ei); + + linphone_core_manager_destroy(callee_mgr); + linphone_core_manager_destroy(caller_mgr); +} static void call_declined(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); @@ -5736,6 +5778,7 @@ static void call_with_network_reachable_down_in_callback(void){ test_t call_tests[] = { TEST_NO_TAG("Early declined call", early_declined_call), TEST_NO_TAG("Call declined", call_declined), + TEST_NO_TAG("Call declined with error", call_declined_with_error), TEST_NO_TAG("Cancelled call", cancelled_call), TEST_NO_TAG("Early cancelled call", early_cancelled_call), TEST_NO_TAG("Call with DNS timeout", call_with_dns_time_out),