diff --git a/include/linphone/api/c-chat-message.h b/include/linphone/api/c-chat-message.h index d37931c74..715ed8b41 100644 --- a/include/linphone/api/c-chat-message.h +++ b/include/linphone/api/c-chat-message.h @@ -381,25 +381,13 @@ LINPHONE_PUBLIC const char *linphone_chat_message_get_text_content (const Linpho LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer_in_progress (LinphoneChatMessage *msg); /** - * Gets the list of participants that displayed this message and the time at which they did. + * Gets the list of participants for which the imdn state has reached the specified state and the time at which they did. * @param[in] msg #LinphoneChatMessage object. + * @param[in] state The LinphoneChatMessageState the imdn have reached (only use LinphoneChatMessageStateDelivered, + * LinphoneChatMessageStateDeliveredToUser, LinphoneChatMessageStateDisplayed and LinphoneChatMessageStateNotDelivered) * @return \bctbx_list{LinphoneParticipantImdnState} */ -LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_displayed (const LinphoneChatMessage *msg); - -/** - * Gets the list of participants that did not receive this message. - * @param[in] msg #LinphoneChatMessage object. - * @return \bctbx_list{LinphoneParticipantImdnState} - */ -LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_not_received (const LinphoneChatMessage *msg); - -/** - * Gets the list of participants that received this message and the time at which they did. - * @param[in] msg #LinphoneChatMessage object. - * @return \bctbx_list{LinphoneParticipantImdnState} - */ -LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_received (const LinphoneChatMessage *msg); +LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_by_imdn_state (const LinphoneChatMessage *msg, LinphoneChatMessageState state); /** * @} diff --git a/src/c-wrapper/api/c-chat-message.cpp b/src/c-wrapper/api/c-chat-message.cpp index 12314bf52..743b728cd 100644 --- a/src/c-wrapper/api/c-chat-message.cpp +++ b/src/c-wrapper/api/c-chat-message.cpp @@ -251,16 +251,8 @@ bool_t linphone_chat_message_is_file_transfer_in_progress(LinphoneChatMessage *m return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isFileTransferInProgress(); } -bctbx_list_t *linphone_chat_message_get_participants_that_have_displayed (const LinphoneChatMessage *msg) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveDisplayed()); -} - -bctbx_list_t *linphone_chat_message_get_participants_that_have_not_received (const LinphoneChatMessage *msg) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveNotReceived()); -} - -bctbx_list_t *linphone_chat_message_get_participants_that_have_received (const LinphoneChatMessage *msg) { - return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveReceived()); +bctbx_list_t *linphone_chat_message_get_participants_by_imdn_state (const LinphoneChatMessage *msg, LinphoneChatMessageState state) { + return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsByImdnState(LinphonePrivate::ChatMessage::State(state))); } diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h index b013e9b96..86bdff7e1 100644 --- a/src/chat/chat-message/chat-message-p.h +++ b/src/chat/chat-message/chat-message-p.h @@ -60,7 +60,6 @@ public: void setDirection (ChatMessage::Direction dir); - std::list getParticipantsByImdnState (MainDb::ParticipantStateRetrievalFunc func) const; void setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime); virtual void setState (ChatMessage::State newState, bool force = false); diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index f47f42283..9eaaa4086 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -71,26 +71,6 @@ void ChatMessagePrivate::setIsReadOnly (bool readOnly) { isReadOnly = readOnly; } -list ChatMessagePrivate::getParticipantsByImdnState (MainDb::ParticipantStateRetrievalFunc func) const { - L_Q(); - - list result; - if (!(q->getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference) || !dbKey.isValid()) - return result; - - unique_ptr &mainDb = q->getChatRoom()->getCore()->getPrivate()->mainDb; - shared_ptr eventLog = mainDb->getEventFromKey(dbKey); - list dbResults = func(eventLog); - for (const auto &dbResult : dbResults) { - auto sender = q->getChatRoom()->findParticipant(q->getFromAddress()); - auto participant = q->getChatRoom()->findParticipant(dbResult.address); - if (participant && (participant != sender)) - result.emplace_back(participant, dbResult.state, dbResult.timestamp); - } - - return result; -} - void ChatMessagePrivate::setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime) { L_Q(); @@ -1018,25 +998,24 @@ void ChatMessage::setToBeStored (bool value) { // ----------------------------------------------------------------------------- -list ChatMessage::getParticipantsThatHaveDisplayed () const { +list ChatMessage::getParticipantsByImdnState (ChatMessage::State state) const { L_D(); - unique_ptr &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb; - auto func = bind(&MainDb::getChatMessageParticipantsThatHaveDisplayed, mainDb.get(), std::placeholders::_1); - return d->getParticipantsByImdnState(func); -} -list ChatMessage::getParticipantsThatHaveNotReceived () const { - L_D(); - unique_ptr &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb; - auto func = bind(&MainDb::getChatMessageParticipantsThatHaveNotReceived, mainDb.get(), std::placeholders::_1); - return d->getParticipantsByImdnState(func); -} + list result; + if (!(getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference) || !d->dbKey.isValid()) + return result; -list ChatMessage::getParticipantsThatHaveReceived () const { - L_D(); unique_ptr &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb; - auto func = bind(&MainDb::getChatMessageParticipantsThatHaveReceived, mainDb.get(), std::placeholders::_1); - return d->getParticipantsByImdnState(func); + shared_ptr eventLog = mainDb->getEventFromKey(d->dbKey); + list dbResults = mainDb->getChatMessageParticipantsByImdnState(eventLog, state); + for (const auto &dbResult : dbResults) { + auto sender = getChatRoom()->findParticipant(getFromAddress()); + auto participant = getChatRoom()->findParticipant(dbResult.address); + if (participant && (participant != sender)) + result.emplace_back(participant, dbResult.state, dbResult.timestamp); + } + + return result; } // ----------------------------------------------------------------------------- diff --git a/src/chat/chat-message/chat-message.h b/src/chat/chat-message/chat-message.h index 7b5af855a..ef188d8bc 100644 --- a/src/chat/chat-message/chat-message.h +++ b/src/chat/chat-message/chat-message.h @@ -94,9 +94,7 @@ public: bool getToBeStored () const; virtual void setToBeStored (bool value); - std::list getParticipantsThatHaveDisplayed () const; - std::list getParticipantsThatHaveReceived () const; - std::list getParticipantsThatHaveNotReceived () const; + std::list getParticipantsByImdnState (State state) const; const std::list &getContents () const; void addContent (Content *content); diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 35c93f42d..195cd1abe 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -150,6 +150,13 @@ private: long long insertConferenceParticipantDeviceEvent (const std::shared_ptr &eventLog); long long insertConferenceSubjectEvent (const std::shared_ptr &eventLog); + void setChatMessageParticipantState ( + const std::shared_ptr &eventLog, + const IdentityAddress &participantAddress, + ChatMessage::State state, + time_t stateChangeTime + ); + // --------------------------------------------------------------------------- // Cache API. // --------------------------------------------------------------------------- diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index bd5245f67..3a85ed5aa 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -779,6 +779,13 @@ void MainDbPrivate::updateConferenceChatMessageEvent (const shared_ptr deleteContents(eventId); for (const auto &content : chatMessage->getContents()) insertContent(eventId, *content); + + if ((chatMessage->getDirection() == ChatMessage::Direction::Outgoing) + && ((chatMessage->getState() == ChatMessage::State::Delivered) || (chatMessage->getState() == ChatMessage::State::NotDelivered)) + ) { + for (const auto &participant : chatMessage->getChatRoom()->getParticipants()) + setChatMessageParticipantState(eventLog, participant->getAddress(), chatMessage->getState(), std::time(nullptr)); + } } long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr &eventLog, long long *chatRoomId) { @@ -904,6 +911,26 @@ long long MainDbPrivate::insertConferenceSubjectEvent (const shared_ptr &eventLog, + const IdentityAddress &participantAddress, + ChatMessage::State state, + time_t stateChangeTime +) { + const EventLogPrivate *dEventLog = eventLog->getPrivate(); + MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); + const long long &eventId = dEventKey->storageId; + const long long &participantSipAddressId = selectSipAddressId(participantAddress.asString()); + int stateInt = static_cast(state); + const tm &stateChangeTm = Utils::getTimeTAsTm(stateChangeTime); + + *dbSession.getBackendSession() << "UPDATE chat_message_participant SET state = :state," + " state_change_time = :stateChangeTm" + " WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId", + soci::use(stateInt), soci::use(stateChangeTm), soci::use(eventId), soci::use(participantSipAddressId); +} + + // ----------------------------------------------------------------------------- // Cache API. // ----------------------------------------------------------------------------- @@ -1961,8 +1988,9 @@ list> MainDb::getUnreadChatMessages (const ChatRoomId &c }; } -list MainDb::getChatMessageParticipantsThatHaveDisplayed ( - const shared_ptr &eventLog +list MainDb::getChatMessageParticipantsByImdnState ( + const shared_ptr &eventLog, + ChatMessage::State state ) const { return L_DB_TRANSACTION { L_D(); @@ -1970,7 +1998,7 @@ list MainDb::getChatMessageParticipantsThatHaveDisplay const EventLogPrivate *dEventLog = eventLog->getPrivate(); MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); const long long &eventId = dEventKey->storageId; - int stateInt = static_cast(ChatMessage::State::Displayed); + int stateInt = static_cast(state); static const string query = "SELECT sip_address.value, chat_message_participant.state_change_time" " FROM sip_address, chat_message_participant" @@ -1982,60 +2010,7 @@ list MainDb::getChatMessageParticipantsThatHaveDisplay list result; for (const auto &row : rows) - result.emplace_back(IdentityAddress(row.get(0)), ChatMessage::State::Displayed, MainDbPrivate::getTmAsTimeT(row.get(1))); - return result; - }; -} - -list MainDb::getChatMessageParticipantsThatHaveNotReceived ( - const shared_ptr &eventLog -) const { - return L_DB_TRANSACTION { - L_D(); - - const EventLogPrivate *dEventLog = eventLog->getPrivate(); - MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); - const long long &eventId = dEventKey->storageId; - int deliveredStateInt = static_cast(ChatMessage::State::DeliveredToUser); - int displayedStateInt = static_cast(ChatMessage::State::Displayed); - - static const string query = "SELECT sip_address.value, chat_message_participant.state_change_time" - " FROM sip_address, chat_message_participant" - " WHERE event_id = :eventId AND state <> :deliveredState AND state <> :displayedState" - " AND sip_address.id = chat_message_participant.participant_sip_address_id"; - soci::rowset rows = (d->dbSession.getBackendSession()->prepare << query, - soci::use(eventId), soci::use(deliveredStateInt), soci::use(displayedStateInt) - ); - - list result; - for (const auto &row : rows) - result.emplace_back(IdentityAddress(row.get(0)), ChatMessage::State::Idle, 0); - return result; - }; -} - -list MainDb::getChatMessageParticipantsThatHaveReceived ( - const shared_ptr &eventLog -) const { - return L_DB_TRANSACTION { - L_D(); - - const EventLogPrivate *dEventLog = eventLog->getPrivate(); - MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); - const long long &eventId = dEventKey->storageId; - int stateInt = static_cast(ChatMessage::State::DeliveredToUser); - - static const string query = "SELECT sip_address.value, chat_message_participant.state_change_time" - " FROM sip_address, chat_message_participant" - " WHERE event_id = :eventId AND state = :state" - " AND sip_address.id = chat_message_participant.participant_sip_address_id"; - soci::rowset rows = (d->dbSession.getBackendSession()->prepare << query, - soci::use(eventId), soci::use(stateInt) - ); - - list result; - for (const auto &row : rows) - result.emplace_back(IdentityAddress(row.get(0)), ChatMessage::State::DeliveredToUser, MainDbPrivate::getTmAsTimeT(row.get(1))); + result.emplace_back(IdentityAddress(row.get(0)), state, MainDbPrivate::getTmAsTimeT(row.get(1))); return result; }; } @@ -2092,19 +2067,7 @@ void MainDb::setChatMessageParticipantState ( ) { L_DB_TRANSACTION { L_D(); - - const EventLogPrivate *dEventLog = eventLog->getPrivate(); - MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); - const long long &eventId = dEventKey->storageId; - const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString()); - int stateInt = static_cast(state); - const tm &stateChangeTm = Utils::getTimeTAsTm(stateChangeTime); - - *d->dbSession.getBackendSession() << "UPDATE chat_message_participant SET state = :state," - " state_change_time = :stateChangeTm" - " WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId", - soci::use(stateInt), soci::use(stateChangeTm), soci::use(eventId), soci::use(participantSipAddressId); - + d->setChatMessageParticipantState(eventLog, participantAddress, state, stateChangeTime); tr.commit(); }; } diff --git a/src/db/main-db.h b/src/db/main-db.h index e43cb9130..04ed07a71 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -102,14 +102,9 @@ public: void markChatMessagesAsRead (const ChatRoomId &chatRoomId) const; std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId) const; - std::list getChatMessageParticipantsThatHaveDisplayed ( - const std::shared_ptr &eventLog - ) const; - std::list getChatMessageParticipantsThatHaveNotReceived ( - const std::shared_ptr &eventLog - ) const; - std::list getChatMessageParticipantsThatHaveReceived ( - const std::shared_ptr &eventLog + std::list getChatMessageParticipantsByImdnState ( + const std::shared_ptr &eventLog, + ChatMessage::State state ) const; std::list getChatMessageParticipantStates (const std::shared_ptr &eventLog) const; ChatMessage::State getChatMessageParticipantState ( diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c index f183aa73c..1990453bf 100644 --- a/tester/group_chat_tester.c +++ b/tester/group_chat_tester.c @@ -3089,8 +3089,8 @@ static void imdn_for_group_chat_room (void) { // Check that the message has been delivered to Marie and Pauline BC_ASSERT_TRUE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDeliveredToUser, initialChloeStats.number_of_LinphoneMessageDeliveredToUser + 1, 3000)); - BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_displayed(chloeMessage)); - bctbx_list_t *participantsThatReceivedChloeMessage = linphone_chat_message_get_participants_that_have_received(chloeMessage); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDisplayed)); + bctbx_list_t *participantsThatReceivedChloeMessage = linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDeliveredToUser); if (BC_ASSERT_PTR_NOT_NULL(participantsThatReceivedChloeMessage)) { BC_ASSERT_EQUAL((int)bctbx_list_size(participantsThatReceivedChloeMessage), 2, int, "%d"); for (bctbx_list_t *item = participantsThatReceivedChloeMessage; item; item = bctbx_list_next(item)) { @@ -3101,33 +3101,36 @@ static void imdn_for_group_chat_room (void) { } bctbx_list_free_with_data(participantsThatReceivedChloeMessage, (bctbx_list_free_func)linphone_participant_imdn_state_unref); } - BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_not_received(chloeMessage)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDelivered)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateNotDelivered)); // Marie marks the message as read, check that the state is not yet displayed on Chloe's side linphone_chat_room_mark_as_read(marieCr); BC_ASSERT_FALSE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDisplayed, initialChloeStats.number_of_LinphoneMessageDisplayed + 1, 3000)); - bctbx_list_t *participantsThatDisplayedChloeMessage = linphone_chat_message_get_participants_that_have_displayed(chloeMessage); + bctbx_list_t *participantsThatDisplayedChloeMessage = linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDisplayed); if (BC_ASSERT_PTR_NOT_NULL(participantsThatDisplayedChloeMessage)) { BC_ASSERT_EQUAL((int)bctbx_list_size(participantsThatDisplayedChloeMessage), 1, int, "%d"); bctbx_list_free_with_data(participantsThatDisplayedChloeMessage, (bctbx_list_free_func)linphone_participant_imdn_state_unref); } - participantsThatReceivedChloeMessage = linphone_chat_message_get_participants_that_have_received(chloeMessage); + participantsThatReceivedChloeMessage = linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDeliveredToUser); if (BC_ASSERT_PTR_NOT_NULL(participantsThatReceivedChloeMessage)) { BC_ASSERT_EQUAL((int)bctbx_list_size(participantsThatReceivedChloeMessage), 1, int, "%d"); bctbx_list_free_with_data(participantsThatReceivedChloeMessage, (bctbx_list_free_func)linphone_participant_imdn_state_unref); } - BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_not_received(chloeMessage)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDelivered)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateNotDelivered)); // Pauline also marks the message as read, check that the state is now displayed on Chloe's side linphone_chat_room_mark_as_read(paulineCr); BC_ASSERT_TRUE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDisplayed, initialChloeStats.number_of_LinphoneMessageDisplayed + 1, 3000)); - participantsThatDisplayedChloeMessage = linphone_chat_message_get_participants_that_have_displayed(chloeMessage); + participantsThatDisplayedChloeMessage = linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDisplayed); if (BC_ASSERT_PTR_NOT_NULL(participantsThatDisplayedChloeMessage)) { BC_ASSERT_EQUAL((int)bctbx_list_size(participantsThatDisplayedChloeMessage), 2, int, "%d"); bctbx_list_free_with_data(participantsThatDisplayedChloeMessage, (bctbx_list_free_func)linphone_participant_imdn_state_unref); } - BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_received(chloeMessage)); - BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_not_received(chloeMessage)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDeliveredToUser)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDelivered)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateNotDelivered)); linphone_chat_message_unref(chloeMessage); @@ -3303,8 +3306,8 @@ static void imdn_sent_from_db_state (void) { // Check that the message has been delivered to Marie and Pauline BC_ASSERT_TRUE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDeliveredToUser, initialChloeStats.number_of_LinphoneMessageDeliveredToUser + 1, 3000)); - BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_displayed(chloeMessage)); - bctbx_list_t *participantsThatReceivedChloeMessage = linphone_chat_message_get_participants_that_have_received(chloeMessage); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDisplayed)); + bctbx_list_t *participantsThatReceivedChloeMessage = linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDeliveredToUser); if (BC_ASSERT_PTR_NOT_NULL(participantsThatReceivedChloeMessage)) { BC_ASSERT_EQUAL((int)bctbx_list_size(participantsThatReceivedChloeMessage), 2, int, "%d"); for (bctbx_list_t *item = participantsThatReceivedChloeMessage; item; item = bctbx_list_next(item)) { @@ -3315,7 +3318,8 @@ static void imdn_sent_from_db_state (void) { } bctbx_list_free_with_data(participantsThatReceivedChloeMessage, (bctbx_list_free_func)linphone_participant_imdn_state_unref); } - BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_not_received(chloeMessage)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateDelivered)); + BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_by_imdn_state(chloeMessage, LinphoneChatMessageStateNotDelivered)); linphone_chat_message_unref(chloeMessage);