Merge branch 'dev_presence_list'

This commit is contained in:
Ghislain MARY 2015-12-18 15:01:10 +01:00
commit fb6d0dd135
42 changed files with 2050 additions and 538 deletions

View file

@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \
enum.c \
event.c \
friend.c \
friendlist.c \
info.c \
linphonecall.c \
linphonecore.c \

View file

@ -37,6 +37,7 @@ set(LINPHONE_HEADER_FILES
call_params.h
content.h
event.h
friendlist.h
linphonecore.h
linphonecore_utils.h
linphonefriend.h
@ -82,6 +83,7 @@ set(LINPHONE_SOURCE_FILES_C
enum.h
event.c
friend.c
friendlist.c
info.c
ldap/ldapprovider.c
lime.c

View file

@ -31,6 +31,7 @@ linphone_include_HEADERS=\
call_params.h \
content.h \
event.h \
friendlist.h \
linphonecore.h \
linphonecore_utils.h \
linphonefriend.h \
@ -63,6 +64,7 @@ liblinphone_la_SOURCES=\
enum.c enum.h \
event.c \
friend.c \
friendlist.c \
info.c \
ldap/ldapprovider.c ldap/ldapprovider.h \
linphonecall.c \

View file

@ -166,8 +166,7 @@ belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_reque
void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming);
void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body);
bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody);
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg);
SalReason sal_reason_to_sip_code(SalReason r);

View file

@ -669,15 +669,19 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
}
}else{
SalBody salbody;
if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) {
if (sal_body_has_type(&salbody,"application","dtmf-relay")){
belle_sip_message_t *msg = BELLE_SIP_MESSAGE(req);
belle_sip_body_handler_t *body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, msg));
if (body_handler) {
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t);
if (content_type
&& (strcmp(belle_sip_header_content_type_get_type(content_type), "application") == 0)
&& (strcmp(belle_sip_header_content_type_get_subtype(content_type), "dtmf-relay") == 0)) {
char tmp[10];
if (sal_lines_get_value(salbody.data, "Signal",tmp, sizeof(tmp))){
if (sal_lines_get_value(belle_sip_message_get_body(msg), "Signal",tmp, sizeof(tmp))){
op->base.root->callbacks.dtmf_received(op,tmp[0]);
}
}else
op->base.root->callbacks.info_received(op,&salbody);
op->base.root->callbacks.info_received(op, (SalBodyHandler *)body_handler);
} else {
op->base.root->callbacks.info_received(op,NULL);
}

View file

@ -77,7 +77,7 @@ static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_ev
static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
}
static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBody * body){
static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBodyHandler* body_handler){
SalSubscribeStatus sub_state;
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
belle_sip_response_t* resp;
@ -89,7 +89,7 @@ static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *event
} else
sub_state=SalSubscribeActive;
sal_op_ref(op);
op->base.root->callbacks.notify(op,sub_state,eventname,body);
op->base.root->callbacks.notify(op,sub_state,eventname,body_handler);
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
sal_op_unref(op);
@ -102,7 +102,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
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;
SalBody body;
belle_sip_body_handler_t *body_handler;
belle_sip_response_t* resp;
const char *eventname=NULL;
const char *method=belle_sip_request_get_method(req);
@ -112,7 +112,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
op->pending_server_trans=server_transaction;
event_header=belle_sip_message_get_header((belle_sip_message_t*)req,"Event");
sal_op_get_body(op,(belle_sip_message_t*)req,&body);
body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, BELLE_SIP_MESSAGE(req)));
if (event_header==NULL){
ms_warning("No event header in incoming SUBSCRIBE.");
@ -132,7 +132,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
belle_sip_dialog_set_application_data(op->dialog, sal_op_ref(op));
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
}else{ /*this is a NOTIFY*/
handle_notify(op,req,eventname,&body);
handle_notify(op, req, eventname, (SalBodyHandler *)body_handler);
return;
}
}
@ -140,7 +140,10 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL: {
op->base.root->callbacks.subscribe_received(op,eventname,body.type ? &body : NULL);
const char *type = NULL;
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t);
if (content_type) type = belle_sip_header_content_type_get_type(content_type);
op->base.root->callbacks.subscribe_received(op, eventname, type ? (SalBodyHandler *)body_handler : NULL);
break;
}
case BELLE_SIP_DIALOG_EARLY:
@ -149,7 +152,7 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
case BELLE_SIP_DIALOG_CONFIRMED:
if (strcmp("NOTIFY",method)==0) {
handle_notify(op,req,eventname,&body);
handle_notify(op, req, eventname, (SalBodyHandler *)body_handler);
} else if (strcmp("SUBSCRIBE",method)==0) {
/*either a refresh of an unsubscribe*/
if (expires && belle_sip_header_expires_get_expires(expires)>0) {
@ -185,7 +188,7 @@ void sal_op_subscribe_fill_cbs(SalOp*op) {
}
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){
belle_sip_request_t *req=NULL;
if (from)
@ -207,24 +210,33 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
sal_op_add_body(op,(belle_sip_message_t*)req,body);
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);
}else if (op->refresher){
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
/* modify last request to update body*/
sal_op_add_body(op,(belle_sip_message_t*)last_req,body);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_req), BELLE_SIP_BODY_HANDLER(body_handler));
return belle_sip_refresher_refresh(op->refresher,expires);
}
ms_warning("sal_subscribe(): no dialog and no refresher ?");
return -1;
}
int sal_subscribe_refresh(SalOp *op) {
if (op->refresher) {
belle_sip_refresher_refresh(op->refresher,belle_sip_refresher_get_expires(op->refresher));
return 0;
}
ms_warning("sal_refresh_subscribe(): no refresher");
return -1;
}
int sal_unsubscribe(SalOp *op){
if (op->refresher){
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
sal_op_add_body(op,(belle_sip_message_t*)last_req,NULL);
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0);
belle_sip_refresher_refresh(op->refresher,0);
return 0;
}
@ -247,7 +259,7 @@ int sal_subscribe_decline(SalOp *op, SalReason reason){
return 0;
}
int sal_notify(SalOp *op, const SalBody *body){
int sal_notify(SalOp *op, const SalBodyHandler *body_handler){
belle_sip_request_t* notify;
if (!op->dialog) return -1;
@ -258,8 +270,7 @@ int sal_notify(SalOp *op, const SalBody *body){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)));
sal_op_add_body(op,(belle_sip_message_t*)notify, body);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(notify), BELLE_SIP_BODY_HANDLER(body_handler));
return sal_op_send_request(op,notify);
}

View file

@ -706,50 +706,17 @@ const char *sal_op_get_remote_contact(const SalOp *op){
return op->base.remote_contact;
}
void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){
belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-type");
belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-length");
belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-encoding");
belle_sip_message_set_body((belle_sip_message_t*)req,NULL,0);
if (body && body->type && body->subtype && body->data){
belle_sip_message_add_header((belle_sip_message_t*)req,
(belle_sip_header_t*)belle_sip_header_content_type_create(body->type,body->subtype));
belle_sip_message_add_header((belle_sip_message_t*)req,
(belle_sip_header_t*)belle_sip_header_content_length_create(body->size));
belle_sip_message_set_body((belle_sip_message_t*)req,(const char*)body->data,body->size);
if (body->encoding){
belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)
belle_sip_header_create("Content-encoding",body->encoding));
}
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg) {
belle_sip_body_handler_t *body_handler = belle_sip_message_get_body_handler(msg);
if (body_handler != NULL) {
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t);
belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_length_t);
belle_sip_header_t *content_encoding = belle_sip_message_get_header(msg, "Content-Encoding");
if (content_type != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_type));
if (content_length != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_length));
if (content_encoding != NULL) belle_sip_body_handler_add_header(body_handler, content_encoding);
}
}
bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody){
const char *body = NULL;
belle_sip_header_content_type_t *content_type;
belle_sip_header_content_length_t *clen=NULL;
belle_sip_header_t *content_encoding;
content_type=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_type_t);
if (content_type){
body=belle_sip_message_get_body(msg);
clen=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_length_t);
}
content_encoding=belle_sip_message_get_header(msg,"Content-encoding");
memset(salbody,0,sizeof(SalBody));
if (content_type && body && clen) {
salbody->type=belle_sip_header_content_type_get_type(content_type);
salbody->subtype=belle_sip_header_content_type_get_subtype(content_type);
salbody->data=body;
salbody->size=belle_sip_header_content_length_get_content_length(clen);
if (content_encoding)
salbody->encoding=belle_sip_header_get_unparsed_value(content_encoding);
return TRUE;
}
return FALSE;
return (SalBodyHandler *)body_handler;
}
void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) {

View file

@ -19,12 +19,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sal_impl.h"
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBodyHandler *body_handler){
if (op->dialog){
belle_sip_request_t *req;
belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking);
req=belle_sip_dialog_create_queued_request(op->dialog,"INFO");
sal_op_add_body(op,(belle_sip_message_t*)req,body);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
return sal_op_send_request(op,req);
}
return -1;

View file

@ -96,7 +96,7 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expire
}
}
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){
belle_sip_request_t *req=NULL;
if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) {
if (from)
@ -114,7 +114,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname));
sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
if (expires!=-1)
return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener);
else return sal_op_send_request(op,req);
@ -123,7 +123,11 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
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));
/*update body*/
sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? body : NULL);
if (expires == 0) {
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_publish), NULL, 0);
} else {
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_publish), BELLE_SIP_BODY_HANDLER(body_handler));
}
return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires);
}
}

View file

@ -144,4 +144,4 @@ LINPHONE_PUBLIC bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer);
}
#endif
#endif /* LINPHONE_CONTENT_H_ */
#endif /* LINPHONE_BUFFER_H_ */

View file

@ -1122,7 +1122,7 @@ static void is_composing_received(SalOp *op, const SalIsComposing *is_composing)
}
static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
linphone_notify_parse_presence(op, content_type, content_subtype, body, result);
linphone_notify_parse_presence(content_type, content_subtype, body, result);
}
static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) {
@ -1276,9 +1276,9 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
}
}
static void info_received(SalOp *op, const SalBody *body){
static void info_received(SalOp *op, SalBodyHandler *body_handler){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_core_notify_info_message(lc,op,body);
linphone_core_notify_info_message(lc,op,body_handler);
}
static void subscribe_response(SalOp *op, SalSubscribeStatus status){
@ -1299,7 +1299,7 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status){
}
}
static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, const SalBody *body){
static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, SalBodyHandler *body_handler){
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
@ -1308,15 +1308,18 @@ static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, cons
lev=linphone_event_new_with_out_of_dialog_op(lc,op,LinphoneSubscriptionOutgoing,eventname);
}
{
LinphoneContent *ct=linphone_content_from_sal_body(body);
if (ct) linphone_core_notify_notify_received(lc,lev,eventname,ct);
LinphoneContent *ct=linphone_content_from_sal_body_handler(body_handler);
if (ct) {
linphone_core_notify_notify_received(lc,lev,eventname,ct);
linphone_content_unref(ct);
}
}
if (st!=SalSubscribeNone){
linphone_event_set_state(lev,linphone_subscription_state_from_sal(st));
}
}
static void subscribe_received(SalOp *op, const char *eventname, const SalBody *body){
static void subscribe_received(SalOp *op, const char *eventname, const SalBodyHandler *body_handler){
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));

View file

