enhance event API to be notified of publish states.

lp-gen-wrappers is in progress
This commit is contained in:
Simon Morlat 2013-09-17 14:03:52 +02:00
parent f9e0782528
commit fed415507f
18 changed files with 693 additions and 57 deletions

View file

@ -174,7 +174,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e
}
}
static void process_request_event(void *sal, const belle_sip_request_event_t *event) {
static void process_request_event(void *ud, const belle_sip_request_event_t *event) {
Sal *sal=(Sal*)ud;
SalOp* op=NULL;
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event);
@ -195,36 +196,41 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev
return;
}
}else if (strcmp("INVITE",method)==0) {
op=sal_op_new((Sal*)sal);
op=sal_op_new(sal);
op->dir=SalOpDirIncoming;
sal_op_call_fill_cbs(op);
}else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) {
op=sal_op_new((Sal*)sal);
op=sal_op_new(sal);
op->dir=SalOpDirIncoming;
if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){
sal_op_presence_fill_cbs(op);
}else
sal_op_subscribe_fill_cbs(op);
}else if (strcmp("MESSAGE",method)==0) {
op=sal_op_new((Sal*)sal);
op=sal_op_new(sal);
op->dir=SalOpDirIncoming;
sal_op_message_fill_cbs(op);
}else if (strcmp("OPTIONS",method)==0) {
resp=belle_sip_response_create_from_request(req,200);
belle_sip_provider_send_response(((Sal*)sal)->prov,resp);
belle_sip_provider_send_response(sal->prov,resp);
return;
}else if (strcmp("INFO",method)==0) {
resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/
belle_sip_provider_send_response(((Sal*)sal)->prov,resp);
belle_sip_provider_send_response(sal->prov,resp);
return;
}else if (strcmp("BYE",method)==0) {
resp=belle_sip_response_create_from_request(req,481);/*out of dialog BYE */
belle_sip_provider_send_response(((Sal*)sal)->prov,resp);
belle_sip_provider_send_response(sal->prov,resp);
return;
}else if (sal->enable_test_features && strcmp("PUBLISH",method)==0) {
resp=belle_sip_response_create_from_request(req,200);/*out of dialog BYE */
belle_sip_message_add_header((belle_sip_message_t*)resp,belle_sip_header_create("SIP-Etag","4441929FFFZQOA"));
belle_sip_provider_send_response(sal->prov,resp);
return;
}else {
ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req));
resp=belle_sip_response_create_from_request(req,501);
belle_sip_provider_send_response(((Sal*)sal)->prov,resp);
belle_sip_provider_send_response(sal->prov,resp);
return;
}
@ -460,6 +466,10 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;
if (ctx->callbacks.info_received==NULL)
ctx->callbacks.info_received=(SalOnInfoReceived)unimplemented_stub;
if (ctx->callbacks.on_publish_response==NULL)
ctx->callbacks.on_publish_response=(SalOnPublishResponse)unimplemented_stub;
if (ctx->callbacks.on_expire==NULL)
ctx->callbacks.on_expire=(SalOnExpire)unimplemented_stub;
}
@ -825,3 +835,8 @@ int sal_get_refresher_retry_after(const Sal *sal) {
void sal_enable_auto_contacts(Sal *ctx, bool_t enabled){
ctx->auto_contacts=enabled;
}
void sal_enable_test_features(Sal*ctx, bool_t enabled){
ctx->enable_test_features=enabled;
}

View file

@ -46,6 +46,7 @@ struct Sal{
bool_t tls_verify_cn;
bool_t use_dates;
bool_t auto_contacts;
bool_t enable_test_features;
};
typedef enum SalOpState {

View file

@ -22,11 +22,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void subscribe_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
ms_error("subscribe_process_io_error not implemented yet");
}
static void subscribe_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
SalOp* op= (SalOp*)ctx;
if (op->dialog) {
sal_op_unref(op);
op->dialog=NULL;
sal_op_unref(op);
}
}

View file

