Commit 91bce6e6 authored by Ghislain MARY's avatar Ghislain MARY

Correctly handle IMDN for group chat.

parent 87921f73
......@@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "c-wrapper/c-wrapper.h"
#include "call/call-p.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-room/chat-room.h"
#include "chat/chat-room/server-group-chat-room-p.h"
#include "conference/participant.h"
......@@ -565,7 +566,7 @@ static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status)
// Check that the message does not belong to an already destroyed chat room - if so, do not invoke callbacks
if (msg->getChatRoom())
msg->updateState((LinphonePrivate::ChatMessage::State)chatStatusSal2Linphone(status));
L_GET_PRIVATE(msg)->setState((LinphonePrivate::ChatMessage::State)chatStatusSal2Linphone(status));
}
static void info_received(SalOp *op, SalBodyHandler *body_handler) {
......
......@@ -355,7 +355,6 @@ LinphoneChatMessageStateChangedCb linphone_chat_message_get_message_state_change
void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb);
void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data);
void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg);
void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state);
LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call);
void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id);
......
......@@ -209,10 +209,6 @@ void linphone_chat_message_resend_2(LinphoneChatMessage *msg) {
L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send();
}
void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) {
L_GET_CPP_PTR_FROM_C_OBJECT(msg)->updateState((LinphonePrivate::ChatMessage::State) new_state);
}
LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) {
return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->putCharacter(character));
}
......
......@@ -60,7 +60,8 @@ public:
void setDirection (ChatMessage::Direction dir);
void setState (ChatMessage::State state, bool force = false);
void setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState);
void setState (ChatMessage::State newState, bool force = false);
void setTime (time_t time);
......@@ -134,6 +135,8 @@ public:
void updateInDb ();
private:
static bool validStateTransition (ChatMessage::State currentState, ChatMessage::State newState);
// TODO: Clean attributes.
time_t time = ::ms_time(0); // TODO: Change me in all files.
std::string imdnId;
......
......@@ -63,28 +63,65 @@ void ChatMessagePrivate::setIsReadOnly (bool readOnly) {
isReadOnly = readOnly;
}
void ChatMessagePrivate::setState (ChatMessage::State s, bool force) {
void ChatMessagePrivate::setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState) {
L_Q();
if (force)
state = s;
if (!(q->getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference)) {
setState(newState);
return;
}
if (s == state)
if (!dbKey.isValid())
return;
if (
(state == ChatMessage::State::Displayed || state == ChatMessage::State::DeliveredToUser) &&
(
s == ChatMessage::State::DeliveredToUser ||
s == ChatMessage::State::Delivered ||
s == ChatMessage::State::NotDelivered
)
)
unique_ptr<MainDb> &mainDb = q->getChatRoom()->getCore()->getPrivate()->mainDb;
shared_ptr<EventLog> eventLog = mainDb->getEventFromKey(dbKey);
ChatMessage::State currentState = mainDb->getChatMessageParticipantState(eventLog, participantAddress);
if (!validStateTransition(currentState, newState))
return;
mainDb->setChatMessageParticipantState(eventLog, participantAddress, newState);
list<ChatMessage::State> states = mainDb->getChatMessageParticipantStates(eventLog);
size_t nbDisplayedStates = 0;
size_t nbDeliveredToUserStates = 0;
size_t nbNotDeliveredStates = 0;
for (const auto &state : states) {
switch (state) {
case ChatMessage::State::Displayed:
nbDisplayedStates++;
break;
case ChatMessage::State::DeliveredToUser:
nbDeliveredToUserStates++;
break;
case ChatMessage::State::NotDelivered:
nbNotDeliveredStates++;
break;
default:
break;
}
}
if (nbNotDeliveredStates > 0)
setState(ChatMessage::State::NotDelivered);
else if (nbDisplayedStates == states.size())
setState(ChatMessage::State::Displayed);
else if ((nbDisplayedStates + nbDeliveredToUserStates) == states.size())
setState(ChatMessage::State::DeliveredToUser);
}
void ChatMessagePrivate::setState (ChatMessage::State newState, bool force) {
L_Q();
if (force)
state = newState;
if (!validStateTransition(state, newState))
return;
lInfo() << "Chat message " << this << ": moving from " << Utils::toString(state) <<
" to " << Utils::toString(s);
state = s;
" to " << Utils::toString(newState);
state = newState;
LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q);
if (linphone_chat_message_get_message_state_changed_cb(msg))
......@@ -756,6 +793,24 @@ void ChatMessagePrivate::updateInDb () {
// -----------------------------------------------------------------------------
bool ChatMessagePrivate::validStateTransition (ChatMessage::State currentState, ChatMessage::State newState) {
if (newState == currentState)
return false;
if (
(currentState == ChatMessage::State::Displayed || currentState == ChatMessage::State::DeliveredToUser) &&
(
newState == ChatMessage::State::DeliveredToUser ||
newState == ChatMessage::State::Delivered ||
newState == ChatMessage::State::NotDelivered
)
)
return false;
return true;
}
// -----------------------------------------------------------------------------
ChatMessage::ChatMessage (const shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction) :
Object(*new ChatMessagePrivate), CoreAccessor(chatRoom->getCore()) {
L_D();
......@@ -931,12 +986,6 @@ void ChatMessage::removeCustomHeader (const string &headerName) {
d->customHeaders.erase(headerName);
}
void ChatMessage::updateState (State state) {
L_D();
d->setState(state);
}
void ChatMessage::send () {
L_D();
......
......@@ -47,6 +47,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor {
friend class ChatRoomPrivate;
friend class CpimChatMessageModifier;
friend class FileTransferChatMessageModifier;
friend class Imdn;
friend class MainDb;
friend class MainDbPrivate;
friend class RealTimeTextChatRoomPrivate;
......@@ -63,7 +64,6 @@ public:
// ----- TODO: Remove me.
void cancelFileTransfer ();
int putCharacter (uint32_t character);
void updateState (State state);
void sendDeliveryNotification (LinphoneReason reason);
void sendDisplayNotification ();
void setIsSecured (bool isSecured);
......
......@@ -61,7 +61,7 @@ public:
LinphoneReason onSipMessageReceived (SalOp *op, const SalMessage *message) override;
void onChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
void onImdnReceived (const std::string &text);
void onImdnReceived (const std::shared_ptr<ChatMessage> &chatMessage);
void onIsComposingReceived (const Address &remoteAddress, const std::string &text);
void onIsComposingRefreshNeeded () override;
void onIsComposingStateChanged (bool isComposing) override;
......
......@@ -227,7 +227,7 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag
goto end;
}
} else if (msg->getPrivate()->getContentType() == ContentType::Imdn) {
onImdnReceived(msg->getPrivate()->getText());
onImdnReceived(msg);
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) {
goto end;
}
......@@ -246,9 +246,8 @@ void ChatRoomPrivate::onChatMessageReceived (const shared_ptr<ChatMessage> &chat
chatMessage->getPrivate()->notifyReceiving();
}
void ChatRoomPrivate::onImdnReceived (const string &text) {
L_Q();
Imdn::parse(*q, text);
void ChatRoomPrivate::onImdnReceived (const shared_ptr<ChatMessage> &chatMessage) {
Imdn::parse(chatMessage);
}
void ChatRoomPrivate::onIsComposingReceived (const Address &remoteAddress, const string &text) {
......
......@@ -364,24 +364,24 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
message->removeContent(*fileContent);
message->addContent(*fileTransferContent);
message->updateState(ChatMessage::State::FileTransferDone);
message->getPrivate()->setState(ChatMessage::State::FileTransferDone);
releaseHttpRequest();
message->getPrivate()->send();
fileUploadEndBackgroundTask();
} else {
lWarning() << "Received empty response from server, file transfer failed";
message->updateState(ChatMessage::State::NotDelivered);
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
releaseHttpRequest();
fileUploadEndBackgroundTask();
}
} else if (code == 400) {
lWarning() << "Received HTTP code response " << code << " for file transfer, probably meaning file is too large";
message->updateState(ChatMessage::State::FileTransferError);
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
releaseHttpRequest();
fileUploadEndBackgroundTask();
} else {
lWarning() << "Unhandled HTTP code response " << code << " for file transfer";
message->updateState(ChatMessage::State::NotDelivered);
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
releaseHttpRequest();
fileUploadEndBackgroundTask();
}
......@@ -398,7 +398,7 @@ void FileTransferChatMessageModifier::processIoErrorUpload (const belle_sip_io_e
shared_ptr<ChatMessage> message = chatMessage.lock();
if (!message)
return;
message->updateState(ChatMessage::State::NotDelivered);
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
releaseHttpRequest();
}
......@@ -412,7 +412,7 @@ void FileTransferChatMessageModifier::processAuthRequestedUpload (const belle_si
shared_ptr<ChatMessage> message = chatMessage.lock();
if (!message)
return;
message->updateState(ChatMessage::State::NotDelivered);
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
releaseHttpRequest();
}
......@@ -844,7 +844,7 @@ void FileTransferChatMessageModifier::processAuthRequestedDownload (const belle_
shared_ptr<ChatMessage> message = chatMessage.lock();
if (!message)
return;
message->updateState(ChatMessage::State::FileTransferError);
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
releaseHttpRequest();
}
......@@ -858,7 +858,7 @@ void FileTransferChatMessageModifier::processIoErrorDownload (const belle_sip_io
shared_ptr<ChatMessage> message = chatMessage.lock();
if (!message)
return;
message->updateState(ChatMessage::State::FileTransferError);
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
releaseHttpRequest();
}
......
......@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "chat/chat-message/chat-message.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-room/chat-room.h"
#include "core/core.h"
#include "logger/logger.h"
......@@ -133,18 +133,18 @@ string Imdn::createXml (const string &id, time_t time, Imdn::Type imdnType, Linp
return content;
}
void Imdn::parse (ChatRoom &cr, const string &text) {
void Imdn::parse (const shared_ptr<ChatMessage> &chatMessage) {
xmlparsing_context_t *xmlCtx = linphone_xmlparsing_context_new();
xmlSetGenericErrorFunc(xmlCtx, linphone_xmlparsing_genericxml_error);
xmlCtx->doc = xmlReadDoc((const unsigned char *)text.c_str(), 0, nullptr, 0);
xmlCtx->doc = xmlReadDoc((const unsigned char *)chatMessage->getPrivate()->getText().c_str(), 0, nullptr, 0);
if (xmlCtx->doc)
parse(cr, xmlCtx);
parse(chatMessage, xmlCtx);
else
lWarning() << "Wrongly formatted IMDN XML: " << xmlCtx->errorBuffer;
linphone_xmlparsing_context_destroy(xmlCtx);
}
void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
void Imdn::parse (const shared_ptr<ChatMessage> &imdnMessage, xmlparsing_context_t *xmlCtx) {
char xpathStr[MAX_XPATH_LENGTH];
char *messageIdStr = nullptr;
char *datetimeStr = nullptr;
......@@ -164,11 +164,13 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
}
if (messageIdStr && datetimeStr) {
shared_ptr<ChatMessage> cm = cr.findChatMessage(messageIdStr, ChatMessage::Direction::Outgoing);
shared_ptr<AbstractChatRoom> cr = imdnMessage->getChatRoom();
shared_ptr<ChatMessage> cm = cr->findChatMessage(messageIdStr, ChatMessage::Direction::Outgoing);
const IdentityAddress &participantAddress = imdnMessage->getFromAddress().getAddressWithoutGruu();
if (!cm) {
lWarning() << "Received IMDN for unknown message " << messageIdStr;
} else {
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr.getCore()->getCCore());
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());
......@@ -178,9 +180,9 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
xmlNodePtr node = deliveryStatusObject->nodesetval->nodeTab[0];
if (node->children && node->children->name) {
if (strcmp((const char *)node->children->name, "delivered") == 0) {
cm->updateState(ChatMessage::State::DeliveredToUser);
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::DeliveredToUser);
} else if (strcmp((const char *)node->children->name, "error") == 0) {
cm->updateState(ChatMessage::State::NotDelivered);
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::NotDelivered);
}
}
}
......@@ -191,7 +193,7 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
xmlNodePtr node = displayStatusObject->nodesetval->nodeTab[0];
if (node->children && node->children->name) {
if (strcmp((const char *)node->children->name, "displayed") == 0) {
cm->updateState(ChatMessage::State::Displayed);
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::Displayed);
}
}
}
......
......@@ -38,10 +38,10 @@ public:
};
static std::string createXml (const std::string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason);
static void parse (ChatRoom &cr, const std::string &content);
static void parse (const std::shared_ptr<ChatMessage> &chatMessage);
private:
static void parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx);
static void parse (const std::shared_ptr<ChatMessage> &chatMessage, xmlparsing_context_t *xmlCtx);
private:
static const std::string imdnPrefix;
......
......@@ -516,19 +516,12 @@ void MainDbPrivate::insertChatRoomParticipantDevice (
}
void MainDbPrivate::insertChatMessageParticipant (long long eventId, long long sipAddressId, int state) {
// TODO: Deal with read messages.
// Remove if displayed? Think a good alorithm for mark as read.
soci::session *session = dbSession.getBackendSession();
soci::statement statement = (
session->prepare << "UPDATE chat_message_participant SET state = :state"
" WHERE event_id = :eventId AND participant_sip_address_id = :sipAddressId",
soci::use(state), soci::use(eventId), soci::use(sipAddressId)
);
statement.execute();
if (statement.get_affected_rows() == 0 && state != int(ChatMessage::State::Displayed))
if (state != static_cast<int>(ChatMessage::State::Displayed)) {
soci::session *session = dbSession.getBackendSession();
*session << "INSERT INTO chat_message_participant (event_id, participant_sip_address_id, state)"
" VALUES (:eventId, :sipAddressId, :state)",
soci::use(eventId), soci::use(sipAddressId), soci::use(state);
}
}
// -----------------------------------------------------------------------------
......@@ -992,6 +985,11 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr<Even
for (const Content *content : chatMessage->getContents())
insertContent(eventId, *content);
for (const auto &participant : chatRoom->getParticipants()) {
const long long &participantSipAddressId = selectSipAddressId(participant->getAddress().asString());
insertChatMessageParticipant(eventId, participantSipAddressId, state);
}
return eventId;
}
......@@ -2216,6 +2214,75 @@ list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages (const ChatRoomId &c
};
}
list<ChatMessage::State> MainDb::getChatMessageParticipantStates (const shared_ptr<EventLog> &eventLog) const {
return L_SAFE_TRANSACTION {
L_D();
soci::session *session = d->dbSession.getBackendSession();
const EventLogPrivate *dEventLog = eventLog->getPrivate();
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
const long long &eventId = dEventKey->storageId;
list<ChatMessage::State> states;
unsigned int state;
soci::statement statement = (session->prepare
<< "SELECT state FROM chat_message_participant WHERE event_id = :eventId",
soci::into(state), soci::use(eventId)
);
statement.execute();
while (statement.fetch())
states.push_back(static_cast<ChatMessage::State>(state));
return states;
};
}
ChatMessage::State MainDb::getChatMessageParticipantState (
const shared_ptr<EventLog> &eventLog,
const IdentityAddress &participantAddress
) const {
return L_SAFE_TRANSACTION {
L_D();
soci::session *session = d->dbSession.getBackendSession();
const EventLogPrivate *dEventLog = eventLog->getPrivate();
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
const long long &eventId = dEventKey->storageId;
const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString());
unsigned int state;
*session << "SELECT state FROM chat_message_participant"
" WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId",
soci::into(state), soci::use(eventId), soci::use(participantSipAddressId);
return static_cast<ChatMessage::State>(state);
};
}
void MainDb::setChatMessageParticipantState (
const shared_ptr<EventLog> &eventLog,
const IdentityAddress &participantAddress,
ChatMessage::State state
) {
L_SAFE_TRANSACTION {
L_D();
soci::session *session = d->dbSession.getBackendSession();
const EventLogPrivate *dEventLog = eventLog->getPrivate();
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
const long long &eventId = dEventKey->storageId;
const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString());
int stateInt = static_cast<int>(state);
*session << "UPDATE chat_message_participant SET state = :state"
" WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId",
soci::use(stateInt), soci::use(eventId), soci::use(participantSipAddressId);
};
}
shared_ptr<ChatMessage> MainDb::getLastChatMessage (const ChatRoomId &chatRoomId) const {
list<shared_ptr<EventLog>> chatList = getHistory(chatRoomId, 1, Filter::ConferenceChatMessageFilter);
if (chatList.empty())
......
......@@ -25,6 +25,7 @@
#include "linphone/utils/enum-mask.h"
#include "abstract/abstract-db.h"
#include "chat/chat-message/chat-message.h"
#include "chat/chat-room/chat-room-id.h"
#include "core/core-accessor.h"
......@@ -85,6 +86,17 @@ public:
void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const;
std::list<std::shared_ptr<ChatMessage>> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const;
std::list<ChatMessage::State> getChatMessageParticipantStates (const std::shared_ptr<EventLog> &eventLog) const;
ChatMessage::State getChatMessageParticipantState (
const std::shared_ptr<EventLog> &eventLog,
const IdentityAddress &participantAddress
) const;
void setChatMessageParticipantState (
const std::shared_ptr<EventLog> &eventLog,
const IdentityAddress &participantAddress,
ChatMessage::State state
);
std::shared_ptr<ChatMessage> getLastChatMessage (const ChatRoomId &chatRoomId) const;
std::list<std::shared_ptr<ChatMessage>> findChatMessages (
......
......@@ -2614,6 +2614,76 @@ static void group_chat_room_new_unique_one_to_one_chat_room_after_both_participa
linphone_core_manager_destroy(pauline);
}
static void imdn_for_group_chat_room (void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
LinphoneCoreManager *chloe = linphone_core_manager_create("chloe_rc");
bctbx_list_t *coresManagerList = NULL;
bctbx_list_t *participantsAddresses = NULL;
coresManagerList = bctbx_list_append(coresManagerList, marie);
coresManagerList = bctbx_list_append(coresManagerList, pauline);
coresManagerList = bctbx_list_append(coresManagerList, chloe);
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)));
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(chloe->lc)));
stats initialMarieStats = marie->stat;
stats initialPaulineStats = pauline->stat;
stats initialChloeStats = chloe->stat;
// Enable IMDN
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc));
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc));
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(chloe->lc));
// Marie creates a new group chat room
const char *initialSubject = "Colleagues";
LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1);
const LinphoneAddress *confAddr = 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, 2, 0);
// Check that the chat room is correctly created on Chloe's side and that the participants are added
LinphoneChatRoom *chloeCr = check_creation_chat_room_client_side(coresList, chloe, &initialChloeStats, confAddr, initialSubject, 2, 0);
// Chloe begins composing a message
const char *chloeMessage = "Hello";
_send_message(chloeCr, chloeMessage);
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageReceived, initialMarieStats.number_of_LinphoneMessageReceived + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 10000));
LinphoneChatMessage *marieLastMsg = marie->stat.last_received_chat_message;
if (!BC_ASSERT_PTR_NOT_NULL(marieLastMsg))
goto end;
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marieLastMsg), chloeMessage);
LinphoneAddress *chloeAddr = linphone_address_new(linphone_core_get_identity(chloe->lc));
BC_ASSERT_TRUE(linphone_address_weak_equal(chloeAddr, linphone_chat_message_get_from_address(marieLastMsg)));
linphone_address_unref(chloeAddr);
// 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, 10000));
// 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, 1000));
// 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, 1000));
end:
// Clean db from chat room
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
linphone_core_manager_delete_chat_room(chloe, chloeCr, coresList);
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
bctbx_list_free(coresList);
bctbx_list_free(coresManagerList);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(chloe);
}
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"),
......@@ -2651,7 +2721,8 @@ test_t group_chat_tests[] = {
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("Unique one-to-one chatroom recreated from message with app restart", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_with_app_restart, "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_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_TWO_TAGS("IMDN for group chat room", imdn_for_group_chat_room, "Server", "LeaksMemory")
};
test_suite_t group_chat_test_suite = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment