Commit f7a6c72b authored by Benjamin REIS's avatar Benjamin REIS

Feature/add capabilities to linphone friend

parent 3ae9e6f5
......@@ -1725,3 +1725,23 @@ const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const c
void linphone_friend_clear_presence_models(LinphoneFriend *lf) {
lf->presence_models = bctbx_list_free_with_data(lf->presence_models, (bctbx_list_free_func)free_friend_presence);
}
int linphone_friend_get_capabilities(const LinphoneFriend *lf) {
return lf->capabilities;
}
namespace {
const std::unordered_map<std::string, LinphoneFriendCapability> StringToCapability{
{ "groupchat", LinphoneFriendCapabilityGroupChat },
{ "lime", LinphoneFriendCapabilityLimeX3dh }
};
}
void linphone_friend_add_capability(LinphoneFriend *lf, const char *capability_name) {
auto it = StringToCapability.find(capability_name);
if (it == StringToCapability.cend()) {
bctbx_error("Invalid capability %s for friend [%p]", capability_name, lf);
} else {
bctbx_debug("Adding capability %s to friend [%p]", capability_name, lf);
lf->capabilities |= it->second;
}
}
......@@ -293,7 +293,19 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
}
if (lf) {
const char *phone_number = linphone_friend_sip_uri_to_phone_number(lf, uri);
unsigned int nb_services = linphone_presence_model_get_nb_services((LinphonePresenceModel *)presence);
for (unsigned int i = 0; i < nb_services; i++) {
LinphonePresenceService *service = linphone_presence_model_get_nth_service((LinphonePresenceModel *)presence, i);
bctbx_list_t *services_descriptions = linphone_presence_service_get_service_descriptions(service);
while (services_descriptions) {
char *description = (char *)bctbx_list_get_data(services_descriptions);
linphone_friend_add_capability(lf, description);
services_descriptions = bctbx_list_next(services_descriptions);
}
}
lf->presence_received = TRUE;
if (phone_number) {
char *presence_address = linphone_presence_model_get_contact((LinphonePresenceModel *)presence);
bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(presence_address, linphone_friend_ref(lf));
......
......@@ -48,6 +48,7 @@ struct _LinphonePresenceService {
char *contact;
bctbx_list_t *notes; /**< A list of _LinphonePresenceNote structures. */
time_t timestamp;
bctbx_list_t *service_descriptions;
};
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePresenceService);
......@@ -800,6 +801,19 @@ LinphoneStatus linphone_presence_service_set_contact(LinphonePresenceService *se
return 0;
}
bctbx_list_t * linphone_presence_service_get_service_descriptions(const LinphonePresenceService *service) {
return service->service_descriptions;
}
LinphoneStatus linphone_presence_service_set_service_descriptions(LinphonePresenceService *service, bctbx_list_t *descriptions) {
if (!service) return -1;
if (service->service_descriptions)
bctbx_list_free_with_data(service->service_descriptions, bctbx_free);
service->service_descriptions = descriptions;
return 0;
}
unsigned int linphone_presence_service_get_nb_notes(const LinphonePresenceService *service) {
return (unsigned int)bctbx_list_size(service->notes);
}
......@@ -1262,6 +1276,7 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin
char *contact_str;
LinphonePresenceBasicStatus basic_status;
int i;
xmlXPathObjectPtr service_descriptions;
service_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, service_prefix);
if ((service_object != NULL) && (service_object->nodesetval != NULL)) {
......@@ -1298,16 +1313,33 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i);
service_id_str = linphone_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));
if (contact_str != NULL) linphone_presence_service_set_contact(service, contact_str);
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/oma-pres:service-description", service_prefix, i);
service_descriptions = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
bctbx_list_t *services = nullptr;
if (service_descriptions && service_descriptions->nodesetval) {
for (int j = 1; j <= service_descriptions->nodesetval->nodeNr; j++) {
char *service_id = nullptr;
linphone_xml_xpath_context_set_node(xml_ctx, xmlXPathNodeSetItem(service_descriptions->nodesetval, j-1));
service_id = linphone_get_xml_text_content(xml_ctx, "./oma-pres:service-id");
if (service_id) {
services = bctbx_list_append(services, ms_strdup(service_id));
linphone_free_xml_text_content(service_id);
}
}
}
if (service) {
if (timestamp_str) presence_service_set_timestamp(service, parse_timestamp(timestamp_str));
if (contact_str) linphone_presence_service_set_contact(service, contact_str);
if (services) linphone_presence_service_set_service_descriptions(service, services);
process_pidf_xml_presence_service_notes(xml_ctx, service, (unsigned int)i);
linphone_presence_model_add_service(model, service);
linphone_presence_service_unref(service);
}
if (timestamp_str != NULL) linphone_free_xml_text_content(timestamp_str);
if (contact_str != NULL) linphone_free_xml_text_content(contact_str);
if (service_id_str != NULL) linphone_free_xml_text_content(service_id_str);
if (timestamp_str) linphone_free_xml_text_content(timestamp_str);
if (contact_str) linphone_free_xml_text_content(contact_str);
if (service_id_str) linphone_free_xml_text_content(service_id_str);
linphone_free_xml_text_content(basic_status_str);
}
}
......@@ -1506,6 +1538,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing
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");
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"pidfonline", (const xmlChar *)"http://www.linphone.org/xsds/pidfonline.xsd");
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"oma-pres", (const xmlChar *)"urn:oma:xml:prs:pidf:oma-pres");
err = process_pidf_xml_presence_services(xml_ctx, model);
if (err == 0) {
err = process_pidf_xml_presence_persons(xml_ctx, model);
......
......@@ -164,6 +164,7 @@ void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, LinphonePriva
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, LinphonePrivate::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);
void linphone_friend_add_capability(LinphoneFriend *lf, const char *capability_name);
void linphone_friend_clear_presence_models(LinphoneFriend *lf);
LinphoneFriend *linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op);
LinphoneFriend *linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, LinphonePrivate::SalOp *op);
......
......@@ -187,6 +187,7 @@ struct _LinphoneFriend{
unsigned int storage_id;
LinphoneFriendList *friend_list;
LinphoneSubscriptionState out_sub_state;
int capabilities = LinphoneFriendCapabilityNone;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneFriend);
......
......@@ -337,6 +337,12 @@ LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_from_vcard(LinphoneVcard *vc
*/
LINPHONE_PUBLIC void linphone_friend_save(LinphoneFriend *fr, LinphoneCore *lc);
/**
* Returns the capabilities associated to this friend
* @param[in] fr #LinphoneFriend object
*/
LINPHONE_PUBLIC int linphone_friend_get_capabilities(const LinphoneFriend *lf);
/**
* @}
*/
......
......@@ -118,7 +118,7 @@ LINPHONE_PUBLIC LinphoneStatus linphone_presence_model_set_presentity(LinphonePr
*
*/
LINPHONE_PUBLIC const LinphoneAddress * linphone_presence_model_get_presentity(const LinphonePresenceModel *model);
/**
* Gets the first activity of a presence model (there is usually only one).
* @param[in] model The #LinphonePresenceModel object to get the activity from.
......@@ -361,6 +361,23 @@ LINPHONE_PUBLIC char * linphone_presence_service_get_contact(const LinphonePrese
*/
LINPHONE_PUBLIC LinphoneStatus linphone_presence_service_set_contact(LinphonePresenceService *service, const char *contact);
/**
* Gets the service descriptions of a presence service.
* @param[in] service The #LinphonePresenceService object to get the contact from.
* @return A \bctbx_list{char *} containing the services descriptions.
*
* The returned string is to be freed.
*/
LINPHONE_PUBLIC bctbx_list_t * linphone_presence_service_get_service_descriptions(const LinphonePresenceService *service);
/**
* Sets the service descriptions of a presence service.
* @param[in] service The #LinphonePresenceService object for which to set the contact.
* @param[in] descriptions \bctbx_list{char *} The service descriptions.
* @return 0 if successful, a value < 0 in case of error.
*/
LINPHONE_PUBLIC LinphoneStatus linphone_presence_service_set_service_descriptions(LinphonePresenceService *service, bctbx_list_t *descriptions);
/**
* Gets the number of notes included in the presence service.
* @param[in] service The #LinphonePresenceService object to get the number of notes from.
......
......@@ -447,6 +447,16 @@ typedef enum _LinphoneFirewallPolicy {
*/
typedef struct _LinphoneFriend LinphoneFriend;
/**
* Enum describing the status of a LinphoneFriendList operation.
* @ingroup buddy_list
**/
typedef enum _LinphoneFriendCapability {
LinphoneFriendCapabilityNone = 0,
LinphoneFriendCapabilityGroupChat = 1 << 0,
LinphoneFriendCapabilityLimeX3dh = 1 << 1
} LinphoneFriendCapability;
/**
* The #LinphoneFriendList object representing a list of friends.
* @ingroup buddy_list
......
......@@ -720,7 +720,10 @@ belle_sip_header_contact_t *SalOp::createContact () {
if (!mRoot->mLinphoneSpecs.empty()
&& !belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contactHeader), "+org.linphone.specs")
) {
belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contactHeader), "+org.linphone.specs", mRoot->mLinphoneSpecs.c_str());
stringstream ss;
ss << "\"" << mRoot->mLinphoneSpecs << "\"";
string specs = ss.str();
belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contactHeader), "+org.linphone.specs", specs.c_str());
}
return contactHeader;
}
......
......@@ -1849,6 +1849,91 @@ static void multiple_bodyless_list_subscription_with_rc(void) {
}
#endif
static void notify_friend_capabilities(void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_create(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCoreManager *pauline2 = linphone_core_manager_create(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCoreManager *laure = linphone_core_manager_create("laure_tcp_rc");
LinphoneCoreManager *chloe = linphone_core_manager_create("chloe_rc");
LinphoneCoreManager *chloe2 = linphone_core_manager_create("chloe_rc");
linphone_core_set_linphone_specs(pauline->lc, "groupchat");
linphone_core_set_linphone_specs(pauline2->lc, "lime");
linphone_core_set_linphone_specs(laure->lc, "groupchat");
linphone_core_set_linphone_specs(chloe->lc, "groupchat, lime");
linphone_core_manager_start(marie, TRUE);
linphone_core_manager_start(pauline, TRUE);
linphone_core_manager_start(pauline2, TRUE);
linphone_core_manager_start(laure, TRUE);
linphone_core_manager_start(chloe, TRUE);
linphone_core_manager_start(chloe2, TRUE);
LinphoneFriendList *friendList = linphone_core_get_default_friend_list(marie->lc);
LinphoneFriend* paulineFriend = linphone_core_create_friend_with_address(marie->lc, get_identity(pauline));
LinphoneFriend* laureFriend = linphone_core_create_friend_with_address(marie->lc, get_identity(laure));
LinphoneFriend* chloeFriend = linphone_core_create_friend_with_address(marie->lc, get_identity(chloe));
LinphoneCoreCbs *callbacks = linphone_factory_create_core_cbs(linphone_factory_get());
bctbx_list_t *lcs = NULL;
lcs = bctbx_list_append(lcs, marie->lc);
lcs = bctbx_list_append(lcs, pauline->lc);
lcs = bctbx_list_append(lcs, pauline2->lc);
lcs = bctbx_list_append(lcs, laure->lc);
lcs = bctbx_list_append(lcs, chloe->lc);
lcs = bctbx_list_append(lcs, chloe2->lc);
linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL);
linphone_core_set_user_agent(marie->lc, "full-presence-support-bypass", NULL);
linphone_friend_list_enable_subscriptions(friendList, FALSE);
linphone_friend_list_set_rls_uri(friendList, "sip:rls@sip.example.org");
linphone_core_cbs_set_publish_state_changed(callbacks, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, callbacks, TRUE);
linphone_core_cbs_unref(callbacks);
linphone_friend_list_add_friend(friendList, paulineFriend);
linphone_friend_list_add_friend(friendList, laureFriend);
linphone_friend_list_add_friend(friendList, chloeFriend);
linphone_friend_list_enable_subscriptions(friendList, TRUE);
BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_NotifyPresenceReceived, 1, 5000));
BC_ASSERT_TRUE(linphone_friend_get_capabilities(paulineFriend) & LinphoneFriendCapabilityGroupChat);
BC_ASSERT_TRUE(linphone_friend_get_capabilities(paulineFriend) & LinphoneFriendCapabilityLimeX3dh);
BC_ASSERT_TRUE(linphone_friend_get_capabilities(laureFriend) & LinphoneFriendCapabilityGroupChat);
BC_ASSERT_FALSE(linphone_friend_get_capabilities(laureFriend) & LinphoneFriendCapabilityLimeX3dh);
BC_ASSERT_TRUE(linphone_friend_get_capabilities(chloeFriend) & LinphoneFriendCapabilityGroupChat);
BC_ASSERT_TRUE(linphone_friend_get_capabilities(chloeFriend) & LinphoneFriendCapabilityLimeX3dh);
linphone_friend_unref(paulineFriend);
linphone_friend_unref(laureFriend);
linphone_friend_unref(chloeFriend);
linphone_core_manager_stop(marie);
linphone_core_manager_destroy(marie);
linphone_core_manager_stop(pauline);
linphone_core_manager_destroy(pauline);
linphone_core_manager_stop(pauline2);
linphone_core_manager_destroy(pauline2);
linphone_core_manager_stop(laure);
linphone_core_manager_destroy(laure);
linphone_core_manager_stop(chloe);
linphone_core_manager_destroy(chloe);
linphone_core_manager_stop(chloe2);
linphone_core_manager_destroy(chloe2);
bctbx_list_free(lcs);
}
test_t presence_server_tests[] = {
TEST_NO_TAG("Simple Publish", simple_publish),
TEST_NO_TAG("Publish with 2 identities", publish_with_dual_identity),
......@@ -1884,6 +1969,7 @@ test_t presence_server_tests[] = {
TEST_ONE_TAG("Multiple bodyless list subscription", multiple_bodyless_list_subscription, "bodyless"),
TEST_ONE_TAG("Multiple bodyless list subscription with rc", multiple_bodyless_list_subscription_with_rc, "bodyless"),
#endif
TEST_NO_TAG("Notify LinphoneFriend capabilities", notify_friend_capabilities),
};
test_suite_t presence_server_test_suite = {"Presence using server", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
......
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