@ -407,10 +407,15 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal
*sal_reason=SalReasonServiceUnavailable;
break;
default:
if (code>0){
if (code>=300){
*sal_err=SalErrorFailure;
*sal_reason=SalReasonUnknown;
}else *sal_err=SalErrorNoResponse;
}else if (code>=100){
*sal_err=SalErrorNone;
*sal_reason=SalReasonUnknown;
}else if (code==0){
*sal_err=SalErrorNoResponse;
}
/* no break */
}
}

View file

@ -56,7 +56,7 @@ static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog
}
}
static void presence_refresher_listener( const belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){
static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){
SalOp* op = (SalOp*)user_pointer;
switch(status_code){
case 481: {

View file

@ -19,21 +19,43 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sal_impl.h"
static void publish_refresher_listener ( const belle_sip_refresher_t* refresher
static void publish_refresher_listener (belle_sip_refresher_t* refresher
,void* user_pointer
,unsigned int status_code
,const char* reason_phrase) {
SalOp* op = (SalOp*)user_pointer;
/*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/
ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op));
ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op));
if (status_code==412){
/*resubmit the request after removing the SIP-If-Match*/
const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match");
belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES);
}else if (status_code==0){
op->base.root->callbacks.on_expire(op);
}else if (status_code>=200){
SalError err;
SalReason reason;
sal_compute_sal_errors_from_code(status_code,&err,&reason);
op->base.root->callbacks.on_publish_response(op,err,reason);
}
}
static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){
SalOp *op=(SalOp*)userctx;
int code=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
SalError err;
SalReason reason;
sal_compute_sal_errors_from_code(code,&err,&reason);
op->base.root->callbacks.on_publish_response(op,err,reason);
}
void sal_op_publish_fill_cbs(SalOp*op) {
op->callbacks.process_response_event=publish_response_event;
op->type=SalOpPublish;
}
/*presence publish */
int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence){
belle_sip_request_t *req=NULL;
@ -68,7 +90,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
if (to)
sal_op_set_to(op,to);
op->type=SalOpPublish;
sal_op_publish_fill_cbs(op);
req=sal_op_build_request(op,"PUBLISH");
if (sal_op_get_contact(op)){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
@ -82,8 +104,6 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
/*update body*/
sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),body);
return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES);
return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires);
}
}

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sal_impl.h"
static void register_refresher_listener ( const belle_sip_refresher_t* refresher
static void register_refresher_listener (belle_sip_refresher_t* refresher
,void* user_pointer
,unsigned int status_code
,const char* reason_phrase) {

View file

@ -1086,6 +1086,32 @@ static void subscribe_closed(SalOp *op){
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
}
static void on_publish_response(SalOp* op, SalError err, SalReason reason){
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
if (lev==NULL) return;
if (err==SalErrorNone){
if (!lev->terminating)
linphone_event_set_publish_state(lev,LinphonePublishOk);
else
linphone_event_set_publish_state(lev,LinphonePublishCleared);
}else{
linphone_event_set_reason(lev,linphone_reason_from_sal(reason));
linphone_event_set_publish_state(lev,LinphonePublishError);
}
}
static void on_expire(SalOp *op){
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
if (lev==NULL) return;
if (linphone_event_get_publish_state(lev)==LinphonePublishOk){
linphone_event_set_publish_state(lev,LinphonePublishExpiring);
}
}
SalCallbacks linphone_sal_callbacks={
call_received,
call_ringing,
@ -1120,7 +1146,9 @@ SalCallbacks linphone_sal_callbacks={
notify_presence,
ping_reply,
auth_requested,
info_received
info_received,
on_publish_response,
on_expire
};

View file

@ -20,18 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "private.h"
#include "lpconfig.h"
struct _LinphoneEvent{
LinphoneSubscriptionDir dir;
LinphoneCore *lc;
SalOp *op;
LinphoneSubscriptionState state;
LinphoneReason reason;
void *userdata;
int refcnt;
char *name;
LinphoneAddress *from;
LinphoneAddress *resource_addr;
};
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){
switch(ss){
@ -43,6 +31,31 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu
return LinphoneSubscriptionNone;
}
const char *linphone_subscription_state_to_string(LinphoneSubscriptionState state){
switch(state){
case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone";
case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived";
case LinphoneSubscriptionOutoingInit: return "LinphoneSubscriptionOutoingInit";
case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending";
case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive";
case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated";
case LinphoneSubscriptionError: return "LinphoneSubscriptionError";
}
return NULL;
}
LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishState state){
switch(state){
case LinphonePublishNone: return "LinphonePublishNone";
case LinphonePublishProgress: return "LinphonePublishProgress";
case LinphonePublishOk: return "LinphonePublishOk";
case LinphonePublishError: return "LinphonePublishError";
case LinphonePublishCleared: return "LinphonePublishCleared";
case LinphonePublishExpiring: return "LinphonePublishExpiring";
}
return NULL;
}
static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, SalOp *op){
LinphoneEvent *lev=ms_new0(LinphoneEvent,1);
lev->lc=lc;
@ -72,8 +85,9 @@ LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneS
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){
LinphoneCore *lc=lev->lc;
if (lev->state!=state){
lev->state=state;
if (lev->subscription_state!=state){
ms_message("LinphoneEvent [%p] moving to subscription state %s",lev,linphone_subscription_state_to_string(state));
lev->subscription_state=state;
if (lc->vtable.subscription_state_changed){
lc->vtable.subscription_state_changed(lev->lc,lev,state);
}
@ -83,6 +97,21 @@ void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState stat
}
}
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state){
LinphoneCore *lc=lev->lc;
if (lev->publish_state!=state){
ms_message("LinphoneEvent [%p] moving to publish state %s",lev,linphone_publish_state_to_string(state));
lev->publish_state=state;
if (lc->vtable.publish_state_changed){
lc->vtable.publish_state_changed(lev->lc,lev,state);
}
}
}
LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){
return lev->publish_state;
}
void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason){
lev->reason=reason;
}
@ -105,7 +134,7 @@ LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *
int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
SalBody salbody;
if (lev->state!=LinphoneSubscriptionActive){
if (lev->subscription_state!=LinphoneSubscriptionActive){
ms_error("linphone_event_update_subscribe(): cannot update subscription if subscription wasn't accepted.");
return -1;
}
@ -118,7 +147,7 @@ int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *b
int linphone_event_accept_subscription(LinphoneEvent *lev){
int err;
if (lev->state!=LinphoneSubscriptionIncomingReceived){
if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
ms_error("linphone_event_accept_subscription(): cannot accept subscription if subscription wasn't just received.");
return -1;
}
@ -131,7 +160,7 @@ int linphone_event_accept_subscription(LinphoneEvent *lev){
int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){
int err;
if (lev->state!=LinphoneSubscriptionIncomingReceived){
if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received.");
return -1;
}
@ -142,7 +171,7 @@ int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){
int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
SalBody salbody;
if (lev->state!=LinphoneSubscriptionActive){
if (lev->subscription_state!=LinphoneSubscriptionActive){
ms_error("linphone_event_notify(): cannot notify if subscription is not active.");
return -1;
}
@ -155,17 +184,30 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *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);
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));
sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body));
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){
SalBody salbody;
return sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body));
int err;
err=sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body));
if (err==0){
linphone_event_set_publish_state(lev,LinphonePublishProgress);
}else{
linphone_event_set_publish_state(lev,LinphonePublishError);
}
return err;
}
void linphone_event_set_user_data(LinphoneEvent *ev, void *up){
@ -177,15 +219,25 @@ void *linphone_event_get_user_data(const LinphoneEvent *ev){
}
void linphone_event_terminate(LinphoneEvent *lev){
lev->terminating=TRUE;
if (lev->dir==LinphoneSubscriptionIncoming){
sal_notify_close(lev->op);
}else if (lev->dir==LinphoneSubscriptionOutgoing){
sal_unsubscribe(lev->op);
}
if (lev->state!=LinphoneSubscriptionNone){
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
if (lev->publish_state!=LinphonePublishNone){
if (lev->publish_state==LinphonePublishOk){
sal_publish(lev->op,NULL,NULL,NULL,0,NULL);
}
return;
}
if (lev->subscription_state!=LinphoneSubscriptionNone){
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
return;
}
}
@ -213,7 +265,7 @@ LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev){
}
LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev){
return lev->state;
return lev->subscription_state;
}
const char *linphone_event_get_name(const LinphoneEvent *lev){

View file

@ -26,6 +26,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
struct _LinphoneEvent;
/**
* Object representing an event state, which is subcribed or published.
* @see linphone_core_publish()
* @see linphone_core_subscribe()
**/
typedef struct _LinphoneEvent LinphoneEvent;
/**
@ -55,8 +60,32 @@ enum _LinphoneSubscriptionState{
LinphoneSubscriptionError /**<Subscription encountered an error, indicated by linphone_event_get_reason()*/
};
/**
* Typedef for subscription state enum.
**/
typedef enum _LinphoneSubscriptionState LinphoneSubscriptionState;
LINPHONE_PUBLIC const char *linphone_subscription_state_to_string(LinphoneSubscriptionState state);
/**
* Enum for publish states.
**/
enum _LinphonePublishState{
LinphonePublishNone, /**< Initial state, do not use**/
LinphonePublishProgress, /**<An outgoing subcription was created*/
LinphonePublishOk, /**<Publish is accepted.*/
LinphonePublishError, /**<Publish encoutered an error, linphone_event_get_reason() gives reason code*/
LinphonePublishExpiring, /**<Publish is about to expire, only sent if [sip]->refresh_generic_publish property is set to 0.*/
LinphonePublishCleared /**<Event has been un published*/
};
/**
* Typedef for publish state enum
**/
typedef enum _LinphonePublishState LinphonePublishState;
LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishState state);
/**
* Callback prototype for notifying the application about notification received from the network.
**/
@ -67,6 +96,11 @@ typedef void (*LinphoneEventIncomingNotifyCb)(LinphoneCore *lc, LinphoneEvent *l
**/
typedef void (*LinphoneSubscriptionStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state);
/**
* Callback prototype for notifying the application about changes of publish states.
**/
typedef void (*LinphonePublishStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state);
/**
* 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.
@ -105,7 +139,7 @@ LINPHONE_PUBLIC int linphone_event_notify(LinphoneEvent *lev, const LinphoneCont
/**
* Publish an event.
* Publish an event state.
* After expiry, the publication is refreshed unless it is terminated before.
* @param lc the #LinphoneCore
* @param resource the resource uri for the event
@ -134,6 +168,11 @@ LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *le
**/
LINPHONE_PUBLIC LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev);
/**
* Get publish state. If the event object was not created by a publish mechanism, #LinphonePublishNone is returned.
**/
LINPHONE_PUBLIC LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev);
/**
* Get subscription direction.
* If the object wasn't created by a subscription mechanism, #LinphoneSubscriptionInvalidDir is returned.
@ -152,17 +191,26 @@ LINPHONE_PUBLIC void *linphone_event_get_user_data(const LinphoneEvent *ev);
/**
* 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.
*
* For subscribed event, when the subscription is terminated normally or because of an error, the core will unref.
* For published events, no unref is performed. This is because it is allowed to re-publish an expired publish, as well as retry it in case of error.
**/
LINPHONE_PUBLIC void linphone_event_terminate(LinphoneEvent *lev);
/**
* Increase reference count.
* Increase reference count of LinphoneEvent.
* By default LinphoneEvents created by the core are owned by the core only.
* An application that wishes to retain a reference to it must call linphone_event_ref().
* When this reference is no longer needed, linphone_event_unref() must be called.
*
**/
LINPHONE_PUBLIC LinphoneEvent *linphone_event_ref(LinphoneEvent *lev);
/**
* Decrease reference count.
* @see linphone_event_ref()
**/
LINPHONE_PUBLIC void linphone_event_unref(LinphoneEvent *lev);

