From 223bd817a9f829d2f2029d45aa4eb206ed980abb Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 2 Nov 2017 11:57:31 +0100 Subject: [PATCH] feat(core): break completely old message storage api impl --- coreapi/CMakeLists.txt | 1 - coreapi/linphonecore.c | 104 ++- coreapi/message_storage.c | 626 --------------- coreapi/private.h | 10 - coreapi/tester_utils.cpp | 4 - coreapi/tester_utils.h | 1 - src/CMakeLists.txt | 2 + src/c-wrapper/api/c-chat-room.cpp | 17 +- src/chat/chat-message/chat-message-p.h | 17 +- src/chat/chat-message/chat-message.cpp | 745 +++++++++++------- src/chat/chat-message/chat-message.h | 4 +- src/chat/chat-room/basic-chat-room-p.h | 3 +- src/chat/chat-room/basic-chat-room.cpp | 10 +- src/chat/chat-room/basic-chat-room.h | 3 +- src/chat/chat-room/chat-room-p.h | 16 +- src/chat/chat-room/chat-room.cpp | 330 ++------ src/chat/chat-room/chat-room.h | 11 +- src/chat/chat-room/client-group-chat-room-p.h | 3 +- src/chat/chat-room/client-group-chat-room.cpp | 31 +- src/chat/chat-room/client-group-chat-room.h | 11 +- .../chat-room/real-time-text-chat-room-p.h | 4 +- .../chat-room/real-time-text-chat-room.cpp | 31 +- src/chat/chat-room/real-time-text-chat-room.h | 6 +- src/chat/chat-room/server-group-chat-room-p.h | 3 +- .../chat-room/server-group-chat-room-stub.cpp | 9 +- src/chat/chat-room/server-group-chat-room.h | 4 +- .../encryption-chat-message-modifier.cpp | 5 +- .../multipart-chat-message-modifier.cpp | 3 +- src/chat/notification/imdn.cpp | 9 +- src/core/core-accessor.cpp | 58 ++ src/core/core-accessor.h | 52 ++ src/core/core-chat-room.cpp | 8 +- src/core/core.cpp | 5 + src/core/core.h | 8 + src/db/main-db.cpp | 89 ++- src/db/main-db.h | 35 +- src/db/session/db-session-provider.cpp | 42 +- src/db/session/db-session-provider.h | 1 - tester/CMakeLists.txt | 2 +- tester/cpim-tester.cpp | 6 +- tester/main-db-tester.cpp | 8 +- tester/message_tester.c | 157 ---- tester/multipart-tester.cpp | 10 +- tester/tester.c | 2 +- 44 files changed, 984 insertions(+), 1522 deletions(-) delete mode 100644 coreapi/message_storage.c create mode 100644 src/core/core-accessor.cpp create mode 100644 src/core/core-accessor.h diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 4a783cdda..3b05f7ca9 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -87,7 +87,6 @@ set(LINPHONE_SOURCE_FILES_C lpc2xml.c lpconfig.c lsd.c - message_storage.c misc.c nat_policy.c offeranswer.c diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4b5611301..fadfd6224 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6106,9 +6106,6 @@ static void linphone_core_uninit(LinphoneCore *lc) if(lc->rec_file!=NULL){ ms_free(lc->rec_file); } - if (lc->chat_db_file){ - ms_free(lc->chat_db_file); - } if (lc->logs_db_file) { ms_free(lc->logs_db_file); } @@ -6127,7 +6124,6 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_free_payload_types(lc); if (lc->supported_formats) ms_free((void *)lc->supported_formats); - linphone_core_message_storage_close(lc); linphone_core_call_log_storage_close(lc); linphone_core_friends_storage_close(lc); linphone_core_zrtp_cache_close(lc); @@ -6508,6 +6504,90 @@ void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook } +// ============================================================================= +// TODO: Remove me later, code found in message_storage.c. +// ============================================================================= + +#ifdef SQLITE_STORAGE_ENABLED + +#ifndef _WIN32 + #if !defined(__QNXNTO__) && !defined(__ANDROID__) + #include + #include + #include + #include + #include + #endif +#else + #include +#endif + +#define MAX_DB_PATH_SIZE 1024 + +static char *utf8_convert(const char *filename){ + char db_file_utf8[MAX_DB_PATH_SIZE] = ""; +#if defined(_WIN32) + wchar_t db_file_utf16[MAX_DB_PATH_SIZE]={0}; + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, filename, -1, db_file_utf16, MAX_DB_PATH_SIZE); + WideCharToMultiByte(CP_UTF8, 0, db_file_utf16, -1, db_file_utf8, sizeof(db_file_utf8), NULL, NULL); +#elif defined(__QNXNTO__) || defined(__ANDROID__) + strncpy(db_file_utf8, filename, MAX_DB_PATH_SIZE - 1); +#else + char db_file_locale[MAX_DB_PATH_SIZE] = {'\0'}; + char *inbuf=db_file_locale, *outbuf=db_file_utf8; + size_t inbyteleft = MAX_DB_PATH_SIZE, outbyteleft = MAX_DB_PATH_SIZE; + iconv_t cb; + + if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) { + strncpy(db_file_utf8, filename, MAX_DB_PATH_SIZE - 1); + } else { + strncpy(db_file_locale, filename, MAX_DB_PATH_SIZE-1); + cb = iconv_open("UTF-8", nl_langinfo(CODESET)); + if (cb != (iconv_t)-1) { + int ret; + ret = static_cast(iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft)); + if(ret == -1) db_file_utf8[0] = '\0'; + iconv_close(cb); + } + } +#endif + return ms_strdup(db_file_utf8); +} + +int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) { + char* errmsg = NULL; + int ret; + int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; + +#if TARGET_OS_IPHONE + /* the secured filesystem of the iPHone doesn't allow writing while the app is in background mode, which is problematic. + * We workaround by asking that the open is made with no protection*/ + flags |= SQLITE_OPEN_FILEPROTECTION_NONE; +#endif + + /*since we plug our vfs into sqlite, we convert to UTF-8. + * On Windows, the filename has to be converted back to windows native charset.*/ + char *utf8_filename = utf8_convert(db_file); + ret = sqlite3_open_v2(utf8_filename, db, flags, LINPHONE_SQLITE3_VFS); + ms_free(utf8_filename); + + if (ret != SQLITE_OK) return ret; + // Some platforms do not provide a way to create temporary files which are needed + // for transactions... so we work in memory only + // see http ://www.sqlite.org/compile.html#temp_store + ret = sqlite3_exec(*db, "PRAGMA temp_store=MEMORY", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + ms_error("Cannot set sqlite3 temporary store to memory: %s.", errmsg); + sqlite3_free(errmsg); + } + + return ret; +} + +#endif + +// ============================================================================= + void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){ LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(lc); if (lc->zrtp_secrets_cache != NULL) { @@ -6821,19 +6901,13 @@ int linphone_core_get_video_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","video_dscp",0); } -void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){ - if (lc->chat_db_file){ - ms_free(lc->chat_db_file); - lc->chat_db_file=NULL; - } - if (path) { - lc->chat_db_file=ms_strdup(path); - linphone_core_message_storage_init(lc); - } +void linphone_core_set_chat_database_path (LinphoneCore *, const char *) { + lError() << "Do not use `linphone_core_set_chat_database_path`. Not necessary."; } -const char* linphone_core_get_chat_database_path(const LinphoneCore *lc) { - return lc->chat_db_file; +const char *linphone_core_get_chat_database_path (const LinphoneCore *) { + lError() << "Do not use `linphone_core_get_chat_database_path`. Not necessary."; + return ""; } void linphone_core_enable_sdp_200_ack(LinphoneCore *lc, bool_t enable) { diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c deleted file mode 100644 index 803ab530b..000000000 --- a/coreapi/message_storage.c +++ /dev/null @@ -1,626 +0,0 @@ -/* -message_storage.c -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "private.h" -#include "linphone/core.h" - -#ifdef SQLITE_STORAGE_ENABLED - -#include "chat/chat-room/chat-room.h" - -#ifndef _WIN32 -#if !defined(__QNXNTO__) && !defined(__ANDROID__) -#include -#include -#include -#include -#include -#endif -#else -#include -#endif - -#define MAX_PATH_SIZE 1024 - -#include "sqlite3.h" -#include - - -static char *utf8_convert(const char *filename){ - char db_file_utf8[MAX_PATH_SIZE] = ""; -#if defined(_WIN32) - wchar_t db_file_utf16[MAX_PATH_SIZE]={0}; - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, filename, -1, db_file_utf16, MAX_PATH_SIZE); - WideCharToMultiByte(CP_UTF8, 0, db_file_utf16, -1, db_file_utf8, sizeof(db_file_utf8), NULL, NULL); -#elif defined(__QNXNTO__) || defined(__ANDROID__) - strncpy(db_file_utf8, filename, MAX_PATH_SIZE - 1); -#else - char db_file_locale[MAX_PATH_SIZE] = {'\0'}; - char *inbuf=db_file_locale, *outbuf=db_file_utf8; - size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE; - iconv_t cb; - - if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) { - strncpy(db_file_utf8, filename, MAX_PATH_SIZE - 1); - } else { - strncpy(db_file_locale, filename, MAX_PATH_SIZE-1); - cb = iconv_open("UTF-8", nl_langinfo(CODESET)); - if (cb != (iconv_t)-1) { - int ret; - ret = (int)iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft); - if(ret == -1) db_file_utf8[0] = '\0'; - iconv_close(cb); - } - } -#endif - return ms_strdup(db_file_utf8); -} - - -int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) { - char* errmsg = NULL; - int ret; - int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; - -#if TARGET_OS_IPHONE - /* the secured filesystem of the iPHone doesn't allow writing while the app is in background mode, which is problematic. - * We workaround by asking that the open is made with no protection*/ - flags |= SQLITE_OPEN_FILEPROTECTION_NONE; -#endif - - /*since we plug our vfs into sqlite, we convert to UTF-8. - * On Windows, the filename has to be converted back to windows native charset.*/ - char *utf8_filename = utf8_convert(db_file); - ret = sqlite3_open_v2(utf8_filename, db, flags, LINPHONE_SQLITE3_VFS); - ms_free(utf8_filename); - - if (ret != SQLITE_OK) return ret; - // Some platforms do not provide a way to create temporary files which are needed - // for transactions... so we work in memory only - // see http ://www.sqlite.org/compile.html#temp_store - ret = sqlite3_exec(*db, "PRAGMA temp_store=MEMORY", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_error("Cannot set sqlite3 temporary store to memory: %s.", errmsg); - sqlite3_free(errmsg); - } - - /* the lines below have been disabled because they are likely an - * outdated hack */ -#if 0 && TARGET_OS_IPHONE - ret = sqlite3_exec(*db, "PRAGMA journal_mode = OFF", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_error("Cannot set sqlite3 journal_mode to off: %s.", errmsg); - sqlite3_free(errmsg); - } -#endif - return ret; -} -#endif - - - -#ifdef SQLITE_STORAGE_ENABLED - -/* DB layout: - * | 0 | storage_id - * | 1 | type - * | 2 | subtype - * | 3 | name - * | 4 | encoding - * | 5 | size - * | 6 | data (currently not stored) - * | 7 | key size - * | 8 | key - */ -// Callback for sql request when getting linphone content -static int callback_content(void *data, int argc, char **argv, char **colName) { - LinphoneChatMessage *message = (LinphoneChatMessage *)data; - - LinphoneContent *content = linphone_content_new(); - if (argv[1]) linphone_content_set_type(content, argv[1]); - if (argv[2]) linphone_content_set_subtype(content, argv[2]); - if (argv[3]) linphone_content_set_name(content, argv[3]); - if (argv[4]) linphone_content_set_encoding(content, argv[4]); - linphone_content_set_size(content, (size_t)atoi(argv[5])); - if (argv[8]) linphone_content_set_key(content, argv[8], (size_t)atol(argv[7])); - linphone_chat_message_set_file_transfer_information(message, content); - - return 0; -} - -void linphone_chat_message_fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id) { - char* errmsg = NULL; - int ret; - char * buf; - - buf = sqlite3_mprintf("SELECT * FROM content WHERE id = %i", content_id); - ret = sqlite3_exec(db, buf, callback_content, message, &errmsg); - if (ret != SQLITE_OK) { - ms_error("Error in creation: %s.", errmsg); - sqlite3_free(errmsg); - } - sqlite3_free(buf); -} - -// Called when fetching all conversations from database -static int callback_all(void *data, int argc, char **argv, char **colName){ - LinphoneCore* lc = (LinphoneCore*) data; - char* address = argv[0]; - LinphoneAddress *addr = linphone_address_new(address); - if (addr){ - linphone_core_get_chat_room(lc, addr); - linphone_address_unref(addr); - } - return 0; -} - -int linphone_sql_request(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; -} - -// Process the request to fetch all chat contacts -void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg); - if(ret != SQLITE_OK) { - ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.", errmsg); - sqlite3_free(errmsg); - } -} - -static int linphone_chat_message_store_content(LinphoneChatMessage *msg) { - LinphoneCore *lc = linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - int id = -1; - if (lc->db) { - LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg); - char *buf = sqlite3_mprintf("INSERT INTO content VALUES(NULL,%Q,%Q,%Q,%Q,%i,%Q,%lld,%Q);", - linphone_content_get_type(content), - linphone_content_get_subtype(content), - linphone_content_get_name(content), - linphone_content_get_encoding(content), - linphone_content_get_size(content), - NULL, - (int64_t)linphone_content_get_key_size(content), - linphone_content_get_key(content) - ); - linphone_sql_request(lc->db, buf); - sqlite3_free(buf); - id = (int) sqlite3_last_insert_rowid (lc->db); - } - return id; -} - -unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ - LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - unsigned int id = 0; - - if (lc->db){ - int content_id = -1; - char *peer; - char *local_contact; - char *buf; - if (linphone_chat_message_get_file_transfer_information(msg)) { - content_id = linphone_chat_message_store_content(msg); - } - - peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg))); - local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); - buf = sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%lld,%Q,%i,%Q,%Q,%i);", - local_contact, - peer, - linphone_chat_message_get_direction(msg), - linphone_chat_message_get_text(msg), - "-1", /* use UTC field now */ - FALSE, /* use state == LinphoneChatMessageStateDisplayed now */ - linphone_chat_message_get_state(msg), - linphone_chat_message_get_external_body_url(msg), - (int64_t)linphone_chat_message_get_time(msg), - linphone_chat_message_get_appdata(msg), - content_id, - linphone_chat_message_get_message_id(msg), - linphone_chat_message_get_content_type(msg), - (int)linphone_chat_message_is_secured(msg) - ); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - ms_free(local_contact); - ms_free(peer); - id = (unsigned int) sqlite3_last_insert_rowid (lc->db); - } - linphone_chat_message_set_storage_id(msg, id); - return id; -} - -void linphone_chat_message_store_update(LinphoneChatMessage *msg) { - LinphoneCore *lc = linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - - if (lc->db) { - char *peer; - char *local_contact; - char *buf; - - peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(msg))); - local_contact = linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); - buf = sqlite3_mprintf("UPDATE history SET" - " localContact = %Q," - " remoteContact = %Q," - " message = %Q," - " status = %i," - " appdata = %Q," - " messageId = %Q," - " content_type = %Q" - " WHERE (id = %u);", - local_contact, - peer, - linphone_chat_message_get_text(msg), - linphone_chat_message_get_state(msg), - linphone_chat_message_get_appdata(msg), - linphone_chat_message_get_message_id(msg), - linphone_chat_message_get_content_type(msg), - linphone_chat_message_get_storage_id(msg) - ); - linphone_sql_request(lc->db, buf); - sqlite3_free(buf); - ms_free(local_contact); - ms_free(peer); - } -} - -void linphone_chat_message_store_state(LinphoneChatMessage *msg){ - LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - if (lc->db){ - char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (id = %u);", - linphone_chat_message_get_state(msg), linphone_chat_message_get_storage_id(msg)); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - } -} - -void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){ - LinphoneCore *lc=linphone_chat_room_get_core(linphone_chat_message_get_chat_room(msg)); - if (lc->db){ - char *buf=sqlite3_mprintf("UPDATE history SET appdata=%Q WHERE id=%u;", - linphone_chat_message_get_appdata(msg), linphone_chat_message_get_storage_id(msg)); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - } -} - -static void linphone_create_history_table(sqlite3* db){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "localContact TEXT NOT NULL," - "remoteContact TEXT NOT NULL," - "direction INTEGER," - "message TEXT," - "time TEXT NOT NULL," - "read INTEGER," - "status INTEGER" - ");", - 0,0,&errmsg); - if(ret != SQLITE_OK) { - ms_error("Error in creation: %s.\n", errmsg); - sqlite3_free(errmsg); - } -} - - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; -static time_t parse_time_from_db( const char* time ){ - /* messages used to be stored in the DB by using string-based time */ - struct tm ret={0}; - char tmp1[80]={0}; - char tmp2[80]={0}; - int i,j; - time_t parsed = 0; - - if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday, - &ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){ - ret.tm_year-=1900; - for(i=0;i<7;i++) { - if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; - } - for(j=0;j<12;j++) { - if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; - } - ret.tm_isdst=-1; - parsed = mktime(&ret); - } - return parsed; -} - - -static int migrate_messages_timestamp(void* data,int argc, char** argv, char** column_names) { - time_t new_time = parse_time_from_db(argv[1]); - if( new_time ){ - /* replace 'time' by -1 and set 'utc' to the timestamp */ - char *buf = sqlite3_mprintf("UPDATE history SET utc=%lld,time='-1' WHERE id=%i;", (int64_t)new_time, atoi(argv[0])); - if( buf) { - linphone_sql_request((sqlite3*)data, buf); - sqlite3_free(buf); - } - } else { - ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]); - } - return 0; -} - -static void linphone_migrate_timestamps(sqlite3* db){ - int ret; - char* errmsg = NULL; - uint64_t begin=ortp_get_cur_time_ms(); - - linphone_sql_request(db,"BEGIN TRANSACTION"); - - ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1';", migrate_messages_timestamp, db, &errmsg); - if( ret != SQLITE_OK ){ - ms_warning("Error migrating outgoing messages: %s.\n", errmsg); - sqlite3_free(errmsg); - linphone_sql_request(db, "ROLLBACK"); - } else { - uint64_t end; - linphone_sql_request(db, "COMMIT"); - end=ortp_get_cur_time_ms(); - ms_message("Migrated message timestamps to UTC in %lu ms",(unsigned long)(end-begin)); - } -} - -static void linphone_update_history_table(sqlite3* db) { - char* errmsg=NULL; - char *buf; - int ret; - - // for image url storage - ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for URL."); - } - - // for UTC timestamp storage - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg); - if( ret != SQLITE_OK ){ - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for UTC."); - // migrate from old text-based timestamps to unix time-based timestamps - linphone_migrate_timestamps(db); - } - - // new field for app-specific storage - ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN appdata TEXT;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for app-specific data."); - } - - // new field for linphone content storage - ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN content INTEGER;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history updated successfully for content data."); - ret = sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS content (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "type TEXT," - "subtype TEXT," - "name TEXT," - "encoding TEXT," - "size INTEGER," - "data BLOB" - ");", - 0,0,&errmsg); - if(ret != SQLITE_OK) { - ms_error("Error in creation: %s.\n", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table content successfully created."); - } - } - - // new fields for content key storage when using lime - ret=sqlite3_exec(db,"ALTER TABLE content ADD COLUMN key_size INTEGER;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ret=sqlite3_exec(db,"ALTER TABLE content ADD COLUMN key TEXT;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table history content successfully for lime key storage data."); - } - } - - // new field for message_id - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN messageId TEXT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_message("Table already up to date: %s", errmsg); - sqlite3_free(errmsg); - } else { - ms_message("Table history updated successfully for messageId data."); - } - - // Convert is_read to LinphoneChatMessageStateDisplayed - buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE read=1 AND direction=%i;", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming); - linphone_sql_request(db, buf); - sqlite3_free(buf); - - /* New field for content type */ - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN content_type TEXT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_message("Table already up to date: %s", errmsg); - sqlite3_free(errmsg); - } else { - ms_message("Table history updated successfully for content_type data."); - } - - // new field for secured flag - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN is_secured INTEGER DEFAULT 0;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - ms_message("Table already up to date: %s", errmsg); - sqlite3_free(errmsg); - } else { - ms_message("Table history updated successfully for is_secured data."); - } -} - -static void linphone_fix_outgoing_messages_state(sqlite3* db) { - /* Convert Idle and InProgress states of outgoing messages to NotDelivered */ - char *buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE direction=%i AND (status=%i OR status=%i);", - LinphoneChatMessageStateNotDelivered, LinphoneChatMessageOutgoing, LinphoneChatMessageStateIdle, LinphoneChatMessageStateInProgress); - linphone_sql_request(db, buf); - sqlite3_free(buf); -} - -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { - char *buf; - - if (lc->db==NULL) return; - buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;"); - linphone_sql_request_all(lc->db,buf,lc); - sqlite3_free(buf); -} - -static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){ - ms_warning("SQL statement '%s' took %llu microseconds", statement, (unsigned long long)(duration / 1000LL) ); -} - -static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){ - if( debug ){ - sqlite3_profile(db, _linphone_message_storage_profile, NULL ); - } else { - sqlite3_profile(db, NULL, NULL ); - } -} - -void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug){ - - lc->debug_storage = debug; - - if( lc->db ){ - linphone_message_storage_activate_debug(lc->db, debug); - } -} - -void linphone_core_message_storage_init(LinphoneCore *lc){ - int ret; - const char *errmsg; - sqlite3 *db = NULL; - - linphone_core_message_storage_close(lc); - - ret=_linphone_sqlite3_open(lc->chat_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_message_storage_activate_debug(db, lc->debug_storage); - - linphone_create_history_table(db); - linphone_update_history_table(db); - linphone_fix_outgoing_messages_state(db); - lc->db=db; - - // Create a chatroom for each contact in the chat history - linphone_message_storage_init_chat_rooms(lc); -} - -void linphone_core_message_storage_close(LinphoneCore *lc){ - if (lc->db){ - sqlite3_close(lc->db); - lc->db=NULL; - } -} - -#else - -unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ - return 0; -} - -void linphone_chat_message_store_state(LinphoneChatMessage *cr){ -} - -void linphone_chat_message_store_appdata(LinphoneChatMessage *msg){ -} - -void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ -} - -bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ - return NULL; -} - -bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end){ - return NULL; -} - -LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id) { - return NULL; -} - -void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { -} - -void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ -} - -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { -} - -void linphone_core_message_storage_init(LinphoneCore *lc){ -} - -void linphone_core_message_storage_close(LinphoneCore *lc){ -} - -int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ - return 0; -} - -int linphone_chat_room_get_history_size(LinphoneChatRoom *cr){ - return 0; -} - -void linphone_chat_message_store_update(LinphoneChatMessage *msg){ -} - -#endif diff --git a/coreapi/private.h b/coreapi/private.h index b28e80d05..630e1cdc3 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -906,12 +906,10 @@ struct _LinphoneCore int max_calls; LinphoneTunnel *tunnel; char* device_id; - char *chat_db_file; char *logs_db_file; char *friends_db_file; #ifdef SQLITE_STORAGE_ENABLED sqlite3 *zrtp_cache_db; /**< zrtp sqlite cache, used by both zrtp and lime */ - sqlite3 *db; sqlite3 *logs_db; sqlite3 *friends_db; bool_t debug_storage; @@ -1092,15 +1090,7 @@ void linphone_upnp_destroy(LinphoneCore *lc); #ifdef SQLITE_STORAGE_ENABLED int _linphone_sqlite3_open(const char *db_file, sqlite3 **db); -sqlite3 * linphone_message_storage_init(void); -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); #endif -void linphone_chat_message_store_update(LinphoneChatMessage *msg); -void linphone_chat_message_store_state(LinphoneChatMessage *msg); -void linphone_chat_message_store_appdata(LinphoneChatMessage* msg); -void linphone_core_message_storage_init(LinphoneCore *lc); -void linphone_core_message_storage_close(LinphoneCore *lc); -void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug); void linphone_chat_message_set_time(LinphoneChatMessage* msg, time_t time); void linphone_chat_message_set_incoming(LinphoneChatMessage *msg); diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index 77c30ad4c..c48407774 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -36,10 +36,6 @@ void linphone_core_enable_send_call_stats_periodical_updates(LinphoneCore *lc, b lc->send_call_stats_periodical_updates = enabled; } -sqlite3 *linphone_core_get_sqlite_database(const LinphoneCore *lc) { - return lc->db; -} - void linphone_core_set_zrtp_cache_db(LinphoneCore *lc, sqlite3 *cache_db) { lc->zrtp_cache_db = cache_db; } diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index 12cf9b401..c486e59f6 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -60,7 +60,6 @@ LINPHONE_PUBLIC int linphone_run_stun_tests(LinphoneCore *lc, int audioPort, int char *audioCandidateAddr, int *audioCandidatePort, char *videoCandidateAddr, int *videoCandidatePort, char *textCandidateAddr, int *textCandidatePort); LINPHONE_PUBLIC void linphone_core_enable_short_turn_refresh(LinphoneCore *lc, bool_t enable); -LINPHONE_PUBLIC sqlite3 *linphone_core_get_sqlite_database(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_zrtp_cache_db(LinphoneCore *lc, sqlite3 *cache_db); LINPHONE_PUBLIC LinphoneCoreCbs *linphone_core_get_first_callbacks(const LinphoneCore *lc); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ef57a4de0..53ae3b8ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,6 +82,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES content/content-manager.h content/content-type.h content/content.h + core/core-accessor.h core/core-p.h core/core.h core/paths/paths.h @@ -178,6 +179,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES content/content-manager.cpp content/content-type.cpp content/content.cpp + core/core-accessor.cpp core/core-chat-room.cpp core/core.cpp core/paths/paths.cpp diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 10ef56188..6292f863c 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -89,7 +89,7 @@ LinphoneCore *linphone_chat_room_get_lc (const LinphoneChatRoom *cr) { } LinphoneCore *linphone_chat_room_get_core (const LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->getCCore(); } const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr) { @@ -181,7 +181,7 @@ void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) { } int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) { - return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadMessagesCount(); + return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadChatMessagesCount(); } int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { @@ -206,7 +206,7 @@ bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_messa bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb->getHistory( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), nb_events ) @@ -215,7 +215,7 @@ bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int n bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end) { return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST( - L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->cppCore)->mainDb->getHistory( + L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore())->mainDb->getHistory( L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asStringUriOnly(), begin, end @@ -348,14 +348,19 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, me, L_C_TO_STRING(uri), L_C_TO_STRING(subject))); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create( + core->cppCore, me, L_C_TO_STRING(uri), L_C_TO_STRING(subject)) + ); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op) { LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create(core, op)); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, LinphonePrivate::ObjectFactory::create( + core->cppCore, + op + )); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->confirmCreation(); return cr; diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index bd60625ed..b321bb286 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -47,8 +47,8 @@ public: Cpim = 1 << 4 }; - ChatMessagePrivate (const std::shared_ptr &room); - virtual ~ChatMessagePrivate (); + ChatMessagePrivate (); + ~ChatMessagePrivate (); void setChatRoom (std::shared_ptr chatRoom); @@ -119,7 +119,10 @@ public: void send(); private: - std::shared_ptr chatRoom; + std::weak_ptr chatRoom; + Address peerAddress; + + // TODO: Clean attributes. ChatMessage::Direction direction = ChatMessage::Direction::Incoming; ChatMessage::State state = ChatMessage::State::Idle; unsigned int storageId = 0; @@ -157,9 +160,13 @@ private: void fileUploadEndBackgroundTask(); void fileUploadBeginBackgroundTask(); bool isFileTransferInProgressAndValid(); - int startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs); + int startHttpTransfer( + const std::string &url, + const std::string &action, + belle_http_request_listener_callbacks_t *cbs + ); void releaseHttpRequest(); - void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(std::string body); + void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(const std::string &body); L_DECLARE_PUBLIC(ChatMessage); }; diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index eb33fdc22..26e657128 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -26,12 +26,13 @@ #include "chat/chat-message/chat-message-p.h" -#include "content/content.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" #include "chat/modifier/cpim-chat-message-modifier.h" #include "chat/modifier/encryption-chat-message-modifier.h" #include "chat/modifier/multipart-chat-message-modifier.h" +#include "content/content.h" +#include "core/core.h" #include "logger/logger.h" #include "ortp/b64.h" @@ -47,9 +48,7 @@ using namespace std; // ChatMessagePrivate // ============================================================================= -ChatMessagePrivate::ChatMessagePrivate (const shared_ptr &room) -: chatRoom(room) { -} +ChatMessagePrivate::ChatMessagePrivate () {} ChatMessagePrivate::~ChatMessagePrivate () { if (salOp) @@ -66,82 +65,95 @@ void ChatMessagePrivate::setDirection (ChatMessage::Direction dir) { direction = dir; } -void ChatMessagePrivate::setTime(time_t t) { +void ChatMessagePrivate::setTime (time_t t) { time = t; } -void ChatMessagePrivate::setIsReadOnly(bool readOnly) { +void ChatMessagePrivate::setIsReadOnly (bool readOnly) { isReadOnly = readOnly; } -void ChatMessagePrivate::setState(ChatMessage::State s) { +void ChatMessagePrivate::setState (ChatMessage::State s) { L_Q(); - if (s != state && chatRoom) { - if (((state == ChatMessage::State::Displayed) || (state == ChatMessage::State::DeliveredToUser)) - && ((s == ChatMessage::State::DeliveredToUser) || (s == ChatMessage::State::Delivered) || (s == ChatMessage::State::NotDelivered))) { - return; - } - lInfo() << "Chat message " << this << ": moving from state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)state) << " to " << linphone_chat_message_state_to_string((LinphoneChatMessageState)s); - state = s; - LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); - if (linphone_chat_message_get_message_state_changed_cb(msg)) { - linphone_chat_message_get_message_state_changed_cb(msg)(msg, (LinphoneChatMessageState)state, linphone_chat_message_get_message_state_changed_cb_user_data(msg)); - } - LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs)) { - linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); - } - } + if (s == state || !q->getChatRoom()) + return; + + if ( + (state == ChatMessage::State::Displayed || state == ChatMessage::State::DeliveredToUser) && + ( + s == ChatMessage::State::DeliveredToUser || + s == ChatMessage::State::Delivered || + s == ChatMessage::State::NotDelivered + ) + ) + return; + + lInfo() << "Chat message " << this << ": moving from state " << + linphone_chat_message_state_to_string((LinphoneChatMessageState)state) << " to " << + linphone_chat_message_state_to_string((LinphoneChatMessageState)s); + state = s; + + LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); + if (linphone_chat_message_get_message_state_changed_cb(msg)) + linphone_chat_message_get_message_state_changed_cb(msg)( + msg, + (LinphoneChatMessageState)state, + linphone_chat_message_get_message_state_changed_cb_user_data(msg) + ); + + LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); + if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs)) + linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, linphone_chat_message_get_state(msg)); } -unsigned int ChatMessagePrivate::getStorageId() const { +unsigned int ChatMessagePrivate::getStorageId () const { return storageId; } -void ChatMessagePrivate::setStorageId(unsigned int id) { +void ChatMessagePrivate::setStorageId (unsigned int id) { storageId = id; } -belle_http_request_t *ChatMessagePrivate::getHttpRequest() const { +belle_http_request_t *ChatMessagePrivate::getHttpRequest () const { return httpRequest; } -void ChatMessagePrivate::setHttpRequest(belle_http_request_t *request) { +void ChatMessagePrivate::setHttpRequest (belle_http_request_t *request) { httpRequest = request; } -SalOp *ChatMessagePrivate::getSalOp() const { +SalOp *ChatMessagePrivate::getSalOp () const { return salOp; } -void ChatMessagePrivate::setSalOp(SalOp *op) { +void ChatMessagePrivate::setSalOp (SalOp *op) { salOp = op; } -SalCustomHeader *ChatMessagePrivate::getSalCustomHeaders() const { +SalCustomHeader *ChatMessagePrivate::getSalCustomHeaders () const { return salCustomHeaders; } -void ChatMessagePrivate::setSalCustomHeaders(SalCustomHeader *headers) { +void ChatMessagePrivate::setSalCustomHeaders (SalCustomHeader *headers) { salCustomHeaders = headers; } -void ChatMessagePrivate::addSalCustomHeader(const string& name, const string& value) { +void ChatMessagePrivate::addSalCustomHeader (const string &name, const string &value) { salCustomHeaders = sal_custom_header_append(salCustomHeaders, name.c_str(), value.c_str()); } -void ChatMessagePrivate::removeSalCustomHeader(const string& name) { +void ChatMessagePrivate::removeSalCustomHeader (const string &name) { salCustomHeaders = sal_custom_header_remove(salCustomHeaders, name.c_str()); } -string ChatMessagePrivate::getSalCustomHeaderValue(const string& name) { +string ChatMessagePrivate::getSalCustomHeaderValue (const string &name) { return L_C_TO_STRING(sal_custom_header_find(salCustomHeaders, name.c_str())); } // ----------------------------------------------------------------------------- -const ContentType& ChatMessagePrivate::getContentType() { +const ContentType &ChatMessagePrivate::getContentType () { if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { Content content = contents.front(); @@ -162,11 +174,11 @@ const ContentType& ChatMessagePrivate::getContentType() { return cContentType; } -void ChatMessagePrivate::setContentType(const ContentType &contentType) { +void ChatMessagePrivate::setContentType (const ContentType &contentType) { internalContent.setContentType(contentType); } -const string& ChatMessagePrivate::getText() { +const string &ChatMessagePrivate::getText () { if (direction == ChatMessage::Direction::Incoming) { if (contents.size() > 0) { Content content = contents.front(); @@ -187,53 +199,53 @@ const string& ChatMessagePrivate::getText() { return cText; } -void ChatMessagePrivate::setText(const string& text) { +void ChatMessagePrivate::setText (const string &text) { internalContent.setBody(text); } -LinphoneContent * ChatMessagePrivate::getFileTransferInformation() const { +LinphoneContent *ChatMessagePrivate::getFileTransferInformation () const { return cFileTransferInformation; } -void ChatMessagePrivate::setFileTransferInformation(LinphoneContent *content) { +void ChatMessagePrivate::setFileTransferInformation (LinphoneContent *content) { if (cFileTransferInformation) { linphone_content_unref(cFileTransferInformation); - cFileTransferInformation = NULL; + cFileTransferInformation = nullptr; } cFileTransferInformation = content; } // ----------------------------------------------------------------------------- -string ChatMessagePrivate::createImdnXml(Imdn::Type imdnType, LinphoneReason reason) { +string ChatMessagePrivate::createImdnXml (Imdn::Type imdnType, LinphoneReason reason) { xmlBufferPtr buf; xmlTextWriterPtr writer; int err; string content; - char *datetime = NULL; + char *datetime = nullptr; - // Check that the chat message has a message id - if (id.empty()) return NULL; + // Check that the chat message has a message id. + if (id.empty()) return nullptr; buf = xmlBufferCreate(); - if (buf == NULL) { + if (buf == nullptr) { lError() << "Error creating the XML buffer"; return content; } writer = xmlNewTextWriterMemory(buf, 0); - if (writer == NULL) { + if (writer == nullptr) { lError() << "Error creating the XML writer"; return content; } datetime = linphone_timestamp_to_rfc3339_string(time); - err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", nullptr); if (err >= 0) { - err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"imdn", - (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); + err = xmlTextWriterStartElementNS(writer, nullptr, (const xmlChar *)"imdn", + (const xmlChar *)"urn:ietf:params:xml:ns:imdn"); } if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", NULL, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", nullptr, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd"); } if (err >= 0) { err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)id.c_str()); @@ -267,7 +279,7 @@ string ChatMessagePrivate::createImdnXml(Imdn::Type imdnType, LinphoneReason rea err = xmlTextWriterEndElement(writer); } if ((err >= 0) && (reason != LinphoneReasonNone)) { - err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", NULL); + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", nullptr); if (err >= 0) { char codestr[16]; snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason)); @@ -305,23 +317,35 @@ string ChatMessagePrivate::createImdnXml(Imdn::Type imdnType, LinphoneReason rea return content; } -void ChatMessagePrivate::sendImdn(Imdn::Type imdnType, LinphoneReason reason) { - string content = createImdnXml(imdnType, reason); - chatRoom->getPrivate()->sendImdn(content, reason); +void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { + L_Q(); + shared_ptr chatRoom = q->getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->sendImdn(createImdnXml(imdnType, reason), reason); } -static void _chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, size_t total) { +static void _chat_message_file_transfer_on_progress ( + belle_sip_body_handler_t *bh, + belle_sip_message_t *m, + void *data, + size_t offset, + size_t total +) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->fileTransferOnProgress(bh, m, offset, total); } -void ChatMessagePrivate::fileTransferOnProgress(belle_sip_body_handler_t *bh, belle_sip_message_t *m, - size_t offset, size_t total) { +void ChatMessagePrivate::fileTransferOnProgress ( + belle_sip_body_handler_t *bh, + belle_sip_message_t *m, + size_t offset, + size_t total +) { L_Q(); if (!isFileTransferInProgressAndValid()) { - lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; + lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << " msg [" << this << + "], ignoring " << __FUNCTION__; releaseHttpRequest(); return; } @@ -331,44 +355,62 @@ void ChatMessagePrivate::fileTransferOnProgress(belle_sip_body_handler_t *bh, be if (linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)) { linphone_chat_message_cbs_get_file_transfer_progress_indication(cbs)(msg, cFileTransferInformation, offset, total); } else { - // Legacy: call back given by application level - linphone_core_notify_file_transfer_progress_indication(chatRoom->getCore(), msg, cFileTransferInformation, offset, total); + // Legacy: call back given by application level. + shared_ptr core = q->getCore(); + if (core) + linphone_core_notify_file_transfer_progress_indication( + core->getCCore(), + msg, + cFileTransferInformation, + offset, + total + ); } } -static int _chat_message_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - void *data, size_t offset, uint8_t *buffer, size_t *size) { +static int _chat_message_on_send_body ( + belle_sip_user_body_handler_t *bh, + belle_sip_message_t *m, + void *data, + size_t offset, + uint8_t *buffer, + size_t *size +) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; return d->onSendBody(bh, m, offset, buffer, size); } -int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, - size_t offset, uint8_t *buffer, size_t *size) { +int ChatMessagePrivate::onSendBody ( + belle_sip_user_body_handler_t *bh, + belle_sip_message_t *m, + size_t offset, + uint8_t *buffer, + size_t *size +) { L_Q(); - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; int retval = -1; LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q); if (!isFileTransferInProgressAndValid()) { if (httpRequest) { - lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; + lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << + " msg [" << this << "], ignoring " << __FUNCTION__; releaseHttpRequest(); } return BELLE_SIP_STOP; } - lc = chatRoom->getCore(); // if we've not reach the end of file yet, ask for more data // in case of file body handler, won't be called if (fileTransferFilePath.empty() && offset < linphone_content_get_size(cFileTransferInformation)) { // get data from call back LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg); - LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(cbs); + LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = + linphone_chat_message_cbs_get_file_transfer_send(cbs); if (file_transfer_send_cb) { LinphoneBuffer *lb = file_transfer_send_cb(msg, cFileTransferInformation, offset, *size); - if (lb == NULL) { + if (lb == nullptr) { *size = 0; } else { *size = linphone_buffer_get_size(lb); @@ -377,14 +419,21 @@ int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_ } } else { // Legacy - linphone_core_notify_file_transfer_send(lc, msg, cFileTransferInformation, (char *)buffer, size); + shared_ptr core = q->getCore(); + if (core) + linphone_core_notify_file_transfer_send(core->getCCore(), msg, cFileTransferInformation, (char *)buffer, size); } } - imee = linphone_core_get_im_encryption_engine(lc); + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = q->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); - LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); + LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = + linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); if (cb_process_uploading_file) { size_t max_size = *size; uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size); @@ -403,27 +452,29 @@ int ChatMessagePrivate::onSendBody(belle_sip_user_body_handler_t *bh, belle_sip_ return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP; } -static void _chat_message_on_send_end(belle_sip_user_body_handler_t *bh, void *data) { +static void _chat_message_on_send_end (belle_sip_user_body_handler_t *bh, void *data) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->onSendEnd(bh); } -void ChatMessagePrivate::onSendEnd(belle_sip_user_body_handler_t *bh) { +void ChatMessagePrivate::onSendEnd (belle_sip_user_body_handler_t *bh) { L_Q(); - LinphoneCore *lc = chatRoom->getCore(); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = q->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs); if (cb_process_uploading_file) { - cb_process_uploading_file(imee, L_GET_C_BACK_PTR(q), 0, NULL, NULL, NULL); + cb_process_uploading_file(imee, L_GET_C_BACK_PTR(q), 0, nullptr, nullptr, nullptr); } } } -void ChatMessagePrivate::fileUploadEndBackgroundTask() { +void ChatMessagePrivate::fileUploadEndBackgroundTask () { if (backgroundTaskId) { lInfo() << "channel [" << this << "]: ending file upload background task with id=[" << backgroundTaskId << "]."; sal_end_background_task(backgroundTaskId); @@ -431,45 +482,38 @@ void ChatMessagePrivate::fileUploadEndBackgroundTask() { } } -static void _chat_message_file_upload_background_task_ended(void *data) { +static void _chat_message_file_upload_background_task_ended (void *data) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->fileUploadBackgroundTaskEnded(); } -void ChatMessagePrivate::fileUploadBackgroundTaskEnded() { +void ChatMessagePrivate::fileUploadBackgroundTaskEnded () { lWarning() << "channel [" << this << "]: file upload background task has to be ended now, but work isn't finished."; fileUploadEndBackgroundTask(); } -void ChatMessagePrivate::fileUploadBeginBackgroundTask() { +void ChatMessagePrivate::fileUploadBeginBackgroundTask () { if (backgroundTaskId == 0) { backgroundTaskId = sal_begin_background_task("file transfer upload", _chat_message_file_upload_background_task_ended, this); if (backgroundTaskId) lInfo() << "channel [" << this << "]: starting file upload background task with id=[" << backgroundTaskId << "]."; } } -static void _chat_message_on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { +static void _chat_message_on_recv_body (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->onRecvBody(bh, m, offset, buffer, size); } -void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size) { +void ChatMessagePrivate::onRecvBody (belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, size_t offset, uint8_t *buffer, size_t size) { L_Q(); - LinphoneCore *lc = NULL; - LinphoneImEncryptionEngine *imee = NULL; int retval = -1; - uint8_t *decrypted_buffer = NULL; + uint8_t *decrypted_buffer = nullptr; - if (!chatRoom) { + if (!chatRoom.lock()) { q->cancelFileTransfer(); return; } - lc = chatRoom->getCore(); - - if (lc == NULL) { - return; // might happen during linphone_core_destroy() - } if (!httpRequest || belle_http_request_is_cancelled(httpRequest)) { lWarning() << "Cancelled request for msg [" << this << "], ignoring " << __FUNCTION__; @@ -482,7 +526,12 @@ void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip } decrypted_buffer = (uint8_t *)ms_malloc0(size); - imee = linphone_core_get_im_encryption_engine(lc); + + LinphoneImEncryptionEngine *imee = nullptr; + shared_ptr core = q->getCore(); + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); @@ -505,34 +554,35 @@ void ChatMessagePrivate::onRecvBody(belle_sip_user_body_handler_t *bh, belle_sip linphone_buffer_unref(lb); } else { // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(lc, msg, cFileTransferInformation, (const char *)buffer, size); + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, cFileTransferInformation, (const char *)buffer, size); } } } else { lWarning() << "File transfer decrypt failed with code " << (int)retval; setState(ChatMessage::State::FileTransferError); } - - return; } -static void _chat_message_on_recv_end(belle_sip_user_body_handler_t *bh, void *data) { +static void _chat_message_on_recv_end (belle_sip_user_body_handler_t *bh, void *data) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->onRecvEnd(bh); } -void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { +void ChatMessagePrivate::onRecvEnd (belle_sip_user_body_handler_t *bh) { L_Q(); - LinphoneCore *lc = chatRoom->getCore(); - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc); + shared_ptr core = q->getCore(); + if (!core) + return; + + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core->getCCore()); int retval = -1; if (imee) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs); if (cb_process_downloading_file) { - retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), 0, NULL, 0, NULL); + retval = cb_process_downloading_file(imee, L_GET_C_BACK_PTR(q), 0, nullptr, 0, nullptr); } } @@ -546,7 +596,7 @@ void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { linphone_buffer_unref(lb); } else { // Legacy: call back given by application level - linphone_core_notify_file_transfer_recv(lc, msg, cFileTransferInformation, NULL, 0); + linphone_core_notify_file_transfer_recv(core->getCCore(), msg, cFileTransferInformation, nullptr, 0); } } } @@ -556,20 +606,23 @@ void ChatMessagePrivate::onRecvEnd(belle_sip_user_body_handler_t *bh) { } } -bool ChatMessagePrivate::isFileTransferInProgressAndValid() { - return (chatRoom && chatRoom->getCore() && httpRequest && !belle_http_request_is_cancelled(httpRequest)); +bool ChatMessagePrivate::isFileTransferInProgressAndValid () { + L_Q(); + shared_ptr chatRoom = q->getChatRoom(); + return chatRoom && q->getCore() && httpRequest && !belle_http_request_is_cancelled(httpRequest); } -static void _chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event) { +static void _chat_message_process_response_from_post_file (void *data, const belle_http_response_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processResponseFromPostFile(event); } -void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_event_t *event) { +void ChatMessagePrivate::processResponseFromPostFile (const belle_http_response_event_t *event) { L_Q(); if (httpRequest && !isFileTransferInProgressAndValid()) { - lWarning() << "Cancelled request for " << (chatRoom ? "" : "ORPHAN") << " msg [" << this << "], ignoring " << __FUNCTION__; + lWarning() << "Cancelled request for " << (chatRoom.lock() ? "" : "ORPHAN") << + " msg [" << this << "], ignoring " << __FUNCTION__; releaseHttpRequest(); return; } @@ -584,8 +637,15 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e belle_sip_body_handler_t *first_part_bh; bool_t is_file_encryption_enabled = FALSE; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(chatRoom->getCore()); - if (imee) { + LinphoneImEncryptionEngine *imee = nullptr; + + shared_ptr core = q->getCore(); + shared_ptr chatRoom = q->getChatRoom(); + + if (core) + imee = linphone_core_get_im_encryption_engine(core->getCCore()); + + if (imee && chatRoom) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb = linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs); @@ -594,7 +654,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } } // shall we encrypt the file - if (is_file_encryption_enabled) { + if (is_file_encryption_enabled && chatRoom) { LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb = linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs); @@ -607,54 +667,54 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\""; } else { // temporary storage for the Content-disposition header value - first_part_header = "form-data; name=\"File\"; filename=\"" +string(linphone_content_get_name(cFileTransferInformation)) + "\""; + first_part_header = "form-data; name=\"File\"; filename=\"" + string(linphone_content_get_name(cFileTransferInformation)) + "\""; } // create a user body handler to take care of the file and add the content disposition and content-type headers first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new( linphone_content_get_size(cFileTransferInformation), - _chat_message_file_transfer_on_progress, NULL, NULL, + _chat_message_file_transfer_on_progress, nullptr, nullptr, _chat_message_on_send_body, _chat_message_on_send_end, this); if (!fileTransferFilePath.empty()) { belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh; // No need to add again the callback for progression, otherwise it will be called twice - first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), NULL, this); + first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), nullptr, this); linphone_content_set_size(cFileTransferInformation, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh)); belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler); - } else if (linphone_content_get_buffer(cFileTransferInformation) != NULL) { + } else if (linphone_content_get_buffer(cFileTransferInformation) != nullptr) { first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer( - linphone_content_get_buffer(cFileTransferInformation), - linphone_content_get_size(cFileTransferInformation), _chat_message_file_transfer_on_progress, this); + linphone_content_get_buffer(cFileTransferInformation), + linphone_content_get_size(cFileTransferInformation), _chat_message_file_transfer_on_progress, this); } belle_sip_body_handler_add_header(first_part_bh, - belle_sip_header_create("Content-disposition", first_part_header.c_str())); + belle_sip_header_create("Content-disposition", first_part_header.c_str())); belle_sip_body_handler_add_header(first_part_bh, - (belle_sip_header_t *)belle_sip_header_content_type_create( - linphone_content_get_type(cFileTransferInformation), - linphone_content_get_subtype(cFileTransferInformation))); + (belle_sip_header_t *)belle_sip_header_content_type_create( + linphone_content_get_type(cFileTransferInformation), + linphone_content_get_subtype(cFileTransferInformation))); // insert it in a multipart body handler which will manage the boundaries of multipart msg - bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, NULL); + bh = belle_sip_multipart_body_handler_new(_chat_message_file_transfer_on_progress, this, first_part_bh, nullptr); releaseHttpRequest(); fileUploadBeginBackgroundTask(); q->uploadFile(); belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh)); - } else if (code == 200) { // file has been uploaded correctly, get server reply and send it + } else if (code == 200) { // file has been uploaded correctly, get server reply and send it const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); if (body && strlen(body) > 0) { // if we have an encryption key for the file, we must insert it into the msg and restore the correct filename const char *content_key = linphone_content_get_key(cFileTransferInformation); size_t content_key_size = linphone_content_get_key_size(cFileTransferInformation); - if (content_key != NULL) { + if (content_key != nullptr) { // parse the msg body xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body); xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { + if (cur != nullptr) { cur = cur->xmlChildrenNode; - while (cur != NULL) { + while (cur != nullptr) { // we found a file info node, check it has a type="file" attribute if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); @@ -663,20 +723,20 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e // need to parse the children node to update the file-name one xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode; // convert key to base64 - size_t b64Size = b64_encode(NULL, content_key_size, NULL, 0); + size_t b64Size = b64_encode(nullptr, content_key_size, nullptr, 0); char *keyb64 = (char *)ms_malloc0(b64Size + 1); int xmlStringLength; b64Size = b64_encode(content_key, content_key_size, keyb64, b64Size); - keyb64[b64Size] = '\0'; // libxml need a null terminated string + keyb64[b64Size] = '\0'; // libxml need a null terminated string // add the node containing the key to the file-info node - xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64); + xmlNewTextChild(cur, nullptr, (const xmlChar *)"file-key", (const xmlChar *)keyb64); xmlFree(typeAttribute); ms_free(keyb64); // look for the file-name node and update its content - while (fileInfoNodeChildren != NULL) { + while (fileInfoNodeChildren != nullptr) { // we found a the file-name node, update its content with the real filename if (!xmlStrcmp(fileInfoNodeChildren->name, (const xmlChar *)"file-name")) { // update node content @@ -698,7 +758,7 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } } xmlFreeDoc(xmlMessageBody); - } else { // no encryption key, transfer in plain, just copy the msg sent by server + } else { // no encryption key, transfer in plain, just copy the msg sent by server setText(body); } setContentType(ContentType::FileTransfer); @@ -721,19 +781,17 @@ void ChatMessagePrivate::processResponseFromPostFile(const belle_http_response_e } } -static void _chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) { +static void _chat_process_response_headers_from_get_file (void *data, const belle_http_response_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processResponseHeadersFromGetFile(event); } -static LinphoneContent *createFileTransferInformationFromHeaders(const belle_sip_message_t *m) { +static LinphoneContent *createFileTransferInformationFromHeaders (const belle_sip_message_t *m) { LinphoneContent *content = linphone_content_new(); - belle_sip_header_content_length_t *content_length_hdr = - BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); - belle_sip_header_content_type_t *content_type_hdr = - BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); - const char *type = NULL, *subtype = NULL; + belle_sip_header_content_length_t *content_length_hdr = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length")); + belle_sip_header_content_type_t *content_type_hdr = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type")); + const char *type = nullptr, *subtype = nullptr; linphone_content_set_name(content, ""); @@ -757,15 +815,15 @@ static LinphoneContent *createFileTransferInformationFromHeaders(const belle_sip return content; } -void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_response_event_t *event) { +void ChatMessagePrivate::processResponseHeadersFromGetFile (const belle_http_response_event_t *event) { if (event->response) { - //we are receiving a response, set a specific body handler to acquire the response. + // we are receiving a response, set a specific body handler to acquire the response. // if not done, belle-sip will create a memory body handler, the default belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response); - belle_sip_body_handler_t *body_handler = NULL; + belle_sip_body_handler_t *body_handler = nullptr; size_t body_size = 0; - if (cFileTransferInformation == NULL) { + if (cFileTransferInformation == nullptr) { lWarning() << "No file transfer information for msg [" << this << "]: creating..."; cFileTransferInformation = createFileTransferInformationFromHeaders(response); } @@ -775,8 +833,8 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_resp } body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, _chat_message_file_transfer_on_progress, - NULL, _chat_message_on_recv_body, - NULL, _chat_message_on_recv_end, this); + nullptr, _chat_message_on_recv_body, + nullptr, _chat_message_on_recv_end, this); if (!fileTransferFilePath.empty()) { belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler; body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(fileTransferFilePath.c_str(), _chat_message_file_transfer_on_progress, this); @@ -791,12 +849,12 @@ void ChatMessagePrivate::processResponseHeadersFromGetFile(const belle_http_resp } } -static void _chat_message_process_auth_requested_download(void *data, belle_sip_auth_event *event) { +static void _chat_message_process_auth_requested_download (void *data, belle_sip_auth_event *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processAuthRequestedDownload(event); } -void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event *event) { +void ChatMessagePrivate::processAuthRequestedDownload (const belle_sip_auth_event *event) { L_Q(); lError() << "Error during file download : auth requested for msg [" << this << "]"; @@ -804,38 +862,46 @@ void ChatMessagePrivate::processAuthRequestedDownload(const belle_sip_auth_event releaseHttpRequest(); } -static void _chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) { +static void _chat_message_process_io_error_upload (void *data, const belle_sip_io_error_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processIoErrorUpload(event); } -void ChatMessagePrivate::processIoErrorUpload(const belle_sip_io_error_event_t *event) { +void ChatMessagePrivate::processIoErrorUpload (const belle_sip_io_error_event_t *event) { L_Q(); + lError() << "I/O Error during file upload of msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); + + shared_ptr chatRoom = q->getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); } -static void _chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event *event) { +static void _chat_message_process_auth_requested_upload (void *data, belle_sip_auth_event *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processAuthRequestedUpload(event); } -void ChatMessagePrivate::processAuthRequestedUpload(const belle_sip_auth_event *event) { +void ChatMessagePrivate::processAuthRequestedUpload (const belle_sip_auth_event *event) { L_Q(); + lError() << "Error during file upload: auth requested for msg [" << this << "]"; q->updateState(ChatMessage::State::NotDelivered); releaseHttpRequest(); - chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); + + shared_ptr chatRoom = q->getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->removeTransientMessage(q->getSharedFromThis()); } -static void _chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) { +static void _chat_message_process_io_error_download (void *data, const belle_sip_io_error_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processIoErrorDownload(event); } -void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t *event) { +void ChatMessagePrivate::processIoErrorDownload (const belle_sip_io_error_event_t *event) { L_Q(); lError() << "I/O Error during file download msg [" << this << "]"; @@ -843,12 +909,12 @@ void ChatMessagePrivate::processIoErrorDownload(const belle_sip_io_error_event_t releaseHttpRequest(); } -static void _chat_message_process_response_from_get_file(void *data, const belle_http_response_event_t *event) { +static void _chat_message_process_response_from_get_file (void *data, const belle_http_response_event_t *event) { ChatMessagePrivate *d = (ChatMessagePrivate *)data; d->processResponseFromGetFile(event); } -void ChatMessagePrivate::processResponseFromGetFile(const belle_http_response_event_t *event) { +void ChatMessagePrivate::processResponseFromGetFile (const belle_http_response_event_t *event) { // check the answer code if (event->response) { int code = belle_http_response_get_status_code(event->response); @@ -862,23 +928,35 @@ void ChatMessagePrivate::processResponseFromGetFile(const belle_http_response_ev } } -int ChatMessagePrivate::startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs) { - belle_generic_uri_t *uri = NULL; - const char* ua = linphone_core_get_user_agent(chatRoom->getCore()); +int ChatMessagePrivate::startHttpTransfer ( + const string &url, + const string &action, + belle_http_request_listener_callbacks_t *cbs +) { + L_Q(); + + belle_generic_uri_t *uri = nullptr; + + shared_ptr core = q->getCore(); + if (!core) + return -1; + + const char *ua = linphone_core_get_user_agent(core->getCCore()); if (url.empty()) { lWarning() << "Cannot process file transfer msg [" << this << "]: no file remote URI configured."; goto error; } uri = belle_generic_uri_parse(url.c_str()); - if (uri == NULL || belle_generic_uri_get_host(uri) == NULL) { - lWarning() << "Cannot process file transfer msg [" << this << "]: incorrect file remote URI configured '" << url << "'."; + if (uri == nullptr || belle_generic_uri_get_host(uri) == nullptr) { + lWarning() << "Cannot process file transfer msg [" << this << "]: incorrect file remote URI configured '" << + url << "'."; goto error; } - httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), NULL); + httpRequest = belle_http_request_create(action.c_str(), uri, belle_sip_header_create("User-Agent", ua), nullptr); - if (httpRequest == NULL) { + if (httpRequest == nullptr) { lWarning() << "Could not create http request for uri " << url; goto error; } @@ -887,8 +965,9 @@ int ChatMessagePrivate::startHttpTransfer(std::string url, std::string action, b // give msg to listener to be able to start the actual file upload when server answer a 204 No content httpListener = belle_http_request_listener_create_from_callbacks(cbs, this); - belle_http_provider_send_request(chatRoom->getCore()->http_provider, httpRequest, httpListener); + belle_http_provider_send_request(core->getCCore()->http_provider, httpRequest, httpListener); return 0; + error: if (uri) { belle_sip_object_unref(uri); @@ -896,19 +975,19 @@ error: return -1; } -void ChatMessagePrivate::releaseHttpRequest() { +void ChatMessagePrivate::releaseHttpRequest () { if (httpRequest) { belle_sip_object_unref(httpRequest); - httpRequest = NULL; - if (httpListener){ + httpRequest = nullptr; + if (httpListener) { belle_sip_object_unref(httpListener); - httpListener = NULL; + httpListener = nullptr; } } } -void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(string body) { - xmlChar *file_url = NULL; +void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml (const string &body) { + xmlChar *file_url = nullptr; xmlDocPtr xmlMessageBody; xmlNodePtr cur; /* parse the msg body to get all informations from it */ @@ -917,18 +996,18 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(s setFileTransferInformation(content); cur = xmlDocGetRootElement(xmlMessageBody); - if (cur != NULL) { + if (cur != nullptr) { cur = cur->xmlChildrenNode; - while (cur != NULL) { + while (cur != nullptr) { if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check if it has a type="file" attribute */ xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); - if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ - cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ - while (cur != NULL) { + if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur != nullptr) { if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, NULL, 10)); + linphone_content_set_size(content, (size_t)strtol((const char *)fileSizeString, nullptr, 10)); xmlFree(fileSizeString); } @@ -961,7 +1040,7 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(s /* there is a key in the msg: file has been encrypted */ /* convert the key from base 64 */ xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); - size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0); + size_t keyLength = b64::b64_decode((char *)keyb64, strlen((char *)keyb64), nullptr, 0); uint8_t *keyBuffer = (uint8_t *)malloc(keyLength); /* decode the key into local key buffer */ b64::b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength); @@ -987,11 +1066,14 @@ void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(s xmlFree(file_url); } -LinphoneReason ChatMessagePrivate::receive() { +LinphoneReason ChatMessagePrivate::receive () { L_Q(); int errorCode = 0; LinphoneReason reason = LinphoneReasonNone; + shared_ptr core = q->getCore(); + shared_ptr chatRoom = q->getChatRoom(); + // --------------------------------------- // Start of message modification // --------------------------------------- @@ -1005,7 +1087,8 @@ LinphoneReason ChatMessagePrivate::receive() { ChatMessageModifier::Result result = ecmm.decode(q->getSharedFromThis(), errorCode); if (result == ChatMessageModifier::Result::Error) { /* Unable to decrypt message */ - chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); + if (chatRoom) + chatRoom->getPrivate()->notifyUndecryptableMessageReceived(q->getSharedFromThis()); reason = linphone_error_code_to_reason(errorCode); q->sendDeliveryNotification(reason); return reason; @@ -1025,13 +1108,14 @@ LinphoneReason ChatMessagePrivate::receive() { if (errorCode <= 0) { bool foundSupportContentType = false; - for (const auto &c : contents) { - if (linphone_core_is_content_type_supported(chatRoom->getCore(), c.getContentType().asString().c_str())) { - foundSupportContentType = true; - break; - } else - lError() << "Unsupported content-type: " << c.getContentType().asString(); - } + if (core) + for (const auto &c : contents) { + if (linphone_core_is_content_type_supported(core->getCCore(), c.getContentType().asString().c_str())) { + foundSupportContentType = true; + break; + } else + lError() << "Unsupported content-type: " << c.getContentType().asString(); + } if (!foundSupportContentType) { errorCode = 415; @@ -1039,14 +1123,16 @@ LinphoneReason ChatMessagePrivate::receive() { } } - // Check if this is in fact an outgoing message (case where this is a message sent by us from an other device) - Address me(linphone_core_get_identity(chatRoom->getCore())); - if (me.weakEqual(from)) - setDirection(ChatMessage::Direction::Outgoing); + // Check if this is in fact an outgoing message (case where this is a message sent by us from an other device). + if (core) { + Address me(linphone_core_get_identity(core->getCCore())); + if (me.weakEqual(from)) + setDirection(ChatMessage::Direction::Outgoing); + } - /* Check if this is a duplicate message */ - if (chatRoom->findMessageWithDirection(q->getImdnMessageId(), q->getDirection())) - return chatRoom->getCore()->chat_deny_code; + // Check if this is a duplicate message. + if (chatRoom && chatRoom->findMessageWithDirection(q->getImdnMessageId(), q->getDirection())) + return core->getCCore()->chat_deny_code; if (errorCode > 0) { reason = linphone_error_code_to_reason(errorCode); @@ -1068,13 +1154,13 @@ LinphoneReason ChatMessagePrivate::receive() { return reason; } -void ChatMessagePrivate::send() { +void ChatMessagePrivate::send () { L_Q(); SalOp *op = salOp; - LinphoneCall *call = NULL; + LinphoneCall *call = nullptr; int errorCode = 0; - if ((currentSendStep & ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { + if ((currentSendStep &ChatMessagePrivate::Step::FileUpload) == ChatMessagePrivate::Step::FileUpload) { lInfo() << "File upload step already done, skipping"; } else { if (getFileTransferInformation()) { @@ -1087,22 +1173,23 @@ void ChatMessagePrivate::send() { } } - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { - call = linphone_core_get_call_by_remote_address(chatRoom->getCore(), to.asString().c_str()); + shared_ptr core = q->getCore(); + if (core && lp_config_get_int(core->getCCore()->config, "sip", "chat_use_call_dialogs", 0) != 0) { + call = linphone_core_get_call_by_remote_address(core->getCCore(), to.asString().c_str()); if (call) { if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning || - linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || - linphone_call_get_state(call) == LinphoneCallPausedByRemote) { + linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing || + linphone_call_get_state(call) == LinphoneCallPausedByRemote) { lInfo() << "send SIP msg through the existing call."; op = linphone_call_get_op(call); - string identity = linphone_core_find_best_identity(chatRoom->getCore(), linphone_call_get_remote_address(call)); + string identity = linphone_core_find_best_identity(core->getCCore(), linphone_call_get_remote_address(call)); if (identity.empty()) { LinphoneAddress *addr = linphone_address_new(to.asString().c_str()); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(chatRoom->getCore(), addr); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core->getCCore(), addr); if (proxy) { identity = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString(); } else { - identity = linphone_core_get_primary_contact(chatRoom->getCore()); + identity = linphone_core_get_primary_contact(core->getCCore()); } linphone_address_unref(addr); } @@ -1111,15 +1198,15 @@ void ChatMessagePrivate::send() { } } - if (!op) { + if (core && !op) { LinphoneAddress *peer = linphone_address_new(to.asString().c_str()); /* Sending out of call */ - salOp = op = new SalMessageOp(chatRoom->getCore()->sal); + salOp = op = new SalMessageOp(core->getCCore()->sal); linphone_configure_op( - chatRoom->getCore(), op, peer, getSalCustomHeaders(), - !!lp_config_get_int(chatRoom->getCore()->config, "sip", "chat_msg_with_contact", 0) + core->getCCore(), op, peer, getSalCustomHeaders(), + !!lp_config_get_int(core->getCCore()->config, "sip", "chat_msg_with_contact", 0) ); - op->set_user_pointer(L_GET_C_BACK_PTR(q)); /* If out of call, directly store msg */ + op->set_user_pointer(L_GET_C_BACK_PTR(q)); /* If out of call, directly store msg */ linphone_address_unref(peer); } @@ -1127,7 +1214,7 @@ void ChatMessagePrivate::send() { // Start of message modification // --------------------------------------- - //TODO Remove : This won't be necessary once we store the contentsList + // TODO Remove : This won't be necessary once we store the contentsList string clearTextMessage; ContentType clearTextContentType; @@ -1137,10 +1224,10 @@ void ChatMessagePrivate::send() { if (getContentType().isValid()) { clearTextContentType = getContentType(); } - //End of TODO Remove + // End of TODO Remove if (applyModifiers) { - if ((currentSendStep & ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { + if ((currentSendStep &ChatMessagePrivate::Step::Multipart) == ChatMessagePrivate::Step::Multipart) { lInfo() << "Multipart step already done, skipping"; } else { if (contents.size() > 1) { @@ -1150,7 +1237,7 @@ void ChatMessagePrivate::send() { currentSendStep |= ChatMessagePrivate::Step::Multipart; } - if ((currentSendStep & ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { + if ((currentSendStep &ChatMessagePrivate::Step::Encryption) == ChatMessagePrivate::Step::Encryption) { lInfo() << "Encryption step already done, skipping"; } else { EncryptionChatMessageModifier ecmm; @@ -1167,10 +1254,10 @@ void ChatMessagePrivate::send() { currentSendStep |= ChatMessagePrivate::Step::Encryption; } - if ((currentSendStep & ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { + if ((currentSendStep &ChatMessagePrivate::Step::Cpim) == ChatMessagePrivate::Step::Cpim) { lInfo() << "Cpim step already done, skipping"; } else { - if (lp_config_get_int(chatRoom->getCore()->config, "sip", "use_cpim", 1) == 1) { + if (core && lp_config_get_int(core->getCCore()->config, "sip", "use_cpim", 0) == 1) { CpimChatMessageModifier ccmm; ccmm.encode(q->getSharedFromThis(), errorCode); } @@ -1200,8 +1287,8 @@ void ChatMessagePrivate::send() { } } - //TODO Remove : This won't be necessary once we store the contentsList - if (!getText().empty() && getText() != clearTextMessage) { + // TODO Remove : This won't be necessary once we store the contentsList + if (!getText().empty() && getText() == clearTextMessage) { /* We replace the encrypted message by the original one so it can be correctly stored and displayed by the application */ setText(clearTextMessage); } @@ -1209,9 +1296,9 @@ void ChatMessagePrivate::send() { /* We replace the encrypted content type by the original one */ setContentType(clearTextContentType); } - //End of TODO Remove + // End of TODO Remove - q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ + q->setImdnMessageId(op->get_call_id()); /* must be known at that time */ if (call && linphone_call_get_op(call) == op) { /* In this case, chat delivery status is not notified, so unrefing chat message right now */ @@ -1228,25 +1315,37 @@ void ChatMessagePrivate::send() { // ----------------------------------------------------------------------------- -// ============================================================================= -// ChatMessage -// ============================================================================= +ChatMessage::ChatMessage (const shared_ptr &chatRoom) : + Object(*new ChatMessagePrivate), + CoreAccessor(chatRoom->getCore()) { + L_ASSERT(chatRoom); + L_D(); -ChatMessage::ChatMessage (const shared_ptr &room) : Object(*new ChatMessagePrivate(room)) {} + d->chatRoom = chatRoom; + d->peerAddress = chatRoom->getPeerAddress(); +} shared_ptr ChatMessage::getChatRoom () const { L_D(); - return d->chatRoom; + + shared_ptr chatRoom = d->chatRoom.lock(); + if (!chatRoom) { + shared_ptr core = getCore(); + if (core) + chatRoom = core->getOrCreateBasicChatRoom(d->peerAddress); + } + + return chatRoom; } // ----------------------------------------------------------------------------- -const string& ChatMessage::getExternalBodyUrl() const { +const string &ChatMessage::getExternalBodyUrl () const { L_D(); return d->externalBodyUrl; } -void ChatMessage::setExternalBodyUrl(const string &url) { +void ChatMessage::setExternalBodyUrl (const string &url) { L_D(); d->externalBodyUrl = url; } @@ -1261,7 +1360,7 @@ bool ChatMessage::isSecured () const { return d->isSecured; } -void ChatMessage::setIsSecured(bool isSecured) { +void ChatMessage::setIsSecured (bool isSecured) { L_D(); d->isSecured = isSecured; } @@ -1271,32 +1370,42 @@ ChatMessage::Direction ChatMessage::getDirection () const { return d->direction; } -ChatMessage::State ChatMessage::getState() const { +ChatMessage::State ChatMessage::getState () const { L_D(); return d->state; } -const string& ChatMessage::getImdnMessageId () const { +const string &ChatMessage::getImdnMessageId () const { L_D(); return d->id; } -void ChatMessage::setImdnMessageId (const string& id) { +void ChatMessage::setImdnMessageId (const string &id) { L_D(); d->id = id; } -bool ChatMessage::isRead() const { - return false; +bool ChatMessage::isRead () const { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == State::Displayed) return true; - if (linphone_im_notif_policy_get_recv_imdn_delivered(policy) && (d->state == State::DeliveredToUser || d->state == State::Displayed)) return true; + + shared_ptr core = getCore(); + if (!core) + return false; + + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + if (linphone_im_notif_policy_get_recv_imdn_displayed(policy) && d->state == State::Displayed) + return true; + + if ( + linphone_im_notif_policy_get_recv_imdn_delivered(policy) && + (d->state == State::DeliveredToUser || d->state == State::Displayed) + ) + return true; + return d->state == State::Delivered || d->state == State::Displayed || d->state == State::DeliveredToUser; } -const string& ChatMessage::getAppdata () const { +const string &ChatMessage::getAppdata () const { L_D(); return d->appData; } @@ -1304,25 +1413,27 @@ const string& ChatMessage::getAppdata () const { void ChatMessage::setAppdata (const string &appData) { L_D(); d->appData = appData; - linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); + + // TODO: history. + // linphone_chat_message_store_appdata(L_GET_C_BACK_PTR(this)); } -const Address& ChatMessage::getFromAddress () const { +const Address &ChatMessage::getFromAddress () const { L_D(); return d->from; } -void ChatMessage::setFromAddress(Address from) { +void ChatMessage::setFromAddress (Address from) { L_D(); d->from = from; } -const Address& ChatMessage::getToAddress () const { +const Address &ChatMessage::getToAddress () const { L_D(); return d->to; } -void ChatMessage::setToAddress(Address to) { +void ChatMessage::setToAddress (Address to) { L_D(); d->to = to; } @@ -1335,21 +1446,21 @@ const Address &ChatMessage::getRemoteAddress () const { return getDirection() != Direction::Incoming ? getToAddress() : getFromAddress(); } -const string& ChatMessage::getFileTransferFilepath() const { +const string &ChatMessage::getFileTransferFilepath () const { L_D(); return d->fileTransferFilePath; } -void ChatMessage::setFileTransferFilepath(const string &path) { +void ChatMessage::setFileTransferFilepath (const string &path) { L_D(); d->fileTransferFilePath = path; } // ----------------------------------------------------------------------------- -const LinphoneErrorInfo * ChatMessage::getErrorInfo() const { +const LinphoneErrorInfo *ChatMessage::getErrorInfo () const { L_D(); - if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); //let's do it mutable + if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); // let's do it mutable linphone_error_info_from_sal_op(d->errorInfo, d->salOp); return d->errorInfo; } @@ -1359,7 +1470,7 @@ bool ChatMessage::isReadOnly () const { return d->isReadOnly; } -const list& ChatMessage::getContents () const { +const list &ChatMessage::getContents () const { L_D(); return d->contents; } @@ -1378,19 +1489,19 @@ void ChatMessage::addContent (const Content &content) { d->contents.push_back(content); } -void ChatMessage::removeContent (const Content& content) { +void ChatMessage::removeContent (const Content &content) { L_D(); if (d->isReadOnly) return; d->contents.remove(content); } -const Content& ChatMessage::getInternalContent() const { +const Content &ChatMessage::getInternalContent () const { L_D(); return d->internalContent; } -void ChatMessage::setInternalContent(const Content& content) { +void ChatMessage::setInternalContent (const Content &content) { L_D(); d->internalContent = content; } @@ -1421,80 +1532,98 @@ void ChatMessage::removeCustomHeader (const string &headerName) { // ----------------------------------------------------------------------------- -void ChatMessage::store() { +void ChatMessage::store () { L_D(); if (d->storageId != 0) { /* The message has already been stored (probably because of file transfer), update it */ - linphone_chat_message_store_update(L_GET_C_BACK_PTR(this)); + // TODO: history. + // linphone_chat_message_store_update(L_GET_C_BACK_PTR(this)); } else { /* Store the new message */ - linphone_chat_message_store(L_GET_C_BACK_PTR(this)); + // TODO: history. + // linphone_chat_message_store(L_GET_C_BACK_PTR(this)); } } -void ChatMessage::updateState(State state) { +void ChatMessage::updateState (State state) { L_D(); d->setState(state); - linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); + // TODO: history. + // linphone_chat_message_store_state(L_GET_C_BACK_PTR(this)); - if (state == State::Delivered || state == State::NotDelivered) - d->chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); + if (state == State::Delivered || state == State::NotDelivered) { + shared_ptr chatRoom = getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->moveTransientMessageToWeakMessages(getSharedFromThis()); + } } void ChatMessage::send () { L_D(); // Do not allow sending a message that is already being sent or that has been correctly delivered/displayed - if ((d->state == State::InProgress) || (d->state == State::Delivered) || (d->state == State::FileTransferDone) - || (d->state == State::DeliveredToUser) || (d->state == State::Displayed)) { + if ((d->state == State::InProgress) || (d->state == State::Delivered) || (d->state == State::FileTransferDone) || + (d->state == State::DeliveredToUser) || (d->state == State::Displayed)) { lWarning() << "Cannot send chat message in state " << linphone_chat_message_state_to_string((LinphoneChatMessageState)d->state); return; } - d->chatRoom->getPrivate()->sendMessage(getSharedFromThis()); + shared_ptr chatRoom = getChatRoom(); + if (chatRoom) + chatRoom->getPrivate()->sendMessage(getSharedFromThis()); } -void ChatMessage::sendDeliveryNotification(LinphoneReason reason) { +void ChatMessage::sendDeliveryNotification (LinphoneReason reason) { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) { + + shared_ptr core = getCore(); + if (!core) + return; + + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) d->sendImdn(Imdn::Type::Delivery, reason); - } } -void ChatMessage::sendDisplayNotification() { +void ChatMessage::sendDisplayNotification () { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc); - if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) { + + shared_ptr core = getCore(); + if (!core) + return; + + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core->getCCore()); + if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) d->sendImdn(Imdn::Type::Display, LinphoneReasonNone); - } } -int ChatMessage::uploadFile() { +int ChatMessage::uploadFile () { L_D(); + shared_ptr core = getCore(); + if (!core) + return -1; + if (d->httpRequest) { lError() << "linphone_chat_room_upload_file(): there is already an upload in progress."; return -1; } - belle_http_request_listener_callbacks_t cbs = {0}; + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response = _chat_message_process_response_from_post_file; cbs.process_io_error = _chat_message_process_io_error_upload; cbs.process_auth_requested = _chat_message_process_auth_requested_upload; - int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(d->chatRoom->getCore()), "POST", &cbs); - if (err == -1) { + int err = d->startHttpTransfer(linphone_core_get_file_transfer_server(core->getCCore()), "POST", &cbs); + if (err == -1) d->setState(State::NotDelivered); - } + return err; } -int ChatMessage::downloadFile() { +int ChatMessage::downloadFile () { L_D(); if (d->httpRequest) { @@ -1502,7 +1631,7 @@ int ChatMessage::downloadFile() { return -1; } - belle_http_request_listener_callbacks_t cbs = {0}; + belle_http_request_listener_callbacks_t cbs = { 0 }; cbs.process_response_headers = _chat_process_response_headers_from_get_file; cbs.process_response = _chat_message_process_response_from_get_file; cbs.process_io_error = _chat_message_process_io_error_download; @@ -1515,16 +1644,22 @@ int ChatMessage::downloadFile() { return 0; } -void ChatMessage::cancelFileTransfer() { +void ChatMessage::cancelFileTransfer () { L_D(); if (d->httpRequest) { if (d->state == State::InProgress) { d->setState(State::NotDelivered); } if (!belle_http_request_is_cancelled(d->httpRequest)) { - if (d->chatRoom) { - lInfo() << "Canceling file transfer " << (d->externalBodyUrl.empty() ? linphone_core_get_file_transfer_server(d->chatRoom->getCore()) : d->externalBodyUrl.c_str()); - belle_http_provider_cancel_request(d->chatRoom->getCore()->http_provider, d->httpRequest); + shared_ptr chatRoom = getChatRoom(); + shared_ptr core = getCore(); + if (chatRoom && core) { + lInfo() << "Canceling file transfer " << ( + d->externalBodyUrl.empty() + ? linphone_core_get_file_transfer_server(core->getCCore()) + : d->externalBodyUrl.c_str() + ); + belle_http_provider_cancel_request(core->getCCore()->http_provider, d->httpRequest); } else { lInfo() << "Warning: http request still running for ORPHAN msg: this is a memory leak"; } @@ -1535,39 +1670,53 @@ void ChatMessage::cancelFileTransfer() { } } -int ChatMessage::putCharacter(uint32_t character) { +int ChatMessage::putCharacter (uint32_t character) { L_D(); - LinphoneCore *lc = d->chatRoom->getCore(); - if (linphone_core_realtime_text_enabled(lc)) { - shared_ptr rttcr = - static_pointer_cast(d->chatRoom); - LinphoneCall *call = rttcr->getCall(); - const uint32_t new_line = 0x2028; - const uint32_t crlf = 0x0D0A; - const uint32_t lf = 0x0A; - if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) { + shared_ptr core = getCore(); + if (!core) + return -1; + + if (linphone_core_realtime_text_enabled(core->getCCore())) { + static const uint32_t new_line = 0x2028; + static const uint32_t crlf = 0x0D0A; + static const uint32_t lf = 0x0A; + + shared_ptr chatRoom = getChatRoom(); + if (!chatRoom) + return -1; + + shared_ptr rttcr = + static_pointer_cast(chatRoom); + LinphoneCall *call = rttcr->getCall(); + + if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) return -1; - } if (character == new_line || character == crlf || character == lf) { - if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) { + if (lp_config_get_int(core->getCCore()->config, "misc", "store_rtt_messages", 1) == 1) { lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str(); d->setTime(ms_time(0)); d->state = State::Displayed; d->direction = Direction::Outgoing; - setFromAddress(LinphonePrivate::Address(linphone_address_as_string(linphone_address_new(linphone_core_get_identity(lc))))); - linphone_chat_message_store(L_GET_C_BACK_PTR(this)); + setFromAddress(LinphonePrivate::Address( + linphone_address_as_string(linphone_address_new(linphone_core_get_identity(core->getCCore()))) + )); + // TODO: History. + // linphone_chat_message_store(L_GET_C_BACK_PTR(this)); d->rttMessage = ""; } } else { char *value = LinphonePrivate::Utils::utf8ToChar(character); d->rttMessage = d->rttMessage + string(value); - lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character << "), pending text is " << d->rttMessage.c_str(); + lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character << + "), pending text is " << d->rttMessage.c_str(); delete value; } - text_stream_putchar32(reinterpret_cast(linphone_call_get_stream(call, LinphoneStreamTypeText)), character); + text_stream_putchar32(reinterpret_cast( + linphone_call_get_stream(call, LinphoneStreamTypeText)), character + ); return 0; } return -1; diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 76ae99890..cb2742fc6 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -25,6 +25,7 @@ #include "linphone/api/c-types.h" #include "linphone/enums/chat-message-enums.h" +#include "core/core-accessor.h" #include "object/object.h" // ============================================================================= @@ -36,7 +37,7 @@ class ChatRoom; class Content; class ChatMessagePrivate; -class LINPHONE_PUBLIC ChatMessage : public Object { +class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor { friend class ChatRoom; friend class ChatRoomPrivate; friend class CpimChatMessageModifier; @@ -49,6 +50,7 @@ public: L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_MESSAGE_STATE); L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); + // TODO: Make me private. ChatMessage (const std::shared_ptr &chatRoom); // ----- TODO: Remove me. diff --git a/src/chat/chat-room/basic-chat-room-p.h b/src/chat/chat-room/basic-chat-room-p.h index 12b4b986b..a6103d172 100644 --- a/src/chat/chat-room/basic-chat-room-p.h +++ b/src/chat/chat-room/basic-chat-room-p.h @@ -29,8 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class BasicChatRoomPrivate : public ChatRoomPrivate { public: - BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); - virtual ~BasicChatRoomPrivate () = default; + BasicChatRoomPrivate () = default; private: std::string subject; diff --git a/src/chat/chat-room/basic-chat-room.cpp b/src/chat/chat-room/basic-chat-room.cpp index c07afa0af..bb602f9c6 100644 --- a/src/chat/chat-room/basic-chat-room.cpp +++ b/src/chat/chat-room/basic-chat-room.cpp @@ -29,14 +29,8 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -BasicChatRoomPrivate::BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core) { - this->peerAddress = peerAddress; -} - -// ============================================================================= - -BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : - ChatRoom(*new BasicChatRoomPrivate(core, peerAddress)) {} +BasicChatRoom::BasicChatRoom (const shared_ptr &core, const Address &peerAddress) : + ChatRoom(*new BasicChatRoomPrivate, core, peerAddress) {} // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/basic-chat-room.h b/src/chat/chat-room/basic-chat-room.h index 56906844b..402ce990f 100644 --- a/src/chat/chat-room/basic-chat-room.h +++ b/src/chat/chat-room/basic-chat-room.h @@ -30,8 +30,7 @@ class BasicChatRoomPrivate; class LINPHONE_PUBLIC BasicChatRoom : public ChatRoom { public: - BasicChatRoom (LinphoneCore *core, const Address &peerAddress); - virtual ~BasicChatRoom () = default; + BasicChatRoom (const std::shared_ptr &core, const Address &peerAddress); CapabilitiesMask getCapabilities () const override; diff --git a/src/chat/chat-room/chat-room-p.h b/src/chat/chat-room/chat-room-p.h index 069814e53..1c4513389 100644 --- a/src/chat/chat-room/chat-room-p.h +++ b/src/chat/chat-room/chat-room-p.h @@ -34,8 +34,7 @@ class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener { friend class ChatMessagePrivate; public: - ChatRoomPrivate (LinphoneCore *core); - virtual ~ChatRoomPrivate (); + ChatRoomPrivate () = default; private: static int createChatMessageFromDb (void *data, int argc, char **argv, char **colName); @@ -53,7 +52,6 @@ public: void release (); void sendImdn (const std::string &content, LinphoneReason reason); - int getMessagesCount (bool unreadOnly); void setState (ChatRoom::State newState); virtual void sendMessage (const std::shared_ptr &msg); @@ -64,8 +62,6 @@ protected: int createChatMessageFromDb (int argc, char **argv, char **colName); std::shared_ptr getTransientMessage (unsigned int storageId) const; std::shared_ptr getWeakMessage (unsigned int storageId) const; - int sqlRequest (sqlite3 *db, const std::string &stmt); - void sqlRequestMessage (sqlite3 *db, const std::string &stmt); std::list> findMessages (const std::string &messageId); virtual void storeOrUpdateMessage (const std::shared_ptr &msg); @@ -91,18 +87,20 @@ private: void onIsComposingRefreshNeeded () override; public: - LinphoneCore *core = nullptr; LinphoneCall *call = nullptr; ChatRoom::State state = ChatRoom::State::None; Address peerAddress; - int unreadCount = -1; bool isComposing = false; std::unordered_set remoteIsComposing; - std::list> messages; std::list> transientMessages; + std::list> weakMessages; + + // TODO: Remove me. Must be present only in rtt chat room. std::shared_ptr pendingMessage; - IsComposing isComposingHandler; + + // TODO: Use CoreAccessor on IsComposing. And avoid pointer if possible. + std::unique_ptr isComposingHandler; private: L_DECLARE_PUBLIC(ChatRoom); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index 4553bff2f..96401619d 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -25,6 +25,7 @@ #include "chat/chat-room/chat-room-p.h" #include "chat/notification/imdn.h" #include "logger/logger.h" +#include "core/core-p.h" // ============================================================================= @@ -32,11 +33,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core) - : core(core), isComposingHandler(core, this) {} - -ChatRoomPrivate::~ChatRoomPrivate () {} - // ----------------------------------------------------------------------------- int ChatRoomPrivate::createChatMessageFromDb (void *data, int argc, char **argv, char **colName) { @@ -79,38 +75,44 @@ void ChatRoomPrivate::removeTransientMessage (const shared_ptr &msg void ChatRoomPrivate::release () { L_Q(); - isComposingHandler.stopTimers(); + isComposingHandler->stopTimers(); + // TODO: Remove me? + // Why chat room is set to nullptr? Avoid shared ptr lock?! Wtf?! for (auto &message : weakMessages) { try { shared_ptr msg(message); msg->cancelFileTransfer(); msg->getPrivate()->setChatRoom(nullptr); - } catch(const std::bad_weak_ptr& e) {} + } catch (const bad_weak_ptr &) {} } for (auto &message : transientMessages) { message->cancelFileTransfer(); message->getPrivate()->setChatRoom(nullptr); } - core = nullptr; linphone_chat_room_unref(L_GET_C_BACK_PTR(q)); } void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { L_Q(); + shared_ptr core = q->getCore(); + if (!core) + return; + LinphoneCore *cCore = core->getCCore(); + const char *identity = nullptr; LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str()); - LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peer); + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, peer); if (proxy) identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy)); else - identity = linphone_core_get_primary_contact(core); + identity = linphone_core_get_primary_contact(cCore); /* Sending out of call */ - SalMessageOp *op = new SalMessageOp(core->sal); - linphone_configure_op(core, op, peer, nullptr, !!lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0)); + SalMessageOp *op = new SalMessageOp(cCore->sal); + linphone_configure_op(cCore, op, peer, nullptr, !!lp_config_get_int(cCore->config, "sip", "chat_msg_with_contact", 0)); shared_ptr msg = q->createMessage(); msg->setFromAddress(Address(identity)); @@ -123,7 +125,7 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { /* Do not try to encrypt the notification when it is reporting an error (maybe it should be bypassed only for some reasons). */ int retval = -1; - LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core); + LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(cCore); if (imee && (reason == LinphoneReasonNone)) { LinphoneImEncryptionEngineCbs *imeeCbs = linphone_im_encryption_engine_get_callbacks(imee); LinphoneImEncryptionEngineCbsOutgoingMessageCb cbProcessOutgoingMessage = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imeeCbs); @@ -142,42 +144,12 @@ void ChatRoomPrivate::sendImdn (const string &payload, LinphoneReason reason) { // ----------------------------------------------------------------------------- -int ChatRoomPrivate::getMessagesCount (bool unreadOnly) { - if (!core->db) return 0; - - /* Optimization: do not read database if the count is already available in memory */ - if (unreadOnly && unreadCount >= 0) return unreadCount; - - string peer = peerAddress.asStringUriOnly(); - char *option = nullptr; - if (unreadOnly) - option = bctbx_strdup_printf("AND status!=%i AND direction=%i", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming); - char *buf = sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;", peer.c_str(), unreadOnly ? option : ""); - sqlite3_stmt *selectStatement; - int numrows = 0; - int returnValue = sqlite3_prepare_v2(core->db, buf, -1, &selectStatement, nullptr); - if (returnValue == SQLITE_OK) { - if (sqlite3_step(selectStatement) == SQLITE_ROW) { - numrows = sqlite3_column_int(selectStatement, 0); - } - } - sqlite3_finalize(selectStatement); - sqlite3_free(buf); - - /* No need to test the sign of unreadCount here because it has been tested above */ - if (unreadOnly) { - unreadCount = numrows; - } - if (option) bctbx_free(option); - return numrows; -} - void ChatRoomPrivate::setState (ChatRoom::State newState) { L_Q(); if (newState != state) { state = newState; if (state == ChatRoom::State::Instantiated) - linphone_core_notify_chat_room_instantiated(core, L_GET_C_BACK_PTR(q)); + linphone_core_notify_chat_room_instantiated(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q)); notifyStateChanged(); } } @@ -186,9 +158,9 @@ void ChatRoomPrivate::setState (ChatRoom::State newState) { void ChatRoomPrivate::sendIsComposingNotification () { L_Q(); - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore()); if (linphone_im_notif_policy_get_send_is_composing(policy)) { - string payload = isComposingHandler.marshal(isComposing); + string payload = isComposingHandler->marshal(isComposing); if (!payload.empty()) { shared_ptr msg = q->createMessage(); Content content; @@ -222,72 +194,7 @@ void ChatRoomPrivate::sendIsComposingNotification () { * | 14 | secured flag */ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colName) { - L_Q(); - unsigned int storageId = (unsigned int)atoi(argv[0]); - - /* Check if the message exists in the weak messages list, in which case we should return that one. */ - shared_ptr message = getWeakMessage(storageId); - if (!message) { - /* Check if the message exists in the transient list, in which case we should return that one. */ - message = getTransientMessage(storageId); - } - if (!message) { - message = q->createMessage(); - - Content content; - if (argv[4]) { - content.setBody(argv[4]); - } - if (argv[13]) { - content.setContentType(argv[13]); - } - message->addContent(content); - - Address peer(peerAddress.asString()); - if (atoi(argv[3]) == static_cast(ChatMessage::Direction::Incoming)) { - message->getPrivate()->setDirection(ChatMessage::Direction::Incoming); - message->setFromAddress(peer); - } else { - message->getPrivate()->setDirection(ChatMessage::Direction::Outgoing); - message->setToAddress(peer); - } - - message->getPrivate()->setTime((time_t)atol(argv[9])); - message->getPrivate()->setState((ChatMessage::State)atoi(argv[7])); - message->getPrivate()->setStorageId(storageId); - if (argv[8]) { - message->setExternalBodyUrl(argv[8]); - } - if (argv[10]) { - message->setAppdata(argv[10]); - } - if (argv[12]) { - message->setImdnMessageId(argv[12]); - } - message->setIsSecured((bool)atoi(argv[14])); - - if (argv[11]) { - int id = atoi(argv[11]); - if (id >= 0) - linphone_chat_message_fetch_content_from_database(core->db, L_GET_C_BACK_PTR(message), id); - } - - /* Fix content type for old messages that were stored without it */ - /* To keep ? - if (message->getPrivate()->getContentType().empty()) { - if (message->getPrivate()->getFileTransferInformation()) { - message->getPrivate()->setContentType("application/vnd.gsma.rcs-ft-http+xml"); - } else if (!message->getExternalBodyUrl().empty()) { - message->getPrivate()->setContentType("message/external-body"); - } else { - message->getPrivate()->setContentType("text/plain"); - } - }*/ - - /* Add the new message to the weak messages list. */ - addWeakMessage(message); - } - messages.push_front(message); + // TODO: history. return 0; } @@ -310,36 +217,9 @@ std::shared_ptr ChatRoomPrivate::getWeakMessage (unsigned int stora return nullptr; } -int ChatRoomPrivate::sqlRequest (sqlite3 *db, const string &stmt) { - char *errmsg = nullptr; - int ret = sqlite3_exec(db, stmt.c_str(), nullptr, nullptr, &errmsg); - if (ret != SQLITE_OK) { - lError() << "ChatRoomPrivate::sqlRequest: statement " << stmt << " -> error sqlite3_exec(): " << errmsg; - sqlite3_free(errmsg); - } - return ret; -} - -void ChatRoomPrivate::sqlRequestMessage (sqlite3 *db, const string &stmt) { - char *errmsg = nullptr; - int ret = sqlite3_exec(db, stmt.c_str(), createChatMessageFromDb, this, &errmsg); - if (ret != SQLITE_OK) { - lError() << "Error in creation: " << errmsg; - sqlite3_free(errmsg); - } -} - list > ChatRoomPrivate::findMessages (const string &messageId) { - if (!core->db) - return list >(); - string peer = peerAddress.asStringUriOnly(); - char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer.c_str(), messageId.c_str()); - messages.clear(); - sqlRequestMessage(core->db, buf); - sqlite3_free(buf); - list > result = messages; - messages.clear(); - return result; + // TODO: history. + return list>(); } void ChatRoomPrivate::storeOrUpdateMessage (const shared_ptr &msg) { @@ -369,8 +249,8 @@ void ChatRoomPrivate::sendMessage (const shared_ptr &msg) { if (isComposing) isComposing = false; - isComposingHandler.stopIdleTimer(); - isComposingHandler.stopRefreshTimer(); + isComposingHandler->stopIdleTimer(); + isComposingHandler->stopRefreshTimer(); } // ----------------------------------------------------------------------------- @@ -382,6 +262,11 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa LinphoneReason reason = LinphoneReasonNone; shared_ptr msg; + shared_ptr core = q->getCore(); + if (!core) + return reason; + LinphoneCore *cCore = core->getCCore(); + msg = q->createMessage(); Content content; @@ -389,7 +274,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa content.setBody(salMsg->text ? salMsg->text : ""); msg->setInternalContent(content); - msg->setToAddress(Address(op->get_to() ? op->get_to() : linphone_core_get_identity(core))); + msg->setToAddress(Address(op->get_to() ? op->get_to() : linphone_core_get_identity(cCore))); msg->setFromAddress(peerAddress); msg->getPrivate()->setTime(salMsg->time); msg->getPrivate()->setState(ChatMessage::State::Delivered); @@ -413,22 +298,18 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) { isComposingReceived(msg->getFromAddress(), msg->getPrivate()->getText()); increaseMsgCount = FALSE; - if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { + if (lp_config_get_int(cCore->config, "sip", "deliver_imdn", 0) != 1) { goto end; } } else if (msg->getPrivate()->getContentType() == ContentType::Imdn) { imdnReceived(msg->getPrivate()->getText()); increaseMsgCount = FALSE; - if (lp_config_get_int(core->config, "sip", "deliver_imdn", 0) != 1) { + if (lp_config_get_int(cCore->config, "sip", "deliver_imdn", 0) != 1) { goto end; } } if (increaseMsgCount) { - if (unreadCount < 0) - unreadCount = 1; - else - unreadCount++; /* Mark the message as pending so that if ChatRoom::markAsRead() is called in the * ChatRoomPrivate::chatMessageReceived() callback, it will effectively be marked as * being read before being stored. */ @@ -462,7 +343,7 @@ void ChatRoomPrivate::chatMessageReceived (const shared_ptr &msg) { notifyChatMessageReceived(msg); remoteIsComposing.erase(msg->getFromAddress().asStringUriOnly()); - isComposingHandler.stopRemoteRefreshTimer(msg->getFromAddress().asStringUriOnly()); + isComposingHandler->stopRemoteRefreshTimer(msg->getFromAddress().asStringUriOnly()); notifyIsComposingReceived(msg->getFromAddress(), false); msg->sendDeliveryNotification(LinphoneReasonNone); } @@ -474,7 +355,7 @@ void ChatRoomPrivate::imdnReceived (const string &text) { } void ChatRoomPrivate::isComposingReceived (const Address &remoteAddr, const string &text) { - isComposingHandler.parse(remoteAddr, text); + isComposingHandler->parse(remoteAddr, text); } // ----------------------------------------------------------------------------- @@ -484,13 +365,18 @@ void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr & LinphoneChatRoom *cr = L_GET_C_BACK_PTR(q); if (!msg->getPrivate()->getText().empty()) { /* Legacy API */ - linphone_core_notify_text_message_received(core, cr, L_GET_C_BACK_PTR(&msg->getFromAddress()), msg->getPrivate()->getText().c_str()); + linphone_core_notify_text_message_received( + q->getCore()->getCCore(), + cr, + L_GET_C_BACK_PTR(&msg->getFromAddress()), + msg->getPrivate()->getText().c_str() + ); } LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr); LinphoneChatRoomCbsMessageReceivedCb cb = linphone_chat_room_cbs_get_message_received(cbs); if (cb) cb(cr, L_GET_C_BACK_PTR(msg)); - linphone_core_notify_message_received(core, cr, L_GET_C_BACK_PTR(msg)); + linphone_core_notify_message_received(q->getCore()->getCCore(), cr, L_GET_C_BACK_PTR(msg)); } void ChatRoomPrivate::notifyIsComposingReceived (const Address &remoteAddr, bool isComposing) { @@ -504,7 +390,7 @@ void ChatRoomPrivate::notifyIsComposingReceived (const Address &remoteAddr, bool linphone_address_unref(lAddr); } // Legacy notification - linphone_core_notify_is_composing_received(core, cr); + linphone_core_notify_is_composing_received(q->getCore()->getCCore(), cr); } void ChatRoomPrivate::notifyStateChanged () { @@ -523,7 +409,7 @@ void ChatRoomPrivate::notifyUndecryptableMessageReceived (const shared_ptrgetCore()->getCCore(), cr, L_GET_C_BACK_PTR(msg)); } // ----------------------------------------------------------------------------- @@ -547,7 +433,15 @@ void ChatRoomPrivate::onIsComposingRefreshNeeded () { // ============================================================================= -ChatRoom::ChatRoom (ChatRoomPrivate &p) : Object(p) {} +ChatRoom::ChatRoom ( + ChatRoomPrivate &p, + const shared_ptr &core, + const Address &peerAddress +) : Object(p), CoreAccessor(core) { + L_D(); + d->peerAddress = peerAddress; + d->isComposingHandler.reset(new IsComposing(core->getCCore(), d)); +} // ----------------------------------------------------------------------------- @@ -556,9 +450,9 @@ void ChatRoom::compose () { if (!d->isComposing) { d->isComposing = true; d->sendIsComposingNotification(); - d->isComposingHandler.startRefreshTimer(); + d->isComposingHandler->startRefreshTimer(); } - d->isComposingHandler.startIdleTimer(); + d->isComposingHandler->startIdleTimer(); } shared_ptr ChatRoom::createFileTransferMessage (const LinphoneContent *initialContent) { @@ -588,31 +482,17 @@ shared_ptr ChatRoom::createMessage () { L_D(); shared_ptr chatMessage = ObjectFactory::create(getSharedFromThis()); chatMessage->setToAddress(d->peerAddress); - chatMessage->setFromAddress(Address(linphone_core_get_identity(d->core))); + chatMessage->setFromAddress(Address(linphone_core_get_identity(getCore()->getCCore()))); chatMessage->getPrivate()->setTime(ms_time(0)); return chatMessage; } void ChatRoom::deleteHistory () { - L_D(); - if (!d->core->db) return; - string peer = d->peerAddress.asStringUriOnly(); - char *buf = sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;", peer.c_str()); - d->sqlRequest(d->core->db, buf); - sqlite3_free(buf); - if (d->unreadCount > 0) d->unreadCount = 0; + // TODO: history. } void ChatRoom::deleteMessage (const shared_ptr &msg) { - L_D(); - if (!d->core->db) return; - char *buf = sqlite3_mprintf("DELETE FROM history WHERE id = %u;", msg->getPrivate()->getStorageId()); - d->sqlRequest(d->core->db, buf); - sqlite3_free(buf); - - /* Invalidate unread_count when we modify the database, so that next - time we need it it will be recomputed from latest database state */ - d->unreadCount = -1; + // TODO: history. } shared_ptr ChatRoom::findMessage (const string &messageId) { @@ -644,66 +524,19 @@ list > ChatRoom::getHistory (int nbMessages) { int ChatRoom::getHistorySize () { L_D(); - return d->getMessagesCount(false); + shared_ptr core = getCore(); + return core ? core->getPrivate()->mainDb->getChatMessagesCount(d->peerAddress.asStringUriOnly()) : 0; } list > ChatRoom::getHistoryRange (int startm, int endm) { - L_D(); - if (!d->core->db) return list >(); - string peer = d->peerAddress.asStringUriOnly(); - d->messages.clear(); - - /* Since we want to append query parameters depending on arguments given, we use malloc instead of sqlite3_mprintf */ - const int bufMaxSize = 512; - char *buf = reinterpret_cast(ms_malloc(bufMaxSize)); - buf = sqlite3_snprintf(bufMaxSize - 1, buf, "SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC", peer.c_str()); - - if (startm < 0) startm = 0; - if (((endm > 0) && (endm >= startm)) || ((startm == 0) && (endm == 0))) { - char *buf2 = ms_strdup_printf("%s LIMIT %i ", buf, endm + 1 - startm); - ms_free(buf); - buf = buf2; - } else if (startm > 0) { - lInfo() << __FUNCTION__ << "(): end is lower than start (" << endm << " < " << startm << "). Assuming no end limit."; - char *buf2 = ms_strdup_printf("%s LIMIT -1", buf); - ms_free(buf); - buf = buf2; - } - if (startm > 0) { - char *buf2 = ms_strdup_printf("%s OFFSET %i ", buf, startm); - ms_free(buf); - buf = buf2; - } - - uint64_t begin = ortp_get_cur_time_ms(); - d->sqlRequestMessage(d->core->db, buf); - uint64_t end = ortp_get_cur_time_ms(); - - if ((endm + 1 - startm) > 1) { - /* Display message only if at least 2 messages are loaded */ - lInfo() << __FUNCTION__ << "(): completed in " << (int)(end - begin) << " ms"; - } - ms_free(buf); - - if (!d->messages.empty()) { - /* Fill local addr with core identity instead of per message */ - for (auto &message : d->messages) { - if (message->getDirection() == ChatMessage::Direction::Outgoing) { - message->setFromAddress(Address(linphone_core_get_identity(d->core))); - } else { - message->setToAddress(Address(linphone_core_get_identity(d->core))); - } - } - } - - list > result = d->messages; - d->messages.clear(); - return result; + // TODO: history. + return list>(); } -int ChatRoom::getUnreadMessagesCount () { +int ChatRoom::getUnreadChatMessagesCount () { L_D(); - return d->getMessagesCount(true); + shared_ptr core = getCore(); + return core ? core->getPrivate()->mainDb->getUnreadChatMessagesCount(d->peerAddress.asStringUriOnly()) : 0; } bool ChatRoom::isRemoteComposing () const { @@ -714,36 +547,21 @@ bool ChatRoom::isRemoteComposing () const { void ChatRoom::markAsRead () { L_D(); - if (!d->core->db) return; + if (getUnreadChatMessagesCount() == 0) + return; - /* Optimization: do not modify the database if no message is marked as unread */ - if (getUnreadMessagesCount() == 0) return; + shared_ptr core = getCore(); + if (!core) + return; - string peer = d->peerAddress.asStringUriOnly(); - char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer.c_str(), ChatMessage::Direction::Incoming, ChatMessage::State::Displayed); - d->sqlRequestMessage(d->core->db, buf); - sqlite3_free(buf); - for (auto &message : d->messages) { - message->sendDisplayNotification(); - } - d->messages.clear(); - buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", ChatMessage::State::Displayed, peer.c_str(), ChatMessage::Direction::Incoming); - d->sqlRequest(d->core->db, buf); - sqlite3_free(buf); + CorePrivate *dCore = core->getPrivate(); + const string peerAddress = d->peerAddress.asStringUriOnly(); + list> chatMessages = dCore->mainDb->getUnreadChatMessages(peerAddress); - if (d->pendingMessage) { - d->pendingMessage->updateState(ChatMessage::State::Displayed); - d->pendingMessage->sendDisplayNotification(); - } + for (auto &chatMessage : chatMessages) + chatMessage->sendDisplayNotification(); - d->unreadCount = 0; -} - -// ----------------------------------------------------------------------------- - -LinphoneCore *ChatRoom::getCore () const { - L_D(); - return d->core; + dCore->mainDb->markChatMessagesAsRead(peerAddress); } // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-room/chat-room.h b/src/chat/chat-room/chat-room.h index b0e29e3ef..db5c1d4c8 100644 --- a/src/chat/chat-room/chat-room.h +++ b/src/chat/chat-room/chat-room.h @@ -22,6 +22,7 @@ #include "chat/chat-message/chat-message.h" #include "conference/conference-interface.h" +#include "core/core-accessor.h" // ============================================================================= @@ -29,7 +30,7 @@ LINPHONE_BEGIN_NAMESPACE class ChatRoomPrivate; -class LINPHONE_PUBLIC ChatRoom : public Object, public ConferenceInterface { +class LINPHONE_PUBLIC ChatRoom : public Object, public CoreAccessor, public ConferenceInterface { friend class Core; friend class CorePrivate; friend class ChatMessage; @@ -58,18 +59,18 @@ public: std::list> getHistory (int nbMessages); int getHistorySize (); std::list> getHistoryRange (int startm, int endm); - int getUnreadMessagesCount (); + int getUnreadChatMessagesCount (); bool isRemoteComposing () const; - void markAsRead (); - LinphoneCore *getCore () const; + virtual void markAsRead (); const Address &getPeerAddress () const; State getState () const; protected: + explicit ChatRoom (ChatRoomPrivate &p, const std::shared_ptr &core, const Address &address); + virtual void onChatMessageReceived (const std::shared_ptr &msg) = 0; - explicit ChatRoom (ChatRoomPrivate &p); private: L_DECLARE_PRIVATE(ChatRoom); diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index ef874027d..3eeb5ae47 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -29,8 +29,7 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: - ClientGroupChatRoomPrivate (LinphoneCore *core); - virtual ~ClientGroupChatRoomPrivate () = default; + ClientGroupChatRoomPrivate () = default; std::shared_ptr createSession (); void notifyReceived (std::string body); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index e47f34fba..7b0e25656 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -37,8 +37,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} - // ----------------------------------------------------------------------------- shared_ptr ClientGroupChatRoomPrivate::createSession () { @@ -68,11 +66,11 @@ void ClientGroupChatRoomPrivate::notifyReceived (string body) { // ============================================================================= ClientGroupChatRoom::ClientGroupChatRoom ( - LinphoneCore *core, + const std::shared_ptr &core, const Address &me, - const string &uri, - const string &subject -) : ChatRoom(*new ClientGroupChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { + const std::string &uri, + const std::string &subject +) : ChatRoom(*new ClientGroupChatRoomPrivate, core, me), RemoteConference(core->getCCore(), me, nullptr) { L_D_T(RemoteConference, dConference); dConference->focus = ObjectFactory::create(Address(uri)); RemoteConference::setSubject(subject); @@ -178,10 +176,11 @@ void ClientGroupChatRoom::leave () { } void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { - L_D(); - SalReferOp *referOp = new SalReferOp(d->core->sal); + LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + + SalReferOp *referOp = new SalReferOp(cCore->sal); LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); - linphone_configure_op(d->core, referOp, lAddr, nullptr, false); + linphone_configure_op(cCore, referOp, lAddr, nullptr, false); linphone_address_unref(lAddr); Address referToAddr = participant->getAddress(); referToAddr.setParam("text"); @@ -197,8 +196,6 @@ void ClientGroupChatRoom::removeParticipants (const list } void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { - L_D(); - if (isAdmin == participant->isAdmin()) return; @@ -207,9 +204,11 @@ void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &pa return; } - SalReferOp *referOp = new SalReferOp(d->core->sal); + LinphoneCore *cCore = CoreAccessor::getCore()->getCCore(); + + SalReferOp *referOp = new SalReferOp(cCore->sal); LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str()); - linphone_configure_op(d->core, referOp, lAddr, nullptr, false); + linphone_configure_op(cCore, referOp, lAddr, nullptr, false); linphone_address_unref(lAddr); Address referToAddr = participant->getAddress(); referToAddr.setParam("text"); @@ -246,7 +245,7 @@ void ClientGroupChatRoom::setSubject (const string &subject) { // ----------------------------------------------------------------------------- void ClientGroupChatRoom::onChatMessageReceived (const shared_ptr &msg) { - + } void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { @@ -254,9 +253,9 @@ void ClientGroupChatRoom::onConferenceCreated (const Address &addr) { L_D_T(RemoteConference, dConference); dConference->conferenceAddress = addr; d->peerAddress = addr; - d->core->cppCore->getPrivate()->insertChatRoom(getSharedFromThis()); + CoreAccessor::getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); d->setState(ChatRoom::State::Created); - d->core->cppCore->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); + CoreAccessor::getCore()->getPrivate()->insertChatRoomWithDb(getSharedFromThis()); } void ClientGroupChatRoom::onConferenceTerminated (const Address &addr) { diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index c5d9396b1..7ff063a27 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -31,8 +31,13 @@ class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: - ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &uri, const std::string &subject); - virtual ~ClientGroupChatRoom () = default; + // TODO: Make me private. + ClientGroupChatRoom ( + const std::shared_ptr &core, + const Address &me, + const std::string &uri, + const std::string &subject + ); CapabilitiesMask getCapabilities () const override; @@ -52,7 +57,7 @@ public: void setParticipantAdminStatus (std::shared_ptr &participant, bool isAdmin) override; void setSubject (const std::string &subject) override; -private: +protected: void onChatMessageReceived (const std::shared_ptr &msg) override; private: diff --git a/src/chat/chat-room/real-time-text-chat-room-p.h b/src/chat/chat-room/real-time-text-chat-room-p.h index e99f3b8ad..91c2a9cbb 100644 --- a/src/chat/chat-room/real-time-text-chat-room-p.h +++ b/src/chat/chat-room/real-time-text-chat-room-p.h @@ -29,8 +29,8 @@ LINPHONE_BEGIN_NAMESPACE class RealTimeTextChatRoomPrivate : public ChatRoomPrivate { public: - RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress); - virtual ~RealTimeTextChatRoomPrivate (); + RealTimeTextChatRoomPrivate () = default; + ~RealTimeTextChatRoomPrivate (); public: void setCall (LinphoneCall *call) { diff --git a/src/chat/chat-room/real-time-text-chat-room.cpp b/src/chat/chat-room/real-time-text-chat-room.cpp index ae302c82f..6c0dce359 100644 --- a/src/chat/chat-room/real-time-text-chat-room.cpp +++ b/src/chat/chat-room/real-time-text-chat-room.cpp @@ -20,6 +20,7 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-message/chat-message-p.h" #include "conference/participant.h" +#include "core/core.h" #include "logger/logger.h" #include "real-time-text-chat-room-p.h" @@ -29,11 +30,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -RealTimeTextChatRoomPrivate::RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) - : ChatRoomPrivate(core) { - this->peerAddress = peerAddress; -} - RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () { if (!receivedRttCharacters.empty()) { for (auto &rttChars : receivedRttCharacters) @@ -49,6 +45,9 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp const uint32_t crlf = 0x0D0A; const uint32_t lf = 0x0A; + shared_ptr core = q->getCore(); + LinphoneCore *cCore = core->getCCore(); + if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { LinphoneChatMessageCharacter *cmc = bctbx_new0(LinphoneChatMessageCharacter, 1); @@ -60,7 +59,7 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp receivedRttCharacters.push_back(cmc); remoteIsComposing.insert(peerAddress.asStringUriOnly()); - linphone_core_notify_is_composing_received(core, L_GET_C_BACK_PTR(q)); + linphone_core_notify_is_composing_received(cCore, L_GET_C_BACK_PTR(q)); if ((character == new_line) || (character == crlf) || (character == lf)) { /* End of message */ @@ -70,18 +69,15 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp Address( linphone_call_get_dest_proxy(call) ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address) - : linphone_core_get_identity(core) + : linphone_core_get_identity(cCore) ) ); pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered); pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming); - if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1) + if (lp_config_get_int(cCore->config, "misc", "store_rtt_messages", 1) == 1) storeOrUpdateMessage(pendingMessage); - if (unreadCount < 0) unreadCount = 1; - else unreadCount++; - chatMessageReceived(pendingMessage); pendingMessage = nullptr; for (auto &rttChars : receivedRttCharacters) @@ -106,8 +102,8 @@ void RealTimeTextChatRoomPrivate::sendMessage (const std::shared_ptr &core, const Address &peerAddress) : + ChatRoom(*new RealTimeTextChatRoomPrivate, core, peerAddress) {} int RealTimeTextChatRoom::getCapabilities () const { return static_cast(Capabilities::Basic) | static_cast(Capabilities::RealTimeText); @@ -133,6 +129,15 @@ LinphoneCall *RealTimeTextChatRoom::getCall () const { return d->call; } +void RealTimeTextChatRoom::markAsRead () { + L_D(); + ChatRoom::markAsRead(); + if (d->pendingMessage) { + d->pendingMessage->updateState(ChatMessage::State::Displayed); + d->pendingMessage->sendDisplayNotification(); + } +} + // ----------------------------------------------------------------------------- void RealTimeTextChatRoom::onChatMessageReceived(const shared_ptr &msg) {} diff --git a/src/chat/chat-room/real-time-text-chat-room.h b/src/chat/chat-room/real-time-text-chat-room.h index d480700e9..31a24b166 100644 --- a/src/chat/chat-room/real-time-text-chat-room.h +++ b/src/chat/chat-room/real-time-text-chat-room.h @@ -30,14 +30,16 @@ class RealTimeTextChatRoomPrivate; class LINPHONE_PUBLIC RealTimeTextChatRoom : public ChatRoom { public: - RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress); - virtual ~RealTimeTextChatRoom () = default; + // TODO: Make me private. + RealTimeTextChatRoom (const std::shared_ptr &core, const Address &peerAddress); CapabilitiesMask getCapabilities () const override; uint32_t getChar () const; LinphoneCall *getCall () const; + void markAsRead () override; + void onChatMessageReceived (const std::shared_ptr &msg) override; /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index 5df197179..d5c2e7bbc 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -35,8 +35,7 @@ class Participant; class ServerGroupChatRoomPrivate : public ChatRoomPrivate { public: - ServerGroupChatRoomPrivate (LinphoneCore *core); - virtual ~ServerGroupChatRoomPrivate () = default; + ServerGroupChatRoomPrivate () = default; std::shared_ptr addParticipant (const Address &addr); void confirmCreation (); diff --git a/src/chat/chat-room/server-group-chat-room-stub.cpp b/src/chat/chat-room/server-group-chat-room-stub.cpp index d392490a6..306051cd5 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "core/core.h" + #include "server-group-chat-room-p.h" // ============================================================================= @@ -25,8 +27,6 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ServerGroupChatRoomPrivate::ServerGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} - // ----------------------------------------------------------------------------- shared_ptr ServerGroupChatRoomPrivate::addParticipant (const Address &) { @@ -73,8 +73,9 @@ bool ServerGroupChatRoomPrivate::isAdminLeft () const { // ============================================================================= -ServerGroupChatRoom::ServerGroupChatRoom (LinphoneCore *core, SalCallOp *op) - : ChatRoom(*new ServerGroupChatRoomPrivate(core)), LocalConference(core, Address(op->get_to()), nullptr) {} +ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr &core, SalCallOp *op) : + ChatRoom(*new ServerGroupChatRoomPrivate, core, Address(op->get_to())), + LocalConference(core->getCCore(), Address(op->get_to()), nullptr) {} int ServerGroupChatRoom::getCapabilities () const { return 0; diff --git a/src/chat/chat-room/server-group-chat-room.h b/src/chat/chat-room/server-group-chat-room.h index 828e7917a..7f1c54eea 100644 --- a/src/chat/chat-room/server-group-chat-room.h +++ b/src/chat/chat-room/server-group-chat-room.h @@ -36,12 +36,10 @@ class ServerGroupChatRoomPrivate; class ServerGroupChatRoom : public ChatRoom, public LocalConference { public: - ServerGroupChatRoom (LinphoneCore *core, SalCallOp *op); - virtual ~ServerGroupChatRoom () = default; + ServerGroupChatRoom (const std::shared_ptr &core, SalCallOp *op); int getCapabilities () const override; -public: /* ConferenceInterface */ void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override; void addParticipants (const std::list
&addresses, const CallSessionParams *params, bool hasMedia) override; diff --git a/src/chat/modifier/encryption-chat-message-modifier.cpp b/src/chat/modifier/encryption-chat-message-modifier.cpp index e6887b35d..3bb3b28a0 100644 --- a/src/chat/modifier/encryption-chat-message-modifier.cpp +++ b/src/chat/modifier/encryption-chat-message-modifier.cpp @@ -23,6 +23,7 @@ #include "chat/chat-room/chat-room.h" #include "content/content-type.h" #include "content/content.h" +#include "core/core.h" #include "encryption-chat-message-modifier.h" @@ -37,7 +38,7 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::encode ( int &errorCode ) { shared_ptr chatRoom = message->getChatRoom(); - LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; + LinphoneImEncryptionEngine *imee = chatRoom->getCore()->getCCore()->im_encryption_engine; if (!imee) return ChatMessageModifier::Result::Skipped; @@ -70,7 +71,7 @@ ChatMessageModifier::Result EncryptionChatMessageModifier::decode ( int &errorCode ) { shared_ptr chatRoom = message->getChatRoom(); - LinphoneImEncryptionEngine *imee = chatRoom->getCore()->im_encryption_engine; + LinphoneImEncryptionEngine *imee = chatRoom->getCore()->getCCore()->im_encryption_engine; if (!imee) return ChatMessageModifier::Result::Skipped; diff --git a/src/chat/modifier/multipart-chat-message-modifier.cpp b/src/chat/modifier/multipart-chat-message-modifier.cpp index 10eb02133..7ccdff1e1 100644 --- a/src/chat/modifier/multipart-chat-message-modifier.cpp +++ b/src/chat/modifier/multipart-chat-message-modifier.cpp @@ -25,6 +25,7 @@ #include "chat/chat-room/chat-room.h" #include "content/content-type.h" #include "logger/logger.h" +#include "core/core.h" #include "multipart-chat-message-modifier.h" @@ -41,7 +42,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode ( if (message->getContents().size() <= 1) return ChatMessageModifier::Result::Skipped; - LinphoneCore *lc = message->getChatRoom()->getCore(); + LinphoneCore *lc = message->getChatRoom()->getCore()->getCCore(); char tmp[64]; lc->sal->create_uuid(tmp, sizeof(tmp)); string boundary = tmp; diff --git a/src/chat/notification/imdn.cpp b/src/chat/notification/imdn.cpp index 8a63b1966..4fc01dbc6 100644 --- a/src/chat/notification/imdn.cpp +++ b/src/chat/notification/imdn.cpp @@ -17,11 +17,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "logger/logger.h" - #include "chat/chat-message/chat-message.h" #include "chat/chat-room/chat-room.h" -#include "chat/notification/imdn.h" +#include "core/core.h" +#include "logger/logger.h" + +#include "imdn.h" // ============================================================================= @@ -66,7 +67,7 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) { if (!cm) { lWarning() << "Received IMDN for unknown message " << messageIdStr; } else { - LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr.getCore()); + LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr.getCore()->getCCore()); snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:delivery-notification/imdn:status", imdnPrefix.c_str()); xmlXPathObjectPtr deliveryStatusObject = linphone_get_xml_xpath_object_for_node_list(xmlCtx, xpathStr); snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:display-notification/imdn:status", imdnPrefix.c_str()); diff --git a/src/core/core-accessor.cpp b/src/core/core-accessor.cpp new file mode 100644 index 000000000..676847cfa --- /dev/null +++ b/src/core/core-accessor.cpp @@ -0,0 +1,58 @@ +/* + * core-accessor.cpp + * Copyright (C) 2010-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "logger/logger.h" + +#include "core-accessor.h" + +// ============================================================================= + +using namespace std; + +LINPHONE_BEGIN_NAMESPACE + +class CoreAccessorPrivate { +public: + weak_ptr core; +}; + +// ----------------------------------------------------------------------------- + +CoreAccessor::CoreAccessor (const shared_ptr &core) { + L_D(); + d->core = core; +} + +CoreAccessor::CoreAccessor (const shared_ptr &&core) { + L_D(); + d->core = move(core); +} + +CoreAccessor::~CoreAccessor () {} + +shared_ptr CoreAccessor::getCore () const { + L_D(); + + shared_ptr core = d->core.lock(); + if (!core) + lWarning() << "Unable to get valid core instance."; + return core; +} + +LINPHONE_END_NAMESPACE diff --git a/src/core/core-accessor.h b/src/core/core-accessor.h new file mode 100644 index 000000000..0608b1983 --- /dev/null +++ b/src/core/core-accessor.h @@ -0,0 +1,52 @@ +/* + * core-accessor.h + * Copyright (C) 2010-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CORE_ACCESSOR_H_ +#define _CORE_ACCESSOR_H_ + +#include + +#include "linphone/utils/general.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class Core; +class CoreAccessorPrivate; + +class CoreAccessor { +public: + CoreAccessor (const std::shared_ptr &core); + CoreAccessor (const std::shared_ptr &&core); + + virtual ~CoreAccessor () = 0; + + std::shared_ptr getCore () const; + +private: + CoreAccessorPrivate *mPrivate = nullptr; + + L_DISABLE_COPY(CoreAccessor); + L_DECLARE_PRIVATE(CoreAccessor); +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CORE_ACCESSOR_H_ diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 3e8e668c9..63fd95a85 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -58,12 +58,14 @@ static inline string resolveWorkaroundClientGroupChatRoomAddress ( // ----------------------------------------------------------------------------- shared_ptr CorePrivate::createChatRoom (const Address &peerAddress, bool isRtt) { + L_Q(); + shared_ptr chatRoom; if (isRtt) - chatRoom = ObjectFactory::create(cCore, peerAddress); + chatRoom = ObjectFactory::create(q->getSharedFromThis(), peerAddress); else - chatRoom = ObjectFactory::create(cCore, peerAddress); + chatRoom = ObjectFactory::create(q->getSharedFromThis(), peerAddress); ChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); insertChatRoom(chatRoom); @@ -188,7 +190,7 @@ shared_ptr Core::getOrCreateBasicChatRoom (const string &peerAddress, } void Core::deleteChatRoom (const shared_ptr &chatRoom) { - CorePrivate *d = chatRoom->getCore()->cppCore->getPrivate(); + CorePrivate *d = chatRoom->getCore()->getPrivate(); const Address cleanedPeerAddress = getCleanedPeerAddress(chatRoom->getPeerAddress()); d->deleteChatRoomWithDb( chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference) diff --git a/src/core/core.cpp b/src/core/core.cpp index 152276c9a..a554ab223 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -56,6 +56,11 @@ Core::Core (LinphoneCore *cCore) : Object(*new CorePrivate) { d->insertChatRoom(chatRoom); } +LinphoneCore *Core::getCCore () const { + L_D(); + return d->cCore; +} + string Core::getDataPath() const { L_D(); return Paths::getPath(Paths::Data, static_cast(d->cCore->platform_helper)); diff --git a/src/core/core.h b/src/core/core.h index 8a2cd3aa8..80f94a04c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -35,6 +35,7 @@ class ChatRoom; class CorePrivate; class LINPHONE_PUBLIC Core : public Object { + friend class ChatRoom; friend class ClientGroupChatRoom; friend class MainDb; @@ -43,6 +44,13 @@ public: Core (LinphoneCore *cCore); + // --------------------------------------------------------------------------- + // C-Core. + // --------------------------------------------------------------------------- + + // TODO: Remove me later. + LinphoneCore *getCCore () const; + // --------------------------------------------------------------------------- // Paths. // --------------------------------------------------------------------------- diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index e1bd72e3e..ee45b2af5 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -286,8 +286,24 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { time_t date, const string &peerAddress ) const { - // TODO. - return nullptr; + soci::session *session = dbSession.getBackendSession(); + *session << "SELECT event_id, type, date, local_sip_address.value, " + "remote_sip_address.value, imdn_message_id, state, direction, is_secured" + " FROM event, conference_chat_message_event, sip_address AS local_sip_address," + " sip_address AS remote_sip_address" + " WHERE event_id = event.id" + " AND local_sip_address_id = local_sip_address.id" + " AND remote_sip_address_id = remote_sip_address.id" + " AND remote_sip_address.value = :peerAddress", soci::use(peerAddress); + + // TODO: Create me. + shared_ptr chatMessage; + + // TODO: Use cache. + return make_shared( + date, + chatMessage + ); } shared_ptr MainDbPrivate::selectConferenceParticipantEvent ( @@ -889,7 +905,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return events; } - int MainDb::getMessagesCount (const string &peerAddress) const { + int MainDb::getChatMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { @@ -921,7 +937,7 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return count; } - int MainDb::getUnreadMessagesCount (const string &peerAddress) const { + int MainDb::getUnreadChatMessagesCount (const string &peerAddress) const { L_D(); if (!isConnected()) { @@ -956,6 +972,45 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return count; } + void MainDb::markChatMessagesAsRead (const string &peerAddress) const { + L_D(); + + if (!isConnected()) { + lWarning() << "Unable to mark messages as read. Not connected."; + return; + } + + if (getUnreadChatMessagesCount(peerAddress) == 0) + return; + + string query = "UPDATE FROM conference_chat_message_event" + " SET state = " + Utils::toString(static_cast(ChatMessage::State::Displayed)); + query += "WHERE"; + if (!peerAddress.empty()) + query += " event_id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = (" + " SELECT id FROM sip_address WHERE value = :peerAddress" + " )" + ") AND"; + query += " direction = " + Utils::toString(static_cast(ChatMessage::Direction::Incoming)); + + L_BEGIN_LOG_EXCEPTION + + soci::session *session = d->dbSession.getBackendSession(); + + if (peerAddress.empty()) + *session << query; + else + *session << query, soci::use(peerAddress); + + L_END_LOG_EXCEPTION + } + + list> MainDb::getUnreadChatMessages (const std::string &peerAddress) const { + // TODO. + return list>(); + } + list> MainDb::getHistory (const string &peerAddress, int nLast, FilterMask mask) const { return getHistoryRange(peerAddress, 0, nLast - 1, mask); } @@ -1080,6 +1135,13 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { soci::rowset rows = (session->prepare << query); for (const auto &row : rows) { string sipAddress = row.get(0); + shared_ptr chatRoom = d->core->findChatRoom(Address(sipAddress)); + if (chatRoom) { + lInfo() << "Don't fetch chat room from database: `" << sipAddress << "`, it already exists."; + chatRooms.push_back(chatRoom); + continue; + } + tm creationDate = row.get(1); tm lastUpdateDate = row.get(2); int capabilities = row.get(3); @@ -1092,7 +1154,6 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { (void)subject; (void)lastNotifyId; - shared_ptr chatRoom; if (capabilities & static_cast(ChatRoom::Capabilities::Basic)) { chatRoom = d->core ? d->core->getPrivate()->createChatRoom( Address(sipAddress), @@ -1121,11 +1182,19 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return; } + L_BEGIN_LOG_EXCEPTION + + soci::transaction tr(*d->dbSession.getBackendSession()); + d->insertChatRoom( d->insertSipAddress(peerAddress), capabilities, Utils::getTimeTAsTm(time(0)) ); + + tr.commit(); + + L_END_LOG_EXCEPTION } void MainDb::deleteChatRoom (const string &peerAddress) { @@ -1326,14 +1395,20 @@ MainDb::MainDb (Core *core) : AbstractDb(*new MainDbPrivate) { return list>(); } - int MainDb::getMessagesCount (const string &) const { + int MainDb::getChatMessagesCount (const string &) const { return 0; } - int MainDb::getUnreadMessagesCount (const string &) const { + int MainDb::getUnreadChatMessagesCount (const string &) const { return 0; } + void MainDb::markChatMessagesAsRead (const string &) const {} + + list> MainDb::getUnreadChatMessages (const std::string &) const { + return list>(); + } + list> MainDb::getHistory (const string &, int, FilterMask) const { return list>(); } diff --git a/src/db/main-db.h b/src/db/main-db.h index 200d70999..161e6c66f 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -28,14 +28,13 @@ LINPHONE_BEGIN_NAMESPACE +class ChatMessage; class ChatRoom; class Core; class EventLog; class MainDbPrivate; class LINPHONE_PUBLIC MainDb : public AbstractDb { - friend class ChatRoomProvider; - public: enum Filter { NoFilter = 0x0, @@ -48,20 +47,37 @@ public: MainDb (Core *core); + // --------------------------------------------------------------------------- // Generic. + // --------------------------------------------------------------------------- + bool addEvent (const std::shared_ptr &eventLog); bool deleteEvent (const std::shared_ptr &eventLog); void cleanEvents (FilterMask mask = NoFilter); int getEventsCount (FilterMask mask = NoFilter) const; - // Messages, calls and conferences. + // --------------------------------------------------------------------------- + // Conference notified events. + // --------------------------------------------------------------------------- + std::list> getConferenceNotifiedEvents ( const std::string &peerAddress, unsigned int lastNotifyId ); - int getMessagesCount (const std::string &peerAddress = "") const; - int getUnreadMessagesCount (const std::string &peerAddress = "") const; + // --------------------------------------------------------------------------- + // Conference chat message events. + // --------------------------------------------------------------------------- + + int getChatMessagesCount (const std::string &peerAddress = "") const; + int getUnreadChatMessagesCount (const std::string &peerAddress = "") const; + void markChatMessagesAsRead (const std::string &peerAddress = "") const; + std::list> getUnreadChatMessages (const std::string &peerAddress = "") const; + + // --------------------------------------------------------------------------- + // Conference events. + // --------------------------------------------------------------------------- + std::list> getHistory ( const std::string &peerAddress, int nLast, @@ -75,11 +91,18 @@ public: ) const; void cleanHistory (const std::string &peerAddress = "", FilterMask mask = NoFilter); - // ChatRooms. + // --------------------------------------------------------------------------- + // Chat rooms. + // --------------------------------------------------------------------------- + std::list> getChatRooms () const; void insertChatRoom (const std::string &peerAddress, int capabilities); void deleteChatRoom (const std::string &peerAddress); + // --------------------------------------------------------------------------- + // Other. + // --------------------------------------------------------------------------- + // Import legacy messages from old db. bool import (Backend backend, const std::string ¶meters) override; diff --git a/src/db/session/db-session-provider.cpp b/src/db/session/db-session-provider.cpp index da1c9f270..6ce81babe 100644 --- a/src/db/session/db-session-provider.cpp +++ b/src/db/session/db-session-provider.cpp @@ -27,59 +27,31 @@ #include "db-session-provider.h" -#define CLEAN_COUNTER_MAX 1000 - // ============================================================================= using namespace std; LINPHONE_BEGIN_NAMESPACE -class DbSessionProviderPrivate : public ObjectPrivate { -public: - typedef pair, DbSessionPrivate *> InternalSession; - unordered_map sessions; - int cleanCounter = 0; -}; - -DbSessionProvider::DbSessionProvider () : Singleton(*new DbSessionProviderPrivate) {} +DbSessionProvider::DbSessionProvider () : Singleton(*new ObjectPrivate) {} DbSession DbSessionProvider::getSession (const string &uri) { - L_D(); + DbSession session(DbSession::None); #ifdef SOCI_ENABLED - DbSession session(DbSession::Soci); try { - shared_ptr backendSession = d->sessions[uri].first.lock(); - ++d->cleanCounter; - if (!backendSession) { // Create new session. - backendSession = make_shared(uri); - DbSessionPrivate *p = session.getPrivate(); - p->backendSession = backendSession; - p->isValid = true; - d->sessions[uri] = make_pair(backendSession, p); - } else // Share session. - session.setRef(*d->sessions[uri].second); + session = DbSession(DbSession::Soci); + DbSessionPrivate *p = session.getPrivate(); + p->backendSession = make_shared(uri); + p->isValid = true; } catch (const exception &e) { + session = DbSession(DbSession::None); lWarning() << "Unable to get db session: " << e.what(); } #else - DbSession session(DbSession::None); lWarning() << "Unable to get db session: soci not enabled."; #endif // ifdef SOCI_ENABLED - // Remove invalid weak ptrs. - if (d->cleanCounter >= CLEAN_COUNTER_MAX) { - d->cleanCounter = 0; - - for (auto it = d->sessions.begin(), itEnd = d->sessions.end(); it != itEnd;) { - if (it->second.first.expired()) - it = d->sessions.erase(it); - else - ++it; - } - } - return session; } diff --git a/src/db/session/db-session-provider.h b/src/db/session/db-session-provider.h index 82a41c739..f471a7db0 100644 --- a/src/db/session/db-session-provider.h +++ b/src/db/session/db-session-provider.h @@ -38,7 +38,6 @@ public: private: DbSessionProvider (); - L_DECLARE_PRIVATE(DbSessionProvider); L_DISABLE_COPY(DbSessionProvider); }; diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 3e58928c1..7f280fd10 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -196,7 +196,7 @@ set(SOURCE_FILES_C set(SOURCE_FILES_CXX clonable-object-tester.cpp - conference-event-tester.cpp + #conference-event-tester.cpp conference-tester.cpp content-manager-tester.cpp cpim-tester.cpp diff --git a/tester/cpim-tester.cpp b/tester/cpim-tester.cpp index 2b486a58f..ab0a11d2c 100644 --- a/tester/cpim-tester.cpp +++ b/tester/cpim-tester.cpp @@ -22,6 +22,10 @@ #include "chat/cpim/cpim.h" #include "content/content-type.h" #include "content/content.h" +#include "core/core.h" + +// TODO: Remove me later. +#include "private.h" #include "liblinphone_tester.h" @@ -391,7 +395,7 @@ static void cpim_chat_message_modifier_base(bool_t use_multipart) { lp_config_set_int(config, "sip", "use_cpim", 1); Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = ObjectFactory::create(marie->lc, paulineAddress); + shared_ptr marieRoom = ObjectFactory::create(marie->lc->cppCore, paulineAddress); shared_ptr marieMessage = marieRoom->createMessage("Hello CPIM"); if (use_multipart) { diff --git a/tester/main-db-tester.cpp b/tester/main-db-tester.cpp index 714ce9e2c..495671421 100644 --- a/tester/main-db-tester.cpp +++ b/tester/main-db-tester.cpp @@ -55,15 +55,15 @@ static void get_events_count () { static void get_messages_count () { MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(mainDb.getMessagesCount(), 4976, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getChatMessagesCount(), 4976, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getChatMessagesCount("sip:test-39@sip.linphone.org"), 3, int, "%d"); } static void get_unread_messages_count () { MainDb mainDb(nullptr); BC_ASSERT_TRUE(mainDb.connect(MainDb::Sqlite3, getDatabasePath())); - BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount(), 2, int, "%d"); - BC_ASSERT_EQUAL(mainDb.getUnreadMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount(), 2, int, "%d"); + BC_ASSERT_EQUAL(mainDb.getUnreadChatMessagesCount("sip:test-39@sip.linphone.org"), 0, int, "%d"); } static void get_history () { diff --git a/tester/message_tester.c b/tester/message_tester.c index 98c7a1f83..62efe5b44 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -1575,156 +1575,6 @@ void history_message_count_helper(LinphoneChatRoom* chatroom, int x, int y, unsi bctbx_list_free_with_data(messages, (void (*)(void *))linphone_chat_message_unref); } -static void database_migration(void) { - LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); - char *src_db = bc_tester_res("messages.db"); - char *tmp_db = bc_tester_file("tmp.db"); - const bctbx_list_t* chatrooms; - LinphoneChatRoom *cr; - - BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); - - // enable to test the performances of the migration step - //linphone_core_message_storage_set_debug(marie->lc, TRUE); - - // the messages.db has 10000 dummy messages with the very first DB scheme. - // This will test the migration procedure - linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - if (!linphone_core_get_sqlite_database(marie->lc)) goto end; - - chatrooms = linphone_core_get_chat_rooms(marie->lc); - BC_ASSERT(bctbx_list_size(chatrooms) > 0); - - // check that all messages have been migrated to the UTC time storage - BC_ASSERT(sqlite3_exec(linphone_core_get_sqlite_database(marie->lc), "SELECT COUNT(*) FROM history WHERE time != '-1';", check_no_strange_time, NULL, NULL) == SQLITE_OK); - - // check that the read messages (field read=1) has been migrated to the LinphoneChatMessageStateDisplayed state - cr = linphone_core_get_chat_room_from_uri(marie->lc, "sip:Marielle@sip.linphone.org"); - BC_ASSERT_EQUAL(linphone_chat_room_get_unread_messages_count(cr), 8, int, "%i"); - -end: - linphone_core_manager_destroy(marie); - remove(tmp_db); - bc_free(src_db); - bc_free(tmp_db); -} - -static void history_range(void){ - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneAddress *jehan_addr = linphone_address_new(""); - LinphoneChatRoom *chatroom; - char *src_db = bc_tester_res("messages.db"); - char *tmp_db = bc_tester_file("tmp.db"); - - BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); - - linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - if (!linphone_core_get_sqlite_database(marie->lc)) goto end; - - chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); - BC_ASSERT_PTR_NOT_NULL(chatroom); - if (chatroom){ - // We have 20 tests to perform to fully qualify the function, here they are: - history_message_count_helper(chatroom, 0, 0, 1); - history_message_count_helper(chatroom, -1, 0, 1); - history_message_count_helper(chatroom, 0, -1, 1270); - history_message_count_helper(chatroom, 1, 3, 3); - history_message_count_helper(chatroom, 3, 1, 1270-3); - history_message_count_helper(chatroom, 10, 10, 1); - history_message_count_helper(chatroom, -1, -1, 1270); - history_message_count_helper(chatroom, -1, -2, 1270); - history_message_count_helper(chatroom, -2, -1, 1270); - history_message_count_helper(chatroom, 3, -1, 1270-3); - history_message_count_helper(chatroom, 1, -3, 1270-1); - history_message_count_helper(chatroom, 2, -2, 1270-2); - history_message_count_helper(chatroom, 2, 0, 1270-2); - history_message_count_helper(chatroom, 0, 2, 3); - history_message_count_helper(chatroom, -1, 3, 4); - history_message_count_helper(chatroom, -2, 2, 3); - history_message_count_helper(chatroom, -3, 1, 2); - } - -end: - linphone_core_manager_destroy(marie); - linphone_address_unref(jehan_addr); - remove(tmp_db); - bc_free(src_db); - bc_free(tmp_db); -} - -static void history_count(void) { - LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); - LinphoneAddress *jehan_addr = linphone_address_new(""); - LinphoneChatRoom *chatroom; - bctbx_list_t *messages; - char *src_db = bc_tester_res("messages.db"); - char *tmp_db = bc_tester_file("tmp.db"); - - BC_ASSERT_EQUAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d"); - - linphone_core_set_chat_database_path(marie->lc, tmp_db); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - if (!linphone_core_get_sqlite_database(marie->lc)) goto end; - - chatroom = linphone_core_get_chat_room(marie->lc, jehan_addr); - BC_ASSERT_PTR_NOT_NULL(chatroom); - if (chatroom){ - messages=linphone_chat_room_get_history(chatroom,10); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 10, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - messages=linphone_chat_room_get_history(chatroom,1); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - messages=linphone_chat_room_get_history(chatroom,0); - BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(chatroom), 1270, int, "%d"); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1270, unsigned int, "%u"); - - /*check the second most recent msg*/ - BC_ASSERT_PTR_NOT_NULL(messages); - if (messages){ - BC_ASSERT_PTR_NOT_NULL(messages->next->data); - if (messages->next->data){ - BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text((LinphoneChatMessage *)messages->next->data), "Fore and aft follow each other."); - } - } - - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test offset+limit: retrieve the 42th latest msg only and check its content*/ - messages=linphone_chat_room_get_history_range(chatroom, 42, 42); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1, unsigned int, "%u"); - BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text((LinphoneChatMessage *)messages->data), "If you open yourself to the Tao is intangible and evasive, yet prefers to keep us at the mercy of the kingdom, then all of the streams of hundreds of valleys because of its limitless possibilities."); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test offset without limit*/ - messages = linphone_chat_room_get_history_range(chatroom, 1265, -1); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1270-1265, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test limit without offset*/ - messages = linphone_chat_room_get_history_range(chatroom, 0, 5); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 6, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - - /*test invalid start*/ - messages = linphone_chat_room_get_history_range(chatroom, 1265, 1260); - BC_ASSERT_EQUAL((unsigned int)bctbx_list_size(messages), 1270-1265, unsigned int, "%u"); - bctbx_list_free_with_data(messages, (void (*)(void*))linphone_chat_message_unref); - } - -end: - linphone_core_manager_destroy(marie); - linphone_address_unref(jehan_addr); - remove(tmp_db); - bc_free(src_db); - bc_free(tmp_db); -} - - void crash_during_file_transfer(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); @@ -1847,10 +1697,6 @@ static void real_time_text(bool_t audio_stream_enabled, bool_t srtp_enabled, boo if (sql_storage) { linphone_core_set_chat_database_path(marie->lc, marie_db); linphone_core_set_chat_database_path(pauline->lc, pauline_db); -#ifdef SQLITE_STORAGE_ENABLED - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(marie->lc)); - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_sqlite_database(pauline->lc)); -#endif if (do_not_store_rtt_messages_in_sql_storage) { lp_config_set_int(linphone_core_get_config(marie->lc), "misc", "store_rtt_messages", 0); @@ -2506,9 +2352,6 @@ test_t message_tests[] = { TEST_ONE_TAG("Lime transfer message without encryption 2", lime_transfer_message_without_encryption_2, "LIME"), TEST_ONE_TAG("Lime cache migration", lime_cache_migration, "LIME"), TEST_ONE_TAG("Lime unitary", lime_unit, "LIME"), - TEST_NO_TAG("Database migration", database_migration), - TEST_NO_TAG("History range", history_range), - TEST_NO_TAG("History count", history_count), #endif TEST_NO_TAG("Transfer not sent if invalid url", file_transfer_not_sent_if_invalid_url), TEST_NO_TAG("Transfer not sent if host not found", file_transfer_not_sent_if_host_not_found), diff --git a/tester/multipart-tester.cpp b/tester/multipart-tester.cpp index 677b5f62d..4e781281d 100644 --- a/tester/multipart-tester.cpp +++ b/tester/multipart-tester.cpp @@ -21,6 +21,10 @@ #include "chat/chat-room/basic-chat-room.h" #include "content/content-type.h" #include "content/content.h" +#include "core/core.h" + +// TODO: Remove me later. +#include "private.h" #include "liblinphone_tester.h" @@ -32,10 +36,10 @@ using namespace LinphonePrivate; static void chat_message_multipart_modifier_base(bool first_file_transfer, bool second_file_transfer, bool use_cpim) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); Address paulineAddress(linphone_address_as_string_uri_only(pauline->identity)); - shared_ptr marieRoom = ObjectFactory::create(marie->lc, paulineAddress); + shared_ptr marieRoom = ObjectFactory::create(marie->lc->cppCore, paulineAddress); shared_ptr marieMessage; if (first_file_transfer) { @@ -55,7 +59,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool linphone_content_set_type(initialContent,"video"); linphone_content_set_subtype(initialContent,"mkv"); linphone_content_set_name(initialContent,"sintel_trailer_opus_h264.mkv"); - + Content content; content.setContentType(ContentType::FileTransfer); content.setBody(linphone_content_get_string_buffer(initialContent)); diff --git a/tester/tester.c b/tester/tester.c index 48708461e..ca41f129a 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -563,7 +563,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&account_creator_test_suite); bc_tester_add_suite(&stun_test_suite); bc_tester_add_suite(&event_test_suite); - bc_tester_add_suite(&conference_event_test_suite); + //bc_tester_add_suite(&conference_event_test_suite); bc_tester_add_suite(&conference_test_suite); bc_tester_add_suite(&content_manager_test_suite); bc_tester_add_suite(&flexisip_test_suite);