Commit 80bdec52 authored by Ghislain MARY's avatar Ghislain MARY

Associate a presence model to each SIP URI and phone number of a friend.

parent 9243291c
......@@ -114,6 +114,29 @@ static int friend_compare(const void * a, const void * b) {
return ret;
}
static LinphoneFriendPresence * find_presence_model_for_uri_or_tel(const LinphoneFriend *lf, const char *uri_or_tel) {
bctbx_list_t *iterator = lf->presence_models;
while (iterator) {
LinphoneFriendPresence *lfp = (LinphoneFriendPresence *)bctbx_list_get_data(iterator);
if (strcmp(lfp->uri_or_tel, uri_or_tel) == 0) return lfp;
iterator = bctbx_list_next(iterator);
}
return NULL;
}
static void add_presence_model_for_uri_or_tel(LinphoneFriend *lf, const char *uri_or_tel, LinphonePresenceModel *presence) {
LinphoneFriendPresence *lfp = ms_new(LinphoneFriendPresence, 1);
lfp->uri_or_tel = ms_strdup(uri_or_tel);
lfp->presence = presence;
lf->presence_models = bctbx_list_append(lf->presence_models, lfp);
}
static void free_friend_presence(LinphoneFriendPresence *lfp) {
ms_free(lfp->uri_or_tel);
if (lfp->presence) linphone_presence_model_unref(lfp->presence);
}
bctbx_list_t *linphone_find_friend_by_address(bctbx_list_t *fl, const LinphoneAddress *addr, LinphoneFriend **lf){
bctbx_list_t *res=NULL;
......@@ -132,7 +155,8 @@ 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->presence=NULL;
bctbx_list_free_with_data(fr->presence_models, (bctbx_list_free_func)free_friend_presence);
fr->presence_models = NULL;
/*
if (fr->lc->vtable.notify_recv)
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
......@@ -151,7 +175,6 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
LinphoneFriend * linphone_friend_new(void){
LinphoneFriend *obj = belle_sip_object_new(LinphoneFriend);
obj->pol = LinphoneSPAccept;
obj->presence = NULL;
obj->subscribe = TRUE;
obj->vcard = NULL;
obj->storage_id = 0;
......@@ -414,6 +437,7 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){
}
void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
bctbx_list_t *iterator;
LinphoneCore *lc=lf->lc;
if (lf->outsub!=NULL) {
......@@ -423,11 +447,16 @@ void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
}
/* Notify application that we no longer know the presence activity */
if (lf->presence != NULL) {
linphone_presence_model_unref(lf->presence);
lf->presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,"unknown activity");
linphone_core_notify_notify_presence_received(lc,lf);
iterator = lf->presence_models;
while (iterator) {
LinphoneFriendPresence *lfp = (LinphoneFriendPresence *)bctbx_list_get_data(iterator);
linphone_presence_model_unref(lfp->presence);
lfp->presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline, "unknown activity");
linphone_core_notify_notify_presence_received_for_uri_or_tel(lc, lf, lfp->uri_or_tel, lfp->presence);
iterator = bctbx_list_next(iterator);
}
if (bctbx_list_size(lf->presence_models) > 0)
linphone_core_notify_notify_presence_received(lc, lf);
lf->initial_subscribes_sent=FALSE;
}
......@@ -448,7 +477,7 @@ static void _linphone_friend_release_ops(LinphoneFriend *lf){
static void _linphone_friend_destroy(LinphoneFriend *lf){
_linphone_friend_release_ops(lf);
if (lf->presence != NULL) linphone_presence_model_unref(lf->presence);
if (lf->presence_models) bctbx_list_free_with_data(lf->presence_models, (bctbx_list_free_func)free_friend_presence);
if (lf->uri!=NULL) linphone_address_unref(lf->uri);
if (lf->info!=NULL) buddy_info_free(lf->info);
if (lf->vcard != NULL) linphone_vcard_free(lf->vcard);
......@@ -486,15 +515,16 @@ LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneF
}
LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
const LinphonePresenceModel *presence = linphone_friend_get_presence_model(lf);
LinphoneOnlineStatus online_status = LinphoneStatusOffline;
LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusClosed;
LinphonePresenceActivity *activity = NULL;
const char *description = NULL;
unsigned int nb_activities = 0;
if (lf->presence != NULL) {
basic_status = linphone_presence_model_get_basic_status(lf->presence);
nb_activities = linphone_presence_model_get_nb_activities(lf->presence);
if (presence != NULL) {
basic_status = linphone_presence_model_get_basic_status(presence);
nb_activities = linphone_presence_model_get_nb_activities(presence);
online_status = (basic_status == LinphonePresenceBasicStatusOpen) ? LinphoneStatusOnline : LinphoneStatusOffline;
if (nb_activities > 1) {
char *tmp = NULL;
......@@ -508,7 +538,7 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
nb_activities = 1;
}
if (nb_activities == 1) {
activity = linphone_presence_model_get_activity(lf->presence);
activity = linphone_presence_model_get_activity(presence);
description = linphone_presence_activity_get_description(activity);
switch (linphone_presence_activity_get_type(activity)) {
case LinphonePresenceActivityBreakfast:
......@@ -576,15 +606,42 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
return online_status;
}
const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf) {
return lf->presence;
const LinphonePresenceModel * linphone_friend_get_presence_model(const LinphoneFriend *lf) {
const LinphonePresenceModel *presence = NULL;
LinphoneAddress *addr = linphone_friend_get_address(lf);
if (addr) {
char *uri = linphone_address_as_string_uri_only(addr);
presence = linphone_friend_get_presence_model_for_uri_or_tel(lf, uri);
ms_free(uri);
linphone_address_unref(addr);
}
return presence;
}
const LinphonePresenceModel * linphone_friend_get_presence_model_for_uri_or_tel(const LinphoneFriend *lf, const char *uri_or_tel) {
LinphoneFriendPresence *lfp = find_presence_model_for_uri_or_tel(lf, uri_or_tel);
if (lfp) return lfp->presence;
return NULL;
}
void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence) {
if (lf->presence != NULL) {
linphone_presence_model_unref(lf->presence);
LinphoneAddress *addr = linphone_friend_get_address(lf);
if (addr) {
char *uri = linphone_address_as_string_uri_only(addr);
linphone_friend_set_presence_model_for_uri_or_tel(lf, uri, presence);
ms_free(uri);
linphone_address_unref(addr);
}
}
void linphone_friend_set_presence_model_for_uri_or_tel(LinphoneFriend *lf, const char *uri_or_tel, LinphonePresenceModel *presence) {
LinphoneFriendPresence *lfp = find_presence_model_for_uri_or_tel(lf, uri_or_tel);
if (lfp) {
if (lfp->presence) linphone_presence_model_unref(lfp->presence);
lfp->presence = presence;
} else {
add_presence_model_for_uri_or_tel(lf, uri_or_tel, presence);
}
lf->presence = presence;
}
bool_t linphone_friend_is_presence_received(const LinphoneFriend *lf) {
......@@ -1581,3 +1638,48 @@ void linphone_core_migrate_friends_from_rc_to_db(LinphoneCore *lc) {
LinphoneSubscriptionState linphone_friend_get_subscription_state(const LinphoneFriend *lf) {
return lf->out_sub_state;
}
const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const char *phone_number) {
LinphoneFriendPhoneNumberSipUri * lfpnsu;
LinphoneAddress *addr;
char *normalized_number;
char *uri;
char *full_uri;
LinphoneProxyConfig *proxy_config;
bctbx_list_t *iterator = lf->phone_number_sip_uri_map;
while (iterator) {
lfpnsu = (LinphoneFriendPhoneNumberSipUri *)bctbx_list_get_data(iterator);
if (strcmp(lfpnsu->number, phone_number) == 0) return lfpnsu->uri;
iterator = bctbx_list_next(iterator);
}
proxy_config = linphone_core_get_default_proxy_config(linphone_friend_get_core(lf));
if (strstr(phone_number, "tel:") == phone_number) phone_number += 4; /* Remove the "tel:" prefix if it is present. */
normalized_number = linphone_proxy_config_normalize_phone_number(proxy_config, phone_number);
if (!normalized_number) return NULL;
uri = ms_strdup_printf("sip:%s@%s", normalized_number, linphone_proxy_config_get_domain(proxy_config));
ms_free(normalized_number);
addr = linphone_core_create_address(linphone_friend_get_core(lf), uri);
ms_free(uri);
if (!addr) return NULL;
linphone_address_set_uri_param(addr, "user", "phone");
full_uri = linphone_address_as_string_uri_only(addr);
linphone_address_unref(addr);
lfpnsu = ms_new(LinphoneFriendPhoneNumberSipUri, 1);
lfpnsu->number = ms_strdup(phone_number);
lfpnsu->uri = full_uri;
lf->phone_number_sip_uri_map = bctbx_list_append(lf->phone_number_sip_uri_map, lfpnsu);
return full_uri;
}
const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const char *uri) {
bctbx_list_t *iterator = lf->phone_number_sip_uri_map;
while (iterator) {
LinphoneFriendPhoneNumberSipUri *lfpnsu = (LinphoneFriendPhoneNumberSipUri *)bctbx_list_get_data(iterator);
if (strcmp(lfpnsu->uri, uri) == 0) return lfpnsu->number;
iterator = bctbx_list_next(iterator);
}
return NULL;
}
......@@ -140,7 +140,6 @@ static char * create_resource_list_xml(const LinphoneFriendList *list) {
bctbx_list_t *iterator;
bctbx_list_t *addresses = linphone_friend_get_addresses(lf);
bctbx_list_t *numbers = linphone_friend_get_phone_numbers(lf);
LinphoneProxyConfig *proxy_config = linphone_core_get_default_proxy_config(linphone_friend_list_get_core(list));
iterator = addresses;
while (iterator) {
LinphoneAddress *addr = (LinphoneAddress *)bctbx_list_get_data(iterator);
......@@ -156,23 +155,8 @@ static char * create_resource_list_xml(const LinphoneFriendList *list) {
iterator = numbers;
while (iterator) {
const char *number = (const char *)bctbx_list_get_data(iterator);
char *normalized_number;
if (strstr(number, "tel:") == number) number += 4; /* Remove the "tel:" prefix if it is present. */
normalized_number = linphone_proxy_config_normalize_phone_number(proxy_config, number);
if (normalized_number) {
char *uri = ms_strdup_printf("sip:%s@%s", normalized_number, linphone_proxy_config_get_domain(proxy_config));
LinphoneAddress *addr = linphone_core_create_address(lf->lc, uri);
if (addr) {
char *full_uri;
linphone_address_set_uri_param(addr, "user", "phone");
full_uri = linphone_address_as_string_uri_only(addr);
err = add_uri_entry(writer, err, full_uri);
ms_free(full_uri);
linphone_address_unref(addr);
}
ms_free(uri);
ms_free(normalized_number);
}
const char *uri = linphone_friend_phone_number_to_sip_uri(lf, number);
if (uri) err = add_uri_entry(writer, err, uri);
iterator = bctbx_list_next(iterator);
}
if (addresses) bctbx_list_free_with_data(addresses, (bctbx_list_free_func)linphone_address_unref);
......@@ -275,9 +259,12 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
SalPresenceModel *presence = NULL;
linphone_notify_parse_presence(linphone_content_get_type(presence_part), linphone_content_get_subtype(presence_part), linphone_content_get_string_buffer(presence_part), &presence);
if (presence != NULL) {
const char *phone_number = linphone_friend_sip_uri_to_phone_number(lf, uri);
lf->presence_received = TRUE;
linphone_friend_set_presence_model(lf, (LinphonePresenceModel *)presence);
if (phone_number) linphone_friend_set_presence_model_for_uri_or_tel(lf, phone_number, (LinphonePresenceModel *)presence);
if (full_state == FALSE) {
if (phone_number)
linphone_core_notify_notify_presence_received_for_uri_or_tel(list->lc, lf, phone_number, (LinphonePresenceModel *)presence);
linphone_core_notify_notify_presence_received(list->lc, lf);
}
}
......@@ -295,9 +282,30 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
if (resource_object != NULL) xmlXPathFreeObject(resource_object);
if (full_state == TRUE) {
bctbx_list_t *addresses;
bctbx_list_t *numbers;
bctbx_list_t *iterator;
bctbx_list_t *l = list->friends;
for (; l != NULL; l = bctbx_list_next(l)) {
lf = (LinphoneFriend *)bctbx_list_get_data(l);
addresses = linphone_friend_get_addresses(lf);
numbers = linphone_friend_get_phone_numbers(lf);
iterator = addresses;
while (iterator) {
LinphoneAddress *addr = (LinphoneAddress *)bctbx_list_get_data(iterator);
char *uri = linphone_address_as_string_uri_only(addr);
const LinphonePresenceModel *presence = linphone_friend_get_presence_model_for_uri_or_tel(lf, uri);
linphone_core_notify_notify_presence_received_for_uri_or_tel(list->lc, lf, uri, presence);
ms_free(uri);
iterator = bctbx_list_next(iterator);
}
iterator = numbers;
while (iterator) {
const char *number = (const char *)bctbx_list_get_data(iterator);
const LinphonePresenceModel *presence = linphone_friend_get_presence_model_for_uri_or_tel(lf, number);
linphone_core_notify_notify_presence_received_for_uri_or_tel(list->lc, lf, number, presence);
iterator = bctbx_list_next(iterator);
}
if (linphone_friend_is_presence_received(lf) == TRUE) {
linphone_core_notify_notify_presence_received(list->lc, lf);
}
......
......@@ -1925,6 +1925,14 @@ typedef void (*LinphoneCoreCbFunc)(LinphoneCore *lc,void * user_data);
* @param lf Updated #LinphoneFriend .
*/
typedef void (*LinphoneCoreNotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneFriend * lf);
/**
* Reports presence model change for a specific URI or phone number of a friend
* @param lc #LinphoneCore object
* @param lf #LinphoneFriend object
* @param uri_or_tel The URI or phone number for which teh presence model has changed
* @param presence_model The new presence model
*/
typedef void (*LinphoneCoreNotifyPresenceReceivedForUriOrTelCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *uri_or_tel, const LinphonePresenceModel *presence_model);
/**
* Reports that a new subscription request has been received and wait for a decision.
* Status on this subscription request is notified by \link linphone_friend_set_inc_subscribe_policy() changing policy \endlink for this friend
......@@ -2120,6 +2128,7 @@ typedef struct _LinphoneCoreVTable{
LinphoneCoreRegistrationStateChangedCb registration_state_changed;/**<Notifies registration state changes*/
LinphoneCoreCallStateChangedCb call_state_changed;/**<Notifies call state changes*/
LinphoneCoreNotifyPresenceReceivedCb notify_presence_received; /**< Notify received presence events*/
LinphoneCoreNotifyPresenceReceivedForUriOrTelCb notify_presence_received_for_uri_or_tel; /**< Notify received presence events*/
LinphoneCoreNewSubscriptionRequestedCb new_subscription_requested; /**< Notify about pending presence subscription request */
LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< Ask the application some authentication information */
LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */
......
......@@ -285,13 +285,21 @@ LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFr
*/
LINPHONE_PUBLIC LinphoneSubscriptionState linphone_friend_get_subscription_state(const LinphoneFriend *lf);
/**
* Get the presence model of a friend
* @param[in] lf A #LinphoneFriend object
* @return A #LinphonePresenceModel object, or NULL if the friend do not have presence information (in which case he is considered offline)
*/
LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf);
LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model(const LinphoneFriend *lf);
/**
* Get the presence model for a specific SIP URI or phone number of a friend
* @param[in] lf A #LinphoneFriend object
* @param[in] uri_or_tel The SIP URI or phone number for which to get the presence model
* @return A #LinphonePresenceModel object, or NULL if the friend do not have presence information for this SIP URI or phone number
*/
LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model_for_uri_or_tel(const LinphoneFriend *lf, const char *uri_or_tel);
/**
* Set the presence model of a friend
......@@ -300,6 +308,14 @@ LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model
*/
LINPHONE_PUBLIC void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence);
/**
* Set the presence model for a specific SIP URI or phone number of a friend
* @param[in] lf A #LinphoneFriend object
* @param[in] uri_or_tel The SIP URI or phone number for which to set the presence model
* @param[in] presence The #LinphonePresenceModel object to set
*/
LINPHONE_PUBLIC void linphone_friend_set_presence_model_for_uri_or_tel(LinphoneFriend *lf, const char *uri_or_tel, LinphonePresenceModel *presence);
/**
* Tells whether we already received presence information for a friend.
* @param[in] lf A #LinphoneFriend object
......
......@@ -428,6 +428,8 @@ void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence)
void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc);
void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op);
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op);
const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const char *phone_number);
const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const char *uri);
LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op);
LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op);
LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, SalOp *op);
......@@ -693,6 +695,16 @@ typedef struct _LinphoneChatMessageCharacter {
BELLE_SIP_DECLARE_VPTR(LinphoneChatRoom);
typedef struct _LinphoneFriendPresence {
char *uri_or_tel;
LinphonePresenceModel *presence;
} LinphoneFriendPresence;
typedef struct _LinphoneFriendPhoneNumberSipUri {
char *number;
char *uri;
} LinphoneFriendPhoneNumberSipUri;
struct _LinphoneFriend{
belle_sip_object_t base;
void *user_data;
......@@ -700,7 +712,8 @@ struct _LinphoneFriend{
MSList *insubs; /*list of SalOp. There can be multiple instances of a same Friend that subscribe to our presence*/
SalOp *outsub;
LinphoneSubscribePolicy pol;
LinphonePresenceModel *presence;
MSList *presence_models; /* list of LinphoneFriendPresence. It associates SIP URIs and phone numbers with their respective presence models. */
MSList *phone_number_sip_uri_map; /* list of LinphoneFriendPhoneNumberSipUri. It associates phone numbers with their corresponding SIP URIs. */
struct _LinphoneCore *lc;
BuddyInfo *info;
char *refkey;
......@@ -1451,6 +1464,7 @@ void linphone_core_notify_display_message(LinphoneCore *lc, const char *message)
void linphone_core_notify_display_warning(LinphoneCore *lc, const char *message);
void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, const char *url);
void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf);
void linphone_core_notify_notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *lf, const char *uri_or_tel, const LinphonePresenceModel *presence_model);
void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain);
void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl);
......
......@@ -131,23 +131,28 @@ void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, con
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic pop
#endif
void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf){
NOTIFY_IF_EXIST(notify_presence_received, lc,lf);
void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) {
NOTIFY_IF_EXIST(notify_presence_received, lc, lf);
cleanup_dead_vtable_refs(lc);
}
void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
NOTIFY_IF_EXIST(new_subscription_requested, lc,lf,url);
void linphone_core_notify_notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *lf, const char *uri_or_tel, const LinphonePresenceModel *presence_model) {
NOTIFY_IF_EXIST(notify_presence_received_for_uri_or_tel, lc, lf, uri_or_tel, presence_model);
cleanup_dead_vtable_refs(lc);
}
void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain){
NOTIFY_IF_EXIST(auth_info_requested, lc,realm,username,domain);
void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url) {
NOTIFY_IF_EXIST(new_subscription_requested, lc, lf, url);
cleanup_dead_vtable_refs(lc);
}
void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl){
NOTIFY_IF_EXIST(call_log_updated, lc,newcl);
void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
NOTIFY_IF_EXIST(auth_info_requested, lc, realm, username, domain);
cleanup_dead_vtable_refs(lc);
}
void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl) {
NOTIFY_IF_EXIST(call_log_updated, lc, newcl);
cleanup_dead_vtable_refs(lc);
}
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment