From e49f2fedda05681e0c9d168c046652465fb452fb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 26 Jan 2018 14:30:34 +0100 Subject: [PATCH] Handle re-invite of a participant that has left a one-to-one chat room when the other participant sends a message. --- src/chat/chat-room/server-group-chat-room-p.h | 16 ++- .../chat-room/server-group-chat-room-stub.cpp | 6 +- src/db/main-db.cpp | 38 ++++++ src/db/main-db.h | 5 +- tester/group_chat_tester.c | 120 +++++++++++++++++- 5 files changed, 180 insertions(+), 5 deletions(-) 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 23f9bdd9a..08c1771ac 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -43,15 +43,28 @@ public: void update (SalCallOp *op); - void dispatchMessage (const IdentityAddress &fromAddress, const Content &content); void setConferenceAddress (const IdentityAddress &conferenceAddress); void setParticipantDevices (const IdentityAddress &addr, const std::list &devices); void addCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list &compatibleParticipants); + void checkCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list &addressesToCheck); LinphoneReason onSipMessageReceived (SalOp *op, const SalMessage *message) override; private: + struct Message { + Message (const std::string &from, const std::string &contentType, const std::string &text) : fromAddr(from) { + content.setContentType(contentType); + if (!text.empty()) + content.setBodyFromUtf8(text); + } + + IdentityAddress fromAddr; + Content content; + }; + void designateAdmin (); + void dispatchMessage (const Message &message); + void dispatchQueuedMessages (); void finalizeCreation (); bool isAdminLeft () const; @@ -71,6 +84,7 @@ private: ChatRoomListener *chatRoomListener = this; ServerGroupChatRoom::CapabilitiesMask capabilities = ServerGroupChatRoom::Capabilities::Conference; bool joiningPendingAfterCreation = false; + std::list queuedMessages; L_DECLARE_PUBLIC(ServerGroupChatRoom); }; 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 94fdd2429..1bb1f246d 100644 --- a/src/chat/chat-room/server-group-chat-room-stub.cpp +++ b/src/chat/chat-room/server-group-chat-room-stub.cpp @@ -60,8 +60,6 @@ void ServerGroupChatRoomPrivate::update (SalCallOp *) {} // ----------------------------------------------------------------------------- -void ServerGroupChatRoomPrivate::dispatchMessage (const IdentityAddress &, const Content &) {} - void ServerGroupChatRoomPrivate::setConferenceAddress (const IdentityAddress &) {} void ServerGroupChatRoomPrivate::setParticipantDevices (const IdentityAddress &addr, const list &devices) {} @@ -78,6 +76,10 @@ LinphoneReason ServerGroupChatRoomPrivate::onSipMessageReceived (SalOp *, const void ServerGroupChatRoomPrivate::designateAdmin () {} +void ServerGroupChatRoomPrivate::dispatchMessage (const Message &message) {} + +void ServerGroupChatRoomPrivate::dispatchQueuedMessages () {} + void ServerGroupChatRoomPrivate::finalizeCreation () {} bool ServerGroupChatRoomPrivate::isAdminLeft () const { diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 511f6f2d6..7695be90c 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -2554,6 +2554,44 @@ void MainDb::migrateBasicToClientGroupChatRoom ( }; } +IdentityAddress MainDb::findMissingOneToOneConferenceChatRoomParticipantAddress ( + const shared_ptr &chatRoom, + const IdentityAddress &presentParticipantAddr +) { + L_ASSERT(linphone_core_conference_server_enabled(chatRoom->getCore()->getCCore())); + L_ASSERT(chatRoom->getCapabilities() & ChatRoom::Capabilities::OneToOne); + L_ASSERT(chatRoom->getParticipantCount() == 1); + + return L_SAFE_TRANSACTION { + L_D(); + + soci::session *session = d->dbSession.getBackendSession(); + soci::transaction tr(*session); + + string missingParticipantAddress; + string participantASipAddress; + string participantBSipAddress; + + const long long &chatRoomId = d->selectChatRoomId(chatRoom->getChatRoomId()); + L_ASSERT(chatRoomId != -1); + + *session << "SELECT participant_a_sip_address.value, participant_b_sip_address.value" + " FROM one_to_one_chat_room, sip_address AS participant_a_sip_address, sip_address AS participant_b_sip_address" + " WHERE chat_room_id = :chatRoomId" + " AND participant_a_sip_address_id = participant_a_sip_address.id" + " AND participant_b_sip_address_id = participant_b_sip_address.id", + soci::into(participantASipAddress), soci::into(participantBSipAddress), soci::use(chatRoomId); + + string presentParticipantAddress(presentParticipantAddr.asString()); + if (presentParticipantAddress == participantASipAddress) + missingParticipantAddress = participantBSipAddress; + else if (presentParticipantAddress == participantBSipAddress) + missingParticipantAddress = participantASipAddress; + + return IdentityAddress(missingParticipantAddress); + }; +} + IdentityAddress MainDb::findOneToOneConferenceChatRoomAddress ( const IdentityAddress &participantA, const IdentityAddress &participantB diff --git a/src/db/main-db.h b/src/db/main-db.h index 693fda14f..f3301b007 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -125,11 +125,14 @@ public: const std::shared_ptr &clientGroupChatRoom ); + IdentityAddress findMissingOneToOneConferenceChatRoomParticipantAddress ( + const std::shared_ptr &chatRoom, + const IdentityAddress &presentParticipantAddr + ); IdentityAddress findOneToOneConferenceChatRoomAddress ( const IdentityAddress &participantA, const IdentityAddress &participantB ) const; - void insertOneToOneConferenceChatRoom (const std::shared_ptr &chatRoom); // --------------------------------------------------------------------------- diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c index d585b1602..ba27dbee9 100644 --- a/tester/group_chat_tester.c +++ b/tester/group_chat_tester.c @@ -2050,6 +2050,122 @@ static void group_chat_room_unique_one_to_one_chat_room (void) { linphone_core_manager_destroy(pauline); } +static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message (void) { + LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc"); + bctbx_list_t *coresManagerList = NULL; + bctbx_list_t *participantsAddresses = NULL; + 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); + participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc))); + stats initialMarieStats = marie->stat; + stats initialPaulineStats = pauline->stat; + + // Marie creates a new group chat room + const char *initialSubject = "Pauline"; + LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marieCr) & LinphoneChatRoomCapabilitiesOneToOne); + + LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr)); + + // Check that the chat room is correctly created on Pauline's side and that the participants are added + LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, confAddr, initialSubject, 1, 0); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesOneToOne); + + // Marie sends a message + const char *message = "Hello"; + _send_message(marieCr, message); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDelivered, initialMarieStats.number_of_LinphoneMessageDelivered + 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 10000)); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(pauline->stat.last_received_chat_message), message); + + // Marie deletes the chat room + linphone_core_manager_delete_chat_room(marie, marieCr, coresList); + + // Pauline sends a new message + initialMarieStats = marie->stat; + initialPaulineStats = pauline->stat; + + // Marie sends a new message + message = "Hey you"; + _send_message(paulineCr, message); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageDelivered, initialPaulineStats.number_of_LinphoneMessageDelivered + 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageReceived, initialMarieStats.number_of_LinphoneMessageReceived + 1, 10000)); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marie->stat.last_received_chat_message), message); + + // Check that the chat room has been correctly recreated on Marie's side + marieCr = check_creation_chat_room_client_side(coresList, marie, &initialMarieStats, confAddr, initialSubject, 1, 0); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesOneToOne); + + // Clean db from chat room + linphone_core_manager_delete_chat_room(marie, marieCr, coresList); + linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList); + + linphone_address_unref(confAddr); + bctbx_list_free(coresList); + bctbx_list_free(coresManagerList); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left (void) { + LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc"); + bctbx_list_t *coresManagerList = NULL; + bctbx_list_t *participantsAddresses = NULL; + 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); + participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc))); + stats initialMarieStats = marie->stat; + stats initialPaulineStats = pauline->stat; + + // Marie creates a new group chat room + const char *initialSubject = "Pauline"; + LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marieCr) & LinphoneChatRoomCapabilitiesOneToOne); + + LinphoneAddress *firstConfAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr)); + + // Check that the chat room is correctly created on Pauline's side and that the participants are added + LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, firstConfAddr, initialSubject, 1, 0); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesOneToOne); + + // Both participants delete the chat room + linphone_core_manager_delete_chat_room(marie, marieCr, coresList); + linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList); + + // Marie re-creates a chat room with Pauline + initialMarieStats = marie->stat; + initialPaulineStats = pauline->stat; + participantsAddresses = NULL; + participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc))); + marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marieCr) & LinphoneChatRoomCapabilitiesOneToOne); + + LinphoneAddress *secondConfAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr)); + + // Check that the chat room has been correctly recreated on Marie's side + paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, secondConfAddr, initialSubject, 1, 0); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesOneToOne); + + BC_ASSERT_FALSE(linphone_address_equal(firstConfAddr, secondConfAddr)); + + // Clean db from chat room + linphone_core_manager_delete_chat_room(marie, marieCr, coresList); + linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList); + + linphone_address_unref(firstConfAddr); + linphone_address_unref(secondConfAddr); + 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"), @@ -2076,7 +2192,9 @@ test_t group_chat_tests[] = { TEST_TWO_TAGS("Migrate basic chat room to client group chat room not needed", group_chat_donot_room_migrate_from_basic_chat_room, "Server", "LeaksMemory"), TEST_TWO_TAGS("Send file", group_chat_room_send_file, "Server", "LeaksMemory"), TEST_TWO_TAGS("Send file + text", group_chat_room_send_file_plus_text, "Server", "LeaksMemory"), - TEST_TWO_TAGS("Unique one-to-one chatroom", group_chat_room_unique_one_to_one_chat_room, "Server", "LeaksMemory") + TEST_TWO_TAGS("Unique one-to-one chatroom", group_chat_room_unique_one_to_one_chat_room, "Server", "LeaksMemory"), + TEST_TWO_TAGS("Unique one-to-one chatroom recreated from message", group_chat_room_unique_one_to_one_chat_room_recreated_from_message, "Server", "LeaksMemory"), + TEST_TWO_TAGS("New unique one-to-one chatroom after both participants left", group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left, "Server", "LeaksMemory") }; test_suite_t group_chat_test_suite = {