Commit 15c8ed30 authored by Simon Morlat's avatar Simon Morlat
Browse files

modify event API to allow adding custom headers.

It is now possible to first create the LinphoneEvent, configure it with custom headers, then send it.
parent 3b3271db
......@@ -35,7 +35,7 @@ const char *linphone_subscription_state_to_string(LinphoneSubscriptionState stat
switch(state){
case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone";
case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived";
case LinphoneSubscriptionOutoingInit: return "LinphoneSubscriptionOutoingInit";
case LinphoneSubscriptionOutgoingInit: return "LinphoneSubscriptionOutoingInit";
case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending";
case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive";
case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated";
......@@ -68,8 +68,9 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri
return lev;
}
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name){
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires){
LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal));
lev->expires=expires;
return lev;
}
......@@ -121,32 +122,38 @@ LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){
return lev->reason;
}
LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event);
SalBody salbody;
LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires);
linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1));
lev->resource_addr=linphone_address_clone(resource);
lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op));
sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body));
linphone_event_set_state(lev,LinphoneSubscriptionOutoingInit);
return lev;
}
LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
LinphoneEvent *lev=linphone_core_create_subscribe(lc,resource,event,expires);
linphone_event_send_subscribe(lev,body);
return lev;
}
int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
SalBody salbody;
int err;
if (lev->dir!=LinphoneSubscriptionOutgoing){
ms_error("linphone_event_send_subscribe(): cannot send or update something that is not an outgoing subscription.");
return -1;
}
switch (lev->subscription_state){
case LinphoneSubscriptionNone:
ms_error("linphone_event_update_subscribe(): this is not a subscribed event.");
return -1;
break;
case LinphoneSubscriptionIncomingReceived:
case LinphoneSubscriptionOutoingInit:
case LinphoneSubscriptionTerminated:
ms_error("linphone_event_update_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state));
case LinphoneSubscriptionOutgoingInit:
ms_error("linphone_event_send_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state));
return -1;
break;
case LinphoneSubscriptionNone:
case LinphoneSubscriptionActive:
case LinphoneSubscriptionExpiring:
case LinphoneSubscriptionError:
......@@ -154,11 +161,22 @@ int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *b
/*those states are ok*/
break;
}
if (lev->dir!=LinphoneSubscriptionOutgoing){
ms_error("linphone_event_deny_subscription(): cannot update an incoming subscription.");
return -1;
if (lev->send_custom_headers){
sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers);
lev->send_custom_headers=NULL;
}else sal_op_set_sent_custom_header(lev->op,NULL);
err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
if (err==0){
if (lev->subscription_state==LinphoneSubscriptionNone)
linphone_event_set_state(lev,LinphoneSubscriptionOutgoingInit);
}
return sal_subscribe(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body));
return err;
}
int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
return linphone_event_send_subscribe(lev,body);
}
int linphone_event_accept_subscription(LinphoneEvent *lev){
......@@ -198,40 +216,52 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
return sal_notify(lev->op,sal_body_from_content(&salbody,body));
}
LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
SalBody salbody;
int err;
LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event);
LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires);
linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0));
sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
err=sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body));
if (err==0){
linphone_event_set_publish_state(lev,LinphonePublishProgress);
}else{
linphone_event_unref(lev);
lev=NULL;
}
return lev;
}
int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body){
static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){
SalBody salbody;
int err;
if (lev->publish_state==LinphonePublishNone){
if (lev->dir!=LinphoneSubscriptionInvalidDir){
ms_error("linphone_event_update_publish(): this is not a PUBLISH event.");
return -1;
}
err=sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body));
err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
if (err==0){
linphone_event_set_publish_state(lev,LinphonePublishProgress);
}else{
}else if (notify_err){
linphone_event_set_publish_state(lev,LinphonePublishError);
}
return err;
}
LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
int err;
LinphoneEvent *lev=linphone_core_create_publish(lc,resource,event,expires);
err=_linphone_event_send_publish(lev,body,FALSE);
if (err==-1){
linphone_event_unref(lev);
lev=NULL;
}
return lev;
}
int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body){
return _linphone_event_send_publish(lev,body,TRUE);
}
int linphone_event_update_publish(LinphoneEvent* lev, const LinphoneContent* body ) {
return linphone_event_send_publish(lev,body);
}
void linphone_event_set_user_data(LinphoneEvent *ev, void *up){
ev->userdata=up;
}
......@@ -240,6 +270,16 @@ void *linphone_event_get_user_data(const LinphoneEvent *ev){
return ev->userdata;
}
void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value){
ev->send_custom_headers=sal_custom_header_append(ev->send_custom_headers, name, value);
}
const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){
const SalCustomHeader *ch=sal_op_get_recv_custom_header(ev->op);
return sal_custom_header_find(ch,name);
}
void linphone_event_terminate(LinphoneEvent *lev){
lev->terminating=TRUE;
if (lev->dir==LinphoneSubscriptionIncoming){
......@@ -259,7 +299,6 @@ void linphone_event_terminate(LinphoneEvent *lev){
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
return;
}
}
......
......@@ -52,7 +52,7 @@ typedef enum _LinphoneSubscriptionDir LinphoneSubscriptionDir;
**/
enum _LinphoneSubscriptionState{
LinphoneSubscriptionNone, /**< Initial state, should not be used.**/
LinphoneSubscriptionOutoingInit, /**<An outgoing subcription was created*/
LinphoneSubscriptionOutgoingInit, /**<An outgoing subcription was created*/
LinphoneSubscriptionIncomingReceived, /**<An incoming subcription is received*/
LinphoneSubscriptionPending, /**<Subscription is pending, waiting for user approval*/
LinphoneSubscriptionActive, /**<Subscription is accepted.*/
......@@ -60,6 +60,8 @@ enum _LinphoneSubscriptionState{
LinphoneSubscriptionError, /**<Subscription encountered an error, indicated by linphone_event_get_reason()*/
LinphoneSubscriptionExpiring, /**<Subscription is about to expire, only sent if [sip]->refresh_generic_subscribe property is set to 0.*/
};
/*typo compatibility*/
#define LinphoneSubscriptionOutoingInit LinphoneSubscriptionOutgoingInit
/**
* Typedef for subscription state enum.
......@@ -115,7 +117,28 @@ typedef void (*LinphoneCorePublishStateChangedCb)(LinphoneCore *lc, LinphoneEven
LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
/**
* Update an outgoing subscription.
* Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body.
* If accepted, the subscription runs for a finite period, but is automatically renewed if not terminated before.
* Unlike linphone_core_subscribe() the subscription isn't sent immediately. It will be send when calling linphone_event_send_subscribe().
* @param lc the #LinphoneCore
* @param resource the destination resource
* @param event the event name
* @param expires the whished duration of the subscription
* @param body an optional body, may be NULL.
* @return a LinphoneEvent holding the context of the created subcription.
**/
LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires);
/**
* Send a subscription previously created by linphone_core_create_subscribe().
* @param ev the LinphoneEvent
* @param body optional content to attach with the subscription.
* @return 0 if successful, -1 otherwise.
**/
LINPHONE_PUBLIC int linphone_event_send_subscribe(LinphoneEvent *ev, const LinphoneContent *body);
/**
* Update (refresh) an outgoing subscription.
* @param lev a LinphoneEvent
* @param body an optional body to include in the subscription update, may be NULL.
**/
......@@ -141,6 +164,7 @@ LINPHONE_PUBLIC int linphone_event_notify(LinphoneEvent *lev, const LinphoneCont
/**
* Publish an event state.
* This first create a LinphoneEvent with linphone_core_create_publish() and calls linphone_event_send_publish() to actually send it.
* After expiry, the publication is refreshed unless it is terminated before.
* @param lc the #LinphoneCore
* @param resource the resource uri for the event
......@@ -152,7 +176,26 @@ LINPHONE_PUBLIC int linphone_event_notify(LinphoneEvent *lev, const LinphoneCont
LINPHONE_PUBLIC LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
/**
* Update a publication.
* Create a publish context for an event state.
* After being created, the publish must be sent using linphone_event_send_publish().
* After expiry, the publication is refreshed unless it is terminated before.
* @param lc the #LinphoneCore
* @param resource the resource uri for the event
* @param event the event name
* @param expires the lifetime of the publication
* @return the LinphoneEvent holding the context of the publish.
**/
LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires);
/**
* Send a publish created by linphone_core_create_publish().
* @param lev the #LinphoneEvent
* @param body the new data to be published
**/
LINPHONE_PUBLIC int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body);
/**
* Update (refresh) a publish.
* @param lev the #LinphoneEvent
* @param body the new data to be published
**/
......@@ -190,6 +233,22 @@ LINPHONE_PUBLIC void linphone_event_set_user_data(LinphoneEvent *ev, void *up);
**/
LINPHONE_PUBLIC void *linphone_event_get_user_data(const LinphoneEvent *ev);
/**
* Add a custom header to an outgoing susbscription or publish.
* @param ev the LinphoneEvent
* @param name header's name
* @param value the header's value.
**/
LINPHONE_PUBLIC void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value);
/**
* Obtain the value of a given header for an incoming subscription.
* @param ev the LinphoneEvent
* @param name header's name
* @return the header's value or NULL if such header doesn't exist.
**/
LINPHONE_PUBLIC const char *linphone_event_get_custom_header(LinphoneEvent *ev, const char *name);
/**
* Terminate an incoming or outgoing subscription that was previously acccepted, or a previous publication.
* This function does not unref the object. The core will unref() if it does not need this object anymore.
......
......@@ -677,6 +677,7 @@ struct _LinphoneEvent{
LinphoneSubscriptionDir dir;
LinphoneCore *lc;
SalOp *op;
SalCustomHeader *send_custom_headers;
LinphoneSubscriptionState subscription_state;
LinphonePublishState publish_state;
LinphoneReason reason;
......@@ -685,6 +686,7 @@ struct _LinphoneEvent{
char *name;
LinphoneAddress *from;
LinphoneAddress *resource_addr;
int expires;
bool_t terminating;
};
......@@ -793,7 +795,7 @@ LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc);
SalReason linphone_reason_to_sal(LinphoneReason reason);
LinphoneReason linphone_reason_from_sal(SalReason reason);
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name);
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires);
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name);
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state);
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state);
......
......@@ -59,12 +59,13 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li
break;
case LinphoneSubscriptionIncomingReceived:
counters->number_of_LinphoneSubscriptionIncomingReceived++;
mgr->lev=lev;
if (!mgr->decline_subscribe)
linphone_event_accept_subscription(lev);
else
linphone_event_deny_subscription(lev, LinphoneReasonDeclined);
break;
case LinphoneSubscriptionOutoingInit:
case LinphoneSubscriptionOutgoingInit:
counters->number_of_LinphoneSubscriptionOutgoingInit++;
break;
case LinphoneSubscriptionPending:
......@@ -190,6 +191,66 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes
linphone_core_manager_destroy(pauline);
}
static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTestType refresh_type) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneContent content={0};
LinphoneEvent *lev;
int expires= refresh_type!=NoRefresh ? 4 : 600;
MSList* lcs=ms_list_append(NULL,marie->lc);
lcs=ms_list_append(lcs,pauline->lc);
if (refresh_type==ManualRefresh){
lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0);
}
content.type="application";
content.subtype="somexml";
content.data=(char*)subscribe_content;
content.size=strlen(subscribe_content);
lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires);
linphone_event_add_custom_header(lev,"My-Header","pouet");
linphone_event_add_custom_header(lev,"My-Header2","pimpon");
linphone_event_send_subscribe(lev,&content);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000));
/*check good receipt of custom headers*/
CU_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header"),"pouet");
CU_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header2"),"pimpon");
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000));
/*make sure marie receives first notification before terminating*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000));
if (refresh_type==AutoRefresh){
wait_for_list(lcs,NULL,0,6000);
CU_ASSERT_TRUE(linphone_event_get_subscription_state(pauline->lev)==LinphoneSubscriptionActive);
}else if (refresh_type==ManualRefresh){
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionExpiring,1,4000));
linphone_event_update_subscribe(lev,NULL);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,2000));
}
if (terminated_by_subscriber){
linphone_event_terminate(lev);
}else{
CU_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev);
linphone_event_terminate(pauline->lev);
}
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000));
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void subscribe_test_terminated_by_subscriber(void){
subscribe_test_with_args(TRUE,NoRefresh);
}
......@@ -205,6 +266,10 @@ static void subscribe_test_refreshed(void){
subscribe_test_with_args(TRUE,AutoRefresh);
}
static void subscribe_test_with_custom_header(void){
subscribe_test_with_args2(TRUE,NoRefresh);
}
static void subscribe_test_manually_refreshed(void){
subscribe_test_with_args(TRUE,ManualRefresh);
}
......@@ -261,6 +326,7 @@ static void publish_no_auto_test(){
test_t event_tests[] = {
{ "Subscribe declined" , subscribe_test_declined },
{ "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber },
{ "Subscribe with custom headers", subscribe_test_with_custom_header },
{ "Subscribe refreshed", subscribe_test_refreshed },
{ "Subscribe manually refreshed", subscribe_test_manually_refreshed },
{ "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier },
......
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