From 5ff2076896c106da0e33a824f1afd4fb7c2d9d04 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Dec 2017 16:51:04 +0100 Subject: [PATCH] Handle basic to client group chat room migration. --- coreapi/tester_utils.cpp | 7 +- coreapi/tester_utils.h | 2 + include/linphone/enums/chat-room-enums.h | 3 +- src/chat/chat-message/chat-message-p.h | 2 + src/chat/chat-message/chat-message.cpp | 22 ++-- src/chat/chat-message/chat-message.h | 2 + .../basic-to-client-group-chat-room.cpp | 82 +++++++++++++- .../basic-to-client-group-chat-room.h | 6 + src/chat/chat-room/client-group-chat-room.cpp | 11 ++ src/chat/chat-room/client-group-chat-room.h | 3 + src/core/core-chat-room.cpp | 59 +++++++--- src/core/core-p.h | 5 +- src/core/core.h | 2 + src/db/main-db.cpp | 35 +++++- src/db/main-db.h | 1 + tester/group_chat_tester.c | 86 ++++++++++++++- tester/liblinphone_tester.h | 8 +- tester/tester.c | 104 +++++++++--------- 18 files changed, 347 insertions(+), 93 deletions(-) diff --git a/coreapi/tester_utils.cpp b/coreapi/tester_utils.cpp index 0c48bad75..ffa63a644 100644 --- a/coreapi/tester_utils.cpp +++ b/coreapi/tester_utils.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "call/call-p.h" #include "chat/chat-room/chat-room.h" -#include "core/core.h" +#include "core/core-p.h" #include "c-wrapper/c-wrapper.h" #include "conference/session/media-session-p.h" @@ -154,3 +154,8 @@ int _linphone_call_get_main_video_stream_index (const LinphoneCall *call) { return L_GET_PRIVATE(static_pointer_cast( L_GET_PRIVATE_FROM_C_OBJECT(call)->getActiveSession()))->getMainVideoStreamIndex(); } + +void _linphone_chat_room_enable_migration(LinphoneChatRoom *cr, bool_t enable) { + shared_ptr acr = L_GET_CPP_PTR_FROM_C_OBJECT(cr); + L_GET_PRIVATE(acr->getCore())->mainDb->enableChatRoomMigration(acr->getChatRoomId(), !!enable); +} diff --git a/coreapi/tester_utils.h b/coreapi/tester_utils.h index f65d62c62..f6d836b5f 100644 --- a/coreapi/tester_utils.h +++ b/coreapi/tester_utils.h @@ -103,6 +103,8 @@ LINPHONE_PUBLIC mblk_t *_linphone_call_stats_get_received_rtcp (const LinphoneCa LINPHONE_PUBLIC LinphoneQualityReporting *linphone_call_log_get_quality_reporting(LinphoneCallLog *call_log); LINPHONE_PUBLIC reporting_session_report_t **linphone_quality_reporting_get_reports(LinphoneQualityReporting *qreporting); +LINPHONE_PUBLIC void _linphone_chat_room_enable_migration(LinphoneChatRoom *cr, bool_t enable); + LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list); LINPHONE_PUBLIC MSList* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_friend_invalidate_subscription(LinphoneFriend *lf); diff --git a/include/linphone/enums/chat-room-enums.h b/include/linphone/enums/chat-room-enums.h index d0fccb39e..dcbf96a87 100644 --- a/include/linphone/enums/chat-room-enums.h +++ b/include/linphone/enums/chat-room-enums.h @@ -35,6 +35,7 @@ F(Basic, 1 << 0) \ F(RealTimeText, 1 << 1) \ F(Conference, 1 << 2) \ - F(Proxy, 1 << 3) + F(Proxy, 1 << 3) \ + F(Migratable, 1 << 4) #endif // ifndef _CHAT_ROOM_ENUMS_H_ diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index 15839f9db..74ca0ade7 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -90,6 +90,8 @@ public: void loadFileTransferUrlFromBodyToContent(); + void setChatRoom (const std::shared_ptr &chatRoom); + // ----------------------------------------------------------------------------- // Deprecated methods only used for C wrapper, to be removed some day... // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index b2fc886a6..cd6a94f94 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -312,6 +312,18 @@ void ChatMessagePrivate::loadFileTransferUrlFromBodyToContent() { fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode); } +void ChatMessagePrivate::setChatRoom (const shared_ptr &cr) { + chatRoom = cr; + chatRoomId = cr->getChatRoomId(); + if (direction == ChatMessage::Direction::Outgoing) { + fromAddress = chatRoomId.getLocalAddress(); + toAddress = chatRoomId.getPeerAddress(); + } else { + fromAddress = chatRoomId.getPeerAddress(); + toAddress = chatRoomId.getLocalAddress(); + } +} + // ----------------------------------------------------------------------------- void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) { @@ -672,16 +684,8 @@ ChatMessage::ChatMessage (const shared_ptr &chatRoom, ChatMess Object(*new ChatMessagePrivate), CoreAccessor(chatRoom->getCore()) { L_D(); - d->chatRoom = chatRoom; - d->chatRoomId = chatRoom->getChatRoomId(); - if (direction == Direction::Outgoing) { - d->fromAddress = d->chatRoomId.getLocalAddress(); - d->toAddress = d->chatRoomId.getPeerAddress(); - } else { - d->fromAddress = d->chatRoomId.getPeerAddress(); - d->toAddress = d->chatRoomId.getLocalAddress(); - } d->direction = direction; + d->setChatRoom(chatRoom); } ChatMessage::~ChatMessage () { diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 625ca702d..6bef88c26 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -41,6 +41,8 @@ class FileTransferContent; class ChatMessagePrivate; class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor { + friend class BasicToClientGroupChatRoom; + friend class BasicToClientGroupChatRoomPrivate; friend class ChatRoom; friend class ChatRoomPrivate; friend class CpimChatMessageModifier; diff --git a/src/chat/chat-room/basic-to-client-group-chat-room.cpp b/src/chat/chat-room/basic-to-client-group-chat-room.cpp index 2667a4630..17b4f81b5 100644 --- a/src/chat/chat-room/basic-to-client-group-chat-room.cpp +++ b/src/chat/chat-room/basic-to-client-group-chat-room.cpp @@ -19,6 +19,12 @@ #include "basic-to-client-group-chat-room.h" #include "proxy-chat-room-p.h" +#include "client-group-chat-room-p.h" +#include "chat/chat-message/chat-message-p.h" +#include "conference/participant.h" +#include "conference/session/call-session.h" +#include "core/core-p.h" +#include "c-wrapper/c-wrapper.h" // ============================================================================= @@ -30,15 +36,53 @@ LINPHONE_BEGIN_NAMESPACE class BasicToClientGroupChatRoomPrivate : public ProxyChatRoomPrivate { public: - inline void sendChatMessage (const shared_ptr &chatMessage) override { - ProxyChatRoomPrivate::sendChatMessage(chatMessage); - // TODO: Try migration. + void onChatRoomInsertRequested (const shared_ptr &chatRoom) override { + L_Q(); + // Insert the client group chat room temporarily + q->getCore()->getPrivate()->insertChatRoom(chatRoom); } - inline void onChatMessageReceived (const shared_ptr &chatMessage) override { - ProxyChatRoomPrivate::onChatMessageReceived(chatMessage); - // TODO: Try migration. + void onChatRoomInsertInDatabaseRequested (const shared_ptr &chatRoom) override { + // Do not insert the client group chat room in database, the migration will do it } + + void sendChatMessage (const shared_ptr &chatMessage) override { + ProxyChatRoomPrivate::sendChatMessage(chatMessage); + if (!linphone_core_get_conference_factory_uri(chatMessage->getCore()->getCCore()) + || (chatRoom->getCapabilities() & ChatRoom::Capabilities::Conference) + || clientGroupChatRoom + ) { + return; + } + clientGroupChatRoom = static_pointer_cast( + chatRoom->getCore()->getPrivate()->createClientGroupChatRoom(chatRoom->getSubject(), false) + ); + clientGroupChatRoom->getPrivate()->setCallSessionListener(this); + clientGroupChatRoom->getPrivate()->setChatRoomListener(this); + clientGroupChatRoom->addParticipant(chatRoom->getPeerAddress(), nullptr, false); + } + + void onCallSessionStateChanged ( + const shared_ptr &session, + LinphoneCallState newState, + const string &message + ) override { + if (!clientGroupChatRoom) + return; + if ((newState == LinphoneCallError) && (clientGroupChatRoom->getState() == ChatRoom::State::CreationPending)) { + Core::deleteChatRoom(clientGroupChatRoom); + if (session->getReason() == LinphoneReasonNotAcceptable) { + clientGroupChatRoom = nullptr; + return; + } + } + clientGroupChatRoom->getPrivate()->onCallSessionStateChanged(session, newState, message); + } + +private: + shared_ptr clientGroupChatRoom; + + L_DECLARE_PUBLIC(BasicToClientGroupChatRoom); }; // ============================================================================= @@ -46,4 +90,30 @@ public: BasicToClientGroupChatRoom::BasicToClientGroupChatRoom (const shared_ptr &chatRoom) : ProxyChatRoom(*new BasicToClientGroupChatRoomPrivate, chatRoom) {} +shared_ptr BasicToClientGroupChatRoom::createChatMessage () { + shared_ptr msg = ProxyChatRoom::createChatMessage(); + msg->getPrivate()->setChatRoom(getSharedFromThis()); + return msg; +} + +shared_ptr BasicToClientGroupChatRoom::createChatMessage (const string &text) { + shared_ptr msg = ProxyChatRoom::createChatMessage(text); + msg->getPrivate()->setChatRoom(getSharedFromThis()); + return msg; +} + +void BasicToClientGroupChatRoom::migrate(const std::shared_ptr &clientGroupChatRoom, const std::shared_ptr &chatRoom) { + clientGroupChatRoom->getCore()->getPrivate()->mainDb->migrateBasicToClientGroupChatRoom(chatRoom, clientGroupChatRoom); + + if (chatRoom->getCapabilities() & ChatRoom::Capabilities::Proxy) { + shared_ptr btcgcr = static_pointer_cast(chatRoom); + btcgcr->getCore()->getPrivate()->replaceChatRoom(chatRoom, clientGroupChatRoom); + btcgcr->getPrivate()->chatRoom = clientGroupChatRoom; + } else { + LinphoneChatRoom *lcr = L_GET_C_BACK_PTR(chatRoom); + L_SET_CPP_PTR_FROM_C_OBJECT(lcr, clientGroupChatRoom); + clientGroupChatRoom->getCore()->getPrivate()->replaceChatRoom(chatRoom, clientGroupChatRoom); + } +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/basic-to-client-group-chat-room.h b/src/chat/chat-room/basic-to-client-group-chat-room.h index 2bff6bce0..dcc815a67 100644 --- a/src/chat/chat-room/basic-to-client-group-chat-room.h +++ b/src/chat/chat-room/basic-to-client-group-chat-room.h @@ -27,11 +27,17 @@ LINPHONE_BEGIN_NAMESPACE class BasicToClientGroupChatRoomPrivate; +class ClientGroupChatRoom; class LINPHONE_PUBLIC BasicToClientGroupChatRoom : public ProxyChatRoom { public: BasicToClientGroupChatRoom (const std::shared_ptr &chatRoom); + std::shared_ptr createChatMessage () override; + std::shared_ptr createChatMessage (const std::string &text) override; + + static void migrate(const std::shared_ptr &clientGroupChatRoom, const std::shared_ptr &chatRoom); + private: L_DECLARE_PRIVATE(BasicToClientGroupChatRoom); L_DISABLE_COPY(BasicToClientGroupChatRoom); diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index ae517e199..704e558f4 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -21,6 +21,8 @@ #include "address/address-p.h" #include "c-wrapper/c-wrapper.h" +#include "basic-chat-room.h" +#include "basic-to-client-group-chat-room.h" #include "client-group-chat-room-p.h" #include "conference/handlers/remote-conference-event-handler.h" #include "conference/participant-p.h" @@ -382,6 +384,15 @@ void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) { L_D(); d->setState(ChatRoom::State::Created); + if (getParticipantCount() == 1) { + ChatRoomId id(getParticipants().front()->getAddress(), getMe()->getAddress()); + shared_ptr chatRoom = getCore()->findChatRoom(id); + if (chatRoom && (chatRoom->getCapabilities() & ChatRoom::Capabilities::Basic)) { + BasicToClientGroupChatRoom::migrate(getSharedFromThis(), chatRoom); + return; + } + } + d->chatRoomListener->onChatRoomInsertInDatabaseRequested(getSharedFromThis()); // TODO: Bug. Event is inserted many times. diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 4fc33cc19..c7a57f4f5 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -30,9 +30,12 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { + friend class BasicToClientGroupChatRoomPrivate; friend class ClientGroupToBasicChatRoomPrivate; public: + L_OVERRIDE_SHARED_FROM_THIS(ClientGroupChatRoom); + // TODO: Make me private. ClientGroupChatRoom ( const std::shared_ptr &core, diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 1386060c3..1fffb26bf 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -21,6 +21,7 @@ #include "address/identity-address.h" #include "chat/chat-room/basic-chat-room.h" +#include "chat/chat-room/basic-to-client-group-chat-room.h" #include "chat/chat-room/chat-room-p.h" #include "chat/chat-room/real-time-text-chat-room.h" #include "conference/participant.h" @@ -63,16 +64,24 @@ static IdentityAddress getDefaultLocalAddress (const shared_ptr &core, con shared_ptr CorePrivate::createBasicChatRoom ( const ChatRoomId &chatRoomId, - bool isRtt + ChatRoom::CapabilitiesMask capabilities ) { L_Q(); shared_ptr chatRoom; - if (isRtt) + if (capabilities & ChatRoom::Capabilities::RealTimeText) chatRoom.reset(new RealTimeTextChatRoom(q->getSharedFromThis(), chatRoomId)); - else - chatRoom.reset(new BasicChatRoom(q->getSharedFromThis(), chatRoomId)); + else { + bool isToMigrate = (capabilities & ChatRoom::Capabilities::Migratable); + if (isToMigrate) { + shared_ptr bcr; + bcr.reset(new BasicChatRoom(q->getSharedFromThis(), chatRoomId)); + chatRoom.reset(new BasicToClientGroupChatRoom(bcr)); + } else { + chatRoom.reset(new BasicChatRoom(q->getSharedFromThis(), chatRoomId)); + } + } AbstractChatRoomPrivate *dChatRoom = chatRoom->getPrivate(); dChatRoom->setState(ChatRoom::State::Instantiated); @@ -81,6 +90,18 @@ shared_ptr CorePrivate::createBasicChatRoom ( return chatRoom; } +shared_ptr CorePrivate::createClientGroupChatRoom (const string &subject, bool fallback) { + L_Q(); + return L_GET_CPP_PTR_FROM_C_OBJECT( + _linphone_client_group_chat_room_new( + q->getCCore(), + linphone_core_get_conference_factory_uri(q->getCCore()), + L_STRING_TO_C(subject), + fallback ? TRUE : FALSE + ) + ); +} + void CorePrivate::insertChatRoom (const shared_ptr &chatRoom) { L_ASSERT(chatRoom); L_Q(); @@ -95,6 +116,20 @@ void CorePrivate::insertChatRoomWithDb (const shared_ptr &chat mainDb->insertChatRoom(chatRoom); } +void CorePrivate::replaceChatRoom (const shared_ptr &replacedChatRoom, const shared_ptr &newChatRoom) { + const ChatRoomId &replacedChatRoomId = replacedChatRoom->getChatRoomId(); + const ChatRoomId &newChatRoomId = newChatRoom->getChatRoomId(); + if (replacedChatRoom->getCapabilities() & ChatRoom::Capabilities::Proxy) { + chatRooms.remove(newChatRoom); + chatRoomsById.erase(newChatRoomId); + chatRoomsById[newChatRoomId] = replacedChatRoom; + } else { + chatRooms.remove(replacedChatRoom); + chatRoomsById.erase(replacedChatRoomId); + chatRoomsById[newChatRoomId] = newChatRoom; + } +} + // ----------------------------------------------------------------------------- const list> &Core::getChatRooms () const { @@ -146,14 +181,8 @@ shared_ptr Core::findOneToOneChatRoom ( } shared_ptr Core::createClientGroupChatRoom (const string &subject) { - return L_GET_CPP_PTR_FROM_C_OBJECT( - _linphone_client_group_chat_room_new( - getCCore(), - linphone_core_get_conference_factory_uri(getCCore()), - L_STRING_TO_C(subject), - TRUE - ) - ); + L_D(); + return d->createClientGroupChatRoom(subject, true); } shared_ptr Core::getOrCreateBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt) { @@ -163,7 +192,9 @@ shared_ptr Core::getOrCreateBasicChatRoom (const ChatRoomId &c if (chatRoom) return chatRoom; - chatRoom = d->createBasicChatRoom(chatRoomId, isRtt); + chatRoom = d->createBasicChatRoom(chatRoomId, + isRtt ? ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::RealTimeText) : ChatRoom::CapabilitiesMask() + ); d->insertChatRoom(chatRoom); d->insertChatRoomWithDb(chatRoom); @@ -179,7 +210,7 @@ shared_ptr Core::getOrCreateBasicChatRoom (const IdentityAddre shared_ptr chatRoom = d->createBasicChatRoom( ChatRoomId(peerAddress, getDefaultLocalAddress(getSharedFromThis(), peerAddress)), - isRtt + isRtt ? ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::RealTimeText) : ChatRoom::CapabilitiesMask() ); d->insertChatRoom(chatRoom); d->insertChatRoomWithDb(chatRoom); diff --git a/src/core/core-p.h b/src/core/core-p.h index abec29ab1..c87e1c70d 100644 --- a/src/core/core-p.h +++ b/src/core/core-p.h @@ -20,6 +20,7 @@ #ifndef _CORE_P_H_ #define _CORE_P_H_ +#include "chat/chat-room/abstract-chat-room.h" #include "core.h" #include "db/main-db.h" #include "object/object-p.h" @@ -58,7 +59,9 @@ public: void insertChatRoom (const std::shared_ptr &chatRoom); void insertChatRoomWithDb (const std::shared_ptr &chatRoom); - std::shared_ptr createBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt); + std::shared_ptr createBasicChatRoom (const ChatRoomId &chatRoomId, AbstractChatRoom::CapabilitiesMask capabilities); + std::shared_ptr createClientGroupChatRoom (const std::string &subject, bool fallback = true); + void replaceChatRoom (const std::shared_ptr &replacedChatRoom, const std::shared_ptr &newChatRoom); std::unique_ptr mainDb; diff --git a/src/core/core.h b/src/core/core.h index 74edc1d2a..1a09fc193 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -40,6 +40,8 @@ class IdentityAddress; class AbstractChatRoom; class LINPHONE_PUBLIC Core : public Object { + friend class BasicToClientGroupChatRoom; + friend class BasicToClientGroupChatRoomPrivate; friend class CallPrivate; friend class CallSession; friend class ChatMessagePrivate; diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index dee20e146..fa6b6ca51 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -229,7 +229,9 @@ static constexpr string &blobToString (string &in) { return id; } - static const int capabilities = ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::Basic); + static const int capabilities = ChatRoom::CapabilitiesMask( + { ChatRoom::Capabilities::Basic, ChatRoom::Capabilities::Migratable } + ); lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << ", local=" << localSipAddressId << ", capabilities=" << capabilities << ")."; *session << "INSERT INTO chat_room (" @@ -2064,10 +2066,7 @@ static constexpr string &blobToString (string &in) { : static_cast(row.get(7, 0)); if (capabilities & ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::Basic)) { - chatRoom = core->getPrivate()->createBasicChatRoom( - chatRoomId, - capabilities & ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::RealTimeText) - ); + chatRoom = core->getPrivate()->createBasicChatRoom(chatRoomId, capabilities); chatRoom->setSubject(subject); } else if (capabilities & ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::Conference)) { list> participants; @@ -2273,6 +2272,32 @@ static constexpr string &blobToString (string &in) { L_END_LOG_EXCEPTION } + void MainDb::enableChatRoomMigration (const ChatRoomId &chatRoomId, bool enable) { + L_D(); + + if (!isConnected()) { + lWarning() << "Unable to enable chat room migration. Not connected."; + return; + } + + L_BEGIN_LOG_EXCEPTION + + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + + soci::session *session = d->dbSession.getBackendSession(); + int capabilities = 0; + *session << "SELECT capabilities FROM chat_room WHERE id = :chatRoomId", + soci::use(dbChatRoomId), soci::into(capabilities); + if (enable) + capabilities |= static_cast(ChatRoom::Capabilities::Migratable); + else + capabilities &= ~static_cast(ChatRoom::Capabilities::Migratable); + *session << "UPDATE chat_room SET capabilities = :capabilities WHERE id = :chatRoomId", + soci::use(capabilities), soci::use(dbChatRoomId); + + L_END_LOG_EXCEPTION + } + // ----------------------------------------------------------------------------- #define LEGACY_MESSAGE_COL_LOCAL_ADDRESS 1 diff --git a/src/db/main-db.h b/src/db/main-db.h index c2b164f65..ca153e705 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -118,6 +118,7 @@ public: std::list> getChatRooms () const; void insertChatRoom (const std::shared_ptr &chatRoom); void deleteChatRoom (const ChatRoomId &chatRoomId); + void enableChatRoomMigration (const ChatRoomId &chatRoomId, bool enable); void migrateBasicToClientGroupChatRoom ( const std::shared_ptr &basicChatRoom, diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c index 4bc32c695..285eddab9 100644 --- a/tester/group_chat_tester.c +++ b/tester/group_chat_tester.c @@ -1612,6 +1612,89 @@ static void group_chat_room_creation_successful_if_at_least_one_invited_particip linphone_core_manager_destroy(laure); } +static void group_chat_room_migrate_from_basic_chat_room (void) { + LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc"); + bctbx_list_t *coresManagerList = NULL; + int dummy = 0; + coresManagerList = bctbx_list_append(coresManagerList, marie); + coresManagerList = bctbx_list_append(coresManagerList, pauline); + bctbx_list_t *coresList = init_core_for_conference(coresManagerList); + start_core_for_conference(coresManagerList); + stats initialMarieStats = marie->stat; + stats initialPaulineStats = pauline->stat; + + // Create a basic chat room + LinphoneAddress *paulineAddr = linphone_address_new(linphone_core_get_identity(pauline->lc)); + LinphoneChatRoom *marieCr = linphone_core_get_chat_room(marie->lc, paulineAddr); + + // Send a message and check that a basic chat room is create on Pauline's side + LinphoneChatMessage *msg = linphone_chat_room_create_message(marieCr, "Hey Pauline!"); + linphone_chat_message_send(msg); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 1000)); + BC_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_chat_message); + if (pauline->stat.last_received_chat_message) + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_content_type(pauline->stat.last_received_chat_message), "text/plain"); + LinphoneChatRoom *paulineCr = linphone_core_get_chat_room(pauline->lc, linphone_chat_room_get_local_address(marieCr)); + BC_ASSERT_PTR_NOT_NULL(paulineCr); + if (paulineCr) + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesBasic); + + // Enable chat room migration and restart core for Marie + _linphone_chat_room_enable_migration(marieCr, TRUE); + coresList = bctbx_list_remove(coresList, marie->lc); + linphone_core_manager_restart(marie, TRUE); + bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, marie); + init_core_for_conference(tmpCoresManagerList); + bctbx_list_free(tmpCoresManagerList); + coresList = bctbx_list_append(coresList, marie->lc); + + // Send a new message to initiate chat room migration + marieCr = linphone_core_get_chat_room(marie->lc, paulineAddr); + BC_ASSERT_PTR_NOT_NULL(marieCr); + if (marieCr) { + initialMarieStats = marie->stat; + initialPaulineStats = pauline->stat; + BC_ASSERT_EQUAL(linphone_chat_room_get_capabilities(marieCr), LinphoneChatRoomCapabilitiesBasic | LinphoneChatRoomCapabilitiesProxy, int, "%d"); + msg = linphone_chat_room_create_message(marieCr, "Did you migrate?"); + linphone_chat_message_send(msg); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreationPending, initialMarieStats.number_of_LinphoneChatRoomStateCreationPending + 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreated, initialMarieStats.number_of_LinphoneChatRoomStateCreated + 1, 10000)); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marieCr) & LinphoneChatRoomCapabilitiesConference); + BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 1, int, "%d"); + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(marieCr), 2, int, "%d"); + + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateCreationPending, initialPaulineStats.number_of_LinphoneChatRoomStateCreationPending + 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateCreated, initialPaulineStats.number_of_LinphoneChatRoomStateCreated + 1, 10000)); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesConference); + BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 1, int, "%d"); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 1000)); + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(paulineCr), 2, int, "%d"); + + msg = linphone_chat_room_create_message(marieCr, "Let's go drink a beer"); + linphone_chat_message_send(msg); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 2, 1000)); + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(marieCr), 3, int, "%d"); + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(paulineCr), 3, int, "%d"); + + msg = linphone_chat_room_create_message(paulineCr, "Let's go drink mineral water instead"); + linphone_chat_message_send(msg); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageReceived, initialMarieStats.number_of_LinphoneMessageReceived + 1, 1000)); + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(marieCr), 4, int, "%d"); + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(paulineCr), 4, int, "%d"); + } + + // Clean db from chat room + linphone_core_delete_chat_room(marie->lc, marieCr); + linphone_core_delete_chat_room(marie->lc, paulineCr); + + wait_for_list(coresList, &dummy, 1, 1000); + bctbx_list_free(coresList); + bctbx_list_free(coresManagerList); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t group_chat_tests[] = { TEST_TWO_TAGS("Group chat room creation server", group_chat_room_creation_server, "Server", "LeaksMemory"), TEST_TWO_TAGS("Send message", group_chat_room_send_message, "Server", "LeaksMemory"), @@ -1633,7 +1716,8 @@ test_t group_chat_tests[] = { TEST_TWO_TAGS("Create chat room with incompatible friend", group_chat_room_create_room_with_incompatible_friend, "Server", "LeaksMemory"), TEST_TWO_TAGS("Fallback to basic chat room", group_chat_room_fallback_to_basic_chat_room, "Server", "LeaksMemory"), TEST_TWO_TAGS("Group chat room creation fails if invited participants don't support it", group_chat_room_creation_fails_if_invited_participants_dont_support_it, "Server", "LeaksMemory"), - TEST_TWO_TAGS("Group chat room creation succesful if at least one invited participant supports it", group_chat_room_creation_successful_if_at_least_one_invited_participant_supports_it, "Server", "LeaksMemory") + TEST_TWO_TAGS("Group chat room creation succesful if at least one invited participant supports it", group_chat_room_creation_successful_if_at_least_one_invited_participant_supports_it, "Server", "LeaksMemory"), + TEST_TWO_TAGS("Migrate basic chat room to client group chat room", group_chat_room_migrate_from_basic_chat_room, "Server", "LeaksMemory") }; test_suite_t group_chat_test_suite = { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 5c5190fcb..f2b8009e4 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -299,6 +299,7 @@ typedef struct _LinphoneCoreManager { bool_t decline_subscribe; int number_of_bcunit_error_at_creation; char* phone_alias; + char *rc_path; } LinphoneCoreManager; typedef struct _LinphoneConferenceServer { @@ -318,13 +319,14 @@ typedef struct _LinphoneCallTestParams { void liblinphone_tester_add_suites(void); void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias); -void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies); +void linphone_core_manager_start(LinphoneCoreManager *mgr, bool_t check_for_proxies); LinphoneCoreManager* linphone_core_manager_create2(const char* rc_file, const char* phone_alias); LinphoneCoreManager* linphone_core_manager_create(const char* rc_file); -LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, int check_for_proxies, const char* phone_alias); -LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies); +LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, bool_t check_for_proxies, const char* phone_alias); +LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, bool_t check_for_proxies); LinphoneCoreManager* linphone_core_manager_new(const char* rc_file); void linphone_core_manager_stop(LinphoneCoreManager *mgr); +void linphone_core_manager_restart(LinphoneCoreManager *mgr, bool_t check_for_proxies); void linphone_core_manager_uninit(LinphoneCoreManager *mgr); void linphone_core_manager_wait_for_stun_resolution(LinphoneCoreManager *mgr); void linphone_core_manager_destroy(LinphoneCoreManager* mgr); diff --git a/tester/tester.c b/tester/tester.c index d6c317f1f..48e067f41 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -290,45 +290,11 @@ bool_t transport_supported(LinphoneTransportType transport) { } } -#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) -#pragma GCC diagnostic push -#endif -#ifdef _MSC_VER -#pragma warning(disable : 4996) -#else -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif -void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias) { +void linphone_core_manager_configure (LinphoneCoreManager *mgr) { LinphoneImNotifPolicy *im_notif_policy; - char *rc_path = NULL; char *hellopath = bc_tester_res("sounds/hello8000.wav"); - mgr->number_of_bcunit_error_at_creation = bc_get_number_of_failures(); - mgr->v_table.registration_state_changed=registration_state_changed; - mgr->v_table.auth_info_requested=auth_info_requested; - mgr->v_table.call_state_changed=call_state_changed; - mgr->v_table.text_received=text_message_received; - mgr->v_table.message_received=message_received; - mgr->v_table.is_composing_received=is_composing_received; - mgr->v_table.new_subscription_requested=new_subscription_requested; - mgr->v_table.notify_presence_received=notify_presence_received; - mgr->v_table.notify_presence_received_for_uri_or_tel=notify_presence_received_for_uri_or_tel; - mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; - mgr->v_table.info_received=info_message_received; - mgr->v_table.subscription_state_changed=linphone_subscription_state_change; - mgr->v_table.notify_received=linphone_notify_received; - mgr->v_table.publish_state_changed=linphone_publish_state_changed; - mgr->v_table.configuring_status=linphone_configuration_status; - mgr->v_table.call_encryption_changed=linphone_call_encryption_changed; - mgr->v_table.network_reachable=network_reachable; - mgr->v_table.dtmf_received=dtmf_received; - mgr->v_table.call_stats_updated=call_stats_updated; - - mgr->phone_alias = phone_alias ? ms_strdup(phone_alias) : NULL; - - reset_counters(&mgr->stat); - if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); - mgr->lc=configure_lc_from(&mgr->v_table, bc_tester_get_resource_dir_prefix(), rc_path, mgr); + mgr->lc=configure_lc_from(&mgr->v_table, bc_tester_get_resource_dir_prefix(), mgr->rc_path, mgr); linphone_core_manager_check_accounts(mgr); im_notif_policy = linphone_core_get_im_notif_policy(mgr->lc); if (im_notif_policy != NULL) { @@ -338,8 +304,6 @@ void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, c linphone_im_notif_policy_set_recv_is_composing(im_notif_policy, TRUE); } - manager_count++; - #if TARGET_OS_IPHONE linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device"); linphone_core_set_ringback(mgr->lc, NULL); @@ -369,7 +333,7 @@ void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, c if( manager_count >= 2){ char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",bc_tester_get_writable_dir_prefix(),mgr->lc); - ms_message("Manager for '%s' using files", rc_file ? rc_file : "--"); + ms_message("Manager for '%s' using files", mgr->rc_path ? mgr->rc_path : "--"); linphone_core_set_use_files(mgr->lc, TRUE); linphone_core_set_record_file(mgr->lc,recordpath); ms_free(recordpath); @@ -378,14 +342,52 @@ void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, c linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix()); /*for now, we need the periodical updates facility to compute bandwidth measurements correctly during tests*/ linphone_core_enable_send_call_stats_periodical_updates(mgr->lc, TRUE); +} - if (rc_path) ms_free(rc_path); +#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) +#pragma GCC diagnostic push +#endif +#ifdef _MSC_VER +#pragma warning(disable : 4996) +#else +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file, const char* phone_alias) { + mgr->number_of_bcunit_error_at_creation = bc_get_number_of_failures(); + mgr->v_table.registration_state_changed=registration_state_changed; + mgr->v_table.auth_info_requested=auth_info_requested; + mgr->v_table.call_state_changed=call_state_changed; + mgr->v_table.text_received=text_message_received; + mgr->v_table.message_received=message_received; + mgr->v_table.is_composing_received=is_composing_received; + mgr->v_table.new_subscription_requested=new_subscription_requested; + mgr->v_table.notify_presence_received=notify_presence_received; + mgr->v_table.notify_presence_received_for_uri_or_tel=notify_presence_received_for_uri_or_tel; + mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; + mgr->v_table.info_received=info_message_received; + mgr->v_table.subscription_state_changed=linphone_subscription_state_change; + mgr->v_table.notify_received=linphone_notify_received; + mgr->v_table.publish_state_changed=linphone_publish_state_changed; + mgr->v_table.configuring_status=linphone_configuration_status; + mgr->v_table.call_encryption_changed=linphone_call_encryption_changed; + mgr->v_table.network_reachable=network_reachable; + mgr->v_table.dtmf_received=dtmf_received; + mgr->v_table.call_stats_updated=call_stats_updated; + + mgr->phone_alias = phone_alias ? ms_strdup(phone_alias) : NULL; + + reset_counters(&mgr->stat); + if (rc_file) mgr->rc_path = ms_strdup_printf("rcfiles/%s", rc_file); + + manager_count++; + + linphone_core_manager_configure(mgr); } #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) #pragma GCC diagnostic pop #endif -void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies) { +void linphone_core_manager_start(LinphoneCoreManager *mgr, bool_t check_for_proxies) { LinphoneProxyConfig* proxy; int proxy_count; @@ -436,13 +438,13 @@ LinphoneCoreManager* linphone_core_manager_create(const char* rc_file) { return linphone_core_manager_create2(rc_file, NULL); } -LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, int check_for_proxies, const char* phone_alias) { +LinphoneCoreManager* linphone_core_manager_new3(const char* rc_file, bool_t check_for_proxies, const char* phone_alias) { LinphoneCoreManager *manager = linphone_core_manager_create2(rc_file, phone_alias); linphone_core_manager_start(manager, check_for_proxies); return manager; } -LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) { +LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, bool_t check_for_proxies) { return linphone_core_manager_new3(rc_file, check_for_proxies, NULL); } @@ -454,7 +456,6 @@ LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) { void linphone_core_manager_stop(LinphoneCoreManager *mgr){ if (mgr->lc) { const char *record_file = linphone_core_get_record_file(mgr->lc); - char *chatdb = ms_strdup(linphone_core_get_chat_database_path(mgr->lc)); if (!liblinphone_tester_keep_record_files && record_file && ortp_file_exist(record_file)==0) { if ((bc_get_number_of_failures() - mgr->number_of_bcunit_error_at_creation)>0) { ms_error("Test has failed, keeping recorded file [%s]", record_file); @@ -464,18 +465,17 @@ void linphone_core_manager_stop(LinphoneCoreManager *mgr){ } } linphone_core_unref(mgr->lc); - if (chatdb) { - if (ortp_file_exist(chatdb)==0) { - if (unlink(chatdb) != 0){ - ms_error("Could not delete %s: %s", chatdb, strerror(errno)); - } - } - ms_free(chatdb); - } mgr->lc = NULL; } } +void linphone_core_manager_restart(LinphoneCoreManager *mgr, bool_t check_for_proxies) { + linphone_core_unref(mgr->lc); + linphone_core_manager_configure(mgr); + reset_counters(&mgr->stat); + linphone_core_manager_start(mgr, check_for_proxies); +} + void linphone_core_manager_uninit(LinphoneCoreManager *mgr) { int old_log_level = linphone_core_get_log_level_mask(); linphone_core_set_log_level(ORTP_ERROR);