Use xml parser to get presence status.

This commit is contained in:
Ghislain MARY 2013-06-12 17:36:30 +02:00
parent 79c72fc860
commit 220c471369
10 changed files with 998 additions and 81 deletions

View file

@ -16,7 +16,7 @@ CLEANFILES=$(GITVERSION_FILE)
## Process this file with automake to produce Makefile.in
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h lpconfig.h sipsetup.h event.h
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h
if BUILD_TUNNEL
linphone_include_HEADERS+=linphone_tunnel.h

View file

@ -486,6 +486,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;
if (ctx->callbacks.subscribe_closed==NULL)
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.notify_presence==NULL)
ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;
if (ctx->callbacks.subscribe_presence_received==NULL)

View file

@ -497,6 +497,26 @@ static void presence_process_transaction_terminated(void *user_ctx, const belle_
ms_message("presence_process_transaction_terminated not implemented yet");
}
static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_request_t *req) {
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);
belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_length_t);
const char *body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
SalPresenceModel *result = NULL;
if ((content_type == NULL) || (content_length == NULL))
return NULL;
if (belle_sip_header_content_length_get_content_length(content_length) == 0)
return NULL;
op->base.root->callbacks.parse_presence_requested(op,
belle_sip_header_content_type_get_type(content_type),
belle_sip_header_content_type_get_subtype(content_type),
body,
&result);
return result;
}
static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
@ -505,7 +525,7 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
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_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
SalPresenceStatus estatus=SalPresenceOffline;
SalPresenceModel *presence_model = NULL;
SalSubscribeStatus sub_state;
belle_sip_response_t* resp;
belle_sip_object_ref(server_transaction);
@ -536,41 +556,22 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op));
return;
}
if (strstr(body,"pending")!=NULL){
estatus=SalPresenceOffline;
}else if (strstr(body,"busy")!=NULL){
estatus=SalPresenceBusy;
}else if (strstr(body,"berightback")!=NULL
|| strstr(body,"in-transit")!=NULL ){
estatus=SalPresenceBerightback;
}else if (strstr(body,"away")!=NULL
|| strstr(body,"idle")){
estatus=SalPresenceAway;
}else if (strstr(body,"onthephone")!=NULL
|| strstr(body,"on-the-phone")!=NULL){
estatus=SalPresenceOnthephone;
}else if (strstr(body,"outtolunch")!=NULL
|| strstr(body,"lunch")!=NULL
|| strstr(body,"meal")!=NULL){
estatus=SalPresenceOuttolunch;
}else if (strstr(body,"closed")!=NULL){
estatus=SalPresenceOffline;
}else if ((strstr(body,"online")!=NULL) || (strstr(body,"open")!=NULL)) {
estatus=SalPresenceOnline;
}else if((strstr(body,"vacation")!=NULL)) {
estatus = SalPresenceOnVacation;
}else{
estatus=SalPresenceOffline;
presence_model = process_presence_notification(op, req);
if (presence_model != NULL) {
/* Presence notification body parsed successfully. */
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else {
sub_state=SalSubscribeActive;
}
op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL);
resp = sal_op_create_response_from_request(op, req, 200);
} else {
/* Formatting error in presence notification body. */
ms_error("Wrongly formatted presence notification received");
resp = sal_op_create_response_from_request(op, req, 400);
}
ms_message("We are notified that [%s] has online status [%s]",sal_op_get_to(op),sal_presence_status_to_string(estatus));
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("And outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else
sub_state=SalSubscribeActive;
op->base.root->callbacks.notify_presence(op,sub_state, estatus,NULL);
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
} else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) {
/*either a refresh of an unsubscribe*/

View file

@ -877,9 +877,13 @@ static void text_received(SalOp *op, const SalMessage *msg){
}
}
static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){
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);
}
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,status);
linphone_notify_recv(lc,op,ss,model);
}
static void subscribe_presence_received(SalOp *op, const char *from){
@ -1085,6 +1089,7 @@ SalCallbacks linphone_sal_callbacks={
notify,
subscribe_presence_received,
subscribe_presence_closed,
parse_presence_requested,
notify_presence,
ping_reply,
auth_requested,

View file

@ -119,7 +119,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
if (fr->outsub==NULL){
/* people for which we don't have yet an answer should appear as offline */
fr->status=LinphoneStatusOffline;
fr->presence=NULL;
/*
if (fr->lc->vtable.notify_recv)
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
@ -138,7 +138,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
LinphoneFriend * linphone_friend_new(){
LinphoneFriend *obj=ms_new0(LinphoneFriend,1);
obj->pol=LinphoneSPAccept;
obj->status=LinphoneStatusOffline;
obj->presence=NULL;
obj->subscribe=TRUE;
return obj;
}
@ -304,6 +304,7 @@ void linphone_friend_destroy(LinphoneFriend *lf){
sal_op_release(lf->outsub);
lf->outsub=NULL;
}
if (lf->presence != NULL) linphone_presence_model_delete(lf->presence);
if (lf->uri!=NULL) linphone_address_destroy(lf->uri);
if (lf->info!=NULL) buddy_info_free(lf->info);
ms_free(lf);
@ -322,7 +323,90 @@ LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneF
}
LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
return lf->status;
LinphoneOnlineStatus online_status = LinphoneStatusOffline;
LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusClosed;
LinphonePresenceActivity activity = LinphonePresenceActivityUnknown;
char *activity_description = NULL;
unsigned int nb_activities = 0;
int err = 0;
if (lf->presence != NULL) {
basic_status = linphone_presence_model_get_basic_status(lf->presence);
nb_activities = linphone_presence_model_nb_activities(lf->presence);
online_status = (basic_status == LinphonePresenceBasicStatusOpen) ? LinphoneStatusOnline : LinphoneStatusOffline;
if (nb_activities > 1) {
char *tmp = NULL;
const LinphoneAddress *addr = linphone_friend_get_address(lf);
if (addr) tmp = linphone_address_as_string(addr);
ms_warning("Friend %s has several activities, get status from the first one", tmp ? tmp : "unknown");
if (tmp) ms_free(tmp);
nb_activities = 1;
}
if (nb_activities == 1) {
err = linphone_presence_model_get_activity(lf->presence, 0, &activity, &activity_description);
if (err == 0) {
switch (activity) {
case LinphonePresenceActivityBreakfast:
case LinphonePresenceActivityDinner:
case LinphonePresenceActivityLunch:
case LinphonePresenceActivityMeal:
online_status = LinphoneStatusOutToLunch;
break;
case LinphonePresenceActivityAppointment:
case LinphonePresenceActivityMeeting:
case LinphonePresenceActivityPerformance:
case LinphonePresenceActivityPresentation:
case LinphonePresenceActivitySpectator:
case LinphonePresenceActivityWorking:
case LinphonePresenceActivityWorship:
online_status = LinphoneStatusDoNotDisturb;
break;
case LinphonePresenceActivityAway:
case LinphonePresenceActivitySleeping:
online_status = LinphoneStatusAway;
break;
case LinphonePresenceActivityHoliday:
case LinphonePresenceActivityTravel:
case LinphonePresenceActivityVacation:
online_status = LinphoneStatusVacation;
break;
case LinphonePresenceActivityBusy:
case LinphonePresenceActivityLookingForWork:
case LinphonePresenceActivityPlaying:
case LinphonePresenceActivityShopping:
case LinphonePresenceActivityTV:
online_status = LinphoneStatusBusy;
break;
case LinphonePresenceActivityInTransit:
case LinphonePresenceActivitySteering:
online_status = LinphoneStatusBeRightBack;
break;
case LinphonePresenceActivityOnThePhone:
online_status = LinphoneStatusOnThePhone;
break;
case LinphonePresenceActivityOther:
case LinphonePresenceActivityPermanentAbsence:
online_status = LinphoneStatusMoved;
break;
case LinphonePresenceActivityUnknown:
break;
}
}
}
}
return online_status;
}
LinphonePresenceModel * linphone_friend_get_presence(LinphoneFriend *lf) {
return lf->presence;
}
void linphone_friend_set_presence(LinphoneFriend *lf, LinphonePresenceModel *model) {
if (lf->presence != NULL) {
linphone_presence_model_delete(lf->presence);
}
lf->presence = model;
}
BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){

View file

@ -19,9 +19,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef LINPHONEFRIEND_H_
#define LINPHONEFRIEND_H_
#include "linphonepresence.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup buddy_list
* @{
@ -206,6 +210,10 @@ LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr);
* @return #LinphoneOnlineStatus
*/
LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf);
LinphonePresenceModel * linphone_friend_get_presence(LinphoneFriend *lf);
void linphone_friend_set_presence(LinphoneFriend *lf, LinphonePresenceModel *presence);
BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf);
void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key);
const char *linphone_friend_get_ref_key(const LinphoneFriend *lf);