@ -22,23 +22,46 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void linphone_content_set_sal_body_handler(LinphoneContent *content, SalBodyHandler *body_handler) {
if (content->body_handler != NULL) {
sal_body_handler_unref(content->body_handler);
content->body_handler = NULL;
}
content->body_handler = sal_body_handler_ref(body_handler);
}
static LinphoneContent * linphone_content_new_with_body_handler(SalBodyHandler *body_handler) {
LinphoneContent *content = belle_sip_object_new(LinphoneContent);
belle_sip_object_ref(content);
content->owned_fields = TRUE;
content->cryptoContext = NULL; /* this field is managed externally by encryption/decryption functions so be careful to initialise it to NULL */
if (body_handler == NULL) {
linphone_content_set_sal_body_handler(content, sal_body_handler_new());
} else {
linphone_content_set_sal_body_handler(content, body_handler);
}
return content;
}
static void linphone_content_destroy(LinphoneContent *content) {
if (content->owned_fields == TRUE) {
if (content->lcp.type) belle_sip_free(content->lcp.type);
if (content->lcp.subtype) belle_sip_free(content->lcp.subtype);
if (content->lcp.data) belle_sip_free(content->lcp.data);
if (content->lcp.encoding) belle_sip_free(content->lcp.encoding);
if (content->lcp.name) belle_sip_free(content->lcp.name);
if (content->lcp.key) belle_sip_free(content->lcp.key);
if (content->body_handler) sal_body_handler_unref(content->body_handler);
if (content->name) belle_sip_free(content->name);
if (content->key) belle_sip_free(content->key);
/* note : crypto context is allocated/destroyed by the encryption function */
}
}
static void linphone_content_clone(LinphoneContent *obj, const LinphoneContent *ref) {
obj->owned_fields = TRUE;
linphone_content_set_type(obj, linphone_content_get_type(ref));
linphone_content_set_subtype(obj, linphone_content_get_subtype(ref));
linphone_content_set_encoding(obj, linphone_content_get_encoding(ref));
linphone_content_set_sal_body_handler(obj, sal_body_handler_new());
if ((linphone_content_get_type(ref) != NULL) || (linphone_content_get_subtype(ref) != NULL)) {
linphone_content_set_type(obj, linphone_content_get_type(ref));
linphone_content_set_subtype(obj, linphone_content_get_subtype(ref));
}
if (linphone_content_get_encoding(ref) != NULL) {
linphone_content_set_encoding(obj, linphone_content_get_encoding(ref));
}
linphone_content_set_name(obj, linphone_content_get_name(ref));
linphone_content_set_key(obj, linphone_content_get_key(ref), linphone_content_get_key_size(ref));
if (linphone_content_get_buffer(ref) != NULL) {
@ -81,163 +104,136 @@ void linphone_content_set_user_data(LinphoneContent *content, void *ud) {
}
const char * linphone_content_get_type(const LinphoneContent *content) {
return content->lcp.type;
return sal_body_handler_get_type(content->body_handler);
}
void linphone_content_set_type(LinphoneContent *content, const char *type) {
if (content->lcp.type != NULL) {
belle_sip_free(content->lcp.type);
content->lcp.type = NULL;
}
if (type != NULL) {
content->lcp.type = belle_sip_strdup(type);
}
sal_body_handler_set_type(content->body_handler, type);
}
const char * linphone_content_get_subtype(const LinphoneContent *content) {
return content->lcp.subtype;
return sal_body_handler_get_subtype(content->body_handler);
}
void linphone_content_set_subtype(LinphoneContent *content, const char *subtype) {
if (content->lcp.subtype != NULL) {
belle_sip_free(content->lcp.subtype);
content->lcp.subtype = NULL;
}
if (subtype != NULL) {
content->lcp.subtype = belle_sip_strdup(subtype);
}
sal_body_handler_set_subtype(content->body_handler, subtype);
}
void * linphone_content_get_buffer(const LinphoneContent *content) {
return content->lcp.data;
return sal_body_handler_get_data(content->body_handler);
}
void linphone_content_set_buffer(LinphoneContent *content, const void *buffer, size_t size) {
content->lcp.size = size;
content->lcp.data = belle_sip_malloc(size + 1);
memcpy(content->lcp.data, buffer, size);
((char *)content->lcp.data)[size] = '\0';
void *data;
sal_body_handler_set_size(content->body_handler, size);
data = belle_sip_malloc(size + 1);
memcpy(data, buffer, size);
((char *)data)[size] = '\0';
sal_body_handler_set_data(content->body_handler, data);
}
const char * linphone_content_get_string_buffer(const LinphoneContent *content) {
return (char *)content->lcp.data;
return (const char *)linphone_content_get_buffer(content);
}
void linphone_content_set_string_buffer(LinphoneContent *content, const char *buffer) {
content->lcp.size = strlen(buffer);
content->lcp.data = belle_sip_strdup(buffer);
sal_body_handler_set_size(content->body_handler, strlen(buffer));
sal_body_handler_set_data(content->body_handler, belle_sip_strdup(buffer));
}
size_t linphone_content_get_size(const LinphoneContent *content) {
return content->lcp.size;
return sal_body_handler_get_size(content->body_handler);
}
void linphone_content_set_size(LinphoneContent *content, size_t size) {
content->lcp.size = size;
sal_body_handler_set_size(content->body_handler, size);
}
const char * linphone_content_get_encoding(const LinphoneContent *content) {
return content->lcp.encoding;
return sal_body_handler_get_encoding(content->body_handler);
}
void linphone_content_set_encoding(LinphoneContent *content, const char *encoding) {
if (content->lcp.encoding != NULL) {
belle_sip_free(content->lcp.encoding);
content->lcp.encoding = NULL;
}
if (encoding != NULL) {
content->lcp.encoding = belle_sip_strdup(encoding);
}
sal_body_handler_set_encoding(content->body_handler, encoding);
}
const char * linphone_content_get_name(const LinphoneContent *content) {
return content->lcp.name;
return content->name;
}
void linphone_content_set_name(LinphoneContent *content, const char *name) {
if (content->lcp.name != NULL) {
belle_sip_free(content->lcp.name);
content->lcp.name = NULL;
if (content->name != NULL) {
belle_sip_free(content->name);
content->name = NULL;
}
if (name != NULL) {
content->lcp.name = belle_sip_strdup(name);
content->name = belle_sip_strdup(name);
}
}
size_t linphone_content_get_key_size(const LinphoneContent *content) {
return content->lcp.keyLength;
return content->keyLength;
}
const char * linphone_content_get_key(const LinphoneContent *content) {
return content->lcp.key;
return content->key;
}
void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength) {
if (content->lcp.key != NULL) {
belle_sip_free(content->lcp.key);
content->lcp.key = NULL;
if (content->key != NULL) {
belle_sip_free(content->key);
content->key = NULL;
}
if (key != NULL) {
content->lcp.key = belle_sip_malloc(keyLength);
memcpy(content->lcp.key, key, keyLength);
content->key = belle_sip_malloc(keyLength);
memcpy(content->key, key, keyLength);
}
}
/* crypto context is managed(allocated/freed) by the encryption function, so provide the address of field in the private structure */
void ** linphone_content_get_cryptoContext_address(LinphoneContent *content) {
return &(content->lcp.cryptoContext);
return &(content->cryptoContext);
}
bool_t linphone_content_is_multipart(const LinphoneContent *content) {
return sal_body_handler_is_multipart(content->body_handler);
}
LinphoneContent * linphone_content_get_part(const LinphoneContent *content, int idx) {
SalBodyHandler *part_body_handler;
if (!linphone_content_is_multipart(content)) return NULL;
part_body_handler = sal_body_handler_get_part(content->body_handler, idx);
return linphone_content_from_sal_body_handler(part_body_handler);
}
LinphoneContent * linphone_content_find_part_by_header(const LinphoneContent *content, const char *header_name, const char *header_value) {
SalBodyHandler *part_body_handler;
if (!linphone_content_is_multipart(content)) return NULL;
part_body_handler = sal_body_handler_find_part_by_header(content->body_handler, header_name, header_value);
return linphone_content_from_sal_body_handler(part_body_handler);
}
const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name) {
return sal_body_handler_get_header(content->body_handler, header_name);
}
LinphoneContent * linphone_content_new(void) {
LinphoneContent *content = belle_sip_object_new(LinphoneContent);
belle_sip_object_ref(content);
content->owned_fields = TRUE;
content->lcp.cryptoContext = NULL; /* this field is managed externally by encryption/decryption functions so be careful to initialise it to NULL */
return content;
return linphone_content_new_with_body_handler(NULL);
}
LinphoneContent * linphone_content_copy(const LinphoneContent *ref) {
return (LinphoneContent *)belle_sip_object_ref(belle_sip_object_clone(BELLE_SIP_OBJECT(ref)));
}
LinphoneContent * linphone_content_from_sal_body(const SalBody *ref) {
if (ref && ref->type) {
LinphoneContent *content = linphone_content_new();
linphone_content_set_type(content, ref->type);
linphone_content_set_subtype(content, ref->subtype);
linphone_content_set_encoding(content, ref->encoding);
if (ref->data != NULL) {
linphone_content_set_buffer(content, ref->data, ref->size);
} else {
linphone_content_set_size(content, ref->size);
}
return content;
LinphoneContent * linphone_content_from_sal_body_handler(SalBodyHandler *body_handler) {
if (body_handler) {
return linphone_content_new_with_body_handler(body_handler);
}
return NULL;
}
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *content) {
if (content && linphone_content_get_type(content)) {
body->type = linphone_content_get_type(content);
body->subtype = linphone_content_get_subtype(content);
body->data = linphone_content_get_buffer(content);
body->size = linphone_content_get_size(content);
body->encoding = linphone_content_get_encoding(content);
return body;
}
return NULL;
}
LinphoneContent * linphone_content_private_to_linphone_content(const LinphoneContentPrivate *lcp) {
LinphoneContent *content = belle_sip_object_new(LinphoneContent);
memcpy(&content->lcp, lcp, sizeof(LinphoneContentPrivate));
content->owned_fields = FALSE;
return content;
}
LinphoneContentPrivate * linphone_content_to_linphone_content_private(const LinphoneContent *content) {
return (LinphoneContentPrivate *)&content->lcp;
SalBodyHandler * sal_body_handler_from_content(const LinphoneContent *content) {
if (content == NULL) return NULL;
return content->body_handler;
}

View file

@ -40,51 +40,6 @@ struct _LinphoneContent;
**/
typedef struct _LinphoneContent LinphoneContent;
/**
* @deprecated Use LinphoneContent objects instead of this structure.
*/
struct _LinphoneContentPrivate{
char *type; /**<mime type for the data, for example "application"*/
char *subtype; /**<mime subtype for the data, for example "html"*/
void *data; /**<the actual data buffer, usually a string. Null when provided by callbacks #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferRecvCb*/
size_t size; /**<the size of the data buffer, excluding null character despite null character is always set for convenience.
When provided by callback #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferRecvCb, it states the total number of bytes of the transfered file*/
char *encoding; /**<The encoding of the data buffer, for example "gzip"*/
char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */
char *key; /**< used by RCS File transfer messages to store the key to encrypt file if needed */
size_t keyLength; /**< Length of key in bytes */
void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */
};
/**
* Alias to the LinphoneContentPrivate struct.
* @deprecated
**/
typedef struct _LinphoneContentPrivate LinphoneContentPrivate;
/**
* Convert a LinphoneContentPrivate structure to a LinphoneContent object.
* @deprecated Utility macro to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
*/
#define LINPHONE_CONTENT(lcp) linphone_content_private_to_linphone_content(lcp)
/**
* Convert a LinphoneContentPrivate structure to a LinphoneContent object.
* @deprecated Utility function to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
*/
LINPHONE_PUBLIC LinphoneContent * linphone_content_private_to_linphone_content(const LinphoneContentPrivate *lcp);
/**
* Convert a LinphoneContent object to a LinphoneContentPrivate structure.
* @deprecated Utility macro to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
*/
#define LINPHONE_CONTENT_PRIVATE(lc) linphone_content_to_linphone_content_private(lc)
/**
* Convert a LinphoneContent object to a LinphoneContentPrivate structure.
* @deprecated Utility function to ease porting existing code from LinphoneContentPrivate structure (old LinphoneContent structure) to new LinphoneContent object.
*/
LINPHONE_PUBLIC LinphoneContentPrivate * linphone_content_to_linphone_content_private(const LinphoneContent *content);
/**
* Create a content with default values from Linphone core.
@ -219,6 +174,38 @@ LINPHONE_PUBLIC const char * linphone_content_get_name(const LinphoneContent *co
*/
LINPHONE_PUBLIC void linphone_content_set_name(LinphoneContent *content, const char *name);
/**
* Tell whether a content is a multipart content.
* @param[in] content LinphoneContent object.
* @return A boolean value telling whether the content is multipart or not.
*/
LINPHONE_PUBLIC bool_t linphone_content_is_multipart(const LinphoneContent *content);
/**
* Get a part from a multipart content according to its index.
* @param[in] content LinphoneContent object.
* @param[in] idx The index of the part to get.
* @return A LinphoneContent object holding the part if found, NULL otherwise.
*/
LINPHONE_PUBLIC LinphoneContent * linphone_content_get_part(const LinphoneContent *content, int idx);
/**
* Find a part from a multipart content looking for a part header with a specified value.
* @param[in] content LinphoneContent object.
* @param[in] header_name The name of the header to look for.
* @param[in] header_value The value of the header to look for.
* @return A LinphoneContent object object the part if found, NULL otherwise.
*/
LINPHONE_PUBLIC LinphoneContent * linphone_content_find_part_by_header(const LinphoneContent *content, const char *header_name, const char *header_value);
/**
* Get a custom header value of a content.
* @param[in] content LinphoneContent object.
* @param[in] header_name The name of the header to get the value from.
* @return The value of the header if found, NULL otherwise.
*/
LINPHONE_PUBLIC const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name);
/**
* @}
*/

View file

@ -151,7 +151,7 @@ LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *
int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
SalBody salbody;
SalBodyHandler *body_handler;
int err;
if (lev->dir!=LinphoneSubscriptionOutgoing){
@ -179,7 +179,8 @@ int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *bod
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));
body_handler = sal_body_handler_from_content(body);
err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,body_handler);
if (err==0){
if (lev->subscription_state==LinphoneSubscriptionNone)
linphone_event_set_state(lev,LinphoneSubscriptionOutgoingInit);
@ -191,6 +192,10 @@ int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *b
return linphone_event_send_subscribe(lev,body);
}
int linphone_event_refresh_subscribe(LinphoneEvent *lev) {
return sal_subscribe_refresh(lev->op);
}
int linphone_event_accept_subscription(LinphoneEvent *lev){
int err;
if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
@ -216,7 +221,7 @@ int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){
}
int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
SalBody salbody;
SalBodyHandler *body_handler;
if (lev->subscription_state!=LinphoneSubscriptionActive){
ms_error("linphone_event_notify(): cannot notify if subscription is not active.");
return -1;
@ -225,7 +230,8 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
ms_error("linphone_event_notify(): cannot notify if not an incoming subscription.");
return -1;
}
return sal_notify(lev->op,sal_body_from_content(&salbody,body));
body_handler = sal_body_handler_from_content(body);
return sal_notify(lev->op, body_handler);
}
LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
@ -236,7 +242,7 @@ LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddr
}
static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){
SalBody salbody;
SalBodyHandler *body_handler;
int err;
if (lev->dir!=LinphoneSubscriptionInvalidDir){
@ -247,7 +253,8 @@ static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneConten
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_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
body_handler = sal_body_handler_from_content(body);
err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,body_handler);
if (err==0){
linphone_event_set_publish_state(lev,LinphonePublishProgress);
}else if (notify_err){

View file

@ -138,12 +138,19 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc,
LINPHONE_PUBLIC int linphone_event_send_subscribe(LinphoneEvent *ev, const LinphoneContent *body);
/**
* Update (refresh) an outgoing subscription.
* Update (refresh) an outgoing subscription, changing the body.
* @param lev a LinphoneEvent
* @param body an optional body to include in the subscription update, may be NULL.
**/
LINPHONE_PUBLIC int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body);
/**
* Refresh an outgoing subscription keeping the same body.
* @param lev LinphoneEvent object.
* @return 0 if successful, -1 otherwise.
*/
LINPHONE_PUBLIC int linphone_event_refresh_subscribe(LinphoneEvent *lev);
/**
* Accept an incoming subcription.

View file

@ -88,25 +88,6 @@ MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr,
return res;
}
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){
MSList *elem;
for (elem=l;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend*)elem->data;
if (ms_list_find(lf->insubs, op)) return lf;
}
return NULL;
}
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){
MSList *elem;
LinphoneFriend *lf;
for (elem=l;elem!=NULL;elem=elem->next){
lf=(LinphoneFriend*)elem->data;
if (lf->outsub && (lf->outsub == op || sal_op_is_forked_of(lf->outsub, op))) return lf;
}
return NULL;
}
void __linphone_friend_do_subscribe(LinphoneFriend *fr){
LinphoneCore *lc=fr->lc;
@ -259,19 +240,22 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){
}
}
static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
LinphoneCore *lc=lf->lc;
if (lf->outsub!=NULL) {
LinphoneCore *lc=lf->lc;
sal_op_release(lf->outsub);
lf->outsub=NULL;
lf->subscribe_active=FALSE;
/*notify application that we no longer know the presence activity */
if (lf->presence != NULL) {
linphone_presence_model_unref(lf->presence);
}
lf->presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,"unknown activity");
linphone_core_notify_notify_presence_received(lc,lf);
}
/* Notify application that we no longer know the presence activity */
if (lf->presence != NULL) {
linphone_presence_model_unref(lf->presence);
}
lf->presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,"unknown activity");
linphone_core_notify_notify_presence_received(lc,lf);
lf->initial_subscribes_sent=FALSE;
}
@ -405,6 +389,17 @@ const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend
return lf->presence;
}
void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence) {
if (lf->presence != NULL) {
linphone_presence_model_unref(lf->presence);
}
lf->presence = presence;
}
bool_t linphone_friend_is_presence_received(const LinphoneFriend *lf) {
return lf->presence_received;
}
BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){
return lf->info;
}
@ -467,8 +462,9 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
}
fr->inc_subscribe_pending=FALSE;
}
if (fr->lc)
linphone_friend_update_subscribes(fr,NULL,linphone_core_should_subscribe_friends_only_when_registered(fr->lc));
if (fr->lc) {
linphone_friend_list_update_subscriptions(fr->lc->friendlist, NULL, linphone_core_should_subscribe_friends_only_when_registered(fr->lc));
}
ms_message("linphone_friend_apply() done.");
lc->bl_refresh=TRUE;
fr->commit=FALSE;
@ -491,47 +487,27 @@ LinphoneFriend * linphone_core_create_friend_with_address(LinphoneCore *lc, cons
return linphone_friend_new_with_address(address);
}
void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
{
ms_return_if_fail(lf->lc==NULL);
ms_return_if_fail(lf->uri!=NULL);
if (ms_list_find(lc->friends,lf)!=NULL){
char *tmp=NULL;
const LinphoneAddress *addr=linphone_friend_get_address(lf);
if (addr) tmp=linphone_address_as_string(addr);
ms_warning("Friend %s already in list, ignored.", tmp ? tmp : "unknown");
if (tmp) ms_free(tmp);
return ;
}
lc->friends=ms_list_append(lc->friends,linphone_friend_ref(lf));
if (ms_list_find(lc->subscribers, lf)){
void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) {
if ((lc->friendlist == NULL) || (linphone_friend_list_add_friend(lc->friendlist, lf) != LinphoneFriendListOK)) return;
if (ms_list_find(lc->subscribers, lf)) {
/*if this friend was in the pending subscriber list, now remove it from this list*/
lc->subscribers = ms_list_remove(lc->subscribers, lf);
linphone_friend_unref(lf);
}
lf->lc=lc;
if ( linphone_core_ready(lc)) linphone_friend_apply(lf,lc);
else lf->commit=TRUE;
return ;
lf->lc = lc;
if (linphone_core_ready(lc)) linphone_friend_apply(lf, lc);
else lf->commit = TRUE;
}
void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){
MSList *el=ms_list_find(lc->friends,fl);
if (el!=NULL){
linphone_friend_unref((LinphoneFriend*)el->data);
lc->friends=ms_list_remove_link(lc->friends,el);
linphone_core_write_friends_config(lc);
}else{
ms_error("linphone_core_remove_friend(): friend [%p] is not part of core's list.",fl);
void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *lf) {
if (linphone_friend_list_remove_friend(lc->friendlist, lf) == LinphoneFriendListNonExistentFriend) {
ms_error("linphone_core_remove_friend(): friend [%p] is not part of core's list.", lf);
}
}
void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered){
const MSList *elem;
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *f=(LinphoneFriend*)elem->data;
linphone_friend_update_subscribes(f,cfg,only_when_registered);
}
if (lc->friendlist != NULL)
linphone_friend_list_update_subscriptions(lc->friendlist, cfg, only_when_registered);
}
bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc){
@ -539,17 +515,39 @@ bool_t linphone_core_should_subscribe_friends_only_when_registered(const Linphon
}
void linphone_core_send_initial_subscribes(LinphoneCore *lc){
bool_t proxy_config_for_rls_presence_uri_domain = FALSE;
LinphoneAddress *rls_address = NULL;
const MSList *elem;
if (lc->initial_subscribes_sent) return;
lc->initial_subscribes_sent=TRUE;
linphone_core_update_friends_subscriptions(lc,NULL,linphone_core_should_subscribe_friends_only_when_registered(lc));
if (lc->friendlist->rls_uri != NULL) {
rls_address = linphone_core_create_address(lc, lc->friendlist->rls_uri);
}
if (rls_address != NULL) {
const char *rls_domain = linphone_address_get_domain(rls_address);
if (rls_domain != NULL) {
for (elem = linphone_core_get_proxy_config_list(lc); elem != NULL; elem = elem->next) {
LinphoneProxyConfig *cfg = (LinphoneProxyConfig *)elem->data;
const char *proxy_domain = linphone_proxy_config_get_domain(cfg);
if (strcmp(rls_domain, proxy_domain) == 0) {
proxy_config_for_rls_presence_uri_domain = TRUE;
break;
}
}
}
linphone_address_unref(rls_address);
}
if (proxy_config_for_rls_presence_uri_domain == TRUE) {
ms_message("Presence list activated so do not send initial subscribes it will be done when registered");
} else {
linphone_core_update_friends_subscriptions(lc,NULL,linphone_core_should_subscribe_friends_only_when_registered(lc));
}
}
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc){
const MSList *elem;
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *f=(LinphoneFriend*)elem->data;
linphone_friend_invalidate_subscription(f);
}
if (lc->friendlist != NULL)
linphone_friend_list_invalidate_subscriptions(lc->friendlist);
lc->initial_subscribes_sent=FALSE;
}
@ -569,34 +567,15 @@ const char *linphone_friend_get_ref_key(const LinphoneFriend *lf){
}
LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc, const LinphoneAddress *addr){
LinphoneFriend *lf=NULL;
MSList *elem;
for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){
lf=(LinphoneFriend*)elem->data;
if (linphone_address_weak_equal(lf->uri,addr))
break;
lf=NULL;
}
return lf;
return linphone_friend_list_find_friend_by_address(lc->friendlist, addr);
}
LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri){
LinphoneAddress *puri=linphone_address_new(uri);
LinphoneFriend *lf=puri ? linphone_core_find_friend(lc,puri) : NULL;
if (puri) linphone_address_unref(puri);
return lf;
return linphone_friend_list_find_friend_by_uri(lc->friendlist, uri);
}
LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key){
const MSList *elem;
if (key==NULL) return NULL;
for(elem=linphone_core_get_friend_list(lc);elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend*)elem->data;
if (lf->refkey!=NULL && strcmp(lf->refkey,key)==0){
return lf;
}
}
return NULL;
return linphone_friend_list_find_friend_by_ref_key(lc->friendlist, key);
}
#define key_compare(s1,s2) strcmp(s1,s2)
@ -648,6 +627,8 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde
}
a=lp_config_get_int(config,item,"subscribe",0);
linphone_friend_send_subscribe(lf,a);
a = lp_config_get_int(config, item, "presence_received", 0);
lf->presence_received = (bool_t)a;
linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL));
return lf;
@ -690,6 +671,7 @@ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf,
}
lp_config_set_string(config,key,"pol",__policy_enum_to_str(lf->pol));
lp_config_set_int(config,key,"subscribe",lf->subscribe);
lp_config_set_int(config, key, "presence_received", lf->presence_received);
refkey=linphone_friend_get_ref_key(lf);
if (refkey){
@ -701,11 +683,15 @@ void linphone_core_write_friends_config(LinphoneCore* lc)
{
MSList *elem;
int i;
int store_friends;
if (! linphone_core_ready(lc)) return; /*dont write config when reading it !*/
for (elem=lc->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){
linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i);
store_friends = lp_config_get_int(lc->config, "misc", "store_friends", 1);
if (store_friends) {
for (elem=lc->friendlist->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){
linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i);
}
linphone_friend_write_to_config_file(lc->config,NULL,i); /* set the end */
}
linphone_friend_write_to_config_file(lc->config,NULL,i); /* set the end */
}
LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr){

444
coreapi/friendlist.c Normal file
View file

@ -0,0 +1,444 @@
/*
linphone
Copyright (C) 2010-2015 Belledonne Communications SARL
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 "linphonecore.h"
#include "private.h"
static char * create_resource_list_xml(const LinphoneFriendList *list) {
char *xml_content = NULL;
MSList *elem;
xmlBufferPtr buf;
xmlTextWriterPtr writer;
int err;
if (ms_list_size(list->friends) <= 0) return NULL;
buf = xmlBufferCreate();
if (buf == NULL) {
ms_error("%s: Error creating the XML buffer", __FUNCTION__);
return NULL;
}
writer = xmlNewTextWriterMemory(buf, 0);
if (writer == NULL) {
ms_error("%s: Error creating the XML writer", __FUNCTION__);
return NULL;
}
xmlTextWriterSetIndent(writer,1);
err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
if (err >= 0) {
err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"resource-lists", (const xmlChar *)"urn:ietf:params:xml:ns:resource-lists");
}
if (err >= 0) {
err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"xsi",
NULL, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance");
}
if (err>= 0) {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"list");
}
for (elem = list->friends; elem != NULL; elem = elem->next) {
LinphoneFriend *friend = (LinphoneFriend *)elem->data;
char *uri = linphone_address_as_string_uri_only(friend->uri);
if (err >= 0) {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"entry");
}
if (err >= 0) {
err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"uri", (const xmlChar *)uri);
}
if (err >= 0) {
/* Close the "entry" element. */
err = xmlTextWriterEndElement(writer);
}
if (uri) ms_free(uri);
}
if (err >= 0) {
/* Close the "list" element. */
err = xmlTextWriterEndElement(writer);
}
if (err >= 0) {
/* Close the "resource-lists" element. */
err = xmlTextWriterEndElement(writer);
}
if (err >= 0) {
err = xmlTextWriterEndDocument(writer);
}
if (err > 0) {
/* xmlTextWriterEndDocument returns the size of the content. */
xml_content = ms_strdup((char *)buf->content);
}
xmlFreeTextWriter(writer);
xmlBufferFree(buf);
return xml_content;
}
static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList *list, const LinphoneContent *body, const char *first_part_body) {
xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
xml_ctx->doc = xmlReadDoc((const unsigned char*)first_part_body, 0, NULL, 0);
if (xml_ctx->doc != NULL) {
char xpath_str[MAX_XPATH_LENGTH];
LinphoneFriend *friend;
LinphoneContent *presence_part;
xmlXPathObjectPtr resource_object;
const char *version_str = NULL;
const char *full_state_str = NULL;
const char *uri = NULL;
bool_t full_state = FALSE;
int version;
int i;
if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"rlmi", (const xmlChar *)"urn:ietf:params:xml:ns:rlmi");
version_str = linphone_get_xml_attribute_text_content(xml_ctx, "/rlmi:list", "version");
if (version_str == NULL) {
ms_warning("rlmi+xml: No version attribute in list");
goto end;
}
version = atoi(version_str);
linphone_free_xml_text_content(version_str);
if (version < list->expected_notification_version) {
ms_warning("rlmi+xml: Discarding received notification with version %d because %d was expected", version, list->expected_notification_version);
linphone_friend_list_update_subscriptions(list, NULL, FALSE); /* Refresh subscription to get new full state notify. */
goto end;
}
full_state_str = linphone_get_xml_attribute_text_content(xml_ctx, "/rlmi:list", "fullState");
if (full_state_str == NULL) {
ms_warning("rlmi+xml: No fullState attribute in list");
goto end;
}
if ((strcmp(full_state_str, "true") == 0) || (strcmp(full_state_str, "1") == 0)) {
MSList *l = list->friends;
for (; l != NULL; l = l->next) {
friend = (LinphoneFriend *)l->data;
linphone_friend_set_presence_model(friend, NULL);
}
full_state = TRUE;
}
linphone_free_xml_text_content(full_state_str);
if ((list->expected_notification_version == 0) && (full_state == FALSE)) {
ms_warning("rlmi+xml: Notification with version 0 is not full state, this is not valid");
goto end;
}
list->expected_notification_version = version + 1;
resource_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/rlmi:list/rlmi:resource");
if ((resource_object != NULL) && (resource_object->nodesetval != NULL)) {
for (i = 1; i <= resource_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "/rlmi:list/rlmi:resource[%i]/@uri", i);
uri = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (uri == NULL) continue;
friend = linphone_friend_list_find_friend_by_uri(list, uri);
if (friend != NULL) {
const char *state = NULL;
snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@state", i);
state = linphone_get_xml_text_content(xml_ctx, xpath_str);
if ((state != NULL) && (strcmp(state, "active") == 0)) {
const char *cid = NULL;
snprintf(xpath_str, sizeof(xpath_str),"/rlmi:list/rlmi:resource[%i]/rlmi:instance/@cid", i);
cid = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (cid != NULL) {
presence_part = linphone_content_find_part_by_header(body, "Content-Id", cid);
if (presence_part == NULL) {
ms_warning("rlmi+xml: Cannot find part with Content-Id: %s", cid);
} else {
SalPresenceModel *presence = NULL;
linphone_notify_parse_presence(linphone_content_get_type(presence_part), linphone_content_get_subtype(presence_part), linphone_content_get_string_buffer(presence_part), &presence);
if (presence != NULL) {
friend->presence_received = TRUE;
linphone_friend_set_presence_model(friend, (LinphonePresenceModel *)presence);
if (full_state == FALSE) {
linphone_core_notify_notify_presence_received(list->lc, friend);
}
}
linphone_content_unref(presence_part);
}
}
if (cid != NULL) linphone_free_xml_text_content(cid);
}
if (state != NULL) linphone_free_xml_text_content(state);
friend->subscribe_active = TRUE;
}
linphone_free_xml_text_content(uri);
}
}
if (resource_object != NULL) xmlXPathFreeObject(resource_object);
if (full_state == TRUE) {
MSList *l = list->friends;
for (; l != NULL; l = l->next) {
friend = (LinphoneFriend *)l->data;
if (linphone_friend_is_presence_received(friend) == TRUE) {
linphone_core_notify_notify_presence_received(list->lc, friend);
}
}
}
} else {
ms_warning("Wrongly formatted rlmi+xml body: %s", xml_ctx->errorBuffer);
}
end:
linphone_xmlparsing_context_destroy(xml_ctx);
}
static bool_t linphone_friend_list_has_subscribe_inactive(const LinphoneFriendList *list) {
MSList *l = list->friends;
bool_t has_subscribe_inactive = FALSE;
for (; l != NULL; l = l->next) {
LinphoneFriend *friend = (LinphoneFriend *)l->data;
if (friend->subscribe_active != TRUE) {
has_subscribe_inactive = TRUE;
break;
}
}
return has_subscribe_inactive;
}
static LinphoneFriendList * linphone_friend_list_new(void) {
LinphoneFriendList *list = belle_sip_object_new(LinphoneFriendList);
belle_sip_object_ref(list);
return list;
}
static void linphone_friend_list_destroy(LinphoneFriendList *list) {
if (list->display_name != NULL) ms_free(list->display_name);
if (list->rls_uri != NULL) ms_free(list->rls_uri);
if (list->event != NULL) linphone_event_unref(list->event);
list->friends = ms_list_free_with_data(list->friends, (void (*)(void *))linphone_friend_unref);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendList);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendList, belle_sip_object_t,
(belle_sip_object_destroy_t)linphone_friend_list_destroy,
NULL, // clone
NULL, // marshal
TRUE
);
LinphoneFriendList * linphone_core_create_friend_list(LinphoneCore *lc) {
LinphoneFriendList *list = linphone_friend_list_new();
list->lc = lc;
return list;
}
LinphoneFriendList * linphone_friend_list_ref(LinphoneFriendList *list) {
belle_sip_object_ref(list);
return list;
}
void linphone_friend_list_unref(LinphoneFriendList *list) {
belle_sip_object_unref(list);
}
void * linphone_friend_list_get_user_data(const LinphoneFriendList *list) {
return list->user_data;
}
void linphone_friend_list_set_user_data(LinphoneFriendList *list, void *ud) {
list->user_data = ud;
}
const char * linphone_friend_list_get_display_name(const LinphoneFriendList *list) {
return list->display_name;
}
void linphone_friend_list_set_display_name(LinphoneFriendList *list, const char *display_name) {
if (list->display_name != NULL) {
ms_free(list->display_name);
list->display_name = NULL;
}
if (display_name != NULL) {
list->display_name = ms_strdup(display_name);
}
}
const char * linphone_friend_list_get_rls_uri(const LinphoneFriendList *list) {
return list->rls_uri;
}
void linphone_friend_list_set_rls_uri(LinphoneFriendList *list, const char *rls_uri) {
if (list->rls_uri != NULL) {
ms_free(list->rls_uri);
list->rls_uri = NULL;
}
if (rls_uri != NULL) {
list->rls_uri = ms_strdup(rls_uri);
}
}
LinphoneFriendListStatus linphone_friend_list_add_friend(LinphoneFriendList *list, LinphoneFriend *friend) {
if ((friend->lc != NULL) || (friend->uri == NULL)) return LinphoneFriendListInvalidFriend;
if (ms_list_find(list->friends, friend) != NULL) {
char *tmp = NULL;
const LinphoneAddress *addr = linphone_friend_get_address(friend);
if (addr) tmp = linphone_address_as_string(addr);
ms_warning("Friend %s already in list [%s], ignored.", tmp ? tmp : "unknown", list->display_name);
if (tmp) ms_free(tmp);
} else {
list->friends = ms_list_append(list->friends, linphone_friend_ref(friend));
}
return LinphoneFriendListOK;
}
LinphoneFriendListStatus linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *friend) {
MSList *elem = ms_list_find(list->friends, friend);
if (elem == NULL) return LinphoneFriendListNonExistentFriend;
linphone_friend_unref((LinphoneFriend *)elem->data);
list->friends = ms_list_remove_link(list->friends, elem);
return LinphoneFriendListOK;
}
LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address) {
LinphoneFriend *friend = NULL;
const MSList *elem;
for (elem = list->friends; elem != NULL; elem = elem->next) {
friend = (LinphoneFriend *)elem->data;
if (linphone_address_weak_equal(friend->uri, address))
return friend;
}
return NULL;
}
LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri) {
LinphoneAddress *address = linphone_address_new(uri);
LinphoneFriend *friend = address ? linphone_friend_list_find_friend_by_address(list, address) : NULL;
if (address) linphone_address_unref(address);
return friend;
}
LinphoneFriend * linphone_friend_list_find_friend_by_ref_key(const LinphoneFriendList *list, const char *ref_key) {
const MSList *elem;
if (ref_key == NULL) return NULL;
for (elem = list->friends; elem != NULL; elem = elem->next) {
LinphoneFriend *friend = (LinphoneFriend *)elem->data;
if ((friend->refkey != NULL) && (strcmp(friend->refkey, ref_key) == 0)) return friend;
}
return NULL;
}
LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op) {
const MSList *elem;
for (elem = list->friends; elem != NULL; elem = elem->next) {
LinphoneFriend *friend = (LinphoneFriend *)elem->data;
if (ms_list_find(friend->insubs, op)) return friend;
}
return NULL;
}
LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op) {
const MSList *elem;
for (elem = list->friends; elem != NULL; elem = elem->next) {
LinphoneFriend *friend = (LinphoneFriend *)elem->data;
if (friend->outsub && ((friend->outsub == op) || sal_op_is_forked_of(friend->outsub, op))) return friend;
}
return NULL;
}
void linphone_friend_list_close_subscriptions(LinphoneFriendList *list) {
/* FIXME we should wait until subscription to complete. */
if (list->friends)
ms_list_for_each(list->friends, (void (*)(void *))linphone_friend_close_subscriptions);
}
void linphone_friend_list_update_subscriptions(LinphoneFriendList *list, LinphoneProxyConfig *cfg, bool_t only_when_registered) {
const MSList *elem;
if (list->event != NULL) {
linphone_event_refresh_subscribe(list->event);
} else if (list->rls_uri != NULL) {
LinphoneAddress *address = linphone_address_new(list->rls_uri);
char *xml_content = create_resource_list_xml(list);
if ((address != NULL) && (xml_content != NULL) && (linphone_friend_list_has_subscribe_inactive(list) == TRUE)) {
LinphoneContent *content;
int expires = lp_config_get_int(list->lc->config, "sip", "rls_presence_expires", 3600);
list->expected_notification_version = 0;
list->event = linphone_core_create_subscribe(list->lc, address, "presence", expires);
linphone_event_add_custom_header(list->event, "Require", "recipient-list-subscribe");
linphone_event_add_custom_header(list->event, "Supported", "eventlist");
linphone_event_add_custom_header(list->event, "Accept", "multipart/related, application/pidf+xml, application/rlmi+xml");
linphone_event_add_custom_header(list->event, "Content-Disposition", "recipient-list");
content = linphone_core_create_content(list->lc);
linphone_content_set_type(content, "application");
linphone_content_set_subtype(content, "resource-lists+xml");
linphone_content_set_string_buffer(content, xml_content);
linphone_event_send_subscribe(list->event, content);
linphone_content_unref(content);
}
if (address != NULL) linphone_address_unref(address);
if (xml_content != NULL) ms_free(xml_content);
} else {
for (elem = list->friends; elem != NULL; elem = elem->next) {
LinphoneFriend *friend = (LinphoneFriend *)elem->data;
linphone_friend_update_subscribes(friend, cfg, only_when_registered);
}
}
}
void linphone_friend_list_invalidate_subscriptions(LinphoneFriendList *list) {
const MSList *elem;
for (elem = list->friends; elem != NULL; elem = elem->next) {
LinphoneFriend *friend = (LinphoneFriend *)elem->data;
linphone_friend_invalidate_subscription(friend);
}
}
void linphone_friend_list_notify_presence(LinphoneFriendList *list, LinphonePresenceModel *presence) {
const MSList *elem;
for(elem = list->friends; elem != NULL; elem = elem->next) {
LinphoneFriend *friend = (LinphoneFriend *)elem->data;
linphone_friend_notify(friend, presence);
}
}
void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, LinphoneEvent *lev, const LinphoneContent *body) {
if (linphone_content_is_multipart(body)) {
LinphoneContent *first_part;
const char *type = linphone_content_get_type(body);
const char *subtype = linphone_content_get_subtype(body);
if ((strcmp(type, "multipart") != 0) || (strcmp(subtype, "related") != 0)) {
ms_warning("multipart presence notified but it is not 'multipart/related'");
return;
}
first_part = linphone_content_get_part(body, 0);
if (first_part == NULL) {
ms_warning("'multipart/related' presence notified but it doesn't contain any part");
return;
}
type = linphone_content_get_type(first_part);
subtype = linphone_content_get_subtype(first_part);
if ((strcmp(type, "application") != 0) || (strcmp(subtype, "rlmi+xml") != 0)) {
ms_warning("multipart presence notified but first part is not 'application/rlmi+xml'");
linphone_content_unref(first_part);
return;
}
linphone_friend_list_parse_multipart_related_body(list, body, linphone_content_get_string_buffer(first_part));
linphone_content_unref(first_part);
}
}