View file

@ -273,12 +273,17 @@ LINPHONE_PUBLIC const rtp_stats_t *linphone_call_log_get_remote_stats(const Linp
LINPHONE_PUBLIC const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl);
LINPHONE_PUBLIC char * linphone_call_log_to_str(LinphoneCallLog *cl);
/**
* Private structure definition for LinphoneCallParams.
* @ingroup call_control
**/
struct _LinphoneCallParams;
/**
* The LinphoneCallParams is an object containing various call related parameters.
* It can be used to retrieve parameters from a currently running call or modify the call's characteristics
* dynamically.
* @ingroup call_control
**/
typedef struct _LinphoneCallParams LinphoneCallParams;
@ -1033,6 +1038,7 @@ typedef struct _LinphoneVTable{
LinphoneInfoReceivedCb info_received; /**<Notifies an incoming informational message received.*/
LinphoneSubscriptionStateChangedCb subscription_state_changed; /**<Notifies subscription state change */
LinphoneEventIncomingNotifyCb notify_received; /**< Notifies a an event notification, see linphone_core_subscribe() */
LinphonePublishStateChangedCb publish_state_changed;/**Notifies publish state change (only from #LinphoneEvent api)*/
DisplayStatusCb display_status; /**< @deprecated Callback that notifies various events with human readable text.*/
DisplayMessageCb display_message;/**< @deprecated Callback to display a message to the user */
DisplayMessageCb display_warning;/**< @deprecated Callback to display a warning to the user */

View file

@ -652,6 +652,23 @@ struct _LinphoneCore
#endif //BUILD_UPNP
};
struct _LinphoneEvent{
LinphoneSubscriptionDir dir;
LinphoneCore *lc;
SalOp *op;
LinphoneSubscriptionState subscription_state;
LinphonePublishState publish_state;
LinphoneReason reason;
void *userdata;
int refcnt;
char *name;
LinphoneAddress *from;
LinphoneAddress *resource_addr;
bool_t terminating;
};
LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc);
void linphone_tunnel_destroy(LinphoneTunnel *tunnel);
void linphone_tunnel_configure(LinphoneTunnel *tunnel);
@ -759,6 +776,7 @@ LinphoneReason linphone_reason_from_sal(SalReason reason);
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name);
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);
void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason);
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss);
const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref);

