From fed415507fddb794d2110c3a4e022c12018229e5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Sep 2013 14:03:52 +0200 Subject: [PATCH] enhance event API to be notified of publish states. lp-gen-wrappers is in progress --- coreapi/bellesip_sal/sal_impl.c | 31 +- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_events.c | 3 +- coreapi/bellesip_sal/sal_op_impl.c | 9 +- coreapi/bellesip_sal/sal_op_presence.c | 2 +- coreapi/bellesip_sal/sal_op_publish.c | 32 +- coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/callbacks.c | 30 +- coreapi/event.c | 100 ++++-- coreapi/event.h | 52 ++- coreapi/linphonecore.h | 6 + coreapi/private.h | 18 ++ include/sal/sal.h | 5 + tester/eventapi_tester.c | 78 ++++- tester/liblinphone_tester.c | 5 +- tester/liblinphone_tester.h | 8 +- tools/Makefile.am | 12 +- tools/genwrappers.cc | 356 +++++++++++++++++++++ 18 files changed, 693 insertions(+), 57 deletions(-) create mode 100644 tools/genwrappers.cc diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 5ce18ab0b..d00ba86b7 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -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; +} + diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 4b9120196..371153ea5 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -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 { diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 6f20c1f92..be60a0b98 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -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); } } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index bf6b5f152..640664ecc 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -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 */ } } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index eef7d3916..85ecd4691 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -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: { diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index ce3490eac..f7788808c 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -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); } } - - diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index cfdedc9e5..a611af029 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -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) { diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e6f194532..7d437cf69 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -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 }; diff --git a/coreapi/event.c b/coreapi/event.c index 5f850e0de..9546e9e7b 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -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){ diff --git a/coreapi/event.h b/coreapi/event.h index 8ed3dae4b..fa97c2387 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -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 /**refresh_generic_publish property is set to 0.*/ + LinphonePublishCleared /** #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 }; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 25e91aa1e..a1115c8ce 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -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) { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 70aeaf83e..f9c58d725 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -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); diff --git a/tools/Makefile.am b/tools/Makefile.am index 8757ab27f..9f8233a80 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -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 diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc new file mode 100644 index 000000000..c506f6f71 --- /dev/null +++ b/tools/genwrappers.cc @@ -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 +#include +#include +#include +#include +#include +#include + + +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 '"< mTypes; +}; + +Type Type::sStringType(Type::String); +Type Type::sIntegerType(Type::Integer); +std::map 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 &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 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 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 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."<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 "<getType()->getName(); + methodName=extractMethodName(name,className); + if (!methodName.empty()){ + cout<<"Found "<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"<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."<