diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c
index 61cc949fd..cf46d4f74 100644
--- a/coreapi/bellesip_sal/sal_impl.c
+++ b/coreapi/bellesip_sal/sal_impl.c
@@ -488,6 +488,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.subscribe_closed=(SalOnSubscribeClosed)unimplemented_stub;
if (ctx->callbacks.parse_presence_requested==NULL)
ctx->callbacks.parse_presence_requested=(SalOnParsePresenceRequested)unimplemented_stub;
+ if (ctx->callbacks.convert_presence_to_xml_requested==NULL)
+ ctx->callbacks.convert_presence_to_xml_requested=(SalOnConvertPresenceToXMLRequested)unimplemented_stub;
if (ctx->callbacks.notify_presence==NULL)
ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;
if (ctx->callbacks.subscribe_presence_received==NULL)
diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h
index 61ef731d8..7bc92e2c7 100644
--- a/coreapi/bellesip_sal/sal_impl.h
+++ b/coreapi/bellesip_sal/sal_impl.h
@@ -134,7 +134,7 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even
SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) ;
void sal_add_pending_auth(Sal *sal, SalOp *op);
void sal_remove_pending_auth(Sal *sal, SalOp *op);
-void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status);
+void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence);
belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_request_t *req, int code);
diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c
index 4b4476b40..321f2e0ac 100644
--- a/coreapi/bellesip_sal/sal_op_presence.c
+++ b/coreapi/bellesip_sal/sal_op_presence.c
@@ -18,404 +18,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sal_impl.h"
-typedef enum {
- PIDF = 0,
- RFCxxxx = 1,
- MSOLDPRES = 2
-} presence_type_t;
-/*
- * REVISIT: this static variable forces every dialog to use the same presence description type depending
- * on what is received on a single dialog...
- */
-static presence_type_t presence_style = PIDF;
-
-static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info,
- char *buf, size_t buflen, presence_type_t ptype) {
- switch (ptype) {
- case RFCxxxx: {
- /* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */
- int atom_id = 1000;
-
- if (online_status==SalPresenceOnline)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status == SalPresenceBusy ||
- online_status == SalPresenceDonotdisturb)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==SalPresenceBerightback)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status == SalPresenceAway ||
- online_status == SalPresenceMoved)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==SalPresenceOnthephone)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==SalPresenceOuttolunch)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
- }
- break;
- }
- case MSOLDPRES: {
- /* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence
- * so messages format has been taken from Communigate that can send notify
- * requests with this schema
- */
- int atom_id = 1000;
-
- if (online_status==SalPresenceOnline)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status == SalPresenceBusy ||
- online_status == SalPresenceDonotdisturb)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==SalPresenceBerightback)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status == SalPresenceAway ||
- online_status == SalPresenceMoved)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==SalPresenceOnthephone)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==SalPresenceOuttolunch)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
-
- }
- else
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-\n\
-", contact_info, atom_id, contact_info);
- }
- break;
- }
- default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */
-
- if (online_status==SalPresenceOnline)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-open\n\
-%s\n\
-\n\
-",
-contact_info, contact_info);
- }
- else if (online_status == SalPresenceBusy ||
- online_status == SalPresenceDonotdisturb)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-open\n\
-%s\n\
-\n\
-\n\
-\n\
-\n\
-",
-contact_info, contact_info);
- }
- else if (online_status==SalPresenceBerightback)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-open\n\
-%s\n\
-\n\
-\n\
-\n\
-\n\
-",
-contact_info, contact_info);
- }
- else if (online_status == SalPresenceAway ||
- online_status == SalPresenceMoved)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-open\n\
-%s\n\
-\n\
-\n\
-\n\
-\n\
-",
-contact_info, contact_info);
- }
- else if (online_status == SalPresenceOnVacation)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-open\n\
-%s\n\
-\n\
-\n\
-\n\
-\n\
-",
-contact_info, contact_info);
- }
- else if (online_status==SalPresenceOnthephone)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-open\n\
-%s\n\
-\n\
-\n\
-\n\
-\n\
-",
-contact_info, contact_info);
- }
- else if (online_status==SalPresenceOuttolunch)
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-open\n\
-%s\n\
-\n\
-\n\
-\n\
-Out to lunch \n\
-\n\
-",
-contact_info, contact_info);
- }
- else
- {
- snprintf(buf, buflen, "\n\
-\n\
-\n\
-closed\n\
-%s\n\
-\n\
-\n", contact_info, contact_info);
- }
- break;
- }
- } // switch
-
-}
-
-void sal_add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status) {
- char buf[1000];
+void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence) {
char *contact_info;
+ char *content = NULL;
size_t content_length;
belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t);
contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)));
- mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style);
-
+ op->base.root->callbacks.convert_presence_to_xml_requested(op, presence, contact_info, &content);
+ if (content == NULL) {
+ ms_free(contact_info);
+ return;
+ }
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
- ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application",presence_style?"xpidf+xml":"pidf+xml")));
+ ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml")));
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
- ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(buf))));
- belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),buf,content_length);
+ ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(content))));
+ belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),content,content_length);
ms_free(contact_info);
}
@@ -627,9 +251,9 @@ static belle_sip_request_t *create_presence_notify(SalOp *op){
return notify;
}
-int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
+int sal_notify_presence(SalOp *op, SalPresenceModel *presence){
belle_sip_request_t* notify=create_presence_notify(op);
- sal_add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*FIXME, what about expires ??*/
+ sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),presence); /*FIXME, what about expires ??*/
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)));
return sal_op_send_request(op,notify);
@@ -637,7 +261,7 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_
int sal_notify_presence_close(SalOp *op){
belle_sip_request_t* notify=create_presence_notify(op);
- sal_add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*FIXME, what about expires ??*/
+ sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
return sal_op_send_request(op,notify);
diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c
index cf9dc8f54..2445d20e4 100644
--- a/coreapi/bellesip_sal/sal_op_publish.c
+++ b/coreapi/bellesip_sal/sal_op_publish.c
@@ -30,7 +30,7 @@ static void publish_refresher_listener ( const belle_sip_refresher_t* refresher
}
/*presence publish */
-int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceStatus status){
+int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceModel *presence){
belle_sip_request_t *req=NULL;
if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) {
if (from)
@@ -41,14 +41,13 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenc
op->type=SalOpPublish;
req=sal_op_build_request(op,"PUBLISH");
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence"));
- sal_add_presence_info(BELLE_SIP_MESSAGE(req),status);
+ sal_add_presence_info(op,BELLE_SIP_MESSAGE(req),presence);
return sal_op_send_and_create_refresher(op,req,600,publish_refresher_listener);
} else {
- /*update status*/
+ /*update presence status*/
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 status*/
- sal_add_presence_info(BELLE_SIP_MESSAGE(last_publish),status);
+ sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),presence);
return belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES);
}
}
diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index 6d7e6d58e..9820ae4de 100644
--- a/coreapi/callbacks.c
+++ b/coreapi/callbacks.c
@@ -219,21 +219,31 @@ static void call_received(SalOp *h){
bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE);
/* first check if we can answer successfully to this invite */
- if (lc->presence_mode==LinphoneStatusBusy ||
- lc->presence_mode==LinphoneStatusOffline ||
- lc->presence_mode==LinphoneStatusDoNotDisturb ||
- lc->presence_mode==LinphoneStatusMoved){
- if (lc->presence_mode==LinphoneStatusBusy )
- sal_call_decline(h,SalReasonBusy,NULL);
- else if (lc->presence_mode==LinphoneStatusOffline)
- sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
- else if (lc->presence_mode==LinphoneStatusDoNotDisturb)
- sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
- else if (lc->alt_contact!=NULL && lc->presence_mode==LinphoneStatusMoved)
- sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
- sal_op_release(h);
- return;
+ if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) {
+ LinphonePresenceActivity activity = LinphonePresenceActivityOffline;
+ if (linphone_presence_model_get_activity(lc->presence_model, &activity, NULL)) {
+ switch (activity) {
+ case LinphonePresenceActivityBusy:
+ sal_call_decline(h,SalReasonBusy,NULL);
+ break;
+ case LinphonePresenceActivityAppointment:
+ case LinphonePresenceActivityMeeting:
+ case LinphonePresenceActivityOffline:
+ case LinphonePresenceActivityWorship:
+ sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
+ break;
+ case LinphonePresenceActivityPermanentAbsence:
+ if (lc->alt_contact != NULL)
+ sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
+ break;
+ default:
+ break;
+ }
+ sal_op_release(h);
+ return;
+ }
}
+
if (!linphone_core_can_we_add_call(lc)){/*busy*/
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
@@ -881,6 +891,10 @@ static void parse_presence_requested(SalOp *op, const char *content_type, const
linphone_notify_parse_presence(op, content_type, content_subtype, body, result);
}
+static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) {
+ linphone_notify_convert_presence_to_xml(op, presence, contact, content);
+}
+
static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_notify_recv(lc,op,ss,model);
@@ -1090,6 +1104,7 @@ SalCallbacks linphone_sal_callbacks={
subscribe_presence_received,
subscribe_presence_closed,
parse_presence_requested,
+ convert_presence_to_xml_requested,
notify_presence,
ping_reply,
auth_requested,
diff --git a/coreapi/friend.c b/coreapi/friend.c
index df66ada73..fe33125d4 100644
--- a/coreapi/friend.c
+++ b/coreapi/friend.c
@@ -226,57 +226,12 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri
return 0;
}
-SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){
- switch(os){
- case LinphoneStatusOffline:
- return SalPresenceOffline;
- break;
- case LinphoneStatusOnline:
- return SalPresenceOnline;
- break;
- case LinphoneStatusBusy:
- return SalPresenceBusy;
- break;
- case LinphoneStatusBeRightBack:
- return SalPresenceBerightback;
- break;
- case LinphoneStatusAway:
- return SalPresenceAway;
- break;
- case LinphoneStatusOnThePhone:
- return SalPresenceOnthephone;
- break;
- case LinphoneStatusOutToLunch:
- return SalPresenceOuttolunch;
- break;
- case LinphoneStatusDoNotDisturb:
- return SalPresenceDonotdisturb;
- break;
- case LinphoneStatusMoved:
- return SalPresenceMoved;
- break;
- case LinphoneStatusAltService:
- return SalPresenceAltService;
- break;
- case LinphoneStatusPending:
- return SalPresenceOffline;
- break;
- case LinphoneStatusVacation:
- return SalPresenceOnVacation;
- break;
- default:
- return SalPresenceOffline;
- break;
- }
- return SalPresenceOffline;
-}
-
-void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){
+void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence){
char *addr=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("Want to notify %s, insub=%p",addr,lf->insub);
ms_free(addr);
if (lf->insub!=NULL){
- sal_notify_presence(lf->insub,linphone_online_status_to_sal(os),NULL);
+ sal_notify_presence(lf->insub,(SalPresenceModel *)presence);
}
}
@@ -343,7 +298,7 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
nb_activities = 1;
}
if (nb_activities == 1) {
- err = linphone_presence_model_get_activity(lf->presence, 0, &activity, &activity_description);
+ err = linphone_presence_model_get_activity(lf->presence, &activity, &activity_description);
if (err == 0) {
switch (activity) {
case LinphonePresenceActivityBreakfast:
@@ -389,6 +344,12 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
online_status = LinphoneStatusMoved;
break;
case LinphonePresenceActivityUnknown:
+ /* Rely on the basic status information. */
+ break;
+ case LinphonePresenceActivityOnline:
+ case LinphonePresenceActivityOffline:
+ /* Should not happen! */
+ ms_warning("LinphonePresenceActivityOnline or LinphonePresenceActivityOffline should not happen here!");
break;
}
}
@@ -414,27 +375,30 @@ BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){
}
void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
+ LinphonePresenceModel *model;
+
if (fr->uri==NULL) {
ms_warning("No sip url defined.");
return;
}
-
linphone_core_write_friends_config(lc);
if (fr->inc_subscribe_pending){
switch(fr->pol){
case LinphoneSPWait:
- linphone_friend_notify(fr,LinphoneStatusPending);
+ model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOther, "Waiting for user acceptance");
+ linphone_friend_notify(fr,model);
+ linphone_presence_model_delete(model);
break;
case LinphoneSPAccept:
if (fr->lc!=NULL)
{
- linphone_friend_notify(fr,fr->lc->presence_mode);
+ linphone_friend_notify(fr,fr->lc->presence_model);
}
break;
case LinphoneSPDeny:
- linphone_friend_notify(fr,LinphoneStatusOffline);
+ linphone_friend_notify(fr,NULL);
break;
}
fr->inc_subscribe_pending=FALSE;
diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c
index f4a9c508f..e4d1bca6a 100644
--- a/coreapi/linphonecall.c
+++ b/coreapi/linphonecall.c
@@ -412,8 +412,10 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) {
}
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
+ LinphonePresenceModel *model;
int port_offset;
int min_port, max_port;
+
call->magic=linphone_call_magic;
call->refcnt=1;
call->state=LinphoneCallIdle;
@@ -422,7 +424,9 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->media_start_time=0;
call->log=linphone_call_log_new(call, from, to);
call->owns_call_log=TRUE;
- linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
+ model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL);
+ linphone_core_notify_all_friends(call->core,model);
+ linphone_presence_model_delete(model);
linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
if (min_port == max_port) {
/* Used fixed RTP audio port. */
@@ -630,7 +634,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){
}
if (ms_list_size(lc->calls)==0)
- linphone_core_notify_all_friends(lc,lc->presence_mode);
+ linphone_core_notify_all_friends(lc,lc->presence_model);
linphone_core_conference_check_uninit(lc);
if (call->ringing_beep){
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index f0beca008..605521552 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -1337,7 +1337,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
sip_config_read(lc); /* this will start eXosip*/
video_config_read(lc);
//autoreplier_config_init(&lc->autoreplier_conf);
- lc->presence_mode=LinphoneStatusOnline;
+ lc->presence_model=linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL);
misc_config_read(lc);
ui_config_read(lc);
#ifdef TUNNEL_ENABLED
@@ -3568,12 +3568,12 @@ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const c
}
int linphone_core_send_publish(LinphoneCore *lc,
- LinphoneOnlineStatus presence_mode)
+ LinphonePresenceModel *presence)
{
const MSList *elem;
for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=ms_list_next(elem)){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
- if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence_mode);
+ if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence);
}
return 0;
}
@@ -3642,10 +3642,59 @@ void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){
lc->sip_conf.delayed_timeout=seconds;
}
-void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,
- const char *contact,
- LinphoneOnlineStatus presence_mode)
-{
+void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const char *contact, LinphoneOnlineStatus os) {
+ LinphonePresenceModel *presence = NULL;
+ char *description = NULL;
+ LinphonePresenceActivity activity = LinphonePresenceActivityUnknown;
+ switch (os) {
+ case LinphoneStatusOffline:
+ activity = LinphonePresenceActivityOffline;
+ break;
+ case LinphoneStatusOnline:
+ activity = LinphonePresenceActivityOnline;
+ break;
+ case LinphoneStatusBusy:
+ activity = LinphonePresenceActivityBusy;
+ break;
+ case LinphoneStatusBeRightBack:
+ activity = LinphonePresenceActivityInTransit;
+ break;
+ case LinphoneStatusAway:
+ activity = LinphonePresenceActivityAway;
+ break;
+ case LinphoneStatusOnThePhone:
+ activity = LinphonePresenceActivityOnThePhone;
+ break;
+ case LinphoneStatusOutToLunch:
+ activity = LinphonePresenceActivityLunch;
+ break;
+ case LinphoneStatusDoNotDisturb:
+ activity = LinphonePresenceActivityBusy;
+ description = "Do not disturb";
+ break;
+ case LinphoneStatusMoved:
+ activity = LinphonePresenceActivityPermanentAbsence;
+ break;
+ case LinphoneStatusAltService:
+ activity = LinphonePresenceActivityBusy;
+ description = "Using another messaging service";
+ break;
+ case LinphoneStatusPending:
+ activity = LinphonePresenceActivityOther;
+ description = "Waiting for user acceptance";
+ break;
+ case LinphoneStatusVacation:
+ activity = LinphonePresenceActivityVacation;
+ break;
+ case LinphoneStatusEnd:
+ ms_warning("Invalid status LinphoneStatusEnd");
+ return;
+ }
+ presence = linphone_presence_model_new_with_activity(activity, description);
+ linphone_core_set_presence_model(lc, minutes_away, contact, presence);
+}
+
+void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const char *contact, LinphonePresenceModel *presence) {
if (minutes_away>0) lc->minutes_away=minutes_away;
if (lc->alt_contact!=NULL) {
@@ -3653,20 +3702,75 @@ void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,
lc->alt_contact=NULL;
}
if (contact) lc->alt_contact=ms_strdup(contact);
- if (lc->presence_mode!=presence_mode){
- linphone_core_notify_all_friends(lc,presence_mode);
+ if (!linphone_presence_model_equals(lc->presence_model,presence)){
+ linphone_core_notify_all_friends(lc,presence);
/*
Improve the use of all LINPHONE_STATUS available.
!TODO Do not mix "presence status" with "answer status code"..
Use correct parameter to follow sip_if_match/sip_etag.
*/
- linphone_core_send_publish(lc,presence_mode);
+ linphone_core_send_publish(lc,presence);
+ }
+ if ((lc->presence_model != NULL) && (lc->presence_model != presence)) {
+ linphone_presence_model_delete(lc->presence_model);
+ lc->presence_model = presence;
}
- lc->presence_mode=presence_mode;
}
LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){
- return lc->presence_mode;
+ LinphonePresenceActivity activity = LinphonePresenceActivityOffline;
+ char *description = NULL;
+
+ if ((lc->presence_model == NULL)
+ || (linphone_presence_model_get_activity(lc->presence_model, &activity, &description) < 0))
+ return LinphoneStatusOffline;
+
+ switch (activity) {
+ case LinphonePresenceActivityOffline:
+ return LinphoneStatusOffline;
+ case LinphonePresenceActivityOnline:
+ return LinphoneStatusOnline;
+ case LinphonePresenceActivityBusy:
+ if (description != NULL) {
+ if (strcmp(description, "Do not disturb") == 0)
+ return LinphoneStatusDoNotDisturb;
+ else if (strcmp(description, "Using another messaging service") == 0)
+ return LinphoneStatusAltService;
+ }
+ return LinphoneStatusBusy;
+ case LinphonePresenceActivityInTransit:
+ case LinphonePresenceActivitySteering:
+ return LinphoneStatusBeRightBack;
+ case LinphonePresenceActivityAway:
+ return LinphoneStatusAway;
+ case LinphonePresenceActivityOnThePhone:
+ return LinphoneStatusOnThePhone;
+ case LinphonePresenceActivityBreakfast:
+ case LinphonePresenceActivityDinner:
+ case LinphonePresenceActivityLunch:
+ case LinphonePresenceActivityMeal:
+ return LinphoneStatusOutToLunch;
+ case LinphonePresenceActivityPermanentAbsence:
+ return LinphoneStatusMoved;
+ case LinphonePresenceActivityOther:
+ if (description != NULL) {
+ if (strcmp(description, "Waiting for user acceptance") == 0)
+ return LinphoneStatusPending;
+ }
+ return LinphoneStatusBusy;
+ case LinphonePresenceActivityVacation:
+ return LinphoneStatusVacation;
+ case LinphonePresenceActivityAppointment:
+ case LinphonePresenceActivityMeeting:
+ case LinphonePresenceActivityWorship:
+ return LinphoneStatusDoNotDisturb;
+ default:
+ return LinphoneStatusBusy;
+ }
+}
+
+LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc) {
+ return lc->presence_model;
}
/**
diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h
index e01a5fe44..8ea05e7b1 100644
--- a/coreapi/linphonefriend.h
+++ b/coreapi/linphonefriend.h
@@ -236,13 +236,30 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss);
* @param os #LinphoneOnlineStatus
*/
LINPHONE_PUBLIC void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os);
+
/**
- * get my presence status
+ * Set my presence status
+ * @param lc #LinphoneCore object
+ * @param minutes_away how long in away
+ * @param alternative_contact sip uri used to redirect call in state #LinphoneStatusMoved
+ * @param presence #LinphonePresenceModel
+ */
+LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, int minutes_away, const char *alternative_contact, LinphonePresenceModel *presence);
+
+/**
+ * Get my presence status
* @param lc #LinphoneCore object
* @return #LinphoneOnlineStatus
*/
LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc);
+/**
+ * Get my presence status
+ * @param lc #LinphoneCore object
+ * @return #LinphonePresenceModel
+ */
+LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc);
+
void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result);
/**
* Add a friend to the current buddy list, if \link linphone_friend_enable_subscribes() subscription attribute \endlink is set, a SIP SUBSCRIBE message is sent.
@@ -272,7 +289,7 @@ LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore
* @param lc #LinphoneCore object
* @param os #LinphoneOnlineStatus to notify
* */
-void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os);
+void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence);
LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr);
LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key);
diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h
index 317e25b2e..9244c4ea7 100644
--- a/coreapi/linphonepresence.h
+++ b/coreapi/linphonepresence.h
@@ -33,6 +33,8 @@ typedef enum LinphonePresenceBasicStatus {
/** Activities as defined in section 3.2 of RFC 4480 */
typedef enum LinphonePresenceActivity {
+ LinphonePresenceActivityOffline,
+ LinphonePresenceActivityOnline,
LinphonePresenceActivityAppointment,
LinphonePresenceActivityAway,
LinphonePresenceActivityBreakfast,
@@ -67,10 +69,17 @@ typedef struct _LinphonePresenceModel LinphonePresenceModel;
LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void);
+LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivity activity, const char *description);
+LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivity activity, const char *description, const char *note, const char *lang);
LINPHONE_PUBLIC void linphone_presence_model_delete(LinphonePresenceModel *model);
+LINPHONE_PUBLIC bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2);
LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model);
LINPHONE_PUBLIC unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel *model);
-LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description);
+LINPHONE_PUBLIC int linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description);
+LINPHONE_PUBLIC int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description);
+LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description);
+LINPHONE_PUBLIC const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang);
+LINPHONE_PUBLIC int linphone_presence_model_set_note(LinphonePresenceModel *model, const char *note, const char *lang);
#ifdef __cplusplus
diff --git a/coreapi/presence.c b/coreapi/presence.c
index 9ad01bc07..caab79581 100644
--- a/coreapi/presence.c
+++ b/coreapi/presence.c
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphonecore.h"
#include "private.h"
#include
+#include
#include
#include
@@ -41,6 +42,9 @@ struct _LinphonePresenceNote {
struct _LinphonePresenceService {
char *id;
LinphonePresenceBasicStatus status;
+ char *contact;
+ MSList *notes; /**< A list of _LinphonePresenceNote structures. */
+ time_t timestamp;
};
struct _LinphonePresenceActivity {
@@ -107,6 +111,30 @@ static void xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) {
va_end(args);
}
+static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+static char * generate_presence_id(void) {
+ char id[7];
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ id[i] = presence_id_valid_characters[random() % sizeof(presence_id_valid_characters)];
+ }
+ id[6] = '\0';
+
+ return ms_strdup(id);
+}
+
+static const char * presence_basic_status_to_string(LinphonePresenceBasicStatus basic_status) {
+ switch (basic_status) {
+ case LinphonePresenceBasicStatusOpen:
+ return "open";
+ case LinphonePresenceBasicStatusClosed:
+ default:
+ return "closed";
+ }
+}
+
static struct _LinphonePresenceNote * presence_note_new(const char *content, const char *lang) {
struct _LinphonePresenceNote * note = ms_new0(struct _LinphonePresenceNote, 1);
note->content = ms_strdup(content);
@@ -130,6 +158,7 @@ static struct _LinphonePresenceService * presence_service_new(const char *id, Li
service->id = ms_strdup(id);
}
service->status = status;
+ service->timestamp = time(NULL);
return service;
}
@@ -137,9 +166,26 @@ static void presence_service_delete(struct _LinphonePresenceService *service) {
if (service->id != NULL) {
ms_free(service->id);
}
+ if (service->contact != NULL) {
+ ms_free(service->contact);
+ }
+ ms_list_for_each(service->notes, (MSIterateFunc)presence_service_delete);
+ ms_list_free(service->notes);
ms_free(service);
};
+static void presence_service_set_timestamp(struct _LinphonePresenceService *service, time_t timestamp) {
+ service->timestamp = timestamp;
+}
+
+static void presence_service_set_contact(struct _LinphonePresenceService *service, const char *contact) {
+ service->contact = ms_strdup(contact);
+}
+
+static void presence_service_add_note(struct _LinphonePresenceService *service, struct _LinphonePresenceNote *note) {
+ service->notes = ms_list_append(service->notes, note);
+}
+
static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivity activity, const char *description) {
struct _LinphonePresenceActivity *act = ms_new0(struct _LinphonePresenceActivity, 1);
act->activity = activity;
@@ -174,18 +220,29 @@ static time_t parse_timestamp(const char *timestamp) {
return seconds - timezone;
}
-static struct _LinphonePresencePerson * presence_person_new(const char *id, const char *timestamp) {
+static char * timestamp_to_string(time_t timestamp) {
+ char timestamp_str[22];
+ struct tm *ret;
+#ifndef WIN32
+ struct tm gmt;
+ ret = gmtime_r(×tamp,&gmt);
+#else
+ ret = gmtime(&curtime);
+#endif
+ snprintf(timestamp_str, sizeof(timestamp_str), "%4d-%02d-%02dT%02d:%02d:%02dZ",
+ ret->tm_year + 1900, ret->tm_mon + 1, ret->tm_mday, ret->tm_hour, ret->tm_min, ret->tm_sec);
+ return ms_strdup(timestamp_str);
+}
+
+static struct _LinphonePresencePerson * presence_person_new(const char *id, time_t timestamp) {
struct _LinphonePresencePerson *person = ms_new0(struct _LinphonePresencePerson, 1);
if (id != NULL) {
person->id = ms_strdup(id);
}
- if (timestamp != NULL) {
- person->timestamp = parse_timestamp(timestamp);
- if (person->timestamp == ((time_t)-1))
- person->timestamp = time(NULL);
- } else {
+ if (person->timestamp == ((time_t)-1))
person->timestamp = time(NULL);
- }
+ else
+ person->timestamp = timestamp;
return person;
}
@@ -214,6 +271,11 @@ static void presence_person_add_note(struct _LinphonePresencePerson *person, str
person->notes = ms_list_append(person->notes, note);
}
+static void presence_person_clear_activities(struct _LinphonePresencePerson *person) {
+ ms_list_for_each(person->activities, (MSIterateFunc)presence_activity_delete);
+ ms_list_free(person->activities);
+}
+
static void presence_model_add_service(LinphonePresenceModel *model, struct _LinphonePresenceService *service) {
model->services = ms_list_append(model->services, service);
}
@@ -226,17 +288,151 @@ static void presence_model_add_note(LinphonePresenceModel *model, struct _Linpho
model->notes = ms_list_append(model->notes, note);
}
+static int presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) {
+ struct _LinphonePresenceService *service;
+ char *id;
+ if (ms_list_size(model->services) > 0) {
+ ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete);
+ ms_list_free(model->services);
+ }
+ id = generate_presence_id();
+ service = presence_service_new(id, basic_status);
+ ms_free(id);
+ if (service == NULL) return -1;
+ presence_model_add_service(model, service);
+ return 0;
+}
+
+static void presence_model_clear_activities(LinphonePresenceModel *model) {
+ ms_list_for_each(model->persons, (MSIterateFunc)presence_person_clear_activities);
+}
+
+static int presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description) {
+ char *id = NULL;
+ struct _LinphonePresencePerson *person = NULL;
+ struct _LinphonePresenceActivity *act = NULL;
+
+ /* Do not add activity for special cases Offline and Online. */
+ if ((activity == LinphonePresenceActivityOffline) || (activity == LinphonePresenceActivityOnline))
+ return 0;
+
+ if (ms_list_size(model->persons) == 0) {
+ /* There is no person in the presence model, add one. */
+ id = generate_presence_id();
+ person = presence_person_new(id, time(NULL));
+ if (id != NULL) ms_free(id);
+ if (person == NULL)
+ return -1;
+ presence_model_add_person(model, person);
+ } else {
+ /* Add the activity to the first person in the model. */
+ person = (struct _LinphonePresencePerson *)ms_list_nth_data(model->persons, 0);
+ }
+ act = presence_activity_new(activity, description);
+ if (act == NULL)
+ return -1;
+ presence_person_add_activity(person, act);
+
+ return 0;
+}
+
static void presence_model_find_open_basic_status(struct _LinphonePresenceService *service, LinphonePresenceBasicStatus *status) {
if (service->status == LinphonePresenceBasicStatusOpen) {
*status = LinphonePresenceBasicStatusOpen;
}
}
+static bool_t presence_service_equals(const struct _LinphonePresenceService *s1, const struct _LinphonePresenceService *s2) {
+ if (s1->status != s2->status)
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t presence_note_equals(const struct _LinphonePresenceNote *n1, const struct _LinphonePresenceNote *n2) {
+ if (((n1->lang == NULL) && (n2->lang != NULL))
+ || ((n1->lang != NULL) && (n2->lang == NULL)))
+ return FALSE;
+
+ if (strcmp(n1->content, n2->content) != 0)
+ return FALSE;
+ if ((n1->lang != NULL) && (n2->lang != NULL)) {
+ if (strcmp(n1->lang, n2->lang) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool_t presence_activity_equals(const struct _LinphonePresenceActivity *a1, const struct _LinphonePresenceActivity *a2) {
+ if (((a1->description == NULL) && (a2->description != NULL))
+ || ((a1->description != NULL) && (a2->description == NULL)))
+ return FALSE;
+
+ if (a1->activity != a2->activity)
+ return FALSE;
+
+ if ((a1->description != NULL) && (a2->description != NULL)) {
+ if (strcmp(a1->description, a2->description) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool_t presence_person_equals(const struct _LinphonePresencePerson *p1, const struct _LinphonePresencePerson *p2) {
+ int nb;
+ int i;
+
+ if ((ms_list_size(p1->activities) != ms_list_size(p2->activities))
+ || (ms_list_size(p1->activities_notes) != ms_list_size(p2->activities_notes))
+ || (ms_list_size(p1->notes) != ms_list_size(p2->notes)))
+ return FALSE;
+
+ nb = ms_list_size(p1->activities);
+ for (i = 0; i < nb; i++) {
+ if (presence_activity_equals(ms_list_nth_data(p1->activities, i), ms_list_nth_data(p2->activities, i)) == FALSE)
+ return FALSE;
+ }
+
+ nb = ms_list_size(p1->activities_notes);
+ for (i = 0; i < nb; i++) {
+ if (presence_note_equals(ms_list_nth_data(p1->activities_notes, i), ms_list_nth_data(p2->activities_notes, i)) == FALSE)
+ return FALSE;
+ }
+
+ nb = ms_list_size(p1->notes);
+ for (i = 0; i < nb; i++) {
+ if (presence_note_equals(ms_list_nth_data(p1->notes, i), ms_list_nth_data(p2->notes, i)) == FALSE)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
LinphonePresenceModel * linphone_presence_model_new(void) {
return ms_new0(LinphonePresenceModel, 1);
}
+LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivity activity, const char *description) {
+ LinphonePresenceModel *model = linphone_presence_model_new();
+ if (model != NULL) {
+ linphone_presence_model_set_activity(model, activity, description);
+ }
+ return model;
+}
+
+LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivity activity, const char *description, const char *note, const char *lang) {
+ LinphonePresenceModel *model = linphone_presence_model_new();
+ if (model != NULL) {
+ linphone_presence_model_set_activity(model, activity, description);
+ linphone_presence_model_set_note(model, note, lang);
+ }
+ return model;
+}
+
void linphone_presence_model_delete(LinphonePresenceModel *model) {
+ if (model == NULL) return;
+
ms_list_for_each(model->services, (MSIterateFunc)presence_service_delete);
ms_list_free(model->services);
ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete);
@@ -246,10 +442,61 @@ void linphone_presence_model_delete(LinphonePresenceModel *model) {
ms_free(model);
}
+bool_t linphone_presence_model_equals(const LinphonePresenceModel *m1, const LinphonePresenceModel *m2) {
+ LinphonePresenceActivity activity = LinphonePresenceActivityOffline;
+ int nb;
+ int i;
+
+ /* Two null activities are considered equal. */
+ if ((m1 == NULL) && (m2 == NULL))
+ return TRUE;
+
+ /* A null activity is equal to an activity with no activity but a basic status of Closed. */
+ if (m1 == NULL) {
+ if ((linphone_presence_model_get_activity(m2, &activity, NULL) < 0)
+ || (activity != LinphonePresenceActivityOffline))
+ return FALSE;
+ return TRUE;
+ }
+ if (m2 == NULL) {
+ if ((linphone_presence_model_get_activity(m2, &activity, NULL) < 0)
+ || (activity != LinphonePresenceActivityOffline))
+ return FALSE;
+ return TRUE;
+ }
+
+ if ((ms_list_size(m1->services) != ms_list_size(m2->services))
+ || (ms_list_size(m1->persons) != ms_list_size(m2->persons))
+ || (ms_list_size(m1->notes) != ms_list_size(m2->notes)))
+ return FALSE;
+
+ nb = ms_list_size(m1->services);
+ for (i = 0; i < nb; i++) {
+ if (presence_service_equals(ms_list_nth_data(m1->services, i), ms_list_nth_data(m2->services, i)) == FALSE)
+ return FALSE;
+ }
+
+ nb = ms_list_size(m1->persons);
+ for (i = 0; i < nb; i++) {
+ if (presence_person_equals(ms_list_nth_data(m1->persons, i), ms_list_nth_data(m2->persons, i)) == FALSE)
+ return FALSE;
+ }
+
+ nb = ms_list_size(m1->notes);
+ for (i = 0; i < nb; i++) {
+ if (presence_note_equals(ms_list_nth_data(m1->notes, i), ms_list_nth_data(m2->notes, i)) == FALSE)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* Suppose that if at least one service is open, then the model is open. */
LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model) {
LinphonePresenceBasicStatus status = LinphonePresenceBasicStatusClosed;
- ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status);
+ if (model != NULL) {
+ ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status);
+ }
return status;
}
@@ -284,10 +531,12 @@ static void presence_model_get_activity(const struct _LinphonePresencePerson *pe
}
}
-int linphone_presence_model_get_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description) {
+int linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx, LinphonePresenceActivity *activity, char **description) {
struct _get_activity_st st;
- if ((activity == NULL) || (idx >= linphone_presence_model_nb_activities(model)))
+
+ if ((model == NULL) || (activity == NULL) || (idx >= linphone_presence_model_nb_activities(model)))
return -1;
+
memset(&st, 0, sizeof(st));
st.requested_idx = idx;
st.activity = activity;
@@ -296,9 +545,63 @@ int linphone_presence_model_get_activity(const LinphonePresenceModel *model, uns
st.description = description;
}
ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st);
+
return 0;
}
+int linphone_presence_model_get_activity(const LinphonePresenceModel *model, LinphonePresenceActivity *activity, char **description) {
+ if ((model == NULL) || (activity == NULL))
+ return -1;
+
+ if (linphone_presence_model_get_nth_activity(model, 0, activity, description) < 0) {
+ /* There is no activities, base the result on the basic status. */
+ LinphonePresenceBasicStatus basic_status = linphone_presence_model_get_basic_status(model);
+ if (basic_status == LinphonePresenceBasicStatusOpen)
+ *activity = LinphonePresenceActivityOnline;
+ else
+ *activity = LinphonePresenceActivityOffline;
+ }
+
+ return 0;
+}
+
+int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivity activity, const char *description) {
+ LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen;
+
+ if (model == NULL) return -1;
+
+ switch (activity) {
+ case LinphonePresenceActivityAppointment:
+ case LinphonePresenceActivityBusy:
+ case LinphonePresenceActivityMeeting:
+ case LinphonePresenceActivityPermanentAbsence:
+ case LinphonePresenceActivityOffline:
+ case LinphonePresenceActivityWorship:
+ basic_status = LinphonePresenceBasicStatusClosed;
+ break;
+ default:
+ basic_status = LinphonePresenceBasicStatusOpen;
+ break;
+ }
+ if (presence_model_set_basic_status(model, basic_status) < 0)
+ return -1;
+ presence_model_clear_activities(model);
+ if (presence_model_add_activity(model, activity, description) < 0)
+ return -1;
+
+ return 0;
+}
+
+const char * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) {
+ // TODO
+ return NULL;
+}
+
+int linphone_presence_model_set_note(LinphonePresenceModel *model, const char *note, const char *lang) {
+ // TODO
+ return -1;
+}
+
static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) {
if (xml_ctx->xpath_ctx != NULL) {
xmlXPathFreeContext(xml_ctx->xpath_ctx);
@@ -381,7 +684,7 @@ static int process_rfcxxxx_presence_notification(xmlparsing_context_t *xml_ctx,
presence_model_add_service(model, service);
}
if (activity != NULL) {
- person = presence_person_new(NULL, NULL);
+ person = presence_person_new(NULL, time(NULL));
if (person != NULL) {
presence_person_add_activity(person, activity);
presence_model_add_person(model, person);
@@ -438,7 +741,7 @@ static int process_msoldpres_presence_notification(xmlparsing_context_t *xml_ctx
presence_model_add_service(model, service);
}
if (activity != NULL) {
- person = presence_person_new(NULL, NULL);
+ person = presence_person_new(NULL, time(NULL));
if (person != NULL) {
presence_person_add_activity(person, activity);
presence_model_add_person(model, person);
@@ -450,12 +753,43 @@ static int process_msoldpres_presence_notification(xmlparsing_context_t *xml_ctx
static const char *service_prefix = "/pidf:presence/pidf:tuple";
+static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, struct _LinphonePresenceService *service, unsigned int service_idx) {
+ char xpath_str[MAX_XPATH_LENGTH];
+ xmlXPathObjectPtr note_object;
+ struct _LinphonePresenceNote *note;
+ const char *note_str;
+ const char *lang;
+ int i;
+
+ snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note", service_prefix, service_idx);
+ note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
+ if ((note_object != NULL) && (note_object->nodesetval != NULL)) {
+ for (i = 1; i <= note_object->nodesetval->nodeNr; i++) {
+ snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]", service_prefix, service_idx, i);
+ note_str = get_xml_text_content(xml_ctx, xpath_str);
+ if (note_str == NULL) continue;
+ snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note[%i]/@xml:lang", service_prefix, service_idx, i);
+ lang = get_xml_text_content(xml_ctx, xpath_str);
+
+ note = presence_note_new(note_str, lang);
+ presence_service_add_note(service, note);
+ if (lang != NULL) free_xml_text_content(lang);
+ free_xml_text_content(note_str);
+ }
+ }
+ if (note_object != NULL) xmlXPathFreeObject(note_object);
+
+ return 0;
+}
+
static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) {
char xpath_str[MAX_XPATH_LENGTH];
xmlXPathObjectPtr service_object;
struct _LinphonePresenceService *service;
const char *basic_status_str;
const char *service_id_str;
+ const char *timestamp_str;
+ const char *contact_str;
LinphonePresenceBasicStatus basic_status;
int i;
@@ -477,10 +811,25 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin
return -1;
}
+ snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", service_prefix, i);
+ timestamp_str = get_xml_text_content(xml_ctx, xpath_str);
+
+ snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:contact", service_prefix, i);
+ contact_str = get_xml_text_content(xml_ctx, xpath_str);
+
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i);
service_id_str = get_xml_text_content(xml_ctx, xpath_str);
service = presence_service_new(service_id_str, basic_status);
if (service != NULL) {
+ if (timestamp_str != NULL) {
+ presence_service_set_timestamp(service, parse_timestamp(timestamp_str));
+ free_xml_text_content(timestamp_str);
+ }
+ if (contact_str != NULL) {
+ presence_service_set_contact(service, contact_str);
+ free_xml_text_content(contact_str);
+ }
+ process_pidf_xml_presence_service_notes(xml_ctx, service, i);
presence_model_add_service(model, service);
}
free_xml_text_content(basic_status_str);
@@ -540,6 +889,16 @@ static int activity_name_to_linphone_presence_activity(const char *name, Linphon
return -1;
}
+static const char * presence_activity_to_string(LinphonePresenceActivity activity) {
+ unsigned int i;
+ for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) {
+ if (activity == activity_map[i].activity) {
+ return activity_map[i].name;
+ }
+ }
+ return NULL;
+}
+
static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_idx) {
char xpath_str[MAX_XPATH_LENGTH];
xmlXPathObjectPtr activities_nodes_object;
@@ -638,6 +997,7 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp
struct _LinphonePresencePerson *person;
const char *person_id_str;
const char *person_timestamp_str;
+ time_t timestamp;
int i;
int err = 0;
@@ -646,9 +1006,13 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp
for (i = 1; i <= person_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", person_prefix, i);
person_id_str = get_xml_text_content(xml_ctx, xpath_str);
- snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/timestamp", person_prefix, i);
+ snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", person_prefix, i);
person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str);
- person = presence_person_new(person_id_str, person_timestamp_str);
+ if (person_timestamp_str == NULL)
+ timestamp = time(NULL);
+ else
+ timestamp = parse_timestamp(person_timestamp_str);
+ person = presence_person_new(person_id_str, timestamp);
if (person != NULL) {
err = process_pidf_xml_presence_person_activities(xml_ctx, person, i);
if (err == 0) {
@@ -775,13 +1139,13 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){
linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny);
}
-void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os){
+void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence){
MSList *elem;
- ms_message("Notifying all friends that we are in status %i",os);
+ ms_message("Notifying all friends");
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend *)elem->data;
if (lf->insub){
- linphone_friend_notify(lf,os);
+ linphone_friend_notify(lf,presence);
}
}
}
@@ -864,6 +1228,259 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c
*result = (SalPresenceModel *)model;
}
+struct _presence_service_obj_st {
+ xmlTextWriterPtr writer;
+ const char *contact;
+ int *err;
+};
+
+struct _presence_person_obj_st {
+ xmlTextWriterPtr writer;
+ int *err;
+};
+
+struct _presence_activity_obj_st {
+ xmlTextWriterPtr writer;
+ int *err;
+};
+
+struct _presence_note_obj_st {
+ xmlTextWriterPtr writer;
+ const char *ns;
+ int *err;
+};
+
+static int write_xml_presence_timestamp(xmlTextWriterPtr writer, time_t timestamp) {
+ int err;
+ char *timestamp_str = timestamp_to_string(timestamp);
+ err = xmlTextWriterWriteElement(writer, (const xmlChar *)"timestamp", (const xmlChar *)timestamp_str);
+ if (timestamp_str) ms_free(timestamp_str);
+ return err;
+}
+
+static int write_xml_presence_service(xmlTextWriterPtr writer, struct _LinphonePresenceService *service, const char *contact) {
+ int err = xmlTextWriterStartElement(writer, (const xmlChar *)"tuple");
+ if (err >= 0) {
+ if ((service == NULL) || (service->id == NULL)) {
+ char *text = generate_presence_id();
+ err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)text);
+ if (text != NULL) ms_free(text);
+ } else {
+ err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)service->id);
+ }
+ }
+ if (err >= 0) {
+ err = xmlTextWriterStartElement(writer, (const xmlChar *)"status");
+ }
+ if (err >= 0) {
+ LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusClosed;
+ if (service != NULL) basic_status = service->status;
+ err = xmlTextWriterWriteElement(writer, (const xmlChar *)"basic", (const xmlChar *)presence_basic_status_to_string(basic_status));
+ }
+ if (err >= 0) {
+ /* Close the "status" element. */
+ err = xmlTextWriterEndElement(writer);
+ }
+ if (err >= 0) {
+ err = xmlTextWriterStartElement(writer, (const xmlChar *)"contact");
+ }
+ if (err >= 0) {
+ err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"priority", (const xmlChar *)"0.8");
+ }
+ if (err >= 0) {
+ err = xmlTextWriterWriteString(writer, (const xmlChar *)contact);
+ }
+ if (err >= 0) {
+ /* Close the "contact" element. */
+ err = xmlTextWriterEndElement(writer);
+ }
+ if (err >= 0) {
+ if (service == NULL)
+ err = write_xml_presence_timestamp(writer, time(NULL));
+ else
+ err = write_xml_presence_timestamp(writer, service->timestamp);
+ }
+ if (err >= 0) {
+ /* Close the "tuple" element. */
+ err = xmlTextWriterEndElement(writer);
+ }
+ return err;
+}
+
+static int write_xml_presence_activity(xmlTextWriterPtr writer, struct _LinphonePresenceActivity *activity) {
+ int err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"rpid",
+ (const xmlChar *)presence_activity_to_string(activity->activity), NULL);
+ if ((err >= 0) && (activity->description != NULL)) {
+ err = xmlTextWriterWriteString(writer, (const xmlChar *)activity->description);
+ }
+ if (err >= 0) {
+ err = xmlTextWriterEndElement(writer);
+ }
+ return err;
+}
+
+static void write_xml_presence_activity_obj(struct _LinphonePresenceActivity *activity, struct _presence_activity_obj_st *st) {
+ int err = write_xml_presence_activity(st->writer, activity);
+ if (err < 0) *st->err = err;
+}
+
+static int write_xml_presence_note(xmlTextWriterPtr writer, struct _LinphonePresenceNote *note, const char *ns) {
+ int err;
+ if (ns == NULL) {
+ err = xmlTextWriterStartElement(writer, (const xmlChar *)"note");
+ } else {
+ err = xmlTextWriterStartElementNS(writer, (const xmlChar *)ns, (const xmlChar *)"note", NULL);
+ }
+ if ((err >= 0) && (note->lang != NULL)) {
+ err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xml", (const xmlChar *)"lang", NULL, (const xmlChar *)note->lang);
+ }
+ if (err >= 0) {
+ err = xmlTextWriterWriteString(writer, (const xmlChar *)note->content);
+ }
+ if (err >= 0) {
+ err = xmlTextWriterEndElement(writer);
+ }
+ return err;
+}
+
+static void write_xml_presence_note_obj(struct _LinphonePresenceNote *note, struct _presence_note_obj_st *st) {
+ int err = write_xml_presence_note(st->writer, note, st->ns);
+ if (err < 0) *st->err = err;
+}
+
+static int write_xml_presence_person(xmlTextWriterPtr writer, struct _LinphonePresencePerson *person) {
+ int err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"dm", (const xmlChar *)"person", NULL);
+ if (err >= 0) {
+ if (person->id == NULL) {
+ char *text = generate_presence_id();
+ err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)text);
+ if (text != NULL) ms_free(text);
+ } else {
+ err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)person->id);
+ }
+ }
+ if ((err >= 0) && ((person->activities_notes != NULL) || (person->activities != NULL))) {
+ err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"rpid", (const xmlChar *)"activities", NULL);
+ if ((err >= 0) && (person->activities_notes != NULL)) {
+ struct _presence_note_obj_st st;
+ st.writer = writer;
+ st.ns = "rpid";
+ st.err = &err;
+ ms_list_for_each2(person->activities_notes, (MSIterate2Func)write_xml_presence_note_obj, &st);
+ }
+ if ((err >= 0) && (person->activities != NULL)) {
+ struct _presence_activity_obj_st st;
+ st.writer = writer;
+ st.err = &err;
+ ms_list_for_each2(person->activities, (MSIterate2Func)write_xml_presence_activity_obj, &st);
+ }
+ if (err >= 0) {
+ /* Close the "activities" element. */
+ err = xmlTextWriterEndElement(writer);
+ }
+ }
+ if ((err >= 0) && (person->notes != NULL)) {
+ struct _presence_note_obj_st st;
+ st.writer = writer;
+ st.ns = "dm";
+ st.err = &err;
+ ms_list_for_each2(person->activities_notes, (MSIterate2Func)write_xml_presence_note_obj, &st);
+ }
+ if (err >= 0) {
+ write_xml_presence_timestamp(writer, person->timestamp);
+ }
+ if (err >= 0) {
+ /* Close the "person" element. */
+ err = xmlTextWriterEndElement(writer);
+ }
+ return err;
+}
+
+static void write_xml_presence_service_obj(struct _LinphonePresenceService *service, struct _presence_service_obj_st *st) {
+ int err = write_xml_presence_service(st->writer, service, st->contact);
+ if (err < 0) *st->err = err;
+}
+
+static void write_xml_presence_person_obj(struct _LinphonePresencePerson *person, struct _presence_person_obj_st *st) {
+ int err = write_xml_presence_person(st->writer, person);
+ if (err < 0) *st->err = err;
+}
+
+void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) {
+ LinphonePresenceModel *model;
+ xmlBufferPtr buf;
+ xmlTextWriterPtr writer;
+ int err;
+
+ if ((contact == NULL) || (content == NULL)) return;
+
+ model = (LinphonePresenceModel *)presence;
+ buf = xmlBufferCreate();
+ if (buf == NULL) {
+ ms_error("Error creating the XML buffer");
+ return;
+ }
+ writer = xmlNewTextWriterMemory(buf, 0);
+ if (writer == NULL) {
+ ms_error("Error creating the XML writer");
+ return;
+ }
+
+ err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
+ if (err >= 0) {
+ err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"presence", (const xmlChar *)"urn:ietf:params:xml:ns:pidf");
+ }
+ if (err >= 0) {
+ err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"dm",
+ NULL, (const xmlChar *)"urn:ietf:params:xml:ns:pidf:data-model");
+ }
+ if (err >= 0) {
+ err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"rpid",
+ NULL, (const xmlChar *)"urn:ietf:params:xml:ns:pidf:rpid");
+ }
+ if (err >= 0) {
+ err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"entity", (const xmlChar *)contact);
+ }
+ if (err >= 0) {
+ if ((model == NULL) || (model->services == NULL)) {
+ err = write_xml_presence_service(writer, NULL, contact);
+ } else {
+ struct _presence_service_obj_st st;
+ st.writer = writer;
+ st.contact = contact;
+ st.err = &err;
+ ms_list_for_each2(model->services, (MSIterate2Func)write_xml_presence_service_obj, &st);
+ }
+ }
+ if ((err >= 0) && (model != NULL)) {
+ struct _presence_person_obj_st st;
+ st.writer = writer;
+ st.err = &err;
+ ms_list_for_each2(model->persons, (MSIterate2Func)write_xml_presence_person_obj, &st);
+ }
+ if ((err >= 0) && (model != NULL)) {
+ struct _presence_note_obj_st st;
+ st.writer = writer;
+ st.ns = NULL;
+ st.err = &err;
+ ms_list_for_each2(model->notes, (MSIterate2Func)write_xml_presence_note_obj, &st);
+ }
+ if (err >= 0) {
+ /* Close the "presence" element. */
+ err = xmlTextWriterEndElement(writer);
+ }
+ if (err >= 0) {
+ err = xmlTextWriterEndDocument(writer);
+ }
+
+ xmlFreeTextWriter(writer);
+ if (err > 0) {
+ /* xmlTextWriterEndDocument returns the size of the content. */
+ *content = ms_strdup((char *)buf->content);
+ }
+ xmlBufferFree(buf);
+}
+
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model){
char *tmp;
LinphoneFriend *lf;
diff --git a/coreapi/private.h b/coreapi/private.h
index e2ecef9e8..e85c169fc 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -233,7 +233,7 @@ 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);
-int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os);
+int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence);
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message);
void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc);
/*
@@ -245,7 +245,7 @@ const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphonePro
int linphone_online_status_to_eXosip(LinphoneOnlineStatus os);
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
-void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os);
+void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence);
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
@@ -286,11 +286,11 @@ static inline void set_string(char **dest, const char *src){
#define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0
-SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os);
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_notify_parse_presence(SalOp *op, 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);
@@ -599,7 +599,7 @@ struct _LinphoneCore
MSList *bl_reqs;
MSList *subscribers; /* unknown subscribers */
int minutes_away;
- LinphoneOnlineStatus presence_mode;
+ LinphonePresenceModel *presence_model;
char *alt_contact;
void *data;
char *play_file;
diff --git a/coreapi/proxy.c b/coreapi/proxy.c
index 4bf6e6dc1..814c00766 100644
--- a/coreapi/proxy.c
+++ b/coreapi/proxy.c
@@ -849,8 +849,7 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm
if (realm!=NULL) cfg->realm=ms_strdup(realm);
}
-int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy,
- LinphoneOnlineStatus presence_mode){
+int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){
int err;
if (proxy->publish_op==NULL){
@@ -859,7 +858,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy,
sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy));
sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy));
}
- err=sal_publish_presence(proxy->publish_op,NULL,NULL,linphone_online_status_to_sal(presence_mode));
+ err=sal_publish_presence(proxy->publish_op,NULL,NULL,(SalPresenceModel *)presence);
return err;
}
@@ -1190,7 +1189,7 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){
}
}
if (cfg->publish && cfg->publish_op==NULL && cfg->state==LinphoneRegistrationOk){
- linphone_proxy_config_send_publish(cfg,lc->presence_mode);
+ linphone_proxy_config_send_publish(cfg,lc->presence_model);
}
}
diff --git a/include/sal/sal.h b/include/sal/sal.h
index 6eabe3def..0e94faf5b 100644
--- a/include/sal/sal.h
+++ b/include/sal/sal.h
@@ -359,6 +359,7 @@ typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *ev
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBody *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);
typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg);
typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from);
typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from);
@@ -398,6 +399,7 @@ typedef struct SalCallbacks{
SalOnSubscribePresenceReceived subscribe_presence_received;
SalOnSubscribePresenceClosed subscribe_presence_closed;
SalOnParsePresenceRequested parse_presence_requested;
+ SalOnConvertPresenceToXMLRequested convert_presence_to_xml_requested;
SalOnNotifyPresence notify_presence;
SalOnPingReply ping_reply;
SalOnAuthRequested auth_requested;
@@ -532,11 +534,11 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to);
-int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message);
+int sal_notify_presence(SalOp *op, SalPresenceModel *presence);
int sal_notify_presence_close(SalOp *op);
/*presence publish */
-int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceStatus status);
+int sal_publish_presence(SalOp *op, const char *from, const char *to, SalPresenceModel *presence);
/*ping: main purpose is to obtain its own contact address behind firewalls*/