diff --git a/coreapi/friend.c b/coreapi/friend.c index 4fe618b14c46f2b97abf14a7db08be469e39d77e..1b5eae0e9554c1617270d13cc54ca8349999343c 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -1124,7 +1124,7 @@ void linphone_friend_done(LinphoneFriend *fr) { } } linphone_friend_apply(fr, fr->lc); - linphone_friend_save(fr, fr->lc); + if (fr->friend_list) linphone_friend_save(fr, fr->lc); } #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) @@ -1212,7 +1212,7 @@ void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key) { if (key) { lf->refkey = ms_strdup(key); } - if (lf->lc) { + if (lf->lc && lf->friend_list) { linphone_friend_save(lf, lf->lc); } } @@ -1410,7 +1410,7 @@ void linphone_friend_set_vcard(LinphoneFriend *fr, LinphoneVcard *vcard) { if (fr->vcard) linphone_vcard_unref(fr->vcard); if (vcard) fr->vcard = linphone_vcard_ref(vcard); - linphone_friend_save(fr, fr->lc); + if (fr->friend_list) linphone_friend_save(fr, fr->lc); } bool_t linphone_friend_create_vcard(LinphoneFriend *fr, const char *name) { @@ -1438,7 +1438,7 @@ bool_t linphone_friend_create_vcard(LinphoneFriend *fr, const char *name) { lc = fr->friend_list->lc; } if (lc) { - skip = !linphone_config_get_int(fr->lc->config, "misc", "store_friends", 1); + skip = !linphone_friend_list_database_storage_enabled(fr->friend_list); linphone_vcard_set_skip_validation(vcard, skip); } linphone_vcard_set_full_name(vcard, name); @@ -1712,6 +1712,7 @@ static int create_friend_list(void *data, BCTBX_UNUSED(int argc), char **argv, B unsigned int storage_id = (unsigned int)atoi(argv[0]); LinphoneFriendList *lfl = linphone_core_create_friend_list(NULL); + lfl->store_in_db = TRUE; // Obviously lfl->storage_id = storage_id; linphone_friend_list_set_display_name(lfl, argv[1]); linphone_friend_list_set_rls_uri(lfl, argv[2]); @@ -1806,23 +1807,23 @@ static int linphone_sql_request_friends_list(sqlite3 *db, const char *stmt, bctb void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf) { if (lc && lc->friends_db) { char *buf; - int store_friends = linphone_config_get_int(lc->config, "misc", "store_friends", 1); LinphoneVcard *vcard = NULL; const LinphoneAddress *addr; char *addr_str = NULL; - if (!store_friends) { + if (!lf) { + ms_error("Can't store a NULL friend!"); return; } - if (!lf || !lf->friend_list) { - ms_warning("Either the friend or the friend list is null, skipping..."); + if (!lf->friend_list) { + ms_warning("Can't store friend [%s], not added to any friend list", linphone_friend_get_name(lf)); return; } - if (linphone_friend_list_is_subscription_bodyless( - lf->friend_list)) // Add friend in DB only if its list bodyless subscription is not enabled. + if (!linphone_friend_list_database_storage_enabled(lf->friend_list)) { return; + } /** * The friends_list store logic is hidden into the friend store logic @@ -1862,12 +1863,10 @@ void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf) { } void linphone_core_store_friends_list_in_db(LinphoneCore *lc, LinphoneFriendList *list) { - if (lc && lc->friends_db && - !linphone_friend_list_is_subscription_bodyless(list)) { // Do not store list if bodyless subscription is enabled + if (lc && lc->friends_db) { char *buf; - int store_friends = linphone_config_get_int(lc->config, "misc", "store_friends", 1); - if (!store_friends) { + if (!linphone_friend_list_database_storage_enabled(list)) { return; } @@ -2040,6 +2039,7 @@ void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path) lc->friends_db_file = NULL; } if (path) { + ms_message("Using [%s] file for friends database", path); lc->friends_db_file = ms_strdup(path); linphone_core_friends_storage_init(lc); } diff --git a/coreapi/friendlist.c b/coreapi/friendlist.c index 997ea07bcfa5733cc099d7dcaa13ca2652adabd0..f2ec9530bf30be61b51d240f5a4ee39e24def2d3 100644 --- a/coreapi/friendlist.c +++ b/coreapi/friendlist.c @@ -519,6 +519,8 @@ static LinphoneFriendList *linphone_friend_list_new(void) { list->bodyless_subscription = FALSE; list->type = LinphoneFriendListTypeDefault; list->revision = 0; + list->storage_id = 0; + list->store_in_db = FALSE; return list; } @@ -684,13 +686,14 @@ _linphone_friend_list_add_friend(LinphoneFriendList *list, LinphoneFriend *lf, b } addr = linphone_friend_get_address(lf); - bctbx_list_t *phone_numbers = linphone_friend_get_phone_numbers( - lf); // linphone_friend_get_phone_numbers make a copy of phones. We have to delete them later + // linphone_friend_get_phone_numbers make a copy of phones. We have to delete them later + bctbx_list_t *phone_numbers = linphone_friend_get_phone_numbers(lf); if (addr == NULL && linphone_friend_get_vcard(lf) == NULL && phone_numbers == NULL) { ms_error("linphone_friend_list_add_friend(): invalid friend, no vCard, SIP URI or phone number"); return status; } if (phone_numbers) bctbx_list_free_with_data(phone_numbers, bctbx_free); + bool_t present = FALSE; if (lf->refkey) { present = linphone_friend_list_find_friend_by_ref_key(list, lf->refkey) != NULL; @@ -1442,7 +1445,7 @@ void linphone_friend_list_set_uri(LinphoneFriendList *list, const char *uri) { } } -bool_t linphone_friend_list_is_subscription_bodyless(LinphoneFriendList *list) { +bool_t linphone_friend_list_is_subscription_bodyless(const LinphoneFriendList *list) { return list->bodyless_subscription; } @@ -1596,3 +1599,48 @@ void linphone_friend_list_enable_subscriptions(LinphoneFriendList *list, bool_t bool_t linphone_friend_list_subscriptions_enabled(LinphoneFriendList *list) { return list->enable_subscriptions; } + +bool_t linphone_friend_list_database_storage_enabled(const LinphoneFriendList *list) { + if (list == NULL) return FALSE; + + if (linphone_friend_list_is_subscription_bodyless(list)) { + // Do not store list if bodyless subscription is enabled + return FALSE; + } + + // Legacy setting + int store_friends = linphone_config_get_int(list->lc->config, "misc", "store_friends", 1); + return store_friends || list->store_in_db; +} + +void linphone_friend_list_enable_database_storage(LinphoneFriendList *list, bool_t enable) { + if (enable && linphone_core_get_friends_database_path(list->lc) == NULL) { + ms_error( + "No database path has been set for friends storage, use linphone_core_set_friends_database_path() first!"); + return; + } + + if (enable && linphone_friend_list_is_subscription_bodyless(list)) { + ms_warning("Can't store in DB a friend list [%s] with bodyless subscription enabled", list->display_name); + return; + } + + if (list->store_in_db && !enable) { + ms_warning("We are asked to remove database storage for friend list [%s]", list->display_name); + list->store_in_db = enable; + linphone_core_remove_friends_list_from_db(list->lc, list); + } else if (!list->store_in_db && enable) { + list->store_in_db = enable; + linphone_core_store_friends_list_in_db(list->lc, list); + + const bctbx_list_t *friends = linphone_friend_list_get_friends(list); + while (friends != NULL && bctbx_list_get_data(friends) != NULL) { + LinphoneFriend *lf = (LinphoneFriend *)bctbx_list_get_data(friends); + ms_warning("Found existing friend [%s] in list [%s] that was added before the list was configured to be " + "saved in DB, doing it now", + linphone_friend_get_name(lf), list->display_name); + linphone_friend_save(lf, list->lc); + friends = bctbx_list_next(friends); + } + } +} \ No newline at end of file diff --git a/coreapi/private_structs.h b/coreapi/private_structs.h index 02a2699e1ce01d3b41bc2bdf907e92e6bf6631da..62710f401e9a1817d5e70ff4b6261cbcb247a096 100644 --- a/coreapi/private_structs.h +++ b/coreapi/private_structs.h @@ -156,6 +156,7 @@ struct _LinphoneFriendList { bool_t enable_subscriptions; bool_t bodyless_subscription; LinphoneFriendListType type; + bool_t store_in_db; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneFriendList); diff --git a/include/linphone/friendlist.h b/include/linphone/friendlist.h index 8982863e5f7c55f584aa0b1eb71ee83332c8be94..f955e321a4b5b184b4b1bb955835bf8365b2fbc3 100644 --- a/include/linphone/friendlist.h +++ b/include/linphone/friendlist.h @@ -244,7 +244,7 @@ LINPHONE_PUBLIC void linphone_friend_list_set_uri(LinphoneFriendList *friend_lis * @param friend_list #LinphoneFriendList object. @notnil * @return Wheter the subscription of the friend list is bodyless or not. **/ -LINPHONE_PUBLIC bool_t linphone_friend_list_is_subscription_bodyless(LinphoneFriendList *friend_list); +LINPHONE_PUBLIC bool_t linphone_friend_list_is_subscription_bodyless(const LinphoneFriendList *friend_list); /** * Set wheter the subscription of the friend list is bodyless or not. @@ -448,6 +448,20 @@ LINPHONE_PUBLIC void linphone_friend_list_enable_subscriptions(LinphoneFriendLis */ LINPHONE_PUBLIC bool_t linphone_friend_list_subscriptions_enabled(LinphoneFriendList *friend_list); +/** + * Gets whether this friend list and it's friends will be stored in DB or not + * @param list the #LinphoneFriendList object @notnil + * @return Whether the list and it's friends will be saved in database or not + */ +LINPHONE_PUBLIC bool_t linphone_friend_list_database_storage_enabled(const LinphoneFriendList *list); + +/** + * Sets whether this friend list and it's friends will be stored in DB or not + * @param list the #LinphoneFriendList object @notnil + * @param enable TRUE to enable this friend list storage in DB, FALSE to disable it. + */ +LINPHONE_PUBLIC void linphone_friend_list_enable_database_storage(LinphoneFriendList *list, bool_t enable); + /************ */ /* DEPRECATED */ /* ********** */ diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 712581e5a522759cc4a19b6b806946a751f1bf49..6bc3ff1d13d98307bd18dbf34a028acd287ff1ba 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -3285,6 +3285,158 @@ static void delete_friend_from_rc(void) { linphone_core_manager_destroy(manager); } +static void friend_list_db_storage_base(bool_t set_friends_db_path) { + LinphoneCoreManager *manager = linphone_core_manager_new("marie_rc"); + LinphoneCore *core = manager->lc; + LinphoneConfig *config = linphone_core_get_config(core); + + // Disable legacy friends storage + linphone_config_set_int(config, "misc", "store_friends", 0); + + char *friends_db = bc_tester_file("friends.db"); + unlink(friends_db); + if (set_friends_db_path) { + linphone_core_set_friends_database_path(core, friends_db); + } + + LinphoneFriendList *default_fl = linphone_core_get_default_friend_list(core); + BC_ASSERT_PTR_NOT_NULL(default_fl); + if (default_fl) { + BC_ASSERT_FALSE(linphone_friend_list_database_storage_enabled(default_fl)); + + // Add a friend to that friend list that shoudln't be persisted in DB + LinphoneFriend *claire_friend = linphone_core_create_friend(core); + linphone_friend_set_name(claire_friend, "Claire"); + linphone_friend_add_phone_number(claire_friend, "+3366666666"); + LinphoneFriendListStatus status = linphone_friend_list_add_friend(default_fl, claire_friend); + BC_ASSERT_EQUAL(status, LinphoneFriendListOK, int, "%d"); + linphone_friend_unref(claire_friend); + ms_message("-> Claire added to default friend list"); + } + + LinphoneFriendList *db_stored_fl = linphone_core_create_friend_list(core); + linphone_friend_list_set_display_name(db_stored_fl, "DB_STORED_FL"); + BC_ASSERT_FALSE(linphone_friend_list_database_storage_enabled(db_stored_fl)); + linphone_core_add_friend_list(core, db_stored_fl); + BC_ASSERT_FALSE(linphone_friend_list_database_storage_enabled(db_stored_fl)); + + // Adding a friend while DB storage is still not enabled + LinphoneFriend *pauline_friend = linphone_core_create_friend(core); + linphone_friend_set_name(pauline_friend, "Pauline"); + linphone_friend_add_phone_number(pauline_friend, "+3301020304"); + LinphoneFriendListStatus status = linphone_friend_list_add_friend(db_stored_fl, pauline_friend); + BC_ASSERT_EQUAL(status, LinphoneFriendListOK, int, "%d"); + linphone_friend_unref(pauline_friend); + ms_message("-> Pauline added to db stored friend list"); + + linphone_friend_list_enable_database_storage(db_stored_fl, TRUE); + if (set_friends_db_path) { + BC_ASSERT_TRUE(linphone_friend_list_database_storage_enabled(db_stored_fl)); + } else { + BC_ASSERT_FALSE(linphone_friend_list_database_storage_enabled(db_stored_fl)); + } + + // Adding a new friend now that DB is enabled + LinphoneFriend *marie_friend = linphone_core_create_friend(core); + linphone_friend_set_name(marie_friend, "Marie"); + linphone_friend_add_phone_number(marie_friend, "+3305060708"); + status = linphone_friend_list_add_friend(db_stored_fl, marie_friend); + BC_ASSERT_EQUAL(status, LinphoneFriendListOK, int, "%d"); + linphone_friend_unref(marie_friend); + ms_message("-> Marie added to db stored friend list"); + + linphone_friend_list_unref(db_stored_fl); + + // Add a new friend list without DB storage + LinphoneFriendList *not_db_stored_fl = linphone_core_create_friend_list(core); + linphone_friend_list_set_display_name(not_db_stored_fl, "NOT_DB_STORED_FL"); + BC_ASSERT_FALSE(linphone_friend_list_database_storage_enabled(not_db_stored_fl)); + linphone_core_add_friend_list(core, not_db_stored_fl); + + // Add a friend to that friend list that shoudln't be persisted in DB + LinphoneFriend *laure_friend = linphone_core_create_friend(core); + linphone_friend_set_name(laure_friend, "Laure"); + linphone_friend_add_phone_number(laure_friend, "+3312345678"); + status = linphone_friend_list_add_friend(not_db_stored_fl, laure_friend); + BC_ASSERT_EQUAL(status, LinphoneFriendListOK, int, "%d"); + linphone_friend_unref(laure_friend); + ms_message("-> Laure added to memory cached friend list"); + + linphone_friend_list_unref(not_db_stored_fl); + + // Check that both friends list can be found using display name + LinphoneFriendList *found_list = linphone_core_get_friend_list_by_name(core, "DB_STORED_FL"); + BC_ASSERT_PTR_NOT_NULL(found_list); + + found_list = linphone_core_get_friend_list_by_name(core, "NOT_DB_STORED_FL"); + BC_ASSERT_PTR_NOT_NULL(found_list); + + // Check that all friends can be found by Core + LinphoneFriend *found_friend = linphone_core_find_friend_by_phone_number(core, "+3366666666"); // Claire + BC_ASSERT_PTR_NOT_NULL(found_friend); + found_friend = linphone_core_find_friend_by_phone_number(core, "+3301020304"); // Pauline + BC_ASSERT_PTR_NOT_NULL(found_friend); + found_friend = linphone_core_find_friend_by_phone_number(core, "+3305060708"); // Marie + BC_ASSERT_PTR_NOT_NULL(found_friend); + found_friend = linphone_core_find_friend_by_phone_number(core, "+3312345678"); // Laure + BC_ASSERT_PTR_NOT_NULL(found_friend); + + // Now restart the Core + ms_message("\n-> Restarting Core\n"); + linphone_core_manager_reinit(manager); + linphone_core_manager_start(manager, TRUE); + core = manager->lc; + // Don't forget to set the friends DB path again + if (set_friends_db_path) { + linphone_core_set_friends_database_path(core, friends_db); + } + + // Check that only friends list stored in can be found using display name + found_list = linphone_core_get_friend_list_by_name(core, "DB_STORED_FL"); + if (set_friends_db_path) { + BC_ASSERT_PTR_NOT_NULL(found_list); + } else { + BC_ASSERT_PTR_NULL(found_list); + } + + found_list = linphone_core_get_friend_list_by_name(core, "NOT_DB_STORED_FL"); + BC_ASSERT_PTR_NULL(found_list); + + // Check that only friends in lists that were stored in DB can be found by Core + found_friend = linphone_core_find_friend_by_phone_number(core, "+3366666666"); // Claire + BC_ASSERT_PTR_NULL(found_friend); + + found_friend = linphone_core_find_friend_by_phone_number(core, "+3301020304"); // Pauline + if (set_friends_db_path) { + BC_ASSERT_PTR_NOT_NULL(found_friend); + } else { + BC_ASSERT_PTR_NULL(found_list); + } + + found_friend = linphone_core_find_friend_by_phone_number(core, "+3305060708"); // Marie + if (set_friends_db_path) { + BC_ASSERT_PTR_NOT_NULL(found_friend); + } else { + BC_ASSERT_PTR_NULL(found_list); + } + + found_friend = linphone_core_find_friend_by_phone_number(core, "+3312345678"); // Laure + BC_ASSERT_PTR_NULL(found_friend); + + unlink(friends_db); + bc_free(friends_db); + + linphone_core_manager_destroy(manager); +} + +static void friend_list_db_storage(void) { + friend_list_db_storage_base(TRUE); +} + +static void friend_list_db_storage_without_db(void) { + friend_list_db_storage_base(FALSE); +} + static void dial_plan(void) { bctbx_list_t *dial_plans = linphone_dial_plan_get_all_list(); bctbx_list_t *it; @@ -3581,6 +3733,8 @@ test_t setup_tests[] = { TEST_ONE_TAG("Ldap features more results", ldap_features_more_results, "MagicSearch"), TEST_NO_TAG("Ldap params edition with check", ldap_params_edition_with_check), TEST_NO_TAG("Delete friend in linphone rc", delete_friend_from_rc), + TEST_NO_TAG("Store friends list in DB", friend_list_db_storage), + TEST_NO_TAG("Store friends list in DB without setting path to db file", friend_list_db_storage_without_db), TEST_NO_TAG("Dialplan", dial_plan), TEST_NO_TAG("Friend phone number lookup without plus", friend_phone_number_lookup_without_plus), TEST_NO_TAG("Audio devices", audio_devices),