View file

@ -369,6 +369,8 @@ typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from);
typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from);
typedef void (*SalOnPingReply)(SalOp *salop);
typedef void (*SalOnInfoReceived)(SalOp *salop, const SalBody *body);
typedef void (*SalOnPublishResponse)(SalOp *salop, SalError error, SalReason reason);
typedef void (*SalOnExpire)(SalOp *salop);
/*allows sal implementation to access auth info if available, return TRUE if found*/
@ -408,6 +410,8 @@ typedef struct SalCallbacks{
SalOnPingReply ping_reply;
SalOnAuthRequested auth_requested;
SalOnInfoReceived info_received;
SalOnPublishResponse on_publish_response;
SalOnExpire on_expire;
}SalCallbacks;
@ -446,6 +450,7 @@ void sal_verify_server_certificates(Sal *ctx, bool_t verify);
void sal_verify_server_cn(Sal *ctx, bool_t verify);
void sal_set_uuid(Sal*ctx, const char *uuid);
int sal_create_uuid(Sal*ctx, char *uuid, size_t len);
void sal_enable_test_features(Sal*ctx, bool_t enabled);
int sal_iterate(Sal *sal);
MSList * sal_get_pending_auths(Sal *sal);

View file

@ -20,6 +20,7 @@
#include "CUnit/Basic.h"
#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"
#include <event.h>
#include "liblinphone_tester.h"
@ -78,6 +79,20 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li
}
}
void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){
stats* counters = get_stats(lc);
switch(state){
case LinphonePublishProgress: counters->number_of_LinphonePublishProgress++; break;
case LinphonePublishOk: counters->number_of_LinphonePublishOk++; break;
case LinphonePublishError: counters->number_of_LinphonePublishError++; break;
case LinphonePublishExpiring: counters->number_of_LinphonePublishExpiring++; break;
case LinphonePublishCleared: counters->number_of_LinphonePublishCleared++;break;
default:
break;
}
}
static void subscribe_test_declined(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
@ -151,17 +166,68 @@ static void subscribe_test_terminated_by_notifier(void){
subscribe_test_with_args(FALSE);
}
test_t subscribe_tests[] = {
static void publish_test_with_args(bool_t refresh){
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneContent content;
LinphoneEvent *lev;
MSList* lcs=ms_list_append(NULL,marie->lc);
lcs=ms_list_append(lcs,pauline->lc);
content.type="application";
content.subtype="somexml";
content.data=(char*)subscribe_content;
content.size=strlen(subscribe_content);
lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",!refresh);
lev=linphone_core_publish(marie->lc,pauline->identity,"dodo",5,&content);
linphone_event_ref(lev);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,1000));
if (!refresh){
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishExpiring,1,5000));
linphone_event_update_publish(lev,&content);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,1000));
}else{
}
linphone_event_terminate(lev);
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishCleared,1,1000));
linphone_event_unref(lev);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void publish_test(){
publish_test_with_args(TRUE);
}
static void publish_no_auto_test(){
publish_test_with_args(FALSE);
}
test_t event_tests[] = {
{ "Subscribe declined" , subscribe_test_declined },
{ "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber },
{ "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }
{ "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier },
{ "Publish", publish_test },
{ "Publish without automatic refresh",publish_no_auto_test }
};
test_suite_t subscribe_test_suite = {
"Subscribe",
test_suite_t event_test_suite = {
"Event",
NULL,
NULL,
sizeof(subscribe_tests) / sizeof(subscribe_tests[0]),
subscribe_tests
sizeof(event_tests) / sizeof(event_tests[0]),
event_tests
};

View file

@ -106,7 +106,7 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char*
lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL);
sal_enable_test_features(lc->sal,TRUE);
#ifndef ANDROID
snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cacert.pem", path);
#else
@ -190,6 +190,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f
mgr->v_table.info_received=info_message_received;
mgr->v_table.subscription_state_changed=linphone_subscription_state_change;
mgr->v_table.notify_received=linphone_notify_received;
mgr->v_table.publish_state_changed=linphone_publish_state_changed;
mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_file);
linphone_core_set_user_data(mgr->lc,mgr);
reset_counters(&mgr->stat);
@ -311,7 +312,7 @@ void liblinphone_tester_init(void) {
#ifdef UPNP
add_test_suite(&upnp_test_suite);
#endif
add_test_suite(&subscribe_test_suite);
add_test_suite(&event_test_suite);
}
void liblinphone_tester_uninit(void) {

View file

@ -51,7 +51,7 @@ extern test_suite_t call_test_suite;
extern test_suite_t message_test_suite;
extern test_suite_t presence_test_suite;
extern test_suite_t upnp_test_suite;
extern test_suite_t subscribe_test_suite;
extern test_suite_t event_test_suite;
extern int liblinphone_tester_nb_test_suites(void);
@ -164,6 +164,11 @@ typedef struct _stats {
int number_of_LinphoneSubscriptionTerminated;
int number_of_LinphoneSubscriptionError;
int number_of_LinphonePublishProgress;
int number_of_LinphonePublishOk;
int number_of_LinphonePublishExpiring;
int number_of_LinphonePublishError;
int number_of_LinphonePublishCleared;
}stats;
typedef struct _LinphoneCoreManager {
@ -192,6 +197,7 @@ void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneI
void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state);
void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state);
void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content);
LinphoneAddress * create_linphone_address(const char * domain);

View file

@ -12,6 +12,8 @@ COMMON_CFLAGS=\
$(STRICT_OPTIONS) \
$(LIBXML2_CFLAGS)
AM_CXXFLAGS=$(LIBXML2_CFLAGS)
EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc
if BUILD_TOOLS
@ -39,7 +41,7 @@ liblpc2xml_la_LIBADD=\
libxml2lpc_la_LDFLAGS=-no-undefined
liblpc2xml_la_LDFLAGS=-no-undefined
bin_PROGRAMS=xml2lpc_test lpc2xml_test
bin_PROGRAMS=xml2lpc_test lpc2xml_test lp-gen-wrappers
xml2lpc_test_SOURCES=\
xml2lpc_test.c
@ -55,7 +57,13 @@ xml2lpc_test_LDADD=\
lpc2xml_test_CFLAGS=$(COMMON_CFLAGS)
lpc2xml_test_LDADD=\
$(top_builddir)/coreapi/liblinphone.la \
liblpc2xml.la
liblpc2xml.la
lp_gen_wrappers_SOURCES=genwrappers.cc
lp_gen_wrappers_LDADD= \
$(LIBXML2_LIBS)
endif

356
tools/genwrappers.cc Normal file
View file

@ -0,0 +1,356 @@
/*
linphone
Copyright (C) 2013 Belledonne Communications SARL
Simon Morlat (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>
#include <cstdio>
#include <iostream>
#include <list>
#include <map>
using namespace::std;
class Type{
public:
enum BasicType{
Integer,
String,
Klass
};
static Type *getType(const std::string &tname){
if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){
return &sStringType;
}else if (strcmp(tname.c_str(),"int")==0){
return &sIntegerType;
}else{
Type* ret;
string tmp=tname;
ssize_t pos;
/*really ugly and slow*/
pos=tmp.find('*');
if (pos!=string::npos)
tmp.erase(pos,1);
pos=tmp.find("const");
if (pos!=string::npos)
tmp.erase(pos,strlen("const"));
while ((pos=tmp.find(' '))!=string::npos){
tmp.erase(pos,1);
}
if ((ret=mTypes[tmp])==0){
cout<<"Adding new class type '"<<tmp<<"'"<<endl;
ret=mTypes[tmp]=new Type(Type::Klass,tmp);
}
return ret;
}
cout<<"Unhandled type name"<<tname<<endl;
return NULL;
}
const string &getName()const{
return mName;
}
private:
BasicType mBasic;
string mName;
Type(BasicType basic, const std::string &tname="") : mBasic(basic), mName(tname){
}
static Type sStringType;
static Type sIntegerType;
static std::map<string,Type*> mTypes;
};
Type Type::sStringType(Type::String);
Type Type::sIntegerType(Type::Integer);
std::map<string,Type*> Type::mTypes;
class Argument{
public:
Argument(Type *type, const string &argname, bool isConst) : mType(type), mName(argname), mConst(isConst){
}
Type *getType()const{
return mType;
}
private:
bool mConst;
Type *mType;
string mName;
string mHelp;
};
class Method{
public:
Method(const std::string &uid, Argument* return_arg, const std::string &name, const list<Argument*> &args){
mUid=uid;
mReturn=return_arg;
mName=name;
mArgs=args;
}
void setHelp(const std::string &help){
mHelp=help;
}
private:
string mUid;
Argument *mReturn;
string mName;
list<Argument*> mArgs;
string mHelp;
};
class Class{
public:
Class(const std::string &name): mName(name){
}
void addMethod(Method *method){
mMethods.push_back(method);
}
void setHelp(const std::string &help){
mHelp=help;
}
private:
list<Method*> mMethods;
string mName;
string mHelp;
};
class Project{
public:
Class *getClass(const std::string &name){
Class *ret;
if ((ret=mClasses[name])==NULL){
ret=mClasses[name]=new Class(name);
}
return ret;
}
private:
map<string,Class*> mClasses;
};
static xmlNode * findChild(xmlNode *a_node, const char *element_name){
xmlNode *cur_node;
for (cur_node = a_node->children; cur_node != NULL ; cur_node = cur_node->next){
if (strcmp((const char*)cur_node->name,(const char*)element_name)==0){
return cur_node;
}
}
return NULL;
}
static bool isSpace(const char *str){
for(;*str!='\0';++str){
if (!isspace(*str)) return false;
}
return true;
}
static string findChildContent(xmlNode *a_node, const char *element_name){
xmlNode *node=findChild(a_node,element_name);
string res;
if (node) {
xmlChar *text=xmlNodeGetContent(node);
if (!isSpace((const char*)text))
res=(char*)text;
xmlFree(text);
}
return res;
}
#define nullOrEmpty(p) (p==NULL || *p=='\0')
static Argument *parseArgument(xmlNode *node){
string name=findChildContent(node,"name");
xmlNode *typenode=findChild(node,"type");
if (!typenode) {
cout<<"Cannot find type from node."<<endl;
return NULL;
}
string tname=findChildContent(typenode,"ref");
if (tname.empty()){
return NULL;
}
Type *type=Type::getType(tname);
if (type==NULL) {
return NULL;
}
return new Argument(type,name,false);
}
static string classNameToPrefix(const std::string &classname){
char tmp[classname.size()*2];
char *w=tmp;
ssize_t i;
for(i=0;i<classname.size();i++){
char p=classname[i];
if (isupper(p)){
if (i!=0){
*w++='_';
}
*w++=tolower(p);
}else *w++=p;
}
*w++='\0';
return tmp;
}
static string makeMethodName(const string & suffix){
char tmp[suffix.size()];
char *w=tmp;
ssize_t i;
bool useUpper=false;
for(i=0;i<suffix.size();i++){
char p=suffix[i];
if (p=='_'){
if (i>0)
useUpper=true;
}else{
if (useUpper)
*w++=toupper(p);
else
*w++=p;
useUpper=false;
}
}
*w++='\0';
return tmp;
}
static string extractMethodName(const string &c_name, const std::string& class_name){
string prefix=classNameToPrefix(class_name);
if (c_name.find(prefix)==0){
return makeMethodName(c_name.substr(prefix.size(),string::npos));
}
return "";
}
static void parseFunction(Project *proj, xmlNode *node){
string name;
Argument *first_arg=NULL;
xmlNode *cur_node;
string className;
string methodName;
for (cur_node = node->children; cur_node != NULL ; cur_node = cur_node->next){
if (strcmp((const char*)cur_node->name,"name")==0){
xmlChar *content=xmlNodeGetContent(cur_node);
name=(const char*)content;
xmlFree(content);
}else if (strcmp((const char*)cur_node->name,"param")==0){
if (first_arg==NULL){
first_arg=parseArgument(cur_node);
}
}
}
if (!first_arg){
cout<<"Could not determine first argument of "<<name<<endl;
return;
}
className=first_arg->getType()->getName();
methodName=extractMethodName(name,className);
if (!methodName.empty()){
cout<<"Found "<<className<<"."<<methodName<<"()"<<endl;
}
}
static void parseMemberDef(Project *proj, xmlNode *node){
string brief;
string detailed;
const xmlChar *kind;
brief=findChildContent(node,"briefdescription");
detailed=findChildContent(node,"detaileddescription");
if (brief.empty() && detailed.empty())
return;
kind=xmlGetProp(node,(const xmlChar*)"kind");
//cout<<"Kind="<<(const char*)kind<<endl;
if (kind && xmlStrcmp(kind,(const xmlChar*)"function")==0){
parseFunction(proj,node);
}
}
static void inspectNode(Project *proj, xmlNode *a_node){
xmlNode *cur_node;
for (cur_node = a_node; cur_node != NULL ; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
//printf("node type: Element, name: %s\n", cur_node->name);
if (strcmp((const char*)cur_node->name,"memberdef")==0 ){
//cout<<"Found memberdef"<<endl;
parseMemberDef(proj,cur_node);
}
}
if (cur_node->children) inspectNode(proj,cur_node->children);
}
}
static int parse_file(Project *proj, const char *filename){
xmlDoc *doc = NULL;
xmlNode *root_element = NULL;
/*parse the file and get the DOM */
doc = xmlReadFile(filename, NULL, 0);
if (doc == NULL) {
cerr<<"xmlReadFile failed."<<endl;
return -1;
}
/*Get the root element node */
root_element = xmlDocGetRootElement(doc);
inspectNode(proj,root_element);
/*free the document */
xmlFreeDoc(doc);
}
int main(int argc, char *argv[]){
int i;
Project *proj=new Project();
LIBXML_TEST_VERSION
for(i=1;i<argc;i++){
if (strcmp(argv[i],"--help")==0){
fprintf(stderr,"%s: [--help] file1 file2...\nParses xml files generated by doxygen to output wrappers in a specified language.\n",argv[0]);
return -1;
}else{
if (parse_file(proj,argv[i])==-1)
break;
}
}
return 0;
}