180
coreapi/friendlist.h Normal file
View file

@ -0,0 +1,180 @@
/*
friendlist.h
Copyright (C) 2010-2015 Belledonne Communications SARL
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.
*/
#ifndef LINPHONE_FRIENDLIST_H_
#define LINPHONE_FRIENDLIST_H_
#include "linphonefriend.h"
#include "linphonepresence.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup buddy_list
* @{
*/
/**
* Enum describing the status of a LinphoneFriendList operation.
**/
typedef enum _LinphoneFriendListStatus {
LinphoneFriendListOK,
LinphoneFriendListNonExistentFriend,
LinphoneFriendListInvalidFriend
} LinphoneFriendListStatus;
/**
* The LinphoneFriendList object representing a list of friends.
**/
typedef struct _LinphoneFriendList LinphoneFriendList;
/**
* Create a new empty LinphoneFriendList object.
* @param[in] lc LinphoneCore object.
* @return A new LinphoneFriendList object.
**/
LINPHONE_PUBLIC LinphoneFriendList * linphone_core_create_friend_list(LinphoneCore *lc);
/**
* Set the friend list.
* @param[in] lc LinphoneCore object
* @param[in] list LinphoneFriendList object
*/
LINPHONE_PUBLIC void linphone_core_set_friend_list(LinphoneCore *lc, LinphoneFriendList *list);
/**
* Acquire a reference to the friend list.
* @param[in] list LinphoneFriendList object.
* @return The same LinphoneFriendList object.
**/
LINPHONE_PUBLIC LinphoneFriendList * linphone_friend_list_ref(LinphoneFriendList *list);
/**
* Release reference to the friend list.
* @param[in] list LinphoneFriendList object.
**/
LINPHONE_PUBLIC void linphone_friend_list_unref(LinphoneFriendList *list);
/**
* Retrieve the user pointer associated with the friend list.
* @param[in] list LinphoneFriendList object.
* @return The user pointer associated with the friend list.
**/
LINPHONE_PUBLIC void * linphone_friend_list_get_user_data(const LinphoneFriendList *list);
/**
* Assign a user pointer to the friend list.
* @param[in] list LinphoneFriendList object.
* @param[in] ud The user pointer to associate with the friend list.
**/
LINPHONE_PUBLIC void linphone_friend_list_set_user_data(LinphoneFriendList *list, void *ud);
/**
* Get the display name of the friend list.
* @param[in] list LinphoneFriendList object.
* @return The display name of the friend list.
**/
LINPHONE_PUBLIC const char * linphone_friend_list_get_display_name(const LinphoneFriendList *list);
/**
* Set the display name of the friend list.
* @param[in] list LinphoneFriendList object.
* @param[in] display_name The new display name of the friend list.
**/
LINPHONE_PUBLIC void linphone_friend_list_set_display_name(LinphoneFriendList *list, const char *display_name);
/**
* Get the RLS (Resource List Server) URI associated with the friend list to subscribe to these friends presence.
* @param[in] list LinphoneFriendList object.
* @return The RLS URI associated with the friend list.
**/
LINPHONE_PUBLIC const char * linphone_friend_list_get_rls_uri(const LinphoneFriendList *list);
/**
* Set the RLS (Resource List Server) URI associated with the friend list to subscribe to these friends presence.
* @param[in] list LinphoneFriendList object.
* @param[in] rls_uri The RLS URI to associate with the friend list.
**/
LINPHONE_PUBLIC void linphone_friend_list_set_rls_uri(LinphoneFriendList *list, const char *rls_uri);
/**
* Add a friend to a friend list.
* @param[in] list LinphoneFriendList object.
* @param[in] friend LinphoneFriend object to add to the friend list.
* @return LinphoneFriendListOK if successfully added, LinphoneFriendListInvalidFriend if the friend is not valid.
**/
LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_add_friend(LinphoneFriendList *list, LinphoneFriend *afriend);
/**
* Remove a friend from a friend list.
* @param[in] list LinphoneFriendList object.
* @param[in] friend LinphoneFriend object to remove from the friend list.
* @return LinphoneFriendListOK if removed successfully, LinphoneFriendListNonExistentFriend if the friend is not in the list.
**/
LINPHONE_PUBLIC LinphoneFriendListStatus linphone_friend_list_remove_friend(LinphoneFriendList *list, LinphoneFriend *afriend);
/**
* Find a friend in the friend list using a LinphoneAddress.
* @param[in] list LinphoneFriendList object.
* @param[in] address LinphoneAddress object of the friend we want to search for.
* @return A LinphoneFriend if found, NULL otherwise.
**/
LINPHONE_PUBLIC LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address);
/**
* Find a friend in the friend list using an URI string.
* @param[in] list LinphoneFriendList object.
* @param[in] uri A string containing the URI of the friend we want to search for.
* @return A LinphoneFriend if found, NULL otherwise.
**/
LINPHONE_PUBLIC LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri);
/**
* Find a frient in the friend list using a ref key.
* @param[in] list LinphoneFriendList object.
* @param[in] ref_key The ref key string of the friend we want to search for.
* @return A LinphoneFriend if found, NULL otherwise.
**/
LINPHONE_PUBLIC LinphoneFriend * linphone_friend_list_find_friend_by_ref_key(const LinphoneFriendList *list, const char *ref_key);
LINPHONE_PUBLIC void linphone_friend_list_close_subscriptions(LinphoneFriendList *list);
LINPHONE_PUBLIC void linphone_friend_list_update_subscriptions(LinphoneFriendList *list, LinphoneProxyConfig *cfg, bool_t only_when_registered);
/**
* Notify our presence to all the friends in the friend list that have subscribed to our presence directly (not using a RLS).
* @param[in] list LinphoneFriendList object.
* @param[in] presence LinphonePresenceModel object.
**/
LINPHONE_PUBLIC void linphone_friend_list_notify_presence(LinphoneFriendList *list, LinphonePresenceModel *presence);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* LINPHONE_FRIENDLIST_H_ */

View file

@ -69,10 +69,10 @@ LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc){
* @param call the call
* @param info the info message
**/
int linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info){
SalBody body;
sal_op_set_sent_custom_header(call->op,info->headers);
return sal_send_info(call->op,NULL, NULL, sal_body_from_content(&body,info->content));
int linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info) {
SalBodyHandler *body_handler = sal_body_handler_from_content(info->content);
sal_op_set_sent_custom_header(call->op, info->headers);
return sal_send_info(call->op,NULL, NULL, body_handler);
}
/**
@ -112,12 +112,12 @@ const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMess
return (im->content && linphone_content_get_type(im->content)) ? im->content : NULL;
}
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body){
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body_handler){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call){
LinphoneInfoMessage *info=ms_new0(LinphoneInfoMessage,1);
info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op));
if (body) info->content=linphone_content_from_sal_body(body);
if (body_handler) info->content=linphone_content_from_sal_body_handler(body_handler);
linphone_core_notify_info_received(lc,call,info);
linphone_info_message_destroy(info);
}

View file

@ -1664,16 +1664,26 @@ static void linphone_core_register_default_codecs(LinphoneCore *lc){
linphone_core_register_static_payloads(lc);
}
static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body) {
if (strcmp(notified_event, "Presence") == 0) {
linphone_friend_list_notify_presence_received(lc->friendlist, lev, body);
}
}
static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata){
const char *remote_provisioning_uri = NULL;
LinphoneCoreVTable* local_vtable= linphone_core_v_table_new();
LinphoneCoreVTable *internal_vtable = linphone_core_v_table_new();
ms_message("Initializing LinphoneCore %s", linphone_core_get_version());
lc->config=lp_config_ref(config);
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
linphone_core_set_friend_list(lc, NULL);
linphone_task_list_init(&lc->hooks);
internal_vtable->notify_received = linphone_core_internal_notify_received;
_linphone_core_add_listener(lc, internal_vtable, TRUE);
memcpy(local_vtable,vtable,sizeof(LinphoneCoreVTable));
_linphone_core_add_listener(lc, local_vtable, TRUE);
@ -1906,7 +1916,23 @@ bool_t linphone_core_generic_confort_noise_enabled(const LinphoneCore *lc){
const MSList * linphone_core_get_friend_list(const LinphoneCore *lc)
{
return lc->friends;
return lc->friendlist->friends;
}
void linphone_core_set_friend_list(LinphoneCore *lc, LinphoneFriendList *list) {
if (lc->friendlist != NULL) {
linphone_friend_list_unref(lc->friendlist);
lc->friendlist = NULL;
}
if (list != NULL) {
lc->friendlist = linphone_friend_list_ref(list);
} else {
const char *rls_uri = NULL;
lc->friendlist = linphone_core_create_friend_list(lc);
rls_uri = lp_config_get_string(lc->config, "sip", "rls_uri", NULL);
if (rls_uri && lp_config_get_int(lc->config, "sip", "use_rls_presence", 0))
linphone_friend_list_set_rls_uri(lc->friendlist, rls_uri);
}
}
void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore* lc, bool_t val)
@ -6324,9 +6350,8 @@ static void codecs_config_uninit(LinphoneCore *lc)
void ui_config_uninit(LinphoneCore* lc)
{
ms_message("Destroying friends.");
if (lc->friends){
lc->friends = ms_list_free_with_data(lc->friends, (void (*)(void *))linphone_friend_unref);
}
linphone_friend_list_unref(lc->friendlist);
lc->friendlist = NULL;
if (lc->subscribers){
lc->subscribers = ms_list_free_with_data(lc->subscribers, (void (*)(void *))linphone_friend_unref);
}
@ -6366,9 +6391,7 @@ static void linphone_core_uninit(LinphoneCore *lc)
ms_usleep(50000);
}
if (lc->friends) /* FIXME we should wait until subscription to complete*/
ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions);
linphone_friend_list_close_subscriptions(lc->friendlist);
lc->chatrooms = ms_list_free_with_data(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release);
linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down");

View file

@ -1939,6 +1939,15 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addFriend(JNIEnv* env
) {
linphone_core_add_friend((LinphoneCore*)lc,(LinphoneFriend*)aFriend);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setFriendList(JNIEnv* env
,jobject thiz
,jlong lc
,jlong friendList
) {
linphone_core_set_friend_list((LinphoneCore*)lc,(LinphoneFriendList*)friendList);
}
extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_getFriendList(JNIEnv* env
,jobject thiz
,jlong lc) {
@ -3054,12 +3063,47 @@ extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNI
}
return (jlong)lResult;
}
extern "C" jlong Java_org_linphone_core_LinphoneFriendListImpl_newLinphoneFriendList(JNIEnv* env
,jobject thiz, jlong lc) {
LinphoneFriendList* fl = linphone_core_create_friend_list((LinphoneCore *)lc);
linphone_friend_list_set_user_data(fl,env->NewWeakGlobalRef(thiz));
return (jlong)fl;
}
extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv* env
,jobject thiz
,jlong ptr
,jlong linphoneAddress) {
linphone_friend_set_address((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress);
}
extern "C" void Java_org_linphone_core_LinphoneFriendListImpl_setRLSUri(JNIEnv* env
,jobject thiz
,jlong ptr
,jstring jrlsUri) {
const char* uri = env->GetStringUTFChars(jrlsUri, NULL);
linphone_friend_list_set_rls_uri((LinphoneFriendList*)ptr,uri);
}
extern "C" void Java_org_linphone_core_LinphoneFriendListImpl_addFriend(JNIEnv* env
,jobject thiz
,jlong friendListptr
,jlong friendPtr) {
linphone_friend_list_add_friend((LinphoneFriendList*)friendListptr,(LinphoneFriend*)friendPtr);
}
extern "C" void Java_org_linphone_core_LinphoneFriendListImpl_updateSubscriptions(JNIEnv* env
,jobject thiz
,jlong friendListptr
,jlong proxyConfigPtr
,jboolean jonlyWhenRegistered) {
linphone_friend_list_update_subscriptions((LinphoneFriendList*)friendListptr,(LinphoneProxyConfig*)proxyConfigPtr,jonlyWhenRegistered);
}
extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_getAddress(JNIEnv* env
,jobject thiz
,jlong ptr) {
@ -3103,6 +3147,18 @@ extern "C" jobject Java_org_linphone_core_LinphoneFriendImpl_getCore(JNIEnv* en
}
return NULL;
}
extern "C" jobject Java_org_linphone_core_LinphoneFriendListImpl_getCore(JNIEnv* env
,jobject thiz
,jlong ptr) {
LinphoneCore *lc=linphone_friend_get_core((LinphoneFriend*)ptr);
if (lc!=NULL){
jobject core = (jobject)linphone_core_get_user_data(lc);
return core;
}
return NULL;
}
extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setRefKey(JNIEnv* env
,jobject thiz
,jlong ptr
@ -3127,6 +3183,14 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_finalize(JNIEnv* env
linphone_friend_unref(lfriend);
}
extern "C" void Java_org_linphone_core_LinphoneFriendListImpl_finalize(JNIEnv* env
,jobject thiz
,jlong ptr) {
LinphoneFriendList *lfriendList=(LinphoneFriendList*)ptr;
linphone_friend_list_set_user_data(lfriendList,NULL);
linphone_friend_list_unref(lfriendList);
}
/*
* Class: org_linphone_core_LinphoneFriendImpl
* Method: getPresenceModel
@ -3277,17 +3341,10 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_markAsRead(JNIEnv*
extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createFileTransferMessage(JNIEnv* env, jobject thiz, jlong ptr, jstring jname, jstring jtype, jstring jsubtype, jint data_size) {
LinphoneContentPrivate content = {0};
LinphoneContent content = {0};
LinphoneChatMessage *message = NULL;
content.type = (char*)env->GetStringUTFChars(jtype, NULL);
content.subtype = (char*)env->GetStringUTFChars(jsubtype, NULL);
content.name = (char*)env->GetStringUTFChars(jname, NULL);
content.size = data_size;
message = linphone_chat_room_create_file_transfer_message((LinphoneChatRoom *)ptr, LINPHONE_CONTENT(&content));
env->ReleaseStringUTFChars(jtype, content.type);
env->ReleaseStringUTFChars(jsubtype, content.subtype);
env->ReleaseStringUTFChars(jname, content.name);
message = linphone_chat_room_create_file_transfer_message((LinphoneChatRoom *)ptr, &content);
return (jlong) message;
}
@ -4673,24 +4730,14 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_subscribe(JNIE
jstring jevname, jint expires, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){
LinphoneCore *lc=(LinphoneCore*)coreptr;
LinphoneAddress *addr=(LinphoneAddress*)addrptr;
LinphoneContentPrivate content={0};
LinphoneContent content={0};
LinphoneEvent *ev;
jobject jev=NULL;
const char *evname=env->GetStringUTFChars(jevname,NULL);
ev=linphone_core_subscribe(lc,addr,evname,expires,linphone_content_get_type(&content) ? &content : NULL);
if (jtype){
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL;
content.data=(void*)env->GetByteArrayElements(jdata,NULL);
content.size=env->GetArrayLength(jdata);
}
ev=linphone_core_subscribe(lc,addr,evname,expires,content.type ? LINPHONE_CONTENT(&content) : NULL);
if (jtype){
env->ReleaseStringUTFChars(jtype,content.type);
env->ReleaseStringUTFChars(jsubtype,content.subtype);
if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding);
env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT);
env->ReleaseByteArrayElements(jdata,(jbyte*)linphone_content_get_user_data(&content),JNI_ABORT);
}
env->ReleaseStringUTFChars(jevname,evname);
if (ev){
@ -4708,24 +4755,16 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_publish(JNIEnv
jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){
LinphoneCore *lc=(LinphoneCore*)coreptr;
LinphoneAddress *addr=(LinphoneAddress*)addrptr;
LinphoneContentPrivate content={0};
LinphoneContent content={0};
LinphoneEvent *ev;
jobject jev=NULL;
const char *evname=env->GetStringUTFChars(jevname,NULL);
ev=linphone_core_subscribe(lc,addr,evname,expires,linphone_content_get_type(&content) ? &content : NULL);
if (jtype){
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL;
content.data=(void*)env->GetByteArrayElements(jdata,NULL);
content.size=env->GetArrayLength(jdata);
}
ev=linphone_core_publish(lc,addr,evname,expires,content.type ? LINPHONE_CONTENT(&content) : NULL);
if (jtype){
env->ReleaseStringUTFChars(jtype,content.type);
env->ReleaseStringUTFChars(jsubtype,content.subtype);
if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding);
env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT);
env->ReleaseByteArrayElements(jdata,(jbyte*)linphone_content_get_user_data(&content),JNI_ABORT);
}
env->ReleaseStringUTFChars(jevname,evname);
if (ev){
@ -4868,33 +4907,24 @@ static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *
jstring jtype, jsubtype, jencoding, jname;
jbyteArray jdata = NULL;
jint jsize = 0;
const LinphoneContentPrivate *content = LINPHONE_CONTENT_PRIVATE(icontent);
contentClass = (jclass)env->FindClass("org/linphone/core/LinphoneContentImpl");
ctor = env->GetMethodID(contentClass,"<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;I)V");
jtype = env->NewStringUTF(content->type);
jsubtype = env->NewStringUTF(content->subtype);
jencoding = content->encoding ? env->NewStringUTF(content->encoding) : NULL;
jname = content->name ? env->NewStringUTF(content->name) : NULL;
jsize = (jint) content->size;
jtype = env->NewStringUTF(linphone_content_get_type(icontent));
jsubtype = env->NewStringUTF(linphone_content_get_subtype(icontent));
jencoding = linphone_content_get_encoding(icontent) ? env->NewStringUTF(linphone_content_get_encoding(icontent)) : NULL;
jname = linphone_content_get_name(icontent) ? env->NewStringUTF(linphone_content_get_name(icontent)) : NULL;
jsize = (jint) linphone_content_get_size(icontent);
if (content->data){
jdata = env->NewByteArray(content->size);
env->SetByteArrayRegion(jdata, 0, content->size, (jbyte*)content->data);
if (linphone_content_get_user_data(icontent)){
jdata = env->NewByteArray(linphone_content_get_size(icontent));
env->SetByteArrayRegion(jdata, 0, linphone_content_get_size(icontent), (jbyte*)linphone_content_get_user_data(icontent));
}
jobject jobj = env->NewObject(contentClass, ctor, jname, jtype, jsubtype, jdata, jencoding, jsize);
env->DeleteLocalRef(contentClass);
env->DeleteLocalRef(jtype);
env->DeleteLocalRef(jsubtype);
if (jencoding) {
env->DeleteLocalRef(jencoding);
}
if (jname) {
env->DeleteLocalRef(jname);
}
return jobj;
}
@ -4964,16 +4994,9 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getCont
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_setContent(JNIEnv *env, jobject jobj, jlong infoptr, jstring jtype, jstring jsubtype, jstring jdata){
LinphoneContentPrivate content={0};
LinphoneContent content={0};
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
content.data=(void*)env->GetStringUTFChars(jdata,NULL);
content.size=strlen((char*)content.data);
linphone_info_message_set_content((LinphoneInfoMessage*)infoptr,LINPHONE_CONTENT(&content));
env->ReleaseStringUTFChars(jtype,content.type);
env->ReleaseStringUTFChars(jsubtype,content.subtype);
env->ReleaseStringUTFChars(jdata,(char*)content.data);
linphone_info_message_set_content((LinphoneInfoMessage*)infoptr,&content);
}
/*
@ -5073,26 +5096,13 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_denySubscription
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){
LinphoneContentPrivate content={0};
LinphoneContent content={0};
LinphoneEvent *ev=(LinphoneEvent*)evptr;
jint err;
if (jtype){
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL;
content.data=(void*)env->GetByteArrayElements(jdata,NULL);
content.size=env->GetArrayLength(jdata);
}
err=linphone_event_notify(ev,content.type ? LINPHONE_CONTENT(&content) : NULL);
err=linphone_event_notify(ev,linphone_content_get_type(&content) ? &content : NULL);
if (jtype){
env->ReleaseStringUTFChars(jtype,content.type);
env->ReleaseStringUTFChars(jsubtype,content.subtype);
if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding);
env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT);
}
return err;
}
@ -5102,26 +5112,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *e
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){
LinphoneContentPrivate content={0};
LinphoneContent content={0};
LinphoneEvent *ev=(LinphoneEvent*)evptr;
jint err;
if (jtype){
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL;
content.data=(void*)env->GetByteArrayElements(jdata,NULL);
content.size=env->GetArrayLength(jdata);
}
err=linphone_event_update_subscribe(ev,linphone_content_get_type(&content) ? &content : NULL);
err=linphone_event_update_subscribe(ev,content.type ? LINPHONE_CONTENT(&content) : NULL);
if (jtype){
env->ReleaseStringUTFChars(jtype,content.type);
env->ReleaseStringUTFChars(jsubtype,content.subtype);
if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding);
env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT);
}
return err;
}
@ -5131,26 +5127,12 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe(
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updatePublish(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){
LinphoneContentPrivate content={0};
LinphoneContent content={0};
LinphoneEvent *ev=(LinphoneEvent*)evptr;
jint err;
if (jtype){
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL;
content.data=(void*)env->GetByteArrayElements(jdata,NULL);
content.size=env->GetArrayLength(jdata);
}
err=linphone_event_update_publish(ev,linphone_content_get_type(&content) ? &content : NULL);
err=linphone_event_update_publish(ev,content.type ? LINPHONE_CONTENT(&content) : NULL);
if (jtype){
env->ReleaseStringUTFChars(jtype,content.type);
env->ReleaseStringUTFChars(jsubtype,content.subtype);
if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding);
env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT);
}
return err;
}
@ -5216,21 +5198,8 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createSubscrib
}
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendSubscribe(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) {
LinphoneContentPrivate content = {0};
if (jtype) {
content.type = (char*) env->GetStringUTFChars(jtype, NULL);
content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL);
content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL;
content.data = (void*) env->GetByteArrayElements(jdata, NULL);
content.size = env->GetArrayLength(jdata);
}
linphone_event_send_subscribe((LinphoneEvent*) jevent, content.type ? LINPHONE_CONTENT(&content) : NULL);
if (jtype) {
env->ReleaseStringUTFChars(jtype, content.type);
env->ReleaseStringUTFChars(jsubtype, content.subtype);
if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding);
env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT);
}
LinphoneContent content = {0};
linphone_event_send_subscribe((LinphoneEvent*) jevent, linphone_content_get_type(&content)? &content : NULL);
}
JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createPublish(JNIEnv *env, jobject thiz, jlong jcore, jlong jaddr, jstring jeventname, jint expires) {
@ -5249,21 +5218,10 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createPublish(
}
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendPublish(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) {
LinphoneContentPrivate content = {0};
if (jtype) {
content.type = (char*) env->GetStringUTFChars(jtype, NULL);
content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL);
content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL;
content.data = (void*) env->GetByteArrayElements(jdata, NULL);
content.size = env->GetArrayLength(jdata);
}
linphone_event_send_publish((LinphoneEvent*) jevent, content.type ? LINPHONE_CONTENT(&content) : NULL);
if (jtype) {
env->ReleaseStringUTFChars(jtype, content.type);
env->ReleaseStringUTFChars(jsubtype, content.subtype);
if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding);
env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT);
}
LinphoneContent content = {0};
linphone_event_send_publish((LinphoneEvent*) jevent, linphone_content_get_type(&content)? &content : NULL);
}
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_addCustomHeader(JNIEnv *env, jobject thiz, jlong jevent, jstring jname, jstring jvalue) {

View file

@ -240,6 +240,20 @@ LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFr
*/
LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf);
/**
* Set the presence model of a friend
* @param[in] lf A #LinphoneFriend object
* @param[in] presence The #LinphonePresenceModel object to set for the friend
*/
LINPHONE_PUBLIC void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence);
/**
* Tells whether we already received presence information for a friend.
* @param[in] lf A #LinphoneFriend object
* @return TRUE if presence information has been received for the friend, FALSE otherwise.
*/
LINPHONE_PUBLIC bool_t linphone_friend_is_presence_received(const LinphoneFriend *lf);
/**
* Store user pointer to friend object.
**/

View file

@ -1464,15 +1464,11 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){
}
void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence){
MSList *elem;
LinphonePresenceActivity *activity = linphone_presence_model_get_activity(presence);
char *activity_str = linphone_presence_activity_to_string(activity);
ms_message("Notifying all friends that we are [%s]", activity_str);
if (activity_str != NULL) ms_free(activity_str);
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend *)elem->data;
linphone_friend_notify(lf,presence);
}
linphone_friend_list_notify_presence(lc->friendlist, presence);
}
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
@ -1486,7 +1482,10 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
ms_message("Receiving new subscription from %s.",from);
/* check if we answer to this subscription */
if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){
if (lc->friendlist != NULL) {
lf = linphone_friend_list_find_friend_by_address(lc->friendlist, uri);
}
if (lf!=NULL){
linphone_friend_add_incoming_subscription(lf, op);
lf->inc_subscribe_pending=TRUE;
sal_subscribe_accept(op);
@ -1511,7 +1510,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
ms_free(tmp);
}
void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
xmlparsing_context_t *xml_ctx;
LinphonePresenceModel *model = NULL;
@ -1850,15 +1849,15 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model){
char *tmp;
LinphoneFriend *lf;
LinphoneFriend *lf = NULL;
LinphoneAddress *friend=NULL;
LinphonePresenceModel *presence = model ? (LinphonePresenceModel *)model:linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline, NULL);
lf=linphone_find_friend_by_out_subscribe(lc->friends,op);
if (lc->friendlist != NULL)
lf=linphone_friend_list_find_friend_by_out_subscribe(lc->friendlist,op);
if (lf==NULL && lp_config_get_int(lc->config,"sip","allow_out_of_subscribe_presence",0)){
const SalAddress *addr=sal_op_get_from_address(op);
lf=NULL;
linphone_find_friend_by_address(lc->friends,(LinphoneAddress*)addr,&lf);
lf = linphone_friend_list_find_friend_by_address(lc->friendlist, (LinphoneAddress *)addr);
}
if (lf!=NULL){
LinphonePresenceActivity *activity = NULL;
@ -1869,11 +1868,9 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa
activity_str = linphone_presence_activity_to_string(activity);
ms_message("We are notified that [%s] has presence [%s]", tmp, activity_str);
if (activity_str != NULL) ms_free(activity_str);
if (lf->presence != NULL) {
linphone_presence_model_unref(lf->presence);
}
lf->presence = presence;
linphone_friend_set_presence_model(lf, presence);
lf->subscribe_active=TRUE;
lf->presence_received = TRUE;
linphone_core_notify_notify_presence_received(lc,(LinphoneFriend*)lf);
ms_free(tmp);
if (op != lf->outsub){
@ -1904,9 +1901,11 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa
}
void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){
LinphoneFriend *lf;
lf=linphone_find_friend_by_inc_subscribe(lc->friends,op);
LinphoneFriend *lf = NULL;
if (lc->friendlist != NULL)
lf=linphone_friend_list_find_friend_by_inc_subscribe(lc->friendlist,op);
if (lf!=NULL){
/*this will release the op*/
linphone_friend_remove_incoming_subscription(lf, op);

View file

@ -30,6 +30,7 @@ extern "C" {
#endif
#include "linphonecore.h"
#include "linphonefriend.h"
#include "friendlist.h"
#include "linphone_tunnel.h"
#include "linphonecore_utils.h"
#include "sal/sal.h"
@ -370,7 +371,6 @@ void linphone_core_write_auth_info(LinphoneCore *lc, LinphoneAuthInfo *ai);
const LinphoneAuthInfo *_linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain, bool_t ignore_realm);
void linphone_core_update_proxy_register(LinphoneCore *lc);
void linphone_core_refresh_subscribes(LinphoneCore *lc);
int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error);
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
@ -385,13 +385,16 @@ void _linphone_proxy_config_release(LinphoneProxyConfig *cfg);
* */
const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg);
void linphone_friend_list_invalidate_subscriptions(LinphoneFriendList *list);
void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, LinphoneEvent *lev, const LinphoneContent *body);
void linphone_friend_invalidate_subscription(LinphoneFriend *lf);
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *cfg, bool_t only_when_registered);
void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence);
void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op);
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op);
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op);
LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op);
MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf);
bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc);
void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered);
@ -441,7 +444,7 @@ void linphone_process_authentication(LinphoneCore* lc, SalOp *op);
void linphone_authentication_ok(LinphoneCore *lc, SalOp *op);
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from);
void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence);
void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result);
void linphone_notify_parse_presence(const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result);
void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content);
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model);
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op);
@ -653,11 +656,26 @@ struct _LinphoneFriend{
bool_t inc_subscribe_pending;
bool_t commit;
bool_t initial_subscribes_sent; /*used to know if initial subscribe message was sent or not*/
bool_t presence_received;
};
BELLE_SIP_DECLARE_VPTR(LinphoneFriend);
struct _LinphoneFriendList {
belle_sip_object_t base;
void *user_data;
LinphoneCore *lc;
LinphoneEvent *event;
char *display_name;
char *rls_uri;
MSList *friends;
int expected_notification_version;
};
BELLE_SIP_DECLARE_VPTR(LinphoneFriendList);
typedef struct sip_config
{
char *contact;
@ -848,7 +866,7 @@ struct _LinphoneCore
ui_config_t ui_conf;
autoreplier_config_t autoreplier_conf;
LinphoneProxyConfig *default_proxy;
MSList *friends;
LinphoneFriendList *friendlist;
MSList *auth_info;
struct _RingStream *ringstream;
time_t dmfs_playing_start_time;
@ -1067,10 +1085,10 @@ const char *linphone_core_create_uuid(LinphoneCore *lc);
void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact);
void linphone_call_create_op(LinphoneCall *call);
int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer);
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body);
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body);
LinphoneContent * linphone_content_new(void);
LinphoneContent * linphone_content_copy(const LinphoneContent *ref);
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *content);
SalBodyHandler *sal_body_handler_from_content(const LinphoneContent *content);
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, int expires);
@ -1082,7 +1100,7 @@ LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state);
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state);
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss);
LinphoneContent *linphone_content_from_sal_body(const SalBody *ref);
LinphoneContent *linphone_content_from_sal_body_handler(SalBodyHandler *ref);
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
void linphone_core_register_offer_answer_providers(LinphoneCore *lc);
@ -1090,7 +1108,11 @@ void linphone_core_register_offer_answer_providers(LinphoneCore *lc);
struct _LinphoneContent {
belle_sip_object_t base;
void *user_data;
struct _LinphoneContentPrivate lcp;
SalBodyHandler *body_handler;
char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */
char *key; /**< used by RCS File transfer messages to store the key to encrypt file if needed */
size_t keyLength; /**< Length of key in bytes */
void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */
bool_t owned_fields;
};
@ -1237,6 +1259,7 @@ void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx);
void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...);
int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx);
char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
const char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name);
void linphone_free_xml_text_content(const char *text);
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
@ -1290,6 +1313,7 @@ BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider),
BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch),
BELLE_SIP_TYPE_ID(LinphoneProxyConfig),
BELLE_SIP_TYPE_ID(LinphoneFriend),
BELLE_SIP_TYPE_ID(LinphoneFriendList),
BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequest),
BELLE_SIP_TYPE_ID(LinphoneXmlRpcRequestCbs),
BELLE_SIP_TYPE_ID(LinphoneXmlRpcSession),