View file

@ -0,0 +1,80 @@
/*
linphonepresence.h
Copyright (C) 2010-2013 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 LINPHONEPRESENCE_H_
#define LINPHONEPRESENCE_H_
#ifdef __cplusplus
extern "C" {
#endif
/** Basic status as defined in section 4.1.4 of RFC 3863 */
typedef enum LinphonePresenceBasicStatus {
LinphonePresenceBasicStatusOpen,
LinphonePresenceBasicStatusClosed
} LinphonePresenceBasicStatus;
/** Activities as defined in section 3.2 of RFC 4480 */
typedef enum LinphonePresenceActivity {
LinphonePresenceActivityAppointment,
LinphonePresenceActivityAway,
LinphonePresenceActivityBreakfast,
LinphonePresenceActivityBusy,
LinphonePresenceActivityDinner,
LinphonePresenceActivityHoliday,
LinphonePresenceActivityInTransit,
LinphonePresenceActivityLookingForWork,
LinphonePresenceActivityLunch,
LinphonePresenceActivityMeal,
LinphonePresenceActivityMeeting,
LinphonePresenceActivityOnThePhone,
LinphonePresenceActivityOther,
LinphonePresenceActivityPerformance,
LinphonePresenceActivityPermanentAbsence,
LinphonePresenceActivityPlaying,
LinphonePresenceActivityPresentation,
LinphonePresenceActivityShopping,
LinphonePresenceActivitySleeping,
LinphonePresenceActivitySpectator,
LinphonePresenceActivitySteering,
LinphonePresenceActivityTravel,
LinphonePresenceActivityTV,
LinphonePresenceActivityUnknown,
LinphonePresenceActivityVacation,
LinphonePresenceActivityWorking,
LinphonePresenceActivityWorship
} LinphonePresenceActivity;
struct _LinphonePresenceModel;
typedef struct _LinphonePresenceModel LinphonePresenceModel;
LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void);
LINPHONE_PUBLIC void linphone_presence_model_delete(LinphonePresenceModel *model);
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);
#ifdef __cplusplus
}
#endif
#endif /* LINPHONEPRESENCE_H_ */

