From 56db674e381871665c9133253004ec86608936b9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 17 Dec 2015 16:44:55 +0100 Subject: [PATCH] Started linphone friends database storage --- configure.ac | 36 ++++++ coreapi/call_log.c | 6 +- coreapi/friend.c | 248 +++++++++++++++++++++++++++++++++++---- coreapi/linphonecore.c | 11 +- coreapi/linphonefriend.h | 16 +++ coreapi/private.h | 10 ++ 6 files changed, 302 insertions(+), 25 deletions(-) diff --git a/configure.ac b/configure.ac index 7f2b95aad..2bd3f8de8 100644 --- a/configure.ac +++ b/configure.ac @@ -980,6 +980,41 @@ fi AM_CONDITIONAL(BUILD_CALL_LOGS_STORAGE, test x$enable_call_logs_storage = xtrue) +AC_ARG_ENABLE(friends-db-storage, + [AS_HELP_STRING([--enable-friends-db-storage=[yes/no]], [Turn on compilation of friends database storage (default=auto)])], + [case "${enableval}" in + yes) enable_friends_db_storage=true ;; + no) enable_friends_db_storage=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-friends-db-storage) ;; + esac], + [enable_friends_db_storage=auto] +) + +if test x$enable_friends_db_storage != xfalse; then + PKG_CHECK_MODULES(SQLITE3,[sqlite3 >= 3.6.0],[found_sqlite=yes],[found_sqlite=no]) + if test "$found_sqlite" = "no"; then + dnl Check the lib presence in case the PKG-CONFIG version is not found + AC_CHECK_LIB(sqlite3, sqlite3_open, [SQLITE3_LIBS+=" -lsqlite3 "; found_sqlite=yes], [foo=bar]) + fi + if test "$found_sqlite" = "yes"; then + SQLITE3_CFLAGS+=" -DFRIENDS_SQL_STORAGE_ENABLED" + if test "$build_macos" = "yes" -o "$ios_found" = "yes"; then + SQLITE3_LIBS+=" -liconv" + fi + enable_friends_db_storage=true + else + if test x$enable_friends_db_storage = xtrue; then + AC_MSG_ERROR([sqlite3, required for friends database storage, not found]) + fi + enable_friends_db_storage=false + fi + + AC_SUBST(SQLITE3_CFLAGS) + AC_SUBST(SQLITE3_LIBS) +fi + +AM_CONDITIONAL(BUILD_FRIENDS_DB_STORAGE, test x$enable_friends_db_storage = xtrue) + PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.4.0]) SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" @@ -1139,6 +1174,7 @@ printf "* %-30s %s\n" "Console interface" $console_ui printf "* %-30s %s\n" "Tools" $build_tools printf "* %-30s %s\n" "Message storage" $enable_msg_storage printf "* %-30s %s\n" "Call logs storage" $enable_call_logs_storage +printf "* %-30s %s\n" "Friends db storage" $enable_friends_db_storage printf "* %-30s %s\n" "VCard support" $enable_vcard printf "* %-30s %s\n" "IM encryption" $lime printf "* %-30s %s\n" "uPnP support" $build_upnp diff --git a/coreapi/call_log.c b/coreapi/call_log.c index 2bf8d5b9f..fa3cd5fc8 100644 --- a/coreapi/call_log.c +++ b/coreapi/call_log.c @@ -345,7 +345,7 @@ static void linphone_create_table(sqlite3* db) { } } -void linphone_update_call_log_table(sqlite3* db) { +static void linphone_update_call_log_table(sqlite3* db) { char* errmsg=NULL; int ret; @@ -445,7 +445,7 @@ static int create_call_log(void *data, int argc, char **argv, char **colName) { return 0; } -void linphone_sql_request_call_log(sqlite3 *db, const char *stmt, MSList **list) { +static void linphone_sql_request_call_log(sqlite3 *db, const char *stmt, MSList **list) { char* errmsg = NULL; int ret; ret = sqlite3_exec(db, stmt, create_call_log, list, &errmsg); @@ -455,7 +455,7 @@ void linphone_sql_request_call_log(sqlite3 *db, const char *stmt, MSList **list) } } -int linphone_sql_request_generic(sqlite3* db, const char *stmt) { +static int linphone_sql_request_generic(sqlite3* db, const char *stmt) { char* errmsg = NULL; int ret; ret = sqlite3_exec(db, stmt, NULL, NULL, &errmsg); diff --git a/coreapi/friend.c b/coreapi/friend.c index 21d218513..8a7e5172f 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -26,6 +26,21 @@ #include "private.h" #include "lpconfig.h" +#ifdef FRIENDS_SQL_STORAGE_ENABLED +#ifndef _WIN32 +#if !defined(ANDROID) && !defined(__QNXNTO__) +# include +# include +# include +#endif +#else +#include +#endif + +#define MAX_PATH_SIZE 1024 +#include "sqlite3.h" +#endif + const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ const char *str=NULL; switch(ss){ @@ -128,11 +143,12 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ } LinphoneFriend * linphone_friend_new(){ - LinphoneFriend *obj=belle_sip_object_new(LinphoneFriend); - obj->pol=LinphoneSPAccept; - obj->presence=NULL; - obj->subscribe=TRUE; + LinphoneFriend *obj = belle_sip_object_new(LinphoneFriend); + obj->pol = LinphoneSPAccept; + obj->presence = NULL; + obj->subscribe = TRUE; obj->vcard = NULL; + obj->storage_id = 0; return obj; } @@ -468,7 +484,11 @@ void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig * } void linphone_friend_save(LinphoneFriend *fr, LinphoneCore *lc) { +#ifdef FRIENDS_SQL_STORAGE_ENABLED + linphone_core_store_friend_in_db(lc, fr); +#else linphone_core_write_friends_config(lc); +#endif } void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc) { @@ -555,14 +575,18 @@ void linphone_core_import_friend(LinphoneCore *lc, LinphoneFriend *lf) { else lf->commit = TRUE; } -void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){ - MSList *el=ms_list_find(lc->friends,fl); - if (el!=NULL){ +void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* lf){ + MSList *el = ms_list_find(lc->friends, lf); + if (el != NULL) { linphone_friend_unref((LinphoneFriend*)el->data); - lc->friends=ms_list_remove_link(lc->friends,el); + lc->friends=ms_list_remove_link(lc->friends, el); +#ifdef FRIENDS_SQL_STORAGE_ENABLED + linphone_core_remove_friend_from_db(lc, lf); +#else linphone_core_write_friends_config(lc); - }else{ - ms_error("linphone_core_remove_friend(): friend [%p] is not part of core's list.",fl); +#endif + } else { + ms_error("linphone_core_remove_friend(): friend [%p] is not part of core's list.", lf); } } @@ -594,14 +618,16 @@ void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc){ } void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){ - if (lf->refkey!=NULL){ + if (lf->refkey != NULL) { ms_free(lf->refkey); - lf->refkey=NULL; + lf->refkey = NULL; + } + if (key) { + lf->refkey = ms_strdup(key); + } + if (lf->lc) { + linphone_friend_save(lf, lf->lc); } - if (key) - lf->refkey=ms_strdup(key); - if (lf->lc) - linphone_core_write_friends_config(lf->lc); } const char *linphone_friend_get_ref_key(const LinphoneFriend *lf){ @@ -737,10 +763,12 @@ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, } } -void linphone_core_write_friends_config(LinphoneCore* lc) -{ +void linphone_core_write_friends_config(LinphoneCore* lc) { MSList *elem; int i; +#ifdef FRIENDS_SQL_STORAGE_ENABLED + return; +#endif if (! linphone_core_ready(lc)) return; /*dont write config when reading it !*/ for (elem=lc->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){ linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i); @@ -853,12 +881,17 @@ int linphone_core_import_friends_from_vcard4_file(LinphoneCore *lc, const char * LinphoneFriend *lf = linphone_friend_new_from_vcard(vcard); if (lf) { linphone_core_import_friend(lc, lf); - linphone_friend_unref(lf); +#ifdef FRIENDS_SQL_STORAGE_ENABLED + linphone_core_store_friend_in_db(lc, lf); +#endif + linphone_friend_unref(lf); count++; } vcards = ms_list_next(vcards); } +#ifndef FRIENDS_SQL_STORAGE_ENABLED linphone_core_write_friends_config(lc); +#endif return count; } @@ -895,4 +928,179 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriend, belle_sip_object_t, NULL, // clone _linphone_friend_marshall, FALSE -); \ No newline at end of file +); + +/******************************************************************************* + * SQL storage related functions * + ******************************************************************************/ + +#ifdef FRIENDS_SQL_STORAGE_ENABLED + +static void linphone_create_table(sqlite3* db) { + char* errmsg = NULL; + int ret; + ret = sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS friends (" + + ");",//TODO + 0, 0, &errmsg); + if (ret != SQLITE_OK) { + ms_error("Error in creation: %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + +static void linphone_update_table(sqlite3* db) { + +} + +void linphone_core_friends_storage_init(LinphoneCore *lc) { + int ret; + const char *errmsg; + sqlite3 *db; + + linphone_core_friends_storage_close(lc); + + ret=_linphone_sqlite3_open(lc->friends_db_file, &db); + if (ret != SQLITE_OK) { + errmsg = sqlite3_errmsg(db); + ms_error("Error in the opening: %s.\n", errmsg); + sqlite3_close(db); + return; + } + + linphone_create_table(db); + linphone_update_table(db); + lc->friends_db = db; +} + +void linphone_core_friends_storage_close(LinphoneCore *lc) { + if (lc->friends_db) { + sqlite3_close(lc->friends_db); + lc->friends_db = NULL; + } +} + +/* DB layout: + * | 0 | storage_id + */ +static int create_friend(void *data, int argc, char **argv, char **colName) { + MSList **list = (MSList **)data; + LinphoneFriend *lf = NULL; + //TODO + *list = ms_list_append(*list, lf); + return 0; +} + +static int linphone_sql_request_friend(sqlite3* db, const char *stmt, MSList **list) { + char* errmsg = NULL; + int ret; + ret = sqlite3_exec(db, stmt, create_friend, list, &errmsg); + if (ret != SQLITE_OK) { + ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg); + sqlite3_free(errmsg); + } + return ret; +} + +static int linphone_sql_request_generic(sqlite3* db, const char *stmt) { + char* errmsg = NULL; + int ret; + ret = sqlite3_exec(db, stmt, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg); + sqlite3_free(errmsg); + } + return ret; +} + +void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf) { + if (lc && lc->friends_db) { + char *buf; + + if (lf->storage_id > 0) { + buf = sqlite3_mprintf("UPDATE friends SET WHERE (id = %i);", //TODO + lf->storage_id + ); + } else { + buf = sqlite3_mprintf("INSERT INTO friends VALUES(NULL);"); //TODO + } + linphone_sql_request_generic(lc->friends_db, buf); + sqlite3_free(buf); + + if (lf->storage_id == 0) { + lf->storage_id = sqlite3_last_insert_rowid(lc->friends_db); + } + } +} + +void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf) { + if (lc && lc->friends_db && lf->storage_id > 0) { + char *buf; + + buf = sqlite3_mprintf("DELETE FROM friends WHERE (id = %i);", + lf->storage_id + ); + linphone_sql_request_generic(lc->friends_db, buf); + sqlite3_free(buf); + + lf->storage_id = 0; + } +} + +MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc) { + char *buf; + uint64_t begin,end; + MSList *result = NULL; + + if (!lc || lc->friends_db == NULL) return NULL; + + buf = sqlite3_mprintf("SELECT * FROM friends ORDER BY id"); + + begin = ortp_get_cur_time_ms(); + linphone_sql_request_friend(lc->friends_db, buf, &result); + end = ortp_get_cur_time_ms(); + ms_message("%s(): completed in %i ms",__FUNCTION__, (int)(end-begin)); + sqlite3_free(buf); + + return result; +} + +#else + +void linphone_core_friends_storage_init(LinphoneCore *lc) { +} + +void linphone_core_friends_storage_close(LinphoneCore *lc) { +} + +void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf) { +} + +void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf) { +} + +MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc) { + return NULL; +} + +#endif + +void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path) { + if (lc->friends_db_file){ + ms_free(lc->friends_db_file); + lc->friends_db_file = NULL; + } + if (path) { + lc->friends_db_file = ms_strdup(path); + linphone_core_friends_storage_init(lc); + + linphone_core_migrate_friends_from_rc_to_db(lc); + } +} + +void linphone_core_migrate_friends_from_rc_to_db(LinphoneCore *lc) { +#ifndef FRIENDS_SQL_STORAGE_ENABLED + ms_warning("linphone has been compiled without sqlite, can't migrate friends"); + return; +#endif +} \ No newline at end of file diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 271570951..7538ca56a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1364,10 +1364,17 @@ static void video_config_read(LinphoneCore *lc){ static void ui_config_read(LinphoneCore *lc) { - LinphoneFriend *lf; + LinphoneFriend *lf = NULL; +#ifdef FRIENDS_SQL_STORAGE_ENABLED + MSList *friends = linphone_core_fetch_friends_from_db(lc); + while (friends && friends->data) { + lf = friends->data; + friends = ms_list_next(friends); +#else int i; for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){ - linphone_core_add_friend(lc,lf); +#endif + linphone_core_add_friend(lc, lf); linphone_friend_unref(lf); } diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index cd194f1d1..74d452b33 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -457,6 +457,22 @@ LINPHONE_PUBLIC int linphone_core_import_friends_from_vcard4_file(LinphoneCore * */ LINPHONE_PUBLIC void linphone_core_export_friends_as_vcard4_file(LinphoneCore *lc, const char *vcard_file); +/** + * Sets the database filename where friends will be stored. + * If the file does not exist, it will be created. + * @ingroup initializing + * @param lc the linphone core + * @param path filesystem path +**/ +LINPHONE_PUBLIC void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path); + +/** + * Migrates the friends from the linphonerc to the database if not done yet + * @ingroup initializing + * @param lc the linphone core +**/ +LINPHONE_PUBLIC void linphone_core_migrate_friends_from_rc_to_db(LinphoneCore *lc); + /** * @} */ diff --git a/coreapi/private.h b/coreapi/private.h index 1bd69a40a..22c83669d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -395,6 +395,11 @@ LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf); bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc); void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered); +void linphone_core_friends_storage_init(LinphoneCore *lc); +void linphone_core_friends_storage_close(LinphoneCore *lc); +void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf); +void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf); +MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc); int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port); @@ -654,6 +659,7 @@ struct _LinphoneFriend{ bool_t commit; bool_t initial_subscribes_sent; /*used to know if initial subscribe message was sent or not*/ LinphoneVCard *vcard; + unsigned int storage_id; }; BELLE_SIP_DECLARE_VPTR(LinphoneFriend); @@ -914,6 +920,10 @@ struct _LinphoneCore char *logs_db_file; #ifdef CALL_LOGS_STORAGE_ENABLED sqlite3 *logs_db; +#endif + char *friends_db_file; +#ifdef FRIENDS_SQL_STORAGE_ENABLED + sqlite3 *friends_db; #endif #ifdef BUILD_UPNP UpnpContext *upnp;