View file

@ -855,10 +855,134 @@ int sal_lines_get_value(const char *data, const char *key, char *value, size_t v
return FALSE;
}
int sal_body_has_type(const SalBody *body, const char *type, const char *subtype){
return body->type && body->subtype
&& strcmp(body->type,type)==0
&& strcmp(body->subtype,subtype)==0;
static belle_sip_header_t * sal_body_handler_find_header(const SalBodyHandler *body_handler, const char *header_name) {
belle_sip_body_handler_t *bsbh = BELLE_SIP_BODY_HANDLER(body_handler);
const belle_sip_list_t *l = belle_sip_body_handler_get_headers(bsbh);
for (; l != NULL; l = l->next) {
belle_sip_header_t *header = BELLE_SIP_HEADER(l->data);
if (strcmp(belle_sip_header_get_name(header), header_name) == 0) {
return header;
}
}
return NULL;
}
SalBodyHandler * sal_body_handler_new(void) {
belle_sip_memory_body_handler_t *body_handler = belle_sip_memory_body_handler_new(NULL, NULL);
return (SalBodyHandler *)BELLE_SIP_BODY_HANDLER(body_handler);
}
SalBodyHandler * sal_body_handler_ref(SalBodyHandler *body_handler) {
return (SalBodyHandler *)belle_sip_object_ref(BELLE_SIP_OBJECT(body_handler));
}
void sal_body_handler_unref(SalBodyHandler *body_handler) {
belle_sip_object_unref(BELLE_SIP_OBJECT(body_handler));
}
const char * sal_body_handler_get_type(const SalBodyHandler *body_handler) {
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
if (content_type != NULL) {
return belle_sip_header_content_type_get_type(content_type);
}
return NULL;
}
void sal_body_handler_set_type(SalBodyHandler *body_handler, const char *type) {
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
if (content_type == NULL) {
content_type = belle_sip_header_content_type_new();
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_type));
}
belle_sip_header_content_type_set_type(content_type, type);
}
const char * sal_body_handler_get_subtype(const SalBodyHandler *body_handler) {
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
if (content_type != NULL) {
return belle_sip_header_content_type_get_subtype(content_type);
}
return NULL;
}
void sal_body_handler_set_subtype(SalBodyHandler *body_handler, const char *subtype) {
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
if (content_type == NULL) {
content_type = belle_sip_header_content_type_new();
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_type));
}
belle_sip_header_content_type_set_subtype(content_type, subtype);
}
const char * sal_body_handler_get_encoding(const SalBodyHandler *body_handler) {
belle_sip_header_t *content_encoding = sal_body_handler_find_header(body_handler, "Content-Encoding");
if (content_encoding != NULL) {
return belle_sip_header_get_unparsed_value(content_encoding);
}
return NULL;
}
void sal_body_handler_set_encoding(SalBodyHandler *body_handler, const char *encoding) {
belle_sip_header_t *content_encoding = sal_body_handler_find_header(body_handler, "Content-Encoding");
if (content_encoding != NULL) {
belle_sip_body_handler_remove_header_from_ptr(BELLE_SIP_BODY_HANDLER(body_handler), content_encoding);
}
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), belle_sip_header_create("Content-Encoding", encoding));
}
void * sal_body_handler_get_data(const SalBodyHandler *body_handler) {
return belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(body_handler));
}
void sal_body_handler_set_data(SalBodyHandler *body_handler, void *data) {
belle_sip_memory_body_handler_set_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(body_handler), data);
}
size_t sal_body_handler_get_size(const SalBodyHandler *body_handler) {
return belle_sip_body_handler_get_size(BELLE_SIP_BODY_HANDLER(body_handler));
}
void sal_body_handler_set_size(SalBodyHandler *body_handler, size_t size) {
belle_sip_header_content_length_t *content_length = BELLE_SIP_HEADER_CONTENT_LENGTH(sal_body_handler_find_header(body_handler, "Content-Length"));
if (content_length == NULL) {
content_length = belle_sip_header_content_length_new();
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_length));
}
belle_sip_header_content_length_set_content_length(content_length, size);
belle_sip_body_handler_set_size(BELLE_SIP_BODY_HANDLER(body_handler), size);
}
bool_t sal_body_handler_is_multipart(const SalBodyHandler *body_handler) {
if (BELLE_SIP_IS_INSTANCE_OF(body_handler, belle_sip_multipart_body_handler_t)) return TRUE;
return FALSE;
}
SalBodyHandler * sal_body_handler_get_part(const SalBodyHandler *body_handler, int idx) {
const belle_sip_list_t *l = belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler));
return (SalBodyHandler *)belle_sip_list_nth_data(l, idx);
}
SalBodyHandler * sal_body_handler_find_part_by_header(const SalBodyHandler *body_handler, const char *header_name, const char *header_value) {
const belle_sip_list_t *l = belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler));
for (; l != NULL; l = l->next) {
belle_sip_body_handler_t *bsbh = BELLE_SIP_BODY_HANDLER(l->data);
const belle_sip_list_t *headers = belle_sip_body_handler_get_headers(bsbh);
for (; headers != NULL; headers = headers->next) {
belle_sip_header_t *header = BELLE_SIP_HEADER(headers->data);
if ((strcmp(belle_sip_header_get_name(header), header_name) == 0) && (strcmp(belle_sip_header_get_unparsed_value(header), header_value) == 0)) {
return (SalBodyHandler *)bsbh;
}
}
}
return NULL;
}
const char * sal_body_handler_get_header(const SalBodyHandler *body_handler, const char *header_name) {
belle_sip_header_t *header = sal_body_handler_find_header(body_handler, header_name);
if (header != NULL) {
return belle_sip_header_get_unparsed_value(header);
}
return NULL;
}
belle_sip_stack_t *sal_get_belle_sip_stack(Sal *sal) {

View file

@ -89,6 +89,33 @@ char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *
return (char *)text;
}
const char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name) {
xmlXPathObjectPtr xpath_obj;
xmlChar *text = NULL;
xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
if (xpath_obj != NULL) {
if (xpath_obj->nodesetval != NULL) {
xmlNodeSetPtr nodes = xpath_obj->nodesetval;
if ((nodes != NULL) && (nodes->nodeNr >= 1)) {
xmlNodePtr node = nodes->nodeTab[0];
xmlAttr *attr = node->properties;
while (attr) {
if (strcmp((char *)attr->name, attribute_name) == 0) {
text = xmlStrcat(text, attr->children->content);
attr = NULL;
} else {
attr = attr->next;
}
}
}
}
xmlXPathFreeObject(xpath_obj);
}
return (const char *)text;
}
void linphone_free_xml_text_content(const char *text) {
xmlFree((xmlChar *)text);
}

View file

@ -118,6 +118,7 @@ bool_t linphone_gtk_is_friend(LinphoneCore *lc, const char *contact) {
char *uri = linphone_address_as_string_uri_only(addr);
LinphoneFriend *lf = linphone_core_get_friend_by_address(lc, uri);
linphone_address_destroy(addr);
if (uri) ms_free(uri);
if (lf) return TRUE;
}
return FALSE;

View file

@ -55,6 +55,10 @@ struct SalAddress;
typedef struct SalAddress SalAddress;
struct SalBodyHandler;
typedef struct SalBodyHandler SalBodyHandler;
struct SalCustomHeader;
typedef struct SalCustomHeader SalCustomHeader;
@ -455,14 +459,6 @@ typedef struct SalAuthInfo{
SalCertificatesChain *certificates;
}SalAuthInfo;
typedef struct SalBody{
const char *type;
const char *subtype;
const void *data;
size_t size;
const char *encoding;
}SalBody;
typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnCallAccepted)(SalOp *op);
@ -484,8 +480,8 @@ typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus);
typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing);
typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state);
typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status);
typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, const SalBody *body);
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBody *body);
typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, SalBodyHandler *body);
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBodyHandler *body);
typedef void (*SalOnSubscribeClosed)(SalOp *salop);
typedef void (*SalOnParsePresenceRequested)(SalOp *salop, const char *content_type, const char *content_subtype, const char *content, SalPresenceModel **result);
typedef void (*SalOnConvertPresenceToXMLRequested)(SalOp *salop, SalPresenceModel *presence, const char *contact, char **content);
@ -493,7 +489,7 @@ typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenc
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 (*SalOnInfoReceived)(SalOp *salop, SalBodyHandler *body);
typedef void (*SalOnPublishResponse)(SalOp *salop);
typedef void (*SalOnExpire)(SalOp *salop);
/*allows sal implementation to access auth info if available, return TRUE if found*/
@ -741,16 +737,17 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expire
int sal_ping(SalOp *op, const char *from, const char *to);
/*info messages*/
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body);
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBodyHandler *body);
/*generic subscribe/notify/publish api*/
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body);
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body);
int sal_unsubscribe(SalOp *op);
int sal_subscribe_accept(SalOp *op);
int sal_subscribe_decline(SalOp *op, SalReason reason);
int sal_notify(SalOp *op, const SalBody *body);
int sal_subscribe_refresh(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 SalBody *body);
int sal_publish(SalOp *op, const char *from, const char *to, const char*event_name, int expires, const SalBodyHandler *body);
/*privacy, must be in sync with LinphonePrivacyMask*/
typedef enum _SalPrivacy {
@ -846,7 +843,25 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size);
belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name);
void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer);
int sal_body_has_type(const SalBody *body, const char *type, const char *subtype);
//SalBodyHandler * sal_body_handler_new(const char *type, const char *subtype, void *data, size_t size, const char *encoding);
SalBodyHandler * sal_body_handler_new(void);
SalBodyHandler * sal_body_handler_ref(SalBodyHandler *body_handler);
void sal_body_handler_unref(SalBodyHandler *body_handler);
const char * sal_body_handler_get_type(const SalBodyHandler *body_handler);
void sal_body_handler_set_type(SalBodyHandler *body_handler, const char *type);
const char * sal_body_handler_get_subtype(const SalBodyHandler *body_handler);
void sal_body_handler_set_subtype(SalBodyHandler *body_handler, const char *subtype);
const char * sal_body_handler_get_encoding(const SalBodyHandler *body_handler);
void sal_body_handler_set_encoding(SalBodyHandler *body_handler, const char *encoding);
void * sal_body_handler_get_data(const SalBodyHandler *body_handler);
void sal_body_handler_set_data(SalBodyHandler *body_handler, void *data);
size_t sal_body_handler_get_size(const SalBodyHandler *body_handler);
void sal_body_handler_set_size(SalBodyHandler *body_handler, size_t size);
bool_t sal_body_handler_is_multipart(const SalBodyHandler *body_handler);
SalBodyHandler * sal_body_handler_get_part(const SalBodyHandler *body_handler, int idx);
SalBodyHandler * sal_body_handler_find_part_by_header(const SalBodyHandler *body_handler, const char *header_name, const char *header_value);
const char * sal_body_handler_get_header(const SalBodyHandler *body_handler, const char *header_name);
/*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/
int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size);

View file

@ -998,6 +998,16 @@ public interface LinphoneCore {
* @throws LinphoneCoreException
*/
void addFriend(LinphoneFriend lf) throws LinphoneCoreException;
/**
* Sets the friend list for the linphone core.
*/
void setFriendList(LinphoneFriendList friendList) throws LinphoneCoreException;
/**
* Creates a friend list.
*/
LinphoneFriendList createLinphoneFriendList() throws LinphoneCoreException;
/**
* Get list of LinphoneFriend

View file

@ -0,0 +1,27 @@
/*
LinphoneFriend.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
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.
*/
package org.linphone.core;
public interface LinphoneFriendList {
public void setRLSUri(String uri);
public void addFriend(LinphoneFriend friend);
public void updateSubscriptions(LinphoneProxyConfig proxyConfig,boolean onlyWhenRegistered);
long getNativePtr();
}

View file

@ -94,6 +94,7 @@ class LinphoneCoreImpl implements LinphoneCore {
private native void setPreviewWindowId(long nativePtr, Object wid);
private native void setDeviceRotation(long nativePtr, int rotation);
private native void addFriend(long nativePtr,long friend);
private native void setFriendList(long nativePtr,long friendList);
private native LinphoneFriend[] getFriendList(long nativePtr);
private native void setPresenceInfo(long nativePtr, int minutes_away, String alternative_contact, int status);
private native int getPresenceInfo(long nativePtr);
@ -448,6 +449,15 @@ class LinphoneCoreImpl implements LinphoneCore {
public synchronized void addFriend(LinphoneFriend lf) throws LinphoneCoreException {
addFriend(nativePtr,((LinphoneFriendImpl)lf).nativePtr);
}
public synchronized LinphoneFriendList createLinphoneFriendList() {
return new LinphoneFriendListImpl(this);
}
public synchronized void setFriendList(LinphoneFriendList friendList) throws LinphoneCoreException {
setFriendList(nativePtr,((LinphoneFriendListImpl)friendList).nativePtr);
}
public synchronized LinphoneFriend[] getFriendList() {
return getFriendList(nativePtr);

View file

@ -0,0 +1,80 @@
/*
LinphoneFriendImpl.java
Copyright (C) 2010 Belledonne Communications, Grenoble, France
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.
*/
package org.linphone.core;
import java.io.Serializable;
import org.linphone.core.LinphoneProxyConfigImpl;
class LinphoneFriendListImpl implements LinphoneFriendList, Serializable {
protected final long nativePtr;
private native void finalize(long nativePtr);
private native long newLinphoneFriendList(long corePtr);
private native void setRLSUri(long nativePtr,String uri);
private native void addFriend(long nativePtr,long friendPtr);
private native void updateSubscriptions(long nativePtr,long proxyConfigPtr,boolean onlyWhenRegistered);
private native Object getCore(long ptr);
protected LinphoneFriendListImpl(LinphoneCoreImpl core) {
nativePtr = newLinphoneFriendList(core.nativePtr);
}
@Override
public void setRLSUri(String uri) {
synchronized(getSyncObject()){
setRLSUri(nativePtr, uri);
}
}
@Override
public void addFriend(LinphoneFriend friend) {
synchronized(getSyncObject()){
addFriend(nativePtr, friend.getNativePtr());
}
}
@Override
public void updateSubscriptions(LinphoneProxyConfig proxyConfig,boolean onlyWhenRegistered) {
synchronized(getSyncObject()){
updateSubscriptions(nativePtr, ((LinphoneProxyConfigImpl)proxyConfig).nativePtr,onlyWhenRegistered);
}
}
/*reserved for JNI */
protected LinphoneFriendListImpl(long aNativePtr) {
nativePtr = aNativePtr;
}
@Override
protected void finalize() throws Throwable {
if (nativePtr != 0) {
finalize(nativePtr);
}
super.finalize();
}
@Override
public long getNativePtr() {
return nativePtr;
}
private Object getSyncObject(){
return this;
}
}

View file

@ -48,7 +48,7 @@ void check_rtcp(LinphoneCall *call) {
linphone_call_unref(call);
}
static FILE *sip_start(const char *senario, const char* dest_username, LinphoneAddress* dest_addres) {
FILE *sip_start(const char *senario, const char* dest_username, LinphoneAddress* dest_addres) {
#if HAVE_SIPP
char *dest;
char *command;

View file

@ -39,7 +39,10 @@ const char *liblinphone_tester_get_notify_content(void){
void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){
LinphoneCoreManager *mgr;
BC_ASSERT_PTR_NOT_NULL_FATAL(content);
BC_ASSERT_STRING_EQUAL(notify_content,(const char*)linphone_content_get_buffer(content));
if (!linphone_content_is_multipart(content)) {
/*hack to disable content checking for list notify */
BC_ASSERT_STRING_EQUAL(notify_content,(const char*)linphone_content_get_buffer(content));
}
mgr=get_manager(lc);
mgr->stat.number_of_NotifyReceived++;
}

View file

@ -38,9 +38,9 @@ aliases=localhost sip2.linphone.org sipopen.example.org sip.example.org auth.exa
# Default value: sip:*
#transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061
#note: the ip addresses are explicitely specified here because the machine has several interfaces. In a simple case, using '*' instead of the explicit ip address is sufficient,
#note: the ip addresses are explicitely specified here because the machine has several interfaces. In a simple case, using '*' instead of the explicit ip address is sufficient,
#and there is no need to specify the ipv6 transport addresses.
transports=sip:MacBook-Pro-de-jehan.local:5060 sips:MacBook-Pro-de-jehan.local:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:MacBook-Pro-de-jehan.local:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:MacBook-Pro-de-jehan.local:5063;require-peer-certificate=1 sip:MacBook-Pro-de-jehan.local:5064 sip:[2001:41d0:2:14b0::1]:5060 sips:[2001:41d0:2:14b0::1]:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:[2001:41d0:2:14b0::1]:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:[2001:41d0:2:14b0::1]:5063;require-peer-certificate=1 sip:[2001:41d0:2:14b0::1]:5064
transports=sip:94.23.19.176:5060 sips:94.23.19.176:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:94.23.19.176:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:94.23.19.176:5063;require-peer-certificate=1 sip:94.23.19.176:5064 sip:[2001:41d0:2:14b0::1]:5060 sips:[2001:41d0:2:14b0::1]:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:[2001:41d0:2:14b0::1]:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:[2001:41d0:2:14b0::1]:5063;require-peer-certificate=1 sip:[2001:41d0:2:14b0::1]:5064
# An absolute path of a directory where TLS server certificate and
@ -107,20 +107,19 @@ no-403=user-agent contains 'tester-no-403'
# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain
# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org')
# && (user-agent == 'Linphone v2')
# Default value:
filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains 'auth.example.org' || from.uri.domain contains 'auth1.example.org' || from.uri.domain contains 'auth2.example.org' || from.uri.domain contains 'anonymous.invalid'
# Default value:
filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains 'auth.example.org' || from.uri.domain contains 'auth1.example.org' || from.uri.domain contains 'auth2.example.org' || from.uri.domain contains 'anonymous.invalid'
# List of whitespace separated domain names to challenge. Others
# are denied.
# Default value:
# Default value:
auth-domains= sip.example.org auth.example.org auth1.example.org auth2.example.org
client-certificates-domains=client.example.org
# List of whitespace separated IP which will not be challenged.
# Default value:
trusted-hosts=
# Default value:
trusted-hosts=127.0.0.1 94.23.19.176
# Database backend implementation [odbc, file].
# Default value: odbc
@ -615,3 +614,11 @@ packet-rate-limit=5
# Default value: 2
ban-time=1
[module::Presence]
enabled=true
presence-server = <sip:127.0.0.1:5065;transport=tcp>
[presence-server]
expires = 600
transports = sip:127.0.0.1:5065;transport=tcp

View file

@ -884,6 +884,171 @@ static void dos_module_trigger(void) {
linphone_core_manager_destroy(pauline);
}
static void test_subscribe_notify_with_sipp_publisher(void) {
char *scen;
FILE * sipp_out;
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
/*just to get an identity*/
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LpConfig *pauline_lp = linphone_core_get_config(pauline->lc);
char* lf_identity=linphone_address_as_string_uri_only(marie->identity);
LinphoneFriend *lf = linphone_core_create_friend_with_address(pauline->lc,lf_identity);
ms_free(lf_identity);
lp_config_set_int(pauline_lp,"sip","subscribe_expires",5);
linphone_core_add_friend(pauline->lc,lf);
/*wait for subscribe acknowledgment*/
wait_for_until(pauline->lc,pauline->lc,&pauline->stat.number_of_NotifyReceived,1,2000);
BC_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf), int, "%d");
scen = bc_tester_res("sipp/simple_publish.xml");
sipp_out = sip_start(scen, linphone_address_get_username(marie->identity), marie->identity);
if (TRUE/*sipp_out*/) {
/*wait for marie status*/
wait_for_until(pauline->lc,pauline->lc,&pauline->stat.number_of_NotifyReceived,2,3000);
BC_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf), int, "%d");
pclose(sipp_out);
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void test_subscribe_notify_with_sipp_publisher_double_publish(void) {
char *scen;
FILE * sipp_out;
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
/*just to get an identity*/
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LpConfig *pauline_lp = linphone_core_get_config(pauline->lc);
char* lf_identity=linphone_address_as_string_uri_only(marie->identity);
LinphoneFriend *lf = linphone_core_create_friend_with_address(pauline->lc,lf_identity);
ms_free(lf_identity);
lp_config_set_int(pauline_lp,"sip","subscribe_expires",5);
linphone_core_add_friend(pauline->lc,lf);
/*wait for subscribe acknowledgment*/
wait_for_until(pauline->lc,pauline->lc,&pauline->stat.number_of_NotifyReceived,1,2000);
BC_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf), int, "%d");
scen = bc_tester_res("sipp/double_publish_with_error.xml");
sipp_out = sip_start(scen, linphone_address_get_username(marie->identity), marie->identity);
if (sipp_out) {
/*wait for marie status*/
wait_for_until(pauline->lc,pauline->lc,&pauline->stat.number_of_NotifyReceived,2,3000);
BC_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf), int, "%d");
pclose(sipp_out);
BC_ASSERT_EQUAL(pauline->stat.number_of_NotifyReceived,2,int, "%d");
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void test_publish_unpublish(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneProxyConfig* proxy;
linphone_core_get_default_proxy(marie->lc,&proxy);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
wait_core(marie->lc);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,FALSE);
linphone_proxy_config_done(proxy);
wait_core(marie->lc);
linphone_core_manager_destroy(marie);
}
static void test_list_subscribe (void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc");
char *list = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<resource-lists xmlns=\"urn:ietf:params:xml:ns:resource-lists\"\n"
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
"<list>\n"
"\t<entry uri=\"%s\" />\n"
"\t<entry uri=\"%s\" />\n"
"</list>\n"
"</resource-lists>\n";
LinphoneEvent *lev;
MSList* lcs=ms_list_append(NULL,marie->lc);
char * pauline_uri=linphone_address_as_string_uri_only(pauline->identity);
char * laure_uri=linphone_address_as_string_uri_only(laure->identity);
char * subscribe_content = ms_strdup_printf(list,pauline_uri,laure_uri);
LinphoneContent* content = linphone_core_create_content(marie->lc);
LinphoneAddress *list_name = linphone_address_new("sip:mescops@sip.example.org");
LinphoneProxyConfig* proxy_config;
int dummy=0;
ms_free(pauline_uri);
ms_free(laure_uri);
lcs=ms_list_append(lcs,pauline->lc);
lcs=ms_list_append(lcs,laure->lc);
linphone_content_set_type(content,"application");
linphone_content_set_subtype(content,"resource-lists+xml");
linphone_content_set_buffer(content,subscribe_content,strlen(subscribe_content));
lev=linphone_core_create_subscribe(marie->lc,list_name,"presence",60);
linphone_event_add_custom_header(lev,"Supported","eventlist");
linphone_event_add_custom_header(lev,"Accept","application/pidf+xml, application/rlmi+xml");
linphone_event_add_custom_header(lev,"Content-Disposition", "recipient-list");
linphone_event_send_subscribe(lev,content);
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,5000));
/*make sure marie receives first notification before terminating*/
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,5000));
/*dummy wait to avoid derred notify*/
wait_for_list(lcs,&dummy,1,2000);
linphone_core_get_default_proxy(pauline->lc,&proxy_config);
linphone_proxy_config_edit(proxy_config);
linphone_proxy_config_enable_publish(proxy_config,TRUE);
linphone_proxy_config_done(proxy_config);
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,2,5000));
linphone_core_get_default_proxy(laure->lc,&proxy_config);
linphone_proxy_config_edit(proxy_config);
linphone_proxy_config_enable_publish(proxy_config,TRUE);
linphone_proxy_config_done(proxy_config);
/*make sure notify is not sent "imadiatly but defered*/
BC_ASSERT_FALSE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,3,1000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,3,5000));
linphone_event_terminate(lev);
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,5000));
ms_free(subscribe_content);
linphone_address_destroy(list_name);
linphone_content_unref(content);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(laure);
}
test_t flexisip_tests[] = {
{ "Subscribe forking", subscribe_forking },
{ "Message forking", message_forking },
@ -901,6 +1066,10 @@ test_t flexisip_tests[] = {
{ "Call with sips", call_with_sips },
{ "Call with sips not achievable", call_with_sips_not_achievable },
{ "Call with ipv6", call_with_ipv6 },
{ "Subscribe Notify with sipp publisher", test_subscribe_notify_with_sipp_publisher },
{ "Subscribe Notify with sipp double publish", test_subscribe_notify_with_sipp_publisher_double_publish },
{ "Publish/unpublish", test_publish_unpublish },
{ "List subscribe", test_list_subscribe },
{ "File transfer message rcs to external body client", file_transfer_message_rcs_to_external_body_client },
{ "File transfer message external body to rcs client", file_transfer_message_external_body_to_rcs_client },
{ "File transfer message external body to external body client", file_transfer_message_external_body_to_external_body_client },

View file

@ -153,6 +153,7 @@ typedef struct _stats {
int number_of_NewSubscriptionRequest;
int number_of_NotifyReceived;
int number_of_NotifyPresenceReceived;
int number_of_LinphonePresenceActivityOffline;
int number_of_LinphonePresenceActivityOnline;
int number_of_LinphonePresenceActivityAppointment;
@ -351,6 +352,10 @@ bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, Linph
extern const char *liblinphone_tester_mire_id;
FILE *sip_start(const char *senario, const char* dest_username, LinphoneAddress* dest_addres);
void wait_core(LinphoneCore *core) ;
#ifdef __cplusplus
};

View file

@ -46,10 +46,10 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) {
stats* counters;
LinphonePresenceActivity *activity = NULL;
char* from=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("New Notify request from [%s] ",from);
ms_message("New Notify request from [%s] ",from);
ms_free(from);
counters = get_stats(lc);
counters->number_of_NotifyReceived++;
counters->number_of_NotifyPresenceReceived++;
counters->last_received_presence = linphone_friend_get_presence_model(lf);
activity = linphone_presence_model_get_activity(counters->last_received_presence);
@ -115,7 +115,7 @@ void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) {
}
}
static void wait_core(LinphoneCore *core) {
void wait_core(LinphoneCore *core) {
int i;
for (i = 0; i < 10; i++) {
@ -173,9 +173,9 @@ static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,Linph
BC_ASSERT_EQUAL(callee_mgr->stat.number_of_NewSubscriptionRequest,initial_callee.number_of_NewSubscriptionRequest+1, int, "%d");
/*without proxy, callee cannot subscribe to caller
BC_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyReceived,initial_callee.number_of_NotifyReceived+1, int, "%d");
BC_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyPresenceReceived,initial_callee.number_of_NotifyPresenceReceived+1, int, "%d");
*/
BC_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyReceived,initial_caller.number_of_NotifyReceived+1, int, "%d");
BC_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyPresenceReceived,initial_caller.number_of_NotifyPresenceReceived+1, int, "%d");
ms_free(identity);
return result;
@ -448,7 +448,7 @@ static void test_subscribe_notify_publish(void) {
linphone_core_add_friend(pauline->lc,lf);
/*wait for subscribe acknowledgment*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,1,2000);
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyPresenceReceived,1,2000);
BC_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf), int, "%d");
/*enable publish*/
@ -461,23 +461,23 @@ static void test_subscribe_notify_publish(void) {
linphone_proxy_config_done(proxy);
/*wait for marie status*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,2,2000);
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyPresenceReceived,2,2000);
BC_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf), int, "%d");
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL);
linphone_core_set_presence_model(marie->lc,presence);
/*wait for new status*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,3,2000);
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyPresenceReceived,3,2000);
BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d");
/*wait for refresh*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyPresenceReceived,4,5000);
BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d");
/*linphone_core_remove_friend(pauline->lc,lf);*/
/*wait for final notify*/
/*wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
/*wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyPresenceReceived,4,5000);
BC_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf), int, "%d");
*/
linphone_core_manager_destroy(marie);
@ -507,7 +507,7 @@ static void test_forked_subscribe_notify_publish(void) {
linphone_core_add_friend(pauline->lc,lf);
/*wait for subscribe acknowledgment*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,1,2000);
wait_for_list(lcs,&pauline->stat.number_of_NotifyPresenceReceived,1,2000);
BC_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf), int, "%d");
/*enable publish*/
@ -526,21 +526,21 @@ static void test_forked_subscribe_notify_publish(void) {
/*wait for marie status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,3,2000);
wait_for_list(lcs,&pauline->stat.number_of_NotifyPresenceReceived,3,2000);
BC_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf), int, "%d");
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL);
linphone_core_set_presence_model(marie->lc,presence);
/*wait for new status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,4,2000);
wait_for_list(lcs,&pauline->stat.number_of_NotifyPresenceReceived,4,2000);
BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d");
presence =linphone_presence_model_new_with_activity( LinphonePresenceActivityMeeting,NULL);
linphone_core_set_presence_model(marie2->lc,presence);
/*wait for new status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,5,2000);
wait_for_list(lcs,&pauline->stat.number_of_NotifyPresenceReceived,5,2000);
BC_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf), int, "%d"); /*because liblinphone compositor is very simple for now (I.E only take first occurence)*/
linphone_core_manager_destroy(marie);
@ -551,6 +551,190 @@ static void test_forked_subscribe_notify_publish(void) {
#endif
const char * get_identity(LinphoneCoreManager *mgr) {
LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(mgr->lc);
return linphone_proxy_config_get_identity(cfg);
}
static void enable_publish(LinphoneCoreManager *mgr, bool_t enable) {
LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(mgr->lc);
linphone_proxy_config_edit(cfg);
linphone_proxy_config_enable_publish(cfg, enable);
linphone_proxy_config_set_publish_expires(cfg, 60);
linphone_proxy_config_done(cfg);
}
static void test_presence_list(void) {
LinphoneCoreManager *laure = linphone_core_manager_new("laure_tcp_rc");
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
const char *rls_uri = "sip:rls@sip.example.org";
LinphoneFriendList *lfl;
LinphoneFriend *lf;
const char *laure_identity;
const char *marie_identity;
const char *pauline_identity;
MSList* lcs = NULL;
laure_identity = get_identity(laure);
marie_identity = get_identity(marie);
pauline_identity = get_identity(pauline);
enable_publish(marie, TRUE);
enable_publish(pauline, TRUE);
enable_publish(laure, TRUE);
linphone_core_set_presence_model(marie->lc, linphone_core_create_presence_model_with_activity(marie->lc, LinphonePresenceActivityBusy, NULL));
linphone_core_set_presence_model(pauline->lc, linphone_core_create_presence_model_with_activity(pauline->lc, LinphonePresenceActivityVacation, NULL));
lfl = linphone_core_create_friend_list(laure->lc);
linphone_friend_list_set_rls_uri(lfl, rls_uri);
lf = linphone_core_create_friend_with_address(laure->lc, marie_identity);
linphone_friend_list_add_friend(lfl, lf);
lf = linphone_core_create_friend_with_address(laure->lc, pauline_identity);
linphone_friend_list_add_friend(lfl, lf);
lf = linphone_core_create_friend_with_address(laure->lc, "sip:michelle@sip.inexistentdomain.com");
linphone_friend_list_add_friend(lfl, lf);
linphone_core_set_friend_list(laure->lc, lfl);
linphone_friend_list_unref(lfl);
linphone_core_set_presence_model(laure->lc, linphone_core_create_presence_model_with_activity(laure->lc, LinphonePresenceActivityOnline, NULL));
lcs = ms_list_append(lcs, laure->lc);
lcs = ms_list_append(lcs, marie->lc);
lcs = ms_list_append(lcs, pauline->lc);
wait_for_list(lcs, &laure->stat.number_of_NotifyReceived, 2, 2000);
wait_for_list(lcs, &laure->stat.number_of_NotifyPresenceReceived, 2, 2000);
BC_ASSERT_EQUAL(laure->stat.number_of_NotifyReceived, 2, int, "%d");
BC_ASSERT_EQUAL(laure->stat.number_of_NotifyPresenceReceived, 2, int, "%d");
BC_ASSERT_EQUAL(laure->lc->friendlist->expected_notification_version, 1, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(laure->lc->friendlist, marie_identity);
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusBusy, int, "%d");
BC_ASSERT_EQUAL(lf->presence_received, TRUE, int, "%d");
BC_ASSERT_EQUAL(lf->subscribe_active, TRUE, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(laure->lc->friendlist, pauline_identity);
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d");
BC_ASSERT_EQUAL(lf->presence_received, TRUE, int, "%d");
BC_ASSERT_EQUAL(lf->subscribe_active, TRUE, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(laure->lc->friendlist, "sip:michelle@sip.inexistentdomain.com");
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d");
BC_ASSERT_EQUAL(lf->presence_received, FALSE, int, "%d");
BC_ASSERT_EQUAL(lf->subscribe_active, TRUE, int, "%d");
lfl = linphone_core_create_friend_list(marie->lc);
linphone_friend_list_set_rls_uri(lfl, rls_uri);
lf = linphone_core_create_friend_with_address(marie->lc, laure_identity);
linphone_friend_list_add_friend(lfl, lf);
linphone_core_set_friend_list(marie->lc, lfl);
linphone_friend_list_unref(lfl);
linphone_friend_list_update_subscriptions(marie->lc->friendlist, NULL, FALSE);
wait_for_list(lcs, &marie->stat.number_of_NotifyReceived, 1, 2000);
wait_for_list(lcs, &marie->stat.number_of_NotifyPresenceReceived, 1, 2000);
BC_ASSERT_EQUAL(marie->stat.number_of_NotifyReceived, 1, int, "%d");
BC_ASSERT_EQUAL(marie->stat.number_of_NotifyPresenceReceived, 1, int, "%d");
BC_ASSERT_EQUAL(marie->lc->friendlist->expected_notification_version, 1, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(marie->lc->friendlist, laure_identity);
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOnline, int, "%d");
BC_ASSERT_EQUAL(lf->presence_received, TRUE, int, "%d");
BC_ASSERT_EQUAL(lf->subscribe_active, TRUE, int, "%d");
lfl = linphone_core_create_friend_list(pauline->lc);
linphone_friend_list_set_rls_uri(lfl, rls_uri);
lf = linphone_core_create_friend_with_address(pauline->lc, marie_identity);
linphone_friend_list_add_friend(lfl, lf);
linphone_core_set_friend_list(pauline->lc, lfl);
linphone_friend_list_unref(lfl);
linphone_friend_list_update_subscriptions(pauline->lc->friendlist, NULL, FALSE);
wait_for_list(lcs, &pauline->stat.number_of_NotifyReceived, 1, 2000);
wait_for_list(lcs, &pauline->stat.number_of_NotifyPresenceReceived, 1, 2000);
BC_ASSERT_EQUAL(pauline->stat.number_of_NotifyReceived, 1, int, "%d");
BC_ASSERT_EQUAL(pauline->stat.number_of_NotifyPresenceReceived, 1, int, "%d");
BC_ASSERT_EQUAL(pauline->lc->friendlist->expected_notification_version, 1, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(pauline->lc->friendlist, marie_identity);
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusBusy, int, "%d");
BC_ASSERT_EQUAL(lf->presence_received, TRUE, int, "%d");
BC_ASSERT_EQUAL(lf->subscribe_active, TRUE, int, "%d");
linphone_core_set_presence_model(marie->lc, linphone_core_create_presence_model_with_activity(marie->lc, LinphonePresenceActivityOnThePhone, NULL));
wait_for_list(lcs, &laure->stat.number_of_NotifyReceived, 3, 2000);
wait_for_list(lcs, &laure->stat.number_of_NotifyPresenceReceived, 4, 2000);
BC_ASSERT_EQUAL(laure->stat.number_of_NotifyReceived, 3, int, "%d");
BC_ASSERT_EQUAL(laure->stat.number_of_NotifyPresenceReceived, 4, int, "%d");
BC_ASSERT_EQUAL(laure->lc->friendlist->expected_notification_version, 2, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(laure->lc->friendlist, marie_identity);
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOnThePhone, int, "%d");
wait_for_list(lcs, &pauline->stat.number_of_NotifyReceived, 2, 2000);
wait_for_list(lcs, &pauline->stat.number_of_NotifyPresenceReceived, 2, 2000);
BC_ASSERT_EQUAL(pauline->stat.number_of_NotifyReceived, 2, int, "%d");
BC_ASSERT_EQUAL(pauline->stat.number_of_NotifyPresenceReceived, 2, int, "%d");
BC_ASSERT_EQUAL(pauline->lc->friendlist->expected_notification_version, 2, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(pauline->lc->friendlist, marie_identity);
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOnThePhone, int, "%d");
enable_publish(laure, FALSE);
enable_publish(marie, FALSE);
enable_publish(pauline, FALSE);
linphone_core_manager_destroy(laure);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void test_presence_list_subscribe_before_publish(void) {
LinphoneCoreManager *laure = linphone_core_manager_new("laure_tcp_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
const char *rls_uri = "sip:rls@sip.example.org";
LinphoneFriendList *lfl;
LinphoneFriend *lf;
const char *pauline_identity;
MSList* lcs = NULL;
int dummy = 0;
pauline_identity = get_identity(pauline);
linphone_core_set_presence_model(pauline->lc, linphone_core_create_presence_model_with_activity(pauline->lc, LinphonePresenceActivityVacation, NULL));
lfl = linphone_core_create_friend_list(laure->lc);
linphone_friend_list_set_rls_uri(lfl, rls_uri);
lf = linphone_core_create_friend_with_address(laure->lc, pauline_identity);
linphone_friend_list_add_friend(lfl, lf);
lf = linphone_core_create_friend_with_address(laure->lc, "sip:michelle@sip.inexistentdomain.com");
linphone_friend_list_add_friend(lfl, lf);
linphone_core_set_friend_list(laure->lc, lfl);
linphone_friend_list_unref(lfl);
linphone_core_set_presence_model(laure->lc, linphone_core_create_presence_model_with_activity(laure->lc, LinphonePresenceActivityOnline, NULL));
linphone_friend_list_update_subscriptions(laure->lc->friendlist, NULL, FALSE);
lcs = ms_list_append(lcs, laure->lc);
lcs = ms_list_append(lcs, pauline->lc);
wait_for_list(lcs, &dummy, 1, 2000); /* Wait a little bit for the subscribe to happen */
enable_publish(pauline, TRUE);
wait_for_list(lcs, &pauline->stat.number_of_NotifyReceived, 1, 2000);
wait_for_list(lcs, &pauline->stat.number_of_NotifyPresenceReceived, 1, 2000);
BC_ASSERT_GREATER(laure->stat.number_of_NotifyReceived, 1, int, "%d");
BC_ASSERT_GREATER(laure->stat.number_of_NotifyPresenceReceived, 1, int, "%d");
BC_ASSERT_GREATER(laure->lc->friendlist->expected_notification_version, 1, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(laure->lc->friendlist, pauline_identity);
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusVacation, int, "%d");
BC_ASSERT_EQUAL(lf->presence_received, TRUE, int, "%d");
BC_ASSERT_EQUAL(lf->subscribe_active, TRUE, int, "%d");
lf = linphone_friend_list_find_friend_by_uri(laure->lc->friendlist, "sip:michelle@sip.inexistentdomain.com");
BC_ASSERT_EQUAL(linphone_friend_get_status(lf), LinphoneStatusOffline, int, "%d");
BC_ASSERT_EQUAL(lf->presence_received, FALSE, int, "%d");
BC_ASSERT_EQUAL(lf->subscribe_active, TRUE, int, "%d");
enable_publish(laure, FALSE);
enable_publish(pauline, FALSE);
linphone_core_manager_destroy(laure);
linphone_core_manager_destroy(pauline);
}
test_t presence_tests[] = {
{ "Simple Subscribe", simple_subscribe },
{ "Simple Publish", simple_publish },
@ -565,6 +749,8 @@ test_t presence_tests[] = {
{ "Subscribe with late publish", test_subscribe_notify_publish },
{ "Forked subscribe with late publish", test_forked_subscribe_notify_publish },
#endif
{ "Presence list", test_presence_list },
{ "Presence list (subscribe before publish)", test_presence_list_subscribe_before_publish }
};
test_suite_t presence_test_suite = {"Presence", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,

View file

@ -0,0 +1,46 @@
[sip]
sip_port=5092
sip_tcp_port=5092
sip_tls_port=5093
default_proxy=0
ping_with_options=0
register_only_when_network_is_up=0
[auth_info_0]
username=laure
userid=laure
passwd=secret
realm="sip.example.org"
[proxy_0]
reg_proxy=sip.example.org;transport=tcp
reg_identity=sip:laure@sip.example.org
reg_expires=3600
reg_sendregister=1
publish=0
dial_escape_plus=0
[rtp]
audio_rtp_port=9010-9390
video_rtp_port=9410-9910
[video]
display=0
capture=0
show_local=0
size=qcif
enabled=0
self_view=0
automatically_initiate=0
automatically_accept=0
device=StaticImage: Static picture
[sound]
echocancellation=0 #to not overload cpu in case of VG
[net]
dns_srv_enabled=0 #no srv needed in general
stun_server=stun.linphone.org

View file

@ -41,6 +41,8 @@ static void core_init_test(void) {
static void linphone_address_test(void) {
linphone_address_destroy(create_linphone_address(NULL));
BC_ASSERT_PTR_NULL(linphone_address_new("sip:@sip.linphone.org"));
}
static void core_sip_transport_test(void) {

View file

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<!-- 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 -->
<!-- -->
<!-- Sipp default 'uac' scenario. -->
<!-- -->
<scenario name="Basic Sipstone publish">
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
<!-- generated by sipp. To do so, use [call_id] keyword. -->
<send retrans="500">
<![CDATA[
PUBLISH sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:[service]@sip.example.org>;tag=[pid]SIPpTag00[call_number]
To: sipp <sip:[service]@sip.example.org>
Call-ID: [call_id]
CSeq: 1 PUBLISH
Max-Forwards: 70
Expire: 60
Event: presence
Content-Type: application/pidf+xml
Content-Length: [len]
<?xml version="1.0" encoding="UTF-8"?>
<presence xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:rpid="urn:ietf:params:xml:ns:pidf:rpid" entity="sip:[service]@sip.example.org" xmlns="urn:ietf:params:xml:ns:pidf">
<tuple id="jjlson">
<status>
<basic>open</basic>
</status>
<contact priority="0.8">sip:[service]@[local_ip]:[local_port]</contact>
<timestamp>2015-09-28T15:49:00Z</timestamp>
</tuple>
</presence>
]]>
</send>
<recv response="100"
optional="true">
</recv>
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
<!-- are saved and used for following messages sent. Useful to test -->
<!-- against stateful SIP proxies/B2BUAs. -->
<recv response="200" rrs="true">
</recv>
<send retrans="500">
<![CDATA[
PUBLISH sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:[service]@sip.example.org>;tag=[pid]SIPpTag00[call_number]
To: sipp <sip:[service]-2@sip.example.org>
Call-ID: [call_id]-2
CSeq: 1 PUBLISH
Max-Forwards: 70
Expire: 60
Event: presence
Content-Type: application/pidf+xml
Content-Length: [len]
<?xml version="1.0" encoding="UTF-8"?>
<presence xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:rpid="urn:ietf:params:xml:ns:pidf:rpid" entity="sip:[service]@sip.example.org" xmlns="urn:ietf:params:xml:ns:pidf">
<tuple id="jjlson">
<status>
<basic>open</basic>
</status>
<contact priority="0.8">sip:[service]@[local_ip]:[local_port]</contact>
<timestamp>2015-09-28T15:49:00Z</timestamp>
</tuple>
</presence>
]]>
</send>
<recv response="100"
optional="true">
</recv>
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
<!-- are saved and used for following messages sent. Useful to test -->
<!-- against stateful SIP proxies/B2BUAs. -->
<recv response="200" rrs="true">
</recv>
<!-- definition of the response time repartition table (unit is ms) -->
<!-- definition of the response time repartition table (unit is ms) -->
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
<!-- definition of the call length repartition table (unit is ms) -->
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
</scenario>

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<!-- 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 -->
<!-- -->
<!-- Sipp default 'uac' scenario. -->
<!-- -->
<scenario name="Basic Sipstone publish">
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
<!-- generated by sipp. To do so, use [call_id] keyword. -->
<send retrans="500">
<![CDATA[
PUBLISH sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:[service]@sip.example.org>;tag=[pid]SIPpTag00[call_number]
To: sipp <sip:[service]@sip.example.org>
Call-ID: [call_id]
CSeq: 1 PUBLISH
Max-Forwards: 70
Expire: 60
Event: presence
Content-Type: application/pidf+xml
Content-Length: [len]
<?xml version="1.0" encoding="UTF-8"?>
<presence xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:rpid="urn:ietf:params:xml:ns:pidf:rpid" entity="sip:[service]@sip.example.org" xmlns="urn:ietf:params:xml:ns:pidf">
<tuple id="jjlson">
<status>
<basic>open</basic>
</status>
<contact priority="0.8">sip:[service]@[local_ip]:[local_port]</contact>
<timestamp>2015-09-28T15:49:00Z</timestamp>
</tuple>
</presence>
]]>
</send>
<recv response="100"
optional="true">
</recv>
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
<!-- are saved and used for following messages sent. Useful to test -->
<!-- against stateful SIP proxies/B2BUAs. -->
<recv response="200" rrs="true">
</recv>
<!-- definition of the response time repartition table (unit is ms) -->
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
<!-- definition of the call length repartition table (unit is ms) -->
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
</scenario>