View file

@ -19,11 +19,744 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphonecore.h"
#include "private.h"
#include <libxml/xmlreader.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#define XMLPARSING_BUFFER_LEN 2048
#define MAX_XPATH_LENGTH 256
extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol);
struct _LinphonePresenceNote {
char *lang;
char *content;
};
struct _LinphonePresenceService {
char *id;
LinphonePresenceBasicStatus status;
};
struct _LinphonePresenceActivity {
LinphonePresenceActivity activity;
char *description;
};
struct _LinphonePresencePerson {
char *id;
MSList *activities; /**< A list of _LinphonePresenceActivity structures. */
MSList *activities_notes; /**< A list of _LinphonePresenceNote structures. */
MSList *notes; /**< A list of _LinphonePresenceNote structures. */
time_t timestamp;
};
/**
* Represents the presence model as defined in RFC 4479 and RFC 4480.
* This model is not complete. For example, it does not handle devices.
*/
struct _LinphonePresenceModel {
MSList *services; /**< A list of _LinphonePresenceService structures. Also named tuples in the RFC. */
MSList *persons; /**< A list of _LinphonePresencePerson structures. */
MSList *notes; /**< A list of _LinphonePresenceNote structures. */
};
typedef struct _xmlparsing_context {
xmlDoc *doc;
xmlXPathContextPtr xpath_ctx;
char errorBuffer[XMLPARSING_BUFFER_LEN];
char warningBuffer[XMLPARSING_BUFFER_LEN];
} xmlparsing_context_t;
static xmlparsing_context_t * xmlparsing_context_new() {
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t));
if (xmlCtx != NULL) {
xmlCtx->doc = NULL;
xmlCtx->xpath_ctx = NULL;
xmlCtx->errorBuffer[0] = '\0';
xmlCtx->warningBuffer[0] = '\0';
}
return xmlCtx;
}
static void xmlparsing_context_destroy(xmlparsing_context_t *ctx) {
if (ctx->doc != NULL) {
xmlFreeDoc(ctx->doc);
ctx->doc = NULL;
}
if (ctx->xpath_ctx != NULL) {
xmlXPathFreeContext(ctx->xpath_ctx);
ctx->xpath_ctx = NULL;
}
free(ctx);
}
static void xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) {
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx;
int sl = strlen(xmlCtx->errorBuffer);
va_list args;
va_start(args, fmt);
vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args);
va_end(args);
}
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);
if (lang != NULL) {
note->lang = ms_strdup(lang);
}
return note;
}
static void presence_note_delete(struct _LinphonePresenceNote *note) {
ms_free(note->content);
if (note->lang != NULL) {
ms_free(note->lang);
}
ms_free(note);
}
static struct _LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) {
struct _LinphonePresenceService *service = ms_new0(struct _LinphonePresenceService, 1);
if (id != NULL) {
service->id = ms_strdup(id);
}
service->status = status;
return service;
}
static void presence_service_delete(struct _LinphonePresenceService *service) {
if (service->id != NULL) {
ms_free(service->id);
}
ms_free(service);
};
static struct _LinphonePresenceActivity * presence_activity_new(LinphonePresenceActivity activity, const char *description) {
struct _LinphonePresenceActivity *act = ms_new0(struct _LinphonePresenceActivity, 1);
act->activity = activity;
if (description != NULL) {
act->description = ms_strdup(description);
}
return act;
}
static void presence_activity_delete(struct _LinphonePresenceActivity *activity) {
if (activity->description != NULL) {
ms_free(activity->description);
}
ms_free(activity);
}
static time_t parse_timestamp(const char *timestamp) {
struct tm ret;
time_t seconds;
memset(&ret, 0, sizeof(ret));
sscanf(timestamp, "%d-%d-%dT%d:%d:%d",
&ret.tm_year, &ret.tm_mon, &ret.tm_mday, &ret.tm_hour, &ret.tm_min, &ret.tm_sec);
ret.tm_mon--;
ret.tm_year -= 1900;
ret.tm_isdst = 0;
seconds = mktime(&ret);
if (seconds == (time_t)-1) {
ms_error("mktime() failed: %s", strerror(errno));
return (time_t)-1;
}
return seconds - timezone;
}
static struct _LinphonePresencePerson * presence_person_new(const char *id, const char *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 {
person->timestamp = time(NULL);
}
return person;
}
static void presence_person_delete(struct _LinphonePresencePerson *person) {
if (person->id != NULL) {
ms_free(person->id);
}
ms_list_for_each(person->activities, (MSIterateFunc)presence_activity_delete);
ms_list_free(person->activities);
ms_list_for_each(person->activities_notes, (MSIterateFunc)presence_note_delete);
ms_list_free(person->activities_notes);
ms_list_for_each(person->notes, (MSIterateFunc)presence_note_delete);
ms_list_free(person->notes);
ms_free(person);
}
static void presence_person_add_activity(struct _LinphonePresencePerson *person, struct _LinphonePresenceActivity *activity) {
person->activities = ms_list_append(person->activities, activity);
}
static void presence_person_add_activities_note(struct _LinphonePresencePerson *person, struct _LinphonePresenceNote *note) {
person->activities_notes = ms_list_append(person->activities_notes, note);
}
static void presence_person_add_note(struct _LinphonePresencePerson *person, struct _LinphonePresenceNote *note) {
person->notes = ms_list_append(person->notes, note);
}
static void presence_model_add_service(LinphonePresenceModel *model, struct _LinphonePresenceService *service) {
model->services = ms_list_append(model->services, service);
}
static void presence_model_add_person(LinphonePresenceModel *model, struct _LinphonePresencePerson *person) {
model->persons = ms_list_append(model->persons, person);
}
static void presence_model_add_note(LinphonePresenceModel *model, struct _LinphonePresenceNote *note) {
model->notes = ms_list_append(model->notes, note);
}
static void presence_model_find_open_basic_status(struct _LinphonePresenceService *service, LinphonePresenceBasicStatus *status) {
if (service->status == LinphonePresenceBasicStatusOpen) {
*status = LinphonePresenceBasicStatusOpen;
}
}
LinphonePresenceModel * linphone_presence_model_new(void) {
return ms_new0(LinphonePresenceModel, 1);
}
void linphone_presence_model_delete(LinphonePresenceModel *model) {
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);
ms_list_free(model->persons);
ms_list_for_each(model->notes, (MSIterateFunc)presence_note_delete);
ms_list_free(model->notes);
ms_free(model);
}
/* 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);
return status;
}
static void presence_model_count_activities(const struct _LinphonePresencePerson *person, unsigned int *nb) {
*nb += ms_list_size(person->activities);
}
unsigned int linphone_presence_model_nb_activities(const LinphonePresenceModel *model) {
unsigned int nb = 0;
ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_count_activities, &nb);
return nb;
}
struct _get_activity_st {
unsigned int requested_idx;
unsigned int current_idx;
LinphonePresenceActivity *activity;
char **description;
};
static void presence_model_get_activity(const struct _LinphonePresencePerson *person, struct _get_activity_st *st) {
struct _LinphonePresenceActivity *activity;
unsigned int size = ms_list_size(person->activities);
if (st->requested_idx < (st->current_idx + size)) {
activity = (struct _LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx);
*st->activity = activity->activity;
if (st->description != NULL) {
*st->description = activity->description;
}
} else {
st->current_idx += size;
}
}
int linphone_presence_model_get_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)))
return -1;
memset(&st, 0, sizeof(st));
st.requested_idx = idx;
st.activity = activity;
*st.activity = LinphonePresenceActivityUnknown;
if (description != NULL) {
st.description = description;
}
ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st);
return 0;
}
static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) {
if (xml_ctx->xpath_ctx != NULL) {
xmlXPathFreeContext(xml_ctx->xpath_ctx);
}
xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc);
if (xml_ctx->xpath_ctx == NULL) return -1;
return 0;
}
static char * get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
xmlXPathObjectPtr xpath_obj;
xmlChar *text = NULL;
int i;
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;
for (i = 0; i < nodes->nodeNr; i++) {
xmlNodePtr node = nodes->nodeTab[i];
if (node->children != NULL) {
text = xmlNodeListGetString(xml_ctx->doc, node->children, 1);
}
}
}
xmlXPathFreeObject(xpath_obj);
}
return (char *)text;
}
static void free_xml_text_content(const char *text) {
xmlFree((xmlChar *)text);
}
static xmlXPathObjectPtr get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
}
static int process_rfcxxxx_presence_notification(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) {
LinphonePresenceBasicStatus basic_status;
struct _LinphonePresenceService *service;
struct _LinphonePresencePerson *person;
struct _LinphonePresenceActivity *activity = NULL;
char *status_text = NULL;
char *substatus_text = NULL;
if (create_xml_xpath_context(xml_ctx) < 0)
return -1;
status_text = get_xml_text_content(xml_ctx, "/presence/atom/address/status/@status");
if (status_text == NULL)
return -1;
substatus_text = get_xml_text_content(xml_ctx, "/presence/atom/address/msnsubstatus/@substatus");
if (substatus_text == NULL) {
free_xml_text_content(status_text);
return -1;
}
if (strcmp(status_text, "open") == 0) {
basic_status = LinphonePresenceBasicStatusOpen;
if (strcmp(substatus_text, "berightback") == 0) {
activity = presence_activity_new(LinphonePresenceActivityInTransit, NULL);
} else if (strcmp(substatus_text, "away") == 0) {
activity = presence_activity_new(LinphonePresenceActivityAway, NULL);
} else if (strcmp(substatus_text, "outtolunch") == 0) {
activity = presence_activity_new(LinphonePresenceActivityMeal, NULL);
}
} else if (strcmp(status_text, "inuse") == 0) {
basic_status = LinphonePresenceBasicStatusOpen;
if (strcmp(substatus_text, "busy") == 0) {
activity = presence_activity_new(LinphonePresenceActivityBusy, NULL);
} else if (strcmp(substatus_text, "onthephone") == 0) {
activity = presence_activity_new(LinphonePresenceActivityOnThePhone, NULL);
}
} else if (strcmp(status_text, "closed") == 0) {
basic_status = LinphonePresenceBasicStatusClosed;
}
service = presence_service_new(NULL, basic_status);
if (service != NULL) {
presence_model_add_service(model, service);
}
if (activity != NULL) {
person = presence_person_new(NULL, NULL);
if (person != NULL) {
presence_person_add_activity(person, activity);
presence_model_add_person(model, person);
}
}
free_xml_text_content(status_text);
free_xml_text_content(substatus_text);
return 0;
}
static int process_msoldpres_presence_notification(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) {
LinphonePresenceBasicStatus basic_status;
struct _LinphonePresenceService *service;
struct _LinphonePresencePerson *person;
struct _LinphonePresenceActivity *activity = NULL;
char *status_text = NULL;
char *substatus_text = NULL;
if (create_xml_xpath_context(xml_ctx) < 0)
return -1;
status_text = get_xml_text_content(xml_ctx, "/presence/atom/address/status/@status");
if (status_text == NULL)
return -1;
substatus_text = get_xml_text_content(xml_ctx, "/presence/atom/address/msnsubstatus/@substatus");
if (substatus_text == NULL) {
free_xml_text_content(status_text);
return -1;
}
if (strcmp(status_text, "open") == 0) {
basic_status = LinphonePresenceBasicStatusOpen;
} else if (strcmp(status_text, "inuse") == 0) {
basic_status = LinphonePresenceBasicStatusOpen;
if (strcmp(substatus_text, "busy") == 0) {
activity = presence_activity_new(LinphonePresenceActivityBusy, NULL);
} else if (strcmp(substatus_text, "onthephone") == 0) {
activity = presence_activity_new(LinphonePresenceActivityOnThePhone, NULL);
}
} else if (strcmp(status_text, "inactive") == 0) {
basic_status = LinphonePresenceBasicStatusOpen;
if (strcmp(substatus_text, "berightback") == 0) {
activity = presence_activity_new(LinphonePresenceActivityInTransit, NULL);
} else if (strcmp(substatus_text, "idle") == 0) {
activity = presence_activity_new(LinphonePresenceActivityAway, NULL);
} else if (strcmp(substatus_text, "outtolunch") == 0) {
activity = presence_activity_new(LinphonePresenceActivityMeal, NULL);
}
} else if (strcmp(status_text, "closed") == 0) {
basic_status = LinphonePresenceBasicStatusClosed;
}
service = presence_service_new(NULL, basic_status);
if (service != NULL) {
presence_model_add_service(model, service);
}
if (activity != NULL) {
person = presence_person_new(NULL, NULL);
if (person != NULL) {
presence_person_add_activity(person, activity);
presence_model_add_person(model, person);
}
}
return 0;
}
static const char *service_prefix = "/pidf:presence/pidf:tuple";
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;
LinphonePresenceBasicStatus basic_status;
int i;
service_object = get_xml_xpath_object_for_node_list(xml_ctx, service_prefix);
if ((service_object != NULL) && (service_object->nodesetval != NULL)) {
for (i = 1; i <= service_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:status/pidf:basic", service_prefix, i);
basic_status_str = get_xml_text_content(xml_ctx, xpath_str);
if (basic_status_str == NULL)
continue;
if (strcmp(basic_status_str, "open") == 0) {
basic_status = LinphonePresenceBasicStatusOpen;
} else if (strcmp(basic_status_str, "closed") == 0) {
basic_status = LinphonePresenceBasicStatusClosed;
} else {
/* Invalid value for basic status. */
free_xml_text_content(basic_status_str);
return -1;
}
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) {
presence_model_add_service(model, service);
}
free_xml_text_content(basic_status_str);
if (service_id_str != NULL) free_xml_text_content(service_id_str);
}
}
if (service_object != NULL) xmlXPathFreeObject(service_object);
return 0;
}
static const char *person_prefix = "/pidf:presence/dm:person";
struct _presence_activity_name_map {
const char *name;
LinphonePresenceActivity activity;
};
static struct _presence_activity_name_map activity_map[] = {
{ "appointment", LinphonePresenceActivityAppointment },
{ "away", LinphonePresenceActivityAway },
{ "breakfast", LinphonePresenceActivityBreakfast },
{ "busy", LinphonePresenceActivityBusy },
{ "dinner", LinphonePresenceActivityDinner },
{ "holiday", LinphonePresenceActivityHoliday },
{ "in-transit", LinphonePresenceActivityInTransit },
{ "looking-for-work", LinphonePresenceActivityLookingForWork },
{ "lunch", LinphonePresenceActivityLunch },
{ "meal", LinphonePresenceActivityMeal },
{ "meeting", LinphonePresenceActivityMeeting },
{ "on-the-phone", LinphonePresenceActivityOnThePhone },
{ "other", LinphonePresenceActivityOther },
{ "performance", LinphonePresenceActivityPerformance },
{ "permanent-absence", LinphonePresenceActivityPermanentAbsence },
{ "playing", LinphonePresenceActivityPlaying },
{ "presentation", LinphonePresenceActivityPresentation },
{ "shopping", LinphonePresenceActivityShopping },
{ "sleeping", LinphonePresenceActivitySleeping },
{ "spectator", LinphonePresenceActivitySpectator },
{ "steering", LinphonePresenceActivitySteering },
{ "travel", LinphonePresenceActivityTravel },
{ "tv", LinphonePresenceActivityTV },
{ "unknown", LinphonePresenceActivityUnknown },
{ "vacation", LinphonePresenceActivityVacation },
{ "working", LinphonePresenceActivityWorking },
{ "worship", LinphonePresenceActivityWorship }
};
static int activity_name_to_linphone_presence_activity(const char *name, LinphonePresenceActivity *activity) {
unsigned int i;
for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) {
if (strcmp(name, activity_map[i].name) == 0) {
*activity = activity_map[i].activity;
return 0;
}
}
return -1;
}
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;
xmlXPathObjectPtr activities_object;
xmlNodePtr activity_node;
struct _LinphonePresenceActivity *activity;
const char *description;
int i, j;
int err = 0;
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities", person_prefix, person_idx);
activities_nodes_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
if ((activities_nodes_object != NULL) && (activities_nodes_object->nodesetval != NULL)) {
for (i = 1; i <= activities_nodes_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/*", person_prefix, person_idx, i);
activities_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) {
for (j = 0; j < activities_object->nodesetval->nodeNr; j++) {
activity_node = activities_object->nodesetval->nodeTab[j];
if ((activity_node->name != NULL)
&& (activity_node->ns != NULL)
&& (activity_node->ns->prefix != NULL)
&& (strcmp((const char *)activity_node->ns->prefix, "rpid") == 0)) {
LinphonePresenceActivity linphone_activity;
description = (const char *)xmlNodeGetContent(activity_node);
if ((description != NULL) && (description[0] == '\0')) {
free_xml_text_content(description);
description = NULL;
}
err = activity_name_to_linphone_presence_activity((const char *)activity_node->name, &linphone_activity);
if (err < 0) break;
activity = presence_activity_new(linphone_activity, description);
presence_person_add_activity(person, activity);
if (description != NULL) free_xml_text_content(description);
}
}
}
if (err < 0) break;
}
}
if (activities_nodes_object != NULL) xmlXPathFreeObject(activities_nodes_object);
return err;
}
static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, struct _LinphonePresencePerson *person, unsigned int person_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:activities/rpid:note", person_prefix, person_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:activities/rpid:note[%i]", person_prefix, person_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:activities/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i);
lang = get_xml_text_content(xml_ctx, xpath_str);
note = presence_note_new(note_str, lang);
presence_person_add_activities_note(person, note);
if (lang != NULL) free_xml_text_content(lang);
free_xml_text_content(note_str);
}
}
if (note_object != NULL) xmlXPathFreeObject(note_object);
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:note", person_prefix, person_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]", person_prefix, person_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", person_prefix, person_idx, i);
lang = get_xml_text_content(xml_ctx, xpath_str);
note = presence_note_new(note_str, lang);
presence_person_add_note(person, 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_persons(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) {
char xpath_str[MAX_XPATH_LENGTH];
xmlXPathObjectPtr person_object;
struct _LinphonePresencePerson *person;
const char *person_id_str;
const char *person_timestamp_str;
int i;
int err = 0;
person_object = get_xml_xpath_object_for_node_list(xml_ctx, person_prefix);
if ((person_object != NULL) && (person_object->nodesetval != NULL)) {
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);
person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str);
person = presence_person_new(person_id_str, person_timestamp_str);
if (person != NULL) {
err = process_pidf_xml_presence_person_activities(xml_ctx, person, i);
if (err == 0) {
err = process_pidf_xml_presence_person_notes(xml_ctx, person, i);
}
if (err == 0) {
presence_model_add_person(model, person);
} else {
presence_person_delete(person);
break;
}
}
if (person_id_str != NULL) free_xml_text_content(person_id_str);
if (person_timestamp_str != NULL) free_xml_text_content(person_timestamp_str);
}
}
if (person_object != NULL) xmlXPathFreeObject(person_object);
if (err < 0) {
/* Remove all the persons added since there was an error. */
ms_list_for_each(model->persons, (MSIterateFunc)presence_person_delete);
}
return err;
}
static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) {
char xpath_str[MAX_XPATH_LENGTH];
xmlXPathObjectPtr note_object;
struct _LinphonePresenceNote *note;
const char *note_str;
const char *lang;
int i;
note_object = get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/rpid:note");
if ((note_object != NULL) && (note_object->nodesetval != NULL)) {
for (i = 1; i <= note_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/rpid:note[%i]", i);
note_str = get_xml_text_content(xml_ctx, xpath_str);
if (note_str == NULL) continue;
snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/rpid:note[%i]/@xml:lang", i);
lang = get_xml_text_content(xml_ctx, xpath_str);
note = presence_note_new(note_str, lang);
presence_model_add_note(model, 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 LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing_context_t *xml_ctx) {
LinphonePresenceModel *model = NULL;
int err;
if (create_xml_xpath_context(xml_ctx) < 0)
return NULL;
model = linphone_presence_model_new();
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"pidf", (const xmlChar *)"urn:ietf:params:xml:ns:pidf");
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"dm", (const xmlChar *)"urn:ietf:params:xml:ns:pidf:data-model");
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"rpid", (const xmlChar *)"urn:ietf:params:xml:ns:pidf:rpid");
err = process_pidf_xml_presence_services(xml_ctx, model);
if (err == 0) {
err = process_pidf_xml_presence_persons(xml_ctx, model);
}
if (err == 0) {
err = process_pidf_xml_presence_notes(xml_ctx, model);
}
if (err < 0) {
linphone_presence_model_delete(model);
model = NULL;
}
return model;
}
static LinphonePresenceModel * process_xpidf_xml_presence_notification(xmlparsing_context_t *xml_ctx) {
LinphonePresenceModel *model = NULL;
int err = -1;
xmlDtdPtr dtd = xmlGetIntSubset(xml_ctx->doc);
if (dtd != NULL) {
if (strcmp((const char *)dtd->name, "presence") == 0) {
model = linphone_presence_model_new();
if ((strcmp((const char *)dtd->SystemID, "xpidf.dtd") == 0)
&& (strcmp((const char *)dtd->ExternalID, "-//IETF//DTD RFCxxxx XPIDF 1.0//EN") == 0)) {
err = process_rfcxxxx_presence_notification(xml_ctx, model);
} else if (strcmp((const char *)dtd->SystemID, "http://schemas.microsoft.com/2002/09/sip/presence") == 0) {
err = process_msoldpres_presence_notification(xml_ctx, model);
}
}
}
if ((err < 0) && (model != NULL)) {
linphone_presence_model_delete(model);
model = NULL;
}
return model;
}
void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalOp *op){
LinphoneFriend *fl=linphone_friend_new_with_addr(subscriber);
if (fl==NULL) return ;
@ -100,56 +833,54 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
ms_free(tmp);
}
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus sal_status){
void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
xmlparsing_context_t *xml_ctx;
bool_t pidf_xml = FALSE;
bool_t xpidf_xml = FALSE;
LinphonePresenceModel *model = NULL;
if (strcmp(content_type, "application") != 0) {
*result = NULL;
return;
}
pidf_xml = (strcmp(content_subtype, "pidf+xml") == 0);
xpidf_xml = (strcmp(content_subtype, "xpidf+xml") == 0);
if (pidf_xml || xpidf_xml) {
xml_ctx = xmlparsing_context_new();
xmlSetGenericErrorFunc(xml_ctx, xmlparsing_genericxml_error);
xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
if (xml_ctx->doc != NULL) {
if (pidf_xml)
model = process_pidf_xml_presence_notification(xml_ctx);
if (xpidf_xml)
model = process_xpidf_xml_presence_notification(xml_ctx);
} else {
ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer);
}
xmlparsing_context_destroy(xml_ctx);
}
*result = (SalPresenceModel *)model;
}
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model){
char *tmp;
LinphoneFriend *lf;
LinphoneAddress *friend=NULL;
LinphoneOnlineStatus estatus=LinphoneStatusOffline;
switch(sal_status){
case SalPresenceOffline:
estatus=LinphoneStatusOffline;
break;
case SalPresenceOnline:
estatus=LinphoneStatusOnline;
break;
case SalPresenceBusy:
estatus=LinphoneStatusBusy;
break;
case SalPresenceBerightback:
estatus=LinphoneStatusBeRightBack;
break;
case SalPresenceAway:
estatus=LinphoneStatusAway;
break;
case SalPresenceOnthephone:
estatus=LinphoneStatusOnThePhone;
break;
case SalPresenceOuttolunch:
estatus=LinphoneStatusOutToLunch;
break;
case SalPresenceDonotdisturb:
estatus=LinphoneStatusDoNotDisturb;
break;
case SalPresenceOnVacation:
estatus=LinphoneStatusVacation;
break;
case SalPresenceMoved:
case SalPresenceAltService:
estatus=LinphoneStatusMoved;
break;
}
lf=linphone_find_friend_by_out_subscribe(lc->friends,op);
if (lf!=NULL){
friend=lf->uri;
tmp=linphone_address_as_string(friend);
lf->status=estatus;
linphone_friend_set_presence(lf, (LinphonePresenceModel *)model);
lf->subscribe_active=TRUE;
if (lc->vtable.notify_presence_recv)
lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf);
ms_free(tmp);
}else{
ms_message("But this person is not part of our friend list, so we don't care.");
linphone_presence_model_delete((LinphonePresenceModel *)model);
}
if (ss==SalSubscribeTerminated){
sal_op_release(op);

View file

@ -290,7 +290,8 @@ 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_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status);
void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result);
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model);
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op);
void linphone_subscription_answered(LinphoneCore *lc, SalOp *op);
@ -427,7 +428,7 @@ struct _LinphoneFriend{
SalOp *insub;
SalOp *outsub;
LinphoneSubscribePolicy pol;
LinphoneOnlineStatus status;
LinphonePresenceModel *presence;
struct _LinphoneCore *lc;
BuddyInfo *info;
char *refkey;

View file

@ -292,6 +292,9 @@ typedef enum SalPresenceStatus{
SalPresenceOnVacation
}SalPresenceStatus;
struct _SalPresenceModel;
typedef struct _SalPresenceModel SalPresenceModel;
const char* sal_presence_status_to_string(const SalPresenceStatus status);
typedef enum SalReferStatus{
@ -355,7 +358,8 @@ typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, Sal
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 (*SalOnSubscribeClosed)(SalOp *salop);
typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg);
typedef void (*SalOnParsePresenceRequested)(SalOp *salop, const char *content_type, const char *content_subtype, const char *content, SalPresenceModel **result);
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);
typedef void (*SalOnPingReply)(SalOp *salop);
@ -393,6 +397,7 @@ typedef struct SalCallbacks{
SalOnNotify notify;
SalOnSubscribePresenceReceived subscribe_presence_received;
SalOnSubscribePresenceClosed subscribe_presence_closed;
SalOnParsePresenceRequested parse_presence_requested;
SalOnNotifyPresence notify_presence;
SalOnPingReply ping_reply;
SalOnAuthRequested auth_requested;