Commit 026bbe8d authored by jehan's avatar jehan

Implement support of dialog created by Notify matching subscription

parent 5872dddc
......@@ -235,7 +235,12 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve
if (dialog) {
op=(SalOp*)belle_sip_dialog_get_application_data(dialog);
if (op==NULL || op->state==SalOpStateTerminated){
if (op == NULL && strcmp("NOTIFY",method) == 0) {
/*special case for Dialog created by notify mathing subscribe*/
belle_sip_transaction_t * sub_trans = belle_sip_dialog_get_last_transaction(dialog);
op = (SalOp*)belle_sip_transaction_get_application_data(sub_trans);
} else if (op==NULL || op->state==SalOpStateTerminated){
ms_warning("Receiving request for null or terminated op [%p], ignored",op);
return;
}
......
......@@ -101,7 +101,7 @@ struct SalOp{
int ref;
SalOpType type;
SalPrivacyMask privacy;
belle_sip_header_t *event; /*used by SalOpSubscribe kinds*/
belle_sip_header_event_t *event; /*used by SalOpSubscribe kinds*/
SalOpSDPHandling sdp_handling;
int auth_requests; /*number of auth requested for this op*/
bool_t cnx_ip_to_0000_if_sendonly_enabled;
......@@ -174,4 +174,6 @@ int sal_reason_to_sip_code(SalReason r);
void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg);
SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg);
#endif /* SAL_IMPL_H_ */
......@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sal_impl.h"
SalSubscribeStatus get_subscription_state(belle_sip_message_t *msg){
SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg){
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(msg,belle_sip_header_subscription_state_t);
SalSubscribeStatus sss=SalSubscribeNone;
if (subscription_state_header){
......@@ -73,7 +73,7 @@ static void subscribe_process_dialog_terminated(void *ctx, const belle_sip_dialo
/*notify the app that our subscription is dead*/
const char *eventname = NULL;
if (op->event){
eventname = belle_sip_header_get_unparsed_value(op->event);
eventname = belle_sip_header_event_get_package_name(op->event);
}
op->base.root->callbacks.notify(op, SalSubscribeTerminated, eventname, NULL);
}
......@@ -115,7 +115,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_dialog_state_t dialog_state;
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
belle_sip_header_t *event_header;
belle_sip_header_event_t *event_header;
belle_sip_body_handler_t *body_handler;
belle_sip_response_t* resp;
const char *eventname=NULL;
......@@ -125,7 +125,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
op->pending_server_trans=server_transaction;
event_header=belle_sip_message_get_header((belle_sip_message_t*)req,"Event");
event_header=belle_sip_message_get_header_by_type(req,belle_sip_header_event_t);
body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, BELLE_SIP_MESSAGE(req)));
if (event_header==NULL){
......@@ -139,7 +139,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
op->event=event_header;
belle_sip_object_ref(op->event);
}
eventname=belle_sip_header_get_unparsed_value(event_header);
eventname=belle_sip_header_event_get_package_name(event_header);
if (!op->dialog) {
if (strcmp(method,"SUBSCRIBE")==0){
......@@ -238,10 +238,10 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event
}
if (eventname){
if (op->event) belle_sip_object_unref(op->event);
op->event=belle_sip_header_create("Event",eventname);
op->event=belle_sip_header_event_create(eventname);
belle_sip_object_ref(op->event);
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
return sal_op_send_and_create_refresher(op,req,expires,subscribe_refresher_listener);
......@@ -276,6 +276,29 @@ int sal_subscribe_accept(SalOp *op){
return 0;
}
int sal_notify_pending_state(SalOp *op){
if (op->dialog != NULL && op->pending_server_trans) {
belle_sip_request_t* notify;
belle_sip_header_subscription_state_t* sub_state;
ms_message("Sending NOTIFY with subscription state pending for op [%p]",op);
if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) {
ms_error("Cannot create NOTIFY on op [%p]",op);
return -1;
}
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event));
sub_state=belle_sip_header_subscription_state_new();
belle_sip_header_subscription_state_set_state(sub_state,BELLE_SIP_SUBSCRIPTION_STATE_PENDING);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify), BELLE_SIP_HEADER(sub_state));
return sal_op_send_request(op,notify);
} else {
ms_warning("NOTIFY with subscription state pending for op [%p] not implemented in this case (either dialog pending trans does not exist",op);
}
return 0;
}
int sal_subscribe_decline(SalOp *op, SalReason reason){
belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),
sal_reason_to_sip_code(reason));
......@@ -290,7 +313,7 @@ int sal_notify(SalOp *op, const SalBodyHandler *body_handler){
if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1;
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),op->event);
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)));
......@@ -302,7 +325,7 @@ int sal_notify_close(SalOp *op){
belle_sip_request_t* notify;
if (!op->dialog) return -1;
if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1;
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),op->event);
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
return sal_op_send_request(op,notify);
......
......@@ -229,7 +229,7 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req, belle_sip_dialog_
sub_state=SalSubscribeTerminated;
ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else {
sub_state=SalSubscribeActive;
sub_state=belle_sip_message_get_subscription_state(BELLE_SIP_MESSAGE(req));
}
presence_model = process_presence_notification(op, req);
if (presence_model != NULL || body==NULL) {
......@@ -255,10 +255,23 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
belle_sip_dialog_state_t dialog_state;
belle_sip_response_t* resp;
const char *method=belle_sip_request_get_method(req);
belle_sip_header_event_t *event_header;
belle_sip_object_ref(server_transaction);
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
op->pending_server_trans=server_transaction;
event_header=belle_sip_message_get_header_by_type(req,belle_sip_header_event_t);
if (event_header==NULL){
ms_warning("No event header in incoming SUBSCRIBE.");
resp=sal_op_create_response_from_request(op,req,400);
belle_sip_server_transaction_send_response(server_transaction,resp);
if (!op->dialog) sal_op_release(op);
return;
}
if (op->event==NULL) {
op->event=event_header;
belle_sip_object_ref(op->event);
}
if (!op->dialog) {
......@@ -272,7 +285,10 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
}
set_or_update_dialog(op, dialog);
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
}else{ /* this is a NOTIFY */
}else if (strcmp(method,"NOTIFY")==0 && belle_sip_request_event_get_dialog(event)) {
/*special case of dialog created by notify matching subscribe*/
set_or_update_dialog(op, belle_sip_request_event_get_dialog(event));
} else {/* this is a NOTIFY */
ms_message("Receiving out of dialog notify");
handle_notify(op, req, belle_sip_request_event_get_dialog(event));
return;
......@@ -281,7 +297,11 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL: {
op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op));
if (strcmp("NOTIFY",method)==0) {
handle_notify(op, req, belle_sip_request_event_get_dialog(event));
} else if (strcmp("SUBSCRIBE",method)==0) {
op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op));
}
break;
}
case BELLE_SIP_DIALOG_EARLY:
......@@ -354,14 +374,14 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expi
}
}
if (!op->event){
op->event=belle_sip_header_create("Event","presence");
op->event=belle_sip_header_event_create("presence");
belle_sip_object_ref(op->event);
}
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag");
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag");
req=sal_op_build_request(op,"SUBSCRIBE");
if( req ){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
}
......
......@@ -1552,3 +1552,6 @@ void linphone_core_migrate_friends_from_rc_to_db(LinphoneCore *lc) {
ms_debug("friends migration successful: %i friends migrated", i);
lp_config_set_int(lpc, "misc", "friends_migration_done", 1);
}
LinphoneSubscriptionState linphone_friend_get_subscription_state(const LinphoneFriend *lf) {
return lf->out_sub_state;
}
......@@ -278,6 +278,14 @@ LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr);
*/
LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf);
/**
* Get subscription state of a friend
* @param[in] lf A #LinphoneFriend object
* @return #LinphoneSubscriptionState
*/
LINPHONE_PUBLIC LinphoneSubscriptionState linphone_friend_get_subscription_state(const LinphoneFriend *lf);
/**
* Get the presence model of a friend
* @param[in] lf A #LinphoneFriend object
......
......@@ -1513,6 +1513,9 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
if (lf!=NULL){
linphone_friend_add_incoming_subscription(lf, op);
lf->inc_subscribe_pending=TRUE;
if (lp_config_get_int(lc->config,"sip","notify_pending_state",0)) {
sal_notify_pending_state(op);
}
sal_subscribe_accept(op);
linphone_friend_done(lf); /*this will do all necessary actions */
}else{
......@@ -1904,6 +1907,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa
linphone_friend_set_presence_model(lf, presence);
lf->subscribe_active=TRUE;
lf->presence_received = TRUE;
lf->out_sub_state = linphone_subscription_state_from_sal(ss);
linphone_core_notify_notify_presence_received(lc,(LinphoneFriend*)lf);
ms_free(tmp);
if (op != lf->outsub){
......
......@@ -702,6 +702,7 @@ struct _LinphoneFriend{
LinphoneVcard *vcard;
unsigned int storage_id;
LinphoneFriendList *friend_list;
LinphoneSubscriptionState out_sub_state;
};
BELLE_SIP_DECLARE_VPTR(LinphoneFriend);
......
......@@ -770,6 +770,7 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event
int sal_unsubscribe(SalOp *op);
int sal_subscribe_accept(SalOp *op);
int sal_subscribe_decline(SalOp *op, SalReason reason);
int sal_notify_pending_state(SalOp *op);
int sal_notify(SalOp *op, const SalBodyHandler *body);
int sal_notify_close(SalOp *op);
int sal_publish(SalOp *op, const char *from, const char *to, const char*event_name, int expires, const SalBodyHandler *body);
......
......@@ -272,6 +272,54 @@ static void simple_subscribe(void) {
linphone_core_manager_destroy(pauline);
}
static void simple_subscribe_with_early_notify(void) {
LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie");
LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline");
LinphoneAddress *marie_identity_addr = linphone_address_clone(marie->identity);
LpConfig *pauline_lp;
pauline_lp = linphone_core_get_config(pauline->lc);
lp_config_set_int(pauline_lp,"sip","notify_pending_state",1);
bool_t result=FALSE;
char* pauline_identity=linphone_address_as_string_uri_only(pauline->identity);
char* marie_identity;
LinphoneFriend* pauline_s_friend;
LinphoneFriend* marie_s_friend=linphone_core_create_friend_with_address(marie->lc,pauline_identity);
linphone_friend_edit(marie_s_friend);
linphone_friend_enable_subscribes(marie_s_friend,TRUE);
linphone_friend_done(marie_s_friend);
linphone_core_add_friend(marie->lc,marie_s_friend);
ms_free(pauline_identity);
/*to simulate pending state.*/
linphone_address_set_port(marie_identity_addr,0);
marie_identity=linphone_address_as_string_uri_only(marie_identity_addr);
pauline_s_friend=linphone_core_create_friend_with_address(pauline->lc,marie_identity);
linphone_core_add_friend(pauline->lc,pauline_s_friend);
ms_free(marie_identity);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyPresenceReceived,1));
BC_ASSERT_EQUAL(linphone_friend_get_subscription_state(marie_s_friend), LinphoneSubscriptionPending,int, "%d");
result=wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnline,marie->stat.number_of_LinphonePresenceActivityOnline+1);
BC_ASSERT_EQUAL(marie->stat.number_of_NotifyPresenceReceived,2, int, "%d");
linphone_friend_unref(marie_s_friend);
linphone_friend_unref(pauline_s_friend);
linphone_address_unref(marie_identity_addr);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void unsubscribe_while_subscribing(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
......@@ -399,8 +447,8 @@ static void presence_information(void) {
static void subscribe_presence_forked(void){
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline1 = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCoreManager* pauline2 = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCoreManager* pauline1 = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_tcp_rc" : "pauline_tcp_rc");
LinphoneCoreManager* pauline2 = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_tcp_rc" : "pauline_tcp_rc");
LinphoneFriend *lf;
MSList *lcs = NULL;
......@@ -417,8 +465,10 @@ static void subscribe_presence_forked(void){
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_NewSubscriptionRequest,1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline2->stat.number_of_NewSubscriptionRequest,1, 2000));
/*we should get two notifies*/
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePresenceActivityOnline,2, 10000));
/*we should get only one notify*/
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePresenceActivityOnline,1, 10000));
BC_ASSERT_FALSE(wait_for_list(lcs,&marie->stat.number_of_LinphonePresenceActivityOnline,2, 2000));
/*marie also shall receive two SUBSCRIBEs from the two paulines, but won't be notified to the app since
Marie set Pauline as a friend.*/
......@@ -501,6 +551,7 @@ static void simple_subscribe_with_friend_from_rc(void) {
test_t presence_tests[] = {
TEST_ONE_TAG("Simple Subscribe", simple_subscribe,"presence"),
TEST_ONE_TAG("Simple Subscribe with early NOTIFY", simple_subscribe_with_early_notify,"presence"),
TEST_NO_TAG("Simple Subscribe with friend from rc", simple_subscribe_with_friend_from_rc),
TEST_ONE_TAG("Simple Publish", simple_publish, "LeaksMemory"),
TEST_ONE_TAG("Simple Publish with expires", publish_with_expires, "LeaksMemory"),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment