diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index f2b56c39f29d2fa84dcbc4385e2e216586eacf31..d4da2af8692145445748705dab8c95baa065427f 100644
--- a/coreapi/callbacks.c
+++ b/coreapi/callbacks.c
@@ -808,9 +808,16 @@ static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status)
 	LinphonePrivate::ChatMessage *msg = static_cast<LinphonePrivate::ChatMessage *>(op->getUserPointer());
 	if (!msg) return; // Do not handle delivery status for isComposing messages.
 
+	auto chatRoom = msg->getChatRoom();
 	// Check that the message does not belong to an already destroyed chat room - if so, do not invoke callbacks
-	if (msg->getChatRoom())
+	if (chatRoom) {
+		// It would be better to call setParticipantState but doing so, it causes a memory leak
 		L_GET_PRIVATE(msg)->setState((LinphonePrivate::ChatMessage::State)chatStatusSal2Linphone(status));
+		/*L_GET_PRIVATE(msg)->setParticipantState(chatRoom->getMe()->getAddress(),
+		                                        (LinphonePrivate::ChatMessage::State)chatStatusSal2Linphone(status),
+		                                        ::ms_time(NULL));
+		*/
+	}
 }
 
 static void info_received(SalOp *op, SalBodyHandler *body_handler) {
diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp
index 92b706f94f051fdaeed74c73f81dcd1e1061f205..24d881219f6d9e3da043f3d42ba9f89073a7a986 100644
--- a/src/c-wrapper/api/c-chat-room.cpp
+++ b/src/c-wrapper/api/c-chat-room.cpp
@@ -168,7 +168,8 @@ LinphoneChatMessage *linphone_chat_room_create_message_2(LinphoneChatRoom *cr,
 
 	LinphonePrivate::ChatMessagePrivate *dMsg = L_GET_PRIVATE_FROM_C_OBJECT(msg);
 	dMsg->setTime(time);
-	dMsg->setState(static_cast<LinphonePrivate::ChatMessage::State>(state));
+	dMsg->setParticipantState(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMe()->getAddress(),
+	                          static_cast<LinphonePrivate::ChatMessage::State>(state), ::ms_time(NULL));
 
 	return msg;
 }
diff --git a/src/chat/chat-message/chat-message-p.h b/src/chat/chat-message/chat-message-p.h
index 51a2a3dfc4ff553cc4ea15850eaa5dff3de13b48..a8f66f7e944ae51ae5e1f04058cd2928f66da09a 100644
--- a/src/chat/chat-message/chat-message-p.h
+++ b/src/chat/chat-message/chat-message-p.h
@@ -70,9 +70,9 @@ public:
 
 	void setParticipantState(const std::shared_ptr<Address> &participantAddress,
 	                         ChatMessage::State newState,
-	                         time_t stateChangeTime);
+	                         time_t stateChangeTime,
+	                         LinphoneReason reason = LinphoneReasonNone);
 
-	virtual void setState(ChatMessage::State newState);
 	void forceState(ChatMessage::State newState) {
 		state = newState;
 	}
@@ -244,16 +244,15 @@ public:
 	void updateInDb();
 
 	static bool isValidStateTransition(ChatMessage::State currentState, ChatMessage::State newState);
+	static bool isImdnControlledState(ChatMessage::State state);
 
 	void restoreFileTransferContentAsFileContent();
 
-private:
-	ChatMessagePrivate(const std::shared_ptr<AbstractChatRoom> &cr, ChatMessage::Direction dir);
-	virtual ~ChatMessagePrivate();
-
-public:
 	long long storageId = -1;
 
+	// It should be private if we do so, but it must be called in message_delivery_update to avoid a memory leak
+	virtual void setState(ChatMessage::State newState);
+
 protected:
 	bool displayNotificationRequired = true;
 	bool negativeDeliveryNotificationRequired = true;
@@ -262,6 +261,9 @@ protected:
 	std::string contentEncoding;
 
 private:
+	ChatMessagePrivate(const std::shared_ptr<AbstractChatRoom> &cr, ChatMessage::Direction dir);
+	virtual ~ChatMessagePrivate();
+
 	// TODO: Clean attributes.
 	time_t time = ::ms_time(0); // TODO: Change me in all files.
 	std::string imdnId;
diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp
index d13f92711d1c54dcadffbb6719179a85c5dd5023..28b519649e66584c034d1caef1ab3cabed7fd315 100644
--- a/src/chat/chat-message/chat-message.cpp
+++ b/src/chat/chat-message/chat-message.cpp
@@ -121,39 +121,80 @@ bool ChatMessagePrivate::isMarkedAsRead() const {
 
 void ChatMessagePrivate::setParticipantState(const std::shared_ptr<Address> &participantAddress,
                                              ChatMessage::State newState,
-                                             time_t stateChangeTime) {
+                                             time_t stateChangeTime,
+                                             LinphoneReason reason) {
 	L_Q();
 
 	const auto &chatRoom = q->getChatRoom();
 
-	if (!q->isValid() || !chatRoom) return;
-
-	if (chatRoom->getCapabilities().isSet(ChatRoom::Capabilities::Basic)) {
-		// Basic Chat Room doesn't support participant state
-		setState(newState);
-		return;
-	}
+	if (!chatRoom) return;
 
+	const shared_ptr<ChatMessage> &sharedMessage = q->getSharedFromThis();
+	const bool isBasicChatRoom = chatRoom->getCapabilities().isSet(ChatRoom::Capabilities::Basic);
 	unique_ptr<MainDb> &mainDb = chatRoom->getCore()->getPrivate()->mainDb;
 	shared_ptr<EventLog> eventLog = mainDb->getEvent(mainDb, q->getStorageId());
-	ChatMessage::State currentState = mainDb->getChatMessageParticipantState(eventLog, participantAddress);
+	ChatMessage::State currentState = ChatMessage::State::Idle;
+	if (isBasicChatRoom) {
+		currentState = q->getState();
+	} else if (eventLog) {
+		currentState = mainDb->getChatMessageParticipantState(eventLog, participantAddress);
+	}
 
 	if (!isValidStateTransition(currentState, newState)) {
-		lWarning() << "Chat message " << q->getSharedFromThis() << ": Invalid transaction of participant "
-		           << *participantAddress << " from state " << Utils::toString(currentState) << " to state "
-		           << Utils::toString(newState);
+		if (isBasicChatRoom) {
+			const auto &conferenceAddress = chatRoom->getConferenceAddress();
+			const auto conferenceAddressStr =
+			    conferenceAddress ? conferenceAddress->toString() : std::string("<unknown-conference-address>");
+			lWarning() << "Chat message " << sharedMessage << ": Invalid transaction of basic chat room "
+			           << conferenceAddressStr << " from state " << Utils::toString(currentState) << " to state "
+			           << Utils::toString(newState);
+		} else {
+			lWarning() << "Chat message " << sharedMessage << ": Invalid transaction of participant "
+			           << *participantAddress << " from state " << Utils::toString(currentState) << " to state "
+			           << Utils::toString(newState);
+		}
 		return;
 	}
 
-	lInfo() << "Chat message " << q->getSharedFromThis() << ": moving participant '" << *participantAddress
-	        << "' state to " << Utils::toString(newState);
-	mainDb->setChatMessageParticipantState(eventLog, participantAddress, newState, stateChangeTime);
+	auto me = chatRoom->getMe();
+	const auto isMe = participantAddress->weakEqual(*me->getAddress());
+
+	// Send IMDN if the participant whose state changes is me
+	if (isMe) {
+		switch (newState) {
+			case ChatMessage::State::Displayed:
+				static_cast<ChatRoomPrivate *>(chatRoom->getPrivate())->sendDisplayNotification(sharedMessage);
+				break;
+			case ChatMessage::State::DeliveredToUser:
+				static_cast<ChatRoomPrivate *>(chatRoom->getPrivate())->sendDeliveryNotification(sharedMessage);
+				break;
+			case ChatMessage::State::NotDelivered:
+				if (reason != LinphoneReasonNone) {
+					static_cast<ChatRoomPrivate *>(chatRoom->getPrivate())
+					    ->sendDeliveryErrorNotification(sharedMessage, reason);
+				}
+				break;
+			default:
+				break;
+		}
+	}
+
+	if (!q->isValid()) {
+		if (newState == ChatMessage::State::NotDelivered) {
+			setState(newState);
+		}
+		return;
+	}
+
+	// Participant states are not supported
+	if (isBasicChatRoom) {
+		setState(newState);
+		return;
+	}
 
 	LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q);
 	LinphoneChatRoom *cr = L_GET_C_BACK_PTR(chatRoom);
-	auto me = chatRoom->getMe();
-	auto participant =
-	    participantAddress->weakEqual(*me->getAddress()) ? me : chatRoom->findParticipant(participantAddress);
+	auto participant = isMe ? me : chatRoom->findParticipant(participantAddress);
 	ParticipantImdnState imdnState(participant, newState, stateChangeTime);
 
 	// Legacy callbacks, deprecated !
@@ -173,40 +214,64 @@ void ChatMessagePrivate::setParticipantState(const std::shared_ptr<Address> &par
 		return;
 	}
 
-	const auto states = q->getParticipantsState();
+	lInfo() << "Chat message " << sharedMessage << ": moving participant '" << *participantAddress << "' state to "
+	        << Utils::toString(newState);
+	mainDb->setChatMessageParticipantState(eventLog, participantAddress, newState, stateChangeTime);
+
+	// Update chat message state if it doesn't depend on IMDN
+	if (isMe && !isImdnControlledState(newState)) {
+		setState(newState);
+	}
+
+	const auto imdnStates = q->getParticipantsState();
+	size_t nbRecipients = 0;
 	size_t nbDisplayedStates = 0;
 	size_t nbDeliveredToUserStates = 0;
 	size_t nbNotDeliveredStates = 0;
-	for (const auto &state : states) {
-		switch (state.getState()) {
-			case ChatMessage::State::Displayed:
-				nbDisplayedStates++;
-				break;
-			case ChatMessage::State::DeliveredToUser:
-				nbDeliveredToUserStates++;
-				break;
-			case ChatMessage::State::NotDelivered:
+	for (const auto &imdnState : imdnStates) {
+		const auto &participantState = imdnState.getState();
+		const auto &imdnParticipant = imdnState.getParticipant();
+		if (fromAddress->weakEqual(*(imdnParticipant->getAddress()))) {
+			if (participantState == ChatMessage::State::NotDelivered) {
 				nbNotDeliveredStates++;
-				break;
-			default:
-				break;
+			}
+		} else {
+			nbRecipients++;
+			switch (participantState) {
+				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 ((states.size() > 0) && (nbDisplayedStates == states.size())) {
+	} else if ((nbRecipients > 0) && (nbDisplayedStates == nbRecipients)) {
 		setState(ChatMessage::State::Displayed);
-	} else if ((states.size() > 0) && ((nbDisplayedStates + nbDeliveredToUserStates) == states.size())) {
+	} else if ((nbRecipients > 0) && ((nbDisplayedStates + nbDeliveredToUserStates) == nbRecipients)) {
 		setState(ChatMessage::State::DeliveredToUser);
 	}
 
 	// When we already marked an incoming message as displayed, start ephemeral countdown when all other recipients have
 	// displayed it as well
-	if (isEphemeral && state == ChatMessage::State::Displayed) {
-		if (direction == ChatMessage::Direction::Incoming &&
-		    nbDisplayedStates == states.size()) { // -1 is for ourselves, our own display state isn't stored in db
-			startEphemeralCountDown();
+	if (isEphemeral && state == ChatMessage::State::Displayed && direction == ChatMessage::Direction::Incoming) {
+		startEphemeralCountDown();
+	}
+
+	if (isMe) {
+		// Set me participant state to displayed if we are the sender, set the message as Displayed as soon as we
+		// received the 202 Accepted response
+		if (fromAddress->weakEqual(*participantAddress) && (newState == ChatMessage::State::DeliveredToUser)) {
+			setParticipantState(participantAddress, ChatMessage::State::Displayed, ::ms_time(nullptr));
 		}
 	}
 }
@@ -226,7 +291,6 @@ void ChatMessagePrivate::setState(ChatMessage::State newState) {
 	        << " to " << Utils::toString(newState);
 	ChatMessage::State oldState = state;
 	state = newState;
-	setParticipantState(chatRoom->getMe()->getAddress(), state, ::ms_time(nullptr));
 
 	if (state == ChatMessage::State::NotDelivered) {
 		if (salOp) {
@@ -239,7 +303,10 @@ void ChatMessagePrivate::setState(ChatMessage::State newState) {
 	if (direction == ChatMessage::Direction::Outgoing) {
 		// Delivered state isn't triggered by IMDN, so participants state won't be set unless we manually do so here
 		if (state == ChatMessage::State::Delivered) {
-			for (auto participant : chatRoom->getParticipants()) {
+			// Use list of participants the client is sure have received the message and not the actual list of
+			// participants being part of the chatroom
+			for (const auto &imdnState : q->getParticipantsState()) {
+				const auto &participant = imdnState.getParticipant();
 				setParticipantState(participant->getAddress(), state, q->getTime());
 			}
 		}
@@ -268,16 +335,14 @@ void ChatMessagePrivate::setState(ChatMessage::State newState) {
 		listeners.clear();
 	}
 
-	// 3. Specific case, change to displayed once all file transfers haven been downloaded, and only if chat message has
-	// been marked as read.
+	// 3. Specific case, upon reception do not attempt to store in db before asking the user if he wants to do so or not
 	if (state == ChatMessage::State::FileTransferDone && direction == ChatMessage::Direction::Incoming) {
 		if (!hasFileTransferContent() && isMarkedAsRead()) {
-			setState(ChatMessage::State::Displayed);
+			setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::Displayed, ::ms_time(nullptr));
 			return;
 		}
 	}
 
-	// 4. Specific case, upon reception do not attempt to store in db before asking the user if he wants to do so or not
 	if (state == ChatMessage::State::Delivered && oldState == ChatMessage::State::Idle &&
 	    direction == ChatMessage::Direction::Incoming && !q->isValid()) {
 		// If we're here it's because message is because we're in the middle of the receive() method and
@@ -287,47 +352,13 @@ void ChatMessagePrivate::setState(ChatMessage::State newState) {
 		return;
 	}
 
-	// 5. Send notification
-	if ((state == ChatMessage::State::Displayed) && direction == ChatMessage::Direction::Incoming) {
-		// Wait until all files are downloaded before sending displayed IMDN
-		static_cast<ChatRoomPrivate *>(chatRoom->getPrivate())->sendDisplayNotification(sharedMessage);
-	}
-
-	// 6. update in database for ephemeral message if necessary.
+	// 4. update in database for ephemeral message if necessary.
 	if (isEphemeral && state == ChatMessage::State::Displayed) {
-		bool allParticipantsAreInDisplayedState = false;
-		if (chatRoom->getCapabilities().isSet(ChatRoom::Capabilities::OneToOne)) {
-			allParticipantsAreInDisplayedState = true;
-		} else {
-			if (direction == ChatMessage::Direction::Incoming) {
-				const auto states = q->getParticipantsState();
-				size_t nbDisplayedStates = 0;
-				for (const auto &state : states) {
-					switch (state.getState()) {
-						case ChatMessage::State::Displayed:
-							nbDisplayedStates++;
-							break;
-						default:
-							break;
-					}
-				}
-
-				allParticipantsAreInDisplayedState =
-				    nbDisplayedStates ==
-				    states.size() - 1; // -1 is for ourselves, our own display state isn't stored in db
-			} else {
-				// For outgoing messages state is never displayed until all participants are in display state
-				allParticipantsAreInDisplayedState = true;
-			}
-		}
-
-		if (allParticipantsAreInDisplayedState) {
-			lInfo() << "All participants are in displayed state, starting ephemeral countdown";
-			startEphemeralCountDown();
-		}
+		lInfo() << "All participants are in displayed state, starting ephemeral countdown";
+		startEphemeralCountDown();
 	}
 
-	// 7. Update in database if necessary.
+	// 5. Update in database if necessary.
 	if (state != ChatMessage::State::InProgress && state != ChatMessage::State::FileTransferError &&
 	    state != ChatMessage::State::FileTransferInProgress) {
 		updateInDb();
@@ -754,8 +785,8 @@ LinphoneReason ChatMessagePrivate::receive() {
 			chatRoom->getPrivate()->notifyUndecryptableChatMessageReceived(q->getSharedFromThis());
 			reason = linphone_error_code_to_reason(errorCode);
 			if (!chatRoom) return reason;
-			static_cast<ChatRoomPrivate *>(chatRoom->getPrivate())
-			    ->sendDeliveryErrorNotification(q->getSharedFromThis(), reason);
+			setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::NotDelivered, ::ms_time(nullptr),
+			                    reason);
 			return reason;
 		}
 
@@ -844,7 +875,7 @@ LinphoneReason ChatMessagePrivate::receive() {
 	// a modifier)
 	currentRecvStep = ChatMessagePrivate::Step::None;
 
-	setState(ChatMessage::State::Delivered);
+	setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::Delivered, ::ms_time(nullptr));
 
 	// Check if this is in fact an outgoing message (case where this is a message sent by us from an other device).
 	if (chatRoom->getCapabilities() & ChatRoom::Capabilities::Conference &&
@@ -880,8 +911,8 @@ LinphoneReason ChatMessagePrivate::receive() {
 
 	if (chatRoom && (errorCode > 0)) {
 		reason = linphone_error_code_to_reason(errorCode);
-		static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())
-		    ->sendDeliveryErrorNotification(q->getSharedFromThis(), reason);
+		setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::NotDelivered, ::ms_time(nullptr),
+		                    reason);
 		return reason;
 	}
 
@@ -1007,7 +1038,10 @@ void ChatMessagePrivate::handleAutoDownload() {
 
 	chatRoom->getPrivate()->removeTransientChatMessage(q->getSharedFromThis());
 	setAutoFileTransferDownloadInProgress(false);
-	setState(ChatMessage::State::Delivered);
+	// The message is set to delivered here because this code is hit if the attachment cannot be downloaded or the
+	// download is aborted The delivered state will be set again message_delivery_update upon reception of 200 Ok or 202
+	// Accepted when a message is sent
+	setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::Delivered, ::ms_time(NULL));
 	chatRoom->getPrivate()->onChatMessageReceived(q->getSharedFromThis());
 
 	for (Content *c : contents) {
@@ -1113,14 +1147,16 @@ void ChatMessagePrivate::send() {
 	} else {
 		ChatMessageModifier::Result result = fileTransferChatMessageModifier.encode(q->getSharedFromThis(), errorCode);
 		if (result == ChatMessageModifier::Result::Error) {
-			setState(ChatMessage::State::NotDelivered);
+			setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::NotDelivered, ::ms_time(nullptr),
+			                    linphone_error_code_to_reason(errorCode));
 			// Remove current step so we go through all modifiers if message is re-sent
 			currentSendStep = ChatMessagePrivate::Step::None;
 			return;
 		}
 
 		if (result == ChatMessageModifier::Result::Suspended) {
-			setState(ChatMessage::State::FileTransferInProgress);
+			setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::FileTransferInProgress,
+			                    ::ms_time(nullptr));
 			return;
 		}
 		currentSendStep |= ChatMessagePrivate::Step::FileUpload;
@@ -1213,8 +1249,8 @@ void ChatMessagePrivate::send() {
 					// Remove current step so we go through all modifiers if message is re-sent
 					currentSendStep = ChatMessagePrivate::Step::None;
 					restoreFileTransferContentAsFileContent();
-					setState(
-					    ChatMessage::State::NotDelivered); // Do it after the restore to have the correct message in db
+					setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::NotDelivered,
+					                    ::ms_time(nullptr), linphone_error_code_to_reason(errorCode));
 					chatRoom->getPrivate()->removeTransientChatMessage(q->getSharedFromThis());
 					return;
 				} else if (result == ChatMessageModifier::Result::Suspended) {
@@ -1289,9 +1325,14 @@ void ChatMessagePrivate::send() {
 		// If it is a resend, reset participant states to Idle.
 		// Not doing so, it will lead to the message being incorrectly marked as not delivered when at least one
 		// participant hasn't received it yet.
-		for (auto participant : chatRoom->getParticipants()) {
+		// Use list of participants the client is sure have received the message and not the actual list of participants
+		// being part of the chatroom
+		for (const auto &imdnState : q->getParticipantsState()) {
+			const auto &participant = imdnState.getParticipant();
 			setParticipantState(participant->getAddress(), ChatMessage::State::Idle, q->getTime());
 		}
+		// Update message in DB to store the new IMDN message ID
+		updateInDb();
 	} else if (toBeStored) {
 		// Composing messages and IMDN aren't stored in DB so do not try, it will log an error message Invalid db key
 		// for nothing.
@@ -1307,7 +1348,7 @@ void ChatMessagePrivate::send() {
 	/* If operation failed, we should not change message state */
 	if (direction == ChatMessage::Direction::Outgoing) {
 		setIsReadOnly(true);
-		setState(ChatMessage::State::InProgress);
+		setParticipantState(chatRoom->getMe()->getAddress(), ChatMessage::State::InProgress, ::ms_time(nullptr));
 	}
 
 	if (q->isReaction()) {
@@ -1343,8 +1384,6 @@ void ChatMessagePrivate::storeInDb() {
 	dChatRoom->addEvent(eventLog); // From this point forward the chat message will have a valid dbKey
 	if (!chatRoom->getCapabilities().isSet(ChatRoom::Capabilities::Basic)) {
 		setParticipantState(chatRoom->getMe()->getAddress(), state, ::ms_time(nullptr));
-		setParticipantState(Address::create(q->getFromAddress()->getUriWithoutGruu()), ChatMessage::State::Displayed,
-		                    ::ms_time(nullptr));
 	}
 
 	if (direction == ChatMessage::Direction::Incoming) {
@@ -1397,6 +1436,11 @@ void ChatMessagePrivate::updateInDb() {
 
 // -----------------------------------------------------------------------------
 
+bool ChatMessagePrivate::isImdnControlledState(ChatMessage::State state) {
+	return (state == ChatMessage::State::Displayed || state == ChatMessage::State::DeliveredToUser ||
+	        state == ChatMessage::State::NotDelivered);
+}
+
 bool ChatMessagePrivate::isValidStateTransition(ChatMessage::State currentState, ChatMessage::State newState) {
 	if (newState == currentState) return false;
 
@@ -1659,13 +1703,11 @@ list<ParticipantImdnState> ChatMessage::getParticipantsState() const {
 	unique_ptr<MainDb> &mainDb = chatRoom->getCore()->getPrivate()->mainDb;
 	shared_ptr<EventLog> eventLog = mainDb->getEvent(mainDb, getStorageId());
 	list<MainDb::ParticipantState> dbResults = mainDb->getChatMessageParticipantStates(eventLog);
-	auto sender = chatRoom->findParticipant(getFromAddress());
-	auto meIsSender = chatRoom->isMe(getFromAddress());
 	for (const auto &dbResult : dbResults) {
 		auto isMe = chatRoom->isMe(dbResult.address);
 		auto participant = isMe ? chatRoom->getMe() : chatRoom->findParticipant(dbResult.address);
 		// Do not add myself to the result list if I am the sender.
-		if (participant && ((participant != sender) || !meIsSender)) {
+		if (participant) {
 			result.emplace_back(participant, dbResult.state, dbResult.timestamp);
 		}
 	}
@@ -1769,13 +1811,14 @@ void ChatMessage::cancelFileTransfer() {
 		lInfo() << "File transfer on message [" << getSharedFromThis() << "] has been cancelled";
 
 		if (d->state == State::FileTransferInProgress) {
+			auto chatRoom = getChatRoom();
 			lInfo() << "File transfer on message [" << getSharedFromThis() << "] was in progress, updating state";
 			// For auto download messages, set the state back to Delivered
 			if (d->isAutoFileTransferDownloadInProgress()) {
-				d->setState(State::Delivered);
-				getChatRoom()->getPrivate()->removeTransientChatMessage(getSharedFromThis());
+				d->setParticipantState(chatRoom->getMe()->getAddress(), State::Delivered, ::ms_time(nullptr));
+				chatRoom->getPrivate()->removeTransientChatMessage(getSharedFromThis());
 			} else {
-				d->setState(State::NotDelivered);
+				d->setParticipantState(chatRoom->getMe()->getAddress(), State::NotDelivered, ::ms_time(nullptr));
 			}
 		}
 	} else {
diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp
index fd566c4b6355a8221586be544ac04e146760d29c..88db4eb22759b99a723011dd3286506fbe525c7f 100644
--- a/src/chat/chat-room/chat-room.cpp
+++ b/src/chat/chat-room/chat-room.cpp
@@ -169,7 +169,8 @@ void ChatRoomPrivate::realtimeTextReceived(uint32_t character, const shared_ptr<
 			pendingMessage->addContent(content);
 
 			bctbx_debug("New line received, forge a message with content [%s]", content->getBodyAsString().c_str());
-			pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered);
+			pendingMessage->getPrivate()->setParticipantState(q->getMe()->getAddress(), ChatMessage::State::Delivered,
+			                                                  ::ms_time(nullptr));
 			pendingMessage->getPrivate()->setTime(::ms_time(0));
 
 			if (linphone_config_get_int(linphone_core_get_config(cCore), "misc", "store_rtt_messages", 1) == 1) {
@@ -474,7 +475,8 @@ void ChatRoomPrivate::notifyAggregatedChatMessages() {
 
 	// Notify delivery
 	for (auto &chatMessage : aggregatedMessages) {
-		sendDeliveryNotification(chatMessage);
+		chatMessage->getPrivate()->setParticipantState(q->getMe()->getAddress(), ChatMessage::State::DeliveredToUser,
+		                                               ::ms_time(nullptr));
 	}
 
 	bctbx_list_free_with_data(cMessages, (bctbx_list_free_func)linphone_chat_message_unref);
@@ -771,7 +773,8 @@ void ChatRoom::markAsRead() {
 		chatMessage->getPrivate()->markAsRead();
 		// Do not set the message state has displayed if it contains a file transfer (to prevent imdn sending)
 		if (!chatMessage->getPrivate()->hasFileTransferContent()) {
-			chatMessage->getPrivate()->setState(ChatMessage::State::Displayed);
+			chatMessage->getPrivate()->setParticipantState(getMe()->getAddress(), ChatMessage::State::Displayed,
+			                                               ::ms_time(nullptr));
 		}
 	}
 
@@ -780,7 +783,8 @@ void ChatRoom::markAsRead() {
 		chatMessage->getPrivate()->markAsRead();
 		// Do not set the message state has displayed if it contains a file transfer (to prevent imdn sending)
 		if (!chatMessage->getPrivate()->hasFileTransferContent()) {
-			chatMessage->getPrivate()->setState(ChatMessage::State::Displayed);
+			chatMessage->getPrivate()->setParticipantState(getMe()->getAddress(), ChatMessage::State::Displayed,
+			                                               ::ms_time(nullptr));
 		}
 	}
 
diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp
index 5c52cc648b71fca100997c3eb74a8a12ee97cf40..f3a6995d1f8fb914c8b0cdd71a940570ebefc2f0 100644
--- a/src/chat/chat-room/client-group-chat-room.cpp
+++ b/src/chat/chat-room/client-group-chat-room.cpp
@@ -349,7 +349,8 @@ void ClientGroupChatRoomPrivate::onCallSessionStateChanged(const shared_ptr<Call
 			// If there are chat message pending chat room creation, set state to NotDelivered and remove them from
 			// queue.
 			for (const auto &message : pendingCreationMessages) {
-				message->getPrivate()->setState(ChatMessage::State::NotDelivered);
+				message->getPrivate()->setParticipantState(q->getMe()->getAddress(), ChatMessage::State::NotDelivered,
+				                                           ::ms_time(nullptr));
 			}
 			pendingCreationMessages.clear();
 			if (reason == LinphoneReasonForbidden) {
diff --git a/src/chat/chat-room/server-group-chat-room.cpp b/src/chat/chat-room/server-group-chat-room.cpp
index 2cb00c390c0d421ac1dbaafa8d527746348cec60..514bcce45888214bc16c8583fa8de2a93edb861f 100644
--- a/src/chat/chat-room/server-group-chat-room.cpp
+++ b/src/chat/chat-room/server-group-chat-room.cpp
@@ -1070,7 +1070,7 @@ shared_ptr<CallSession> ServerGroupChatRoomPrivate::makeSession(const std::share
 void ServerGroupChatRoomPrivate::inviteDevice(const shared_ptr<ParticipantDevice> &device) {
 	L_Q();
 
-	lInfo() << q << ": Inviting device '" << device->getAddress()->toString() << "'";
+	lInfo() << q << ": Inviting device '" << *device->getAddress() << "'";
 	shared_ptr<Participant> participant =
 	    const_pointer_cast<Participant>(device->getParticipant()->getSharedFromThis());
 	shared_ptr<CallSession> session = makeSession(device);
@@ -1157,7 +1157,7 @@ void ServerGroupChatRoomPrivate::queueMessage(const shared_ptr<Message> &msg) {
 	for (const auto &participant : q->getParticipants()) {
 		for (const auto &device : participant->getDevices()) {
 			// Queue the message for all devices except the one that sent it
-			if (msg->fromAddr != device->getAddress()) {
+			if (*msg->fromAddr != *device->getAddress()) {
 				queueMessage(msg, device->getAddress());
 			}
 		}
diff --git a/src/chat/encryption/lime-x3dh-encryption-engine.cpp b/src/chat/encryption/lime-x3dh-encryption-engine.cpp
index 59dcc1b874c21b9eb66503b421b821dfdc946d10..c0da0b68c67f69d05d47c12147e556c5899fff5b 100644
--- a/src/chat/encryption/lime-x3dh-encryption-engine.cpp
+++ b/src/chat/encryption/lime-x3dh-encryption-engine.cpp
@@ -423,7 +423,8 @@ ChatMessageModifier::Result LimeX3dhEncryptionEngine::processOutgoingMessage(con
 				    }
 			    } else {
 				    lError() << "[LIME] operation failed: " << errorMessage;
-				    message->getPrivate()->setState(ChatMessage::State::NotDelivered);
+				    message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+				                                               ChatMessage::State::NotDelivered, ::ms_time(nullptr));
 				    *result = ChatMessageModifier::Result::Error;
 			    }
 		    },
diff --git a/src/chat/modifier/file-transfer-chat-message-modifier.cpp b/src/chat/modifier/file-transfer-chat-message-modifier.cpp
index 199decae08c5bde245e365ad7dbdbcf51dc257f0..b1676d21d0f316efb7af39341bb80a44ae567427 100644
--- a/src/chat/modifier/file-transfer-chat-message-modifier.cpp
+++ b/src/chat/modifier/file-transfer-chat-message-modifier.cpp
@@ -30,6 +30,7 @@
 #include "chat/chat-message/chat-message-p.h"
 #include "chat/chat-room/chat-room-p.h"
 #include "chat/encryption/encryption-engine.h"
+#include "conference/participant.h"
 #include "content/content-type.h"
 #include "content/content.h"
 #include "core/core.h"
@@ -359,7 +360,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile(const belle_ht
 					delete currentFileTransferContent;
 					currentFileTransferContent = nullptr;
 
-					message->getPrivate()->setState(ChatMessage::State::NotDelivered);
+					message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+					                                           ChatMessage::State::NotDelivered, ::ms_time(nullptr));
 					releaseHttpRequest();
 					fileUploadEndBackgroundTask();
 
@@ -389,7 +391,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile(const belle_ht
 				currentFileTransferContent->setBodyFromUtf8(xml_body.c_str());
 				currentFileTransferContent = nullptr;
 
-				message->getPrivate()->setState(ChatMessage::State::FileTransferDone);
+				message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+				                                           ChatMessage::State::FileTransferDone, ::ms_time(nullptr));
 				releaseHttpRequest();
 				message->getPrivate()->send();
 				fileUploadEndBackgroundTask();
@@ -399,7 +402,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile(const belle_ht
 				delete currentFileTransferContent;
 				currentFileTransferContent = nullptr;
 
-				message->getPrivate()->setState(ChatMessage::State::NotDelivered);
+				message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+				                                           ChatMessage::State::NotDelivered, ::ms_time(nullptr));
 				releaseHttpRequest();
 				fileUploadEndBackgroundTask();
 			}
@@ -410,7 +414,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile(const belle_ht
 			delete currentFileTransferContent;
 			currentFileTransferContent = nullptr;
 
-			message->getPrivate()->setState(ChatMessage::State::FileTransferError);
+			message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+			                                           ChatMessage::State::FileTransferError, ::ms_time(nullptr));
 			releaseHttpRequest();
 			fileUploadEndBackgroundTask();
 		} else if (code == 401) {
@@ -420,7 +425,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile(const belle_ht
 			delete currentFileTransferContent;
 			currentFileTransferContent = nullptr;
 
-			message->getPrivate()->setState(ChatMessage::State::FileTransferError);
+			message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+			                                           ChatMessage::State::FileTransferError, ::ms_time(nullptr));
 			releaseHttpRequest();
 			fileUploadEndBackgroundTask();
 		} else {
@@ -429,7 +435,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile(const belle_ht
 			delete currentFileTransferContent;
 			currentFileTransferContent = nullptr;
 
-			message->getPrivate()->setState(ChatMessage::State::NotDelivered);
+			message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+			                                           ChatMessage::State::NotDelivered, ::ms_time(nullptr));
 			releaseHttpRequest();
 			fileUploadEndBackgroundTask();
 		}
@@ -445,7 +452,8 @@ void FileTransferChatMessageModifier::processIoErrorUpload(BCTBX_UNUSED(const be
 	shared_ptr<ChatMessage> message = chatMessage.lock();
 	lError() << "I/O Error during file upload of message [" << message << "]";
 	if (!message) return;
-	message->getPrivate()->setState(ChatMessage::State::NotDelivered);
+	message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+	                                           ChatMessage::State::NotDelivered, ::ms_time(nullptr));
 	releaseHttpRequest();
 }
 
@@ -665,7 +673,8 @@ void FileTransferChatMessageModifier::onRecvBody(BCTBX_UNUSED(belle_sip_user_bod
 		}
 	} else {
 		lWarning() << "File transfer decrypt failed with code -" << hex << (int)(-retval);
-		message->getPrivate()->setState(ChatMessage::State::FileTransferError);
+		message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+		                                           ChatMessage::State::FileTransferError, ::ms_time(nullptr));
 	}
 }
 
@@ -751,7 +760,8 @@ void FileTransferChatMessageModifier::onRecvEnd(BCTBX_UNUSED(belle_sip_user_body
 			}
 
 			releaseHttpRequest();
-			message->getPrivate()->setState(ChatMessage::State::FileTransferDone);
+			message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+			                                           ChatMessage::State::FileTransferDone, ::ms_time(nullptr));
 			if (message->getPrivate()->isAutoFileTransferDownloadInProgress()) {
 				renameFileAfterAutoDownload(core, fileContent);
 				message->getPrivate()->handleAutoDownload();
@@ -759,7 +769,8 @@ void FileTransferChatMessageModifier::onRecvEnd(BCTBX_UNUSED(belle_sip_user_body
 		}
 	} else {
 		lWarning() << "File transfer decrypt failed with code " << (int)retval;
-		message->getPrivate()->setState(ChatMessage::State::FileTransferError);
+		message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+		                                           ChatMessage::State::FileTransferError, ::ms_time(nullptr));
 		releaseHttpRequest();
 		currentFileTransferContent = nullptr;
 	}
@@ -802,7 +813,8 @@ void FileTransferChatMessageModifier::processResponseHeadersFromGetFile(const be
 
 		if (code >= 400 && code < 500) {
 			lWarning() << "File transfer failed with code " << code;
-			message->getPrivate()->setState(ChatMessage::State::FileTransferError);
+			message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+			                                           ChatMessage::State::FileTransferDone, ::ms_time(nullptr));
 			releaseHttpRequest();
 			currentFileTransferContent = nullptr;
 			return;
@@ -864,7 +876,8 @@ void FileTransferChatMessageModifier::onDownloadFailed() {
 		releaseHttpRequest();
 		message->getPrivate()->handleAutoDownload();
 	} else {
-		message->getPrivate()->setState(ChatMessage::State::FileTransferError);
+		message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+		                                           ChatMessage::State::FileTransferError, ::ms_time(nullptr));
 		releaseHttpRequest();
 		currentFileTransferContent = nullptr;
 	}
@@ -983,7 +996,8 @@ bool FileTransferChatMessageModifier::downloadFile(const shared_ptr<ChatMessage>
 	int err = startHttpTransfer(url, "GET", nullptr, &cbs);
 	if (err == -1) return false;
 	// start the download, status is In Progress
-	message->getPrivate()->setState(ChatMessage::State::FileTransferInProgress);
+	message->getPrivate()->setParticipantState(message->getChatRoom()->getMe()->getAddress(),
+	                                           ChatMessage::State::FileTransferInProgress, ::ms_time(nullptr));
 	return true;
 }
 
diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp
index b0d7f29f8b126ef3287cb69d89950ff87fc9bdc4..e5b3f58888ba8876dcc77b5d6641477f47f02d51 100644
--- a/src/db/main-db.cpp
+++ b/src/db/main-db.cpp
@@ -1532,6 +1532,7 @@ void MainDbPrivate::updateConferenceChatMessageEvent(const shared_ptr<EventLog>
 	const EventLogPrivate *dEventLog = eventLog->getPrivate();
 	MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
 	const long long &eventId = dEventKey->storageId;
+	soci::session *session = dbSession.getBackendSession();
 
 	// 1. Get current chat message state and database state.
 	const ChatMessage::State state = chatMessage->getState();
@@ -1540,8 +1541,7 @@ void MainDbPrivate::updateConferenceChatMessageEvent(const shared_ptr<EventLog>
 	{
 		int intState;
 		int intMarkedAsRead;
-		*dbSession.getBackendSession()
-		    << "SELECT state, marked_as_read FROM conference_chat_message_event WHERE event_id = :eventId",
+		*session << "SELECT state, marked_as_read FROM conference_chat_message_event WHERE event_id = :eventId",
 		    soci::into(intState), soci::into(intMarkedAsRead), soci::use(eventId);
 		dbState = ChatMessage::State(intState);
 		dbMarkedAsRead = intMarkedAsRead == 1;
@@ -1550,7 +1550,7 @@ void MainDbPrivate::updateConferenceChatMessageEvent(const shared_ptr<EventLog>
 
 	// 2. Update unread chat message count if necessary.
 	const bool isOutgoing = chatMessage->getDirection() == ChatMessage::Direction::Outgoing;
-	shared_ptr<AbstractChatRoom> chatRoom(chatMessage->getChatRoom());
+	shared_ptr<AbstractChatRoom> chatRoom = chatMessage->getChatRoom();
 	if (!isOutgoing && markedAsRead) {
 		int *count = unreadChatMessageCountCache[chatRoom->getConferenceId()];
 		if (count && !dbMarkedAsRead) {
@@ -1570,9 +1570,9 @@ void MainDbPrivate::updateConferenceChatMessageEvent(const shared_ptr<EventLog>
 		            ? dbState
 		            : state);
 		const int markedAsReadInt = markedAsRead ? 1 : 0;
-		*dbSession.getBackendSession() << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = "
-		                                  ":imdnMessageId, marked_as_read = :markedAsRead"
-		                                  " WHERE event_id = :eventId",
+		*session << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = "
+		            ":imdnMessageId, marked_as_read = :markedAsRead"
+		            " WHERE event_id = :eventId",
 		    soci::use(stateInt), soci::use(imdnMessageId), soci::use(markedAsReadInt), soci::use(eventId);
 	}
 
@@ -1582,9 +1582,21 @@ void MainDbPrivate::updateConferenceChatMessageEvent(const shared_ptr<EventLog>
 		insertContent(eventId, *content);
 
 	// 5. Update participants.
-	if (isOutgoing && (state == ChatMessage::State::Delivered || state == ChatMessage::State::NotDelivered))
-		for (const auto &participant : chatRoom->getParticipants())
-			setChatMessageParticipantState(eventLog, participant->getAddress(), state, std::time(nullptr));
+	if (isOutgoing && (state == ChatMessage::State::Delivered || state == ChatMessage::State::NotDelivered) &&
+	    (chatRoom->getCapabilities() & AbstractChatRoom::Capabilities::Conference) && chatMessage->isValid()) {
+		static const string query = "SELECT sip_address.value"
+		                            " FROM sip_address"
+		                            " WHERE event_id = :eventId"
+		                            " AND sip_address.id = chat_message_participant.participant_sip_address_id";
+		soci::rowset<soci::row> rows = (session->prepare << query, soci::use(chatMessage->getStorageId()));
+
+		// Use list of participants the client is sure have received the message and not the actual list of participants
+		// being part of the chatroom
+		for (const auto &row : rows) {
+			const auto address = Address::create(row.get<string>(0));
+			setChatMessageParticipantState(eventLog, address, state, std::time(nullptr));
+		}
+	}
 #endif
 }
 
diff --git a/src/event-log/conference/conference-participant-event.cpp b/src/event-log/conference/conference-participant-event.cpp
index 9517d84703572641f3890c3e64032a65723e35a4..1e579155ffc8eb9c0103823e804591f099721fe0 100644
--- a/src/event-log/conference/conference-participant-event.cpp
+++ b/src/event-log/conference/conference-participant-event.cpp
@@ -36,7 +36,9 @@ ConferenceParticipantEvent::ConferenceParticipantEvent(Type type,
     : ConferenceNotifiedEvent(*new ConferenceParticipantEventPrivate, type, creationTime, conferenceId) {
 	L_D();
 	L_ASSERT(type == Type::ConferenceParticipantAdded || type == Type::ConferenceParticipantRemoved ||
-	         type == Type::ConferenceParticipantSetAdmin || type == Type::ConferenceParticipantUnsetAdmin);
+	         type == Type::ConferenceParticipantSetAdmin || type == Type::ConferenceParticipantUnsetAdmin ||
+	         type == Type::ConferenceParticipantRoleUnknown || type == Type::ConferenceParticipantRoleListener ||
+	         type == Type::ConferenceParticipantRoleSpeaker);
 	d->participantAddress = participantAddress;
 }
 
diff --git a/tester/local_chat_imdn_tester.cpp b/tester/local_chat_imdn_tester.cpp
index 9dddc2d16955f829dcdfae440604e91ad4290c97..8afe5dab1a44c0d83bcdf74ba9f82dff26db1977 100644
--- a/tester/local_chat_imdn_tester.cpp
+++ b/tester/local_chat_imdn_tester.cpp
@@ -24,6 +24,211 @@
 
 namespace LinphoneTest {
 
+static void group_chat_room_with_imdn(void) {
+	Focus focus("chloe_rc");
+	{ // to make sure focus is destroyed after clients.
+		bool_t encrypted = FALSE;
+		ClientConference marie("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference marie2("marie_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference michelle2("michelle_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline("pauline_rc", focus.getIdentity(), encrypted);
+		ClientConference pauline2("pauline_rc", focus.getIdentity(), encrypted);
+
+		focus.registerAsParticipantDevice(marie);
+		focus.registerAsParticipantDevice(marie2);
+		focus.registerAsParticipantDevice(michelle);
+		focus.registerAsParticipantDevice(michelle2);
+		focus.registerAsParticipantDevice(pauline);
+		focus.registerAsParticipantDevice(pauline2);
+
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie2.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(michelle2.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline.getLc()));
+		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline2.getLc()));
+
+		stats marie_stat = marie.getStats();
+		stats marie2_stat = marie.getStats();
+		stats michelle_stat = michelle.getStats();
+		stats michelle2_stat = michelle2.getStats();
+		stats pauline_stat = pauline.getStats();
+		stats pauline2_stat = pauline2.getStats();
+		bctbx_list_t *coresList = bctbx_list_append(NULL, focus.getLc());
+		coresList = bctbx_list_append(coresList, marie.getLc());
+		coresList = bctbx_list_append(coresList, marie2.getLc());
+		coresList = bctbx_list_append(coresList, michelle.getLc());
+		coresList = bctbx_list_append(coresList, michelle2.getLc());
+		coresList = bctbx_list_append(coresList, pauline.getLc());
+		coresList = bctbx_list_append(coresList, pauline2.getLc());
+
+		if (encrypted) {
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_X3dhUserCreationSuccess,
+			                             marie_stat.number_of_X3dhUserCreationSuccess + 1, x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &marie2.getStats().number_of_X3dhUserCreationSuccess,
+			                             marie2_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_X3dhUserCreationSuccess,
+			                             michelle_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_X3dhUserCreationSuccess,
+			                             michelle2_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_X3dhUserCreationSuccess,
+			                             pauline_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+			BC_ASSERT_TRUE(wait_for_list(coresList, &pauline2.getStats().number_of_X3dhUserCreationSuccess,
+			                             pauline2_stat.number_of_X3dhUserCreationSuccess + 1,
+			                             x3dhServer_creationTimeout));
+
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(marie2.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(michelle2.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline.getLc()));
+			BC_ASSERT_TRUE(linphone_core_lime_x3dh_enabled(pauline2.getLc()));
+		}
+
+		bctbx_list_t *participantsAddresses = NULL;
+		Address michelleAddr = michelle.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelleAddr.toC()));
+		Address michelle2Addr = michelle2.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(michelle2Addr.toC()));
+		Address paulineAddr = pauline.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(paulineAddr.toC()));
+		Address pauline2Addr = pauline2.getIdentity();
+		participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_ref(pauline2Addr.toC()));
+
+		// Marie creates a new group chat room
+		const char *initialSubject = "Colleagues (characters: $ £ çà)";
+		LinphoneChatRoom *marieCr = create_chat_room_client_side_with_expected_number_of_participants(
+		    coresList, marie.getCMgr(), &marie_stat, participantsAddresses, initialSubject, 2, encrypted,
+		    LinphoneChatRoomEphemeralModeDeviceManaged);
+		BC_ASSERT_PTR_NOT_NULL(marieCr);
+		const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
+
+		LinphoneChatRoom *marie2Cr = check_creation_chat_room_client_side(coresList, marie.getCMgr(), &marie_stat,
+		                                                                  confAddr, initialSubject, 2, TRUE);
+		BC_ASSERT_PTR_NOT_NULL(marie2Cr);
+
+		// Check that the chat room is correctly created on Michelle's side and that the participants are added
+		LinphoneChatRoom *michelleCr = check_creation_chat_room_client_side(
+		    coresList, michelle.getCMgr(), &michelle_stat, confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(michelleCr);
+		LinphoneChatRoom *michelle2Cr = check_creation_chat_room_client_side(
+		    coresList, michelle2.getCMgr(), &michelle2_stat, confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(michelle2Cr);
+
+		// 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.getCMgr(), &pauline_stat,
+		                                                                   confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(paulineCr);
+		LinphoneChatRoom *pauline2Cr = check_creation_chat_room_client_side(
+		    coresList, pauline2.getCMgr(), &pauline2_stat, confAddr, initialSubject, 2, FALSE);
+		BC_ASSERT_PTR_NOT_NULL(pauline2Cr);
+
+		// Marie sends the message
+		const char *marieMessage = "Hey ! What's up ?";
+		LinphoneChatMessage *msg = ClientConference::sendTextMsg(marieCr, marieMessage);
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie2.getStats().number_of_LinphoneMessageReceived,
+		                             marie2_stat.number_of_LinphoneMessageReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		LinphoneChatMessage *marie2LastMsg = marie2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(marie2LastMsg);
+		if (marie2LastMsg) {
+			LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(marie2LastMsg);
+			linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneMessageReceived,
+		                             michelle_stat.number_of_LinphoneMessageReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		LinphoneChatMessage *michelleLastMsg = michelle.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelleLastMsg);
+		if (michelleLastMsg) {
+			LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(michelleLastMsg);
+			linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneMessageReceived,
+		                             michelle2_stat.number_of_LinphoneMessageReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		LinphoneChatMessage *michelle2LastMsg = michelle2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(michelle2LastMsg);
+		if (michelle2LastMsg) {
+			LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(michelle2LastMsg);
+			linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageReceived,
+		                             pauline_stat.number_of_LinphoneMessageReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		LinphoneChatMessage *paulineLastMsg = pauline.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(paulineLastMsg);
+		if (paulineLastMsg) {
+			LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(paulineLastMsg);
+			linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
+		}
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline2.getStats().number_of_LinphoneMessageReceived,
+		                             pauline2_stat.number_of_LinphoneMessageReceived + 1,
+		                             liblinphone_tester_sip_timeout));
+		LinphoneChatMessage *pauline2LastMsg = pauline2.getStats().last_received_chat_message;
+		BC_ASSERT_PTR_NOT_NULL(pauline2LastMsg);
+		if (pauline2LastMsg) {
+			LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(pauline2LastMsg);
+			linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
+		}
+
+		linphone_chat_room_mark_as_read(michelleCr);
+		linphone_chat_room_mark_as_read(paulineCr);
+
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneMessageDisplayed,
+		                             marie_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &marie2.getStats().number_of_LinphoneMessageDisplayed,
+		                             marie2_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneMessageDisplayed,
+		                             michelle_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneMessageDisplayed,
+		                             michelle2_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline.getStats().number_of_LinphoneMessageDisplayed,
+		                             pauline_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+		BC_ASSERT_TRUE(wait_for_list(coresList, &pauline2.getStats().number_of_LinphoneMessageDisplayed,
+		                             pauline2_stat.number_of_LinphoneMessageDisplayed + 1,
+		                             liblinphone_tester_sip_timeout));
+
+		linphone_chat_message_unref(msg);
+		msg = nullptr;
+
+		for (auto chatRoom : focus.getCore().getChatRooms()) {
+			for (auto participant : chatRoom->getParticipants()) {
+				//  force deletion by removing devices
+				std::shared_ptr<Address> participantAddress = participant->getAddress();
+				linphone_chat_room_set_participant_devices(L_GET_C_BACK_PTR(chatRoom), participantAddress->toC(), NULL);
+			}
+		}
+
+		// wait until chatroom is deleted server side
+		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, marie2, michelle, michelle2, pauline, pauline2}).wait([&focus] {
+			return focus.getCore().getChatRooms().size() == 0;
+		}));
+
+		// wait bit more to detect side effect if any
+		CoreManagerAssert({focus, marie, marie2, michelle, michelle2, pauline, pauline2})
+		    .waitUntil(chrono::seconds(2), [] { return false; });
+
+		// to avoid creation attempt of a new chatroom
+		auto config = focus.getDefaultProxyConfig();
+		linphone_proxy_config_edit(config);
+		linphone_proxy_config_set_conference_factory_uri(config, NULL);
+		linphone_proxy_config_done(config);
+
+		bctbx_list_free(coresList);
+	}
+}
+
 static void
 group_chat_room_with_client_idmn_after_restart_base(bool_t encrypted, bool_t add_participant, bool_t stop_core) {
 	Focus focus("chloe_rc");
@@ -674,6 +879,7 @@ static test_t local_conference_chat_imdn_tests[] = {
     TEST_ONE_TAG("Secure group chat with client IMDN sent after restart and participant added",
                  LinphoneTest::secure_group_chat_room_with_client_idmn_sent_after_restart_and_participant_added,
                  "LeaksMemory"), /* because of network up and down */
+    TEST_NO_TAG("Secure Group chat with IMDN", LinphoneTest::group_chat_room_with_imdn),
     TEST_ONE_TAG(
         "Secure group chat with client IMDN sent after restart and participant added and core stopped before sending "
         "IMDN",
diff --git a/tester/local_chat_tester.cpp b/tester/local_chat_tester.cpp
index 5ff42f5e411ae6b1e9b3831a38539732550150fb..2a1ff017b0eee4719888e332cc4498729872010d 100644
--- a/tester/local_chat_tester.cpp
+++ b/tester/local_chat_tester.cpp
@@ -1653,7 +1653,6 @@ static void group_chat_room_with_creator_without_groupchat_capability(void) {
 		    linphone_core_create_chat_room_6(marie.getLc(), params, NULL, participantsAddresses);
 		linphone_chat_room_params_unref(params);
 		BC_ASSERT_PTR_NOT_NULL(chatRoom);
-
 		// linphone_core_create_chat_room_6 takes a ref to the chatroom
 		if (chatRoom) linphone_chat_room_unref(chatRoom);
 
@@ -2624,12 +2623,8 @@ static test_t local_conference_chat_tests[] = {
 };
 
 static test_t local_conference_chat_error_tests[] = {
-    TEST_ONE_TAG("Group chat with INVITE session error",
-                 LinphoneTest::group_chat_room_with_invite_error,
-                 "LeaksMemory"), /* because of network up and down */
-    TEST_ONE_TAG("Group chat with SUBSCRIBE session error",
-                 LinphoneTest::group_chat_room_with_subscribe_error,
-                 "LeaksMemory"), /* because of network up and down */
+    TEST_NO_TAG("Group chat with INVITE session error", LinphoneTest::group_chat_room_with_invite_error),
+    TEST_NO_TAG("Group chat with SUBSCRIBE session error", LinphoneTest::group_chat_room_with_subscribe_error),
     TEST_NO_TAG("Group chat Add participant with invalid address",
                 LinphoneTest::group_chat_room_add_participant_with_invalid_address),
     TEST_NO_TAG("Group chat Only participant with invalid address",
diff --git a/tester/local_conference_tester_functions.cpp b/tester/local_conference_tester_functions.cpp
index 76e2b2186411da9563ce557027ed9be857ebceba..7cb2bcbf74478fc4962eaa4327503b6e9386cfcf 100644
--- a/tester/local_conference_tester_functions.cpp
+++ b/tester/local_conference_tester_functions.cpp
@@ -617,11 +617,15 @@ void group_chat_room_with_client_restart_base(bool encrypted) {
 
 static void chat_room_participant_added_sip_error(LinphoneChatRoom *cr,
                                                   BCTBX_UNUSED(const LinphoneEventLog *event_log)) {
-	if (bctbx_list_size(linphone_chat_room_get_participants(cr)) == 2) {
+	bctbx_list_t *participants = linphone_chat_room_get_participants(cr);
+	if (bctbx_list_size(participants) == 2) {
 		LinphoneCoreManager *initiator = (LinphoneCoreManager *)linphone_chat_room_get_user_data(cr);
 		ms_message("Turning off network for core %s", linphone_core_get_identity(initiator->lc));
 		linphone_core_set_network_reachable(initiator->lc, FALSE);
 	}
+	if (participants) {
+		bctbx_list_free_with_data(participants, (bctbx_list_free_func)linphone_participant_unref);
+	}
 }
 
 static void
@@ -717,6 +721,22 @@ void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_erro
 		initialMarieStats = marie.getStats();
 		initialBertheStats = berthe.getStats();
 
+		std::list<LinphoneCoreManager *> shutdownNetworkClients;
+		std::list<stats> initialStatsList;
+		if (invite_error) {
+			shutdownNetworkClients.push_back(michelle2.getCMgr());
+			initialStatsList.push_back(michelle2.getStats());
+			shutdownNetworkClients.push_back(berthe.getCMgr());
+			initialStatsList.push_back(berthe.getStats());
+		} else if (subscribe_error) {
+			shutdownNetworkClients.push_back(marie.getCMgr());
+			initialStatsList.push_back(marie.getStats());
+			shutdownNetworkClients.push_back(michelle2.getCMgr());
+			initialStatsList.push_back(michelle2.getStats());
+			shutdownNetworkClients.push_back(berthe.getCMgr());
+			initialStatsList.push_back(berthe.getStats());
+		}
+
 		focus.registerAsParticipantDevice(marie);
 		focus.registerAsParticipantDevice(michelle);
 		focus.registerAsParticipantDevice(michelle2);
@@ -727,6 +747,7 @@ void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_erro
 			LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
 			linphone_core_cbs_set_chat_room_state_changed(cbs, server_core_chat_room_state_changed_sip_error);
 			linphone_core_add_callbacks(focus.getLc(), cbs);
+			linphone_core_cbs_unref(cbs);
 		}
 
 		linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie.getLc()));
@@ -758,6 +779,7 @@ void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_erro
 		LinphoneChatRoom *marieCr =
 		    linphone_core_create_chat_room_2(marie.getLc(), params, initialSubject, participantsAddresses);
 		linphone_chat_room_params_unref(params);
+		if (marieCr) linphone_chat_room_unref(marieCr);
 
 		BC_ASSERT_TRUE(CoreManagerAssert({focus, marie, pauline, michelle, michelle2, laure, berthe}).wait([&focus] {
 			return focus.getCore().getChatRooms().size() == 1;
@@ -767,43 +789,18 @@ void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_erro
 			linphone_chat_room_set_user_data(L_GET_C_BACK_PTR(chatRoom), marie.getCMgr());
 		}
 
-		if (invite_error) {
-			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneConferenceStateCreated,
-			                             initialMichelle2Stats.number_of_LinphoneConferenceStateCreated + 1,
-			                             liblinphone_tester_sip_timeout));
-			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(michelle2.getLc()),
-			           linphone_address_as_string(linphone_proxy_config_get_contact(
-			               linphone_core_get_default_proxy_config(michelle2.getLc()))));
-			linphone_core_set_network_reachable(michelle2.getLc(), FALSE);
-			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneConferenceStateCreated,
-			                             initialBertheStats.number_of_LinphoneConferenceStateCreated + 1,
+		for (const auto &client : shutdownNetworkClients) {
+			stats &initialStats = initialStatsList.front();
+			BC_ASSERT_TRUE(wait_for_list(coresList, &client->stat.number_of_LinphoneConferenceStateCreated,
+			                             initialStats.number_of_LinphoneConferenceStateCreated + 1,
 			                             liblinphone_tester_sip_timeout));
-			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(berthe.getLc()),
-			           linphone_address_as_string(
-			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(berthe.getLc()))));
-			linphone_core_set_network_reachable(berthe.getLc(), FALSE);
-		} else if (subscribe_error) {
-			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneSubscriptionActive,
-			                             initialMarieStats.number_of_LinphoneSubscriptionActive + 1,
-			                             liblinphone_tester_sip_timeout));
-			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(marie.getLc()),
-			           linphone_address_as_string(
-			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie.getLc()))));
-			linphone_core_set_network_reachable(marie.getLc(), FALSE);
-			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneSubscriptionActive,
-			                             initialMichelle2Stats.number_of_LinphoneSubscriptionActive + 1,
-			                             liblinphone_tester_sip_timeout));
-			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(michelle2.getLc()),
-			           linphone_address_as_string(linphone_proxy_config_get_contact(
-			               linphone_core_get_default_proxy_config(michelle2.getLc()))));
-			linphone_core_set_network_reachable(michelle2.getLc(), FALSE);
-			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneSubscriptionActive,
-			                             initialBertheStats.number_of_LinphoneSubscriptionActive + 1,
-			                             liblinphone_tester_sip_timeout));
-			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(berthe.getLc()),
-			           linphone_address_as_string(
-			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(berthe.getLc()))));
-			linphone_core_set_network_reachable(berthe.getLc(), FALSE);
+			char *proxy_contact_str = linphone_address_as_string(
+			    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(client->lc)));
+			ms_message("Disabling network of core %s (contact %s)", linphone_core_get_identity(client->lc),
+			           proxy_contact_str);
+			ms_free(proxy_contact_str);
+			linphone_core_set_network_reachable(client->lc, FALSE);
+			initialStatsList.pop_front();
 		}
 
 		BC_ASSERT_TRUE(wait_for_list(coresList, &focus.getStats().number_of_participants_added,
@@ -862,9 +859,11 @@ void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_erro
 		                              initialMichelleStats.number_of_LinphoneMessageDisplayed + 1, 3000));
 
 		if (invite_error || subscribe_error) {
+			char *marie_proxy_contact_str = linphone_address_as_string(
+			    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie.getLc())));
 			ms_message("Enabling network of core %s (contact %s)", linphone_core_get_identity(marie.getLc()),
-			           linphone_address_as_string(
-			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(marie.getLc()))));
+			           marie_proxy_contact_str);
+			ms_free(marie_proxy_contact_str);
 			linphone_core_set_network_reachable(marie.getLc(), TRUE);
 			BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_LinphoneRegistrationOk,
 			                             initialMarieStats.number_of_LinphoneRegistrationOk + 1,
@@ -934,10 +933,11 @@ void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_erro
 		                              initialLaureStats.number_of_LinphoneMessageDisplayed + 1, 3000));
 
 		if (invite_error || subscribe_error) {
+			char *michelle2_proxy_contact_str = linphone_address_as_string(
+			    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(michelle2.getLc())));
 			ms_message("Enabling network of core %s (contact %s)", linphone_core_get_identity(michelle2.getLc()),
-			           linphone_address_as_string(linphone_proxy_config_get_contact(
-			               linphone_core_get_default_proxy_config(michelle2.getLc()))));
-
+			           michelle2_proxy_contact_str);
+			ms_free(michelle2_proxy_contact_str);
 			linphone_core_set_network_reachable(michelle2.getLc(), TRUE);
 			BC_ASSERT_TRUE(wait_for_list(coresList, &michelle2.getStats().number_of_LinphoneRegistrationOk,
 			                             initialMichelle2Stats.number_of_LinphoneRegistrationOk + 1,
@@ -945,9 +945,11 @@ void group_chat_room_with_sip_errors_base(bool invite_error, bool subscribe_erro
 			michelle2Cr = check_creation_chat_room_client_side(coresList, michelle2.getCMgr(), &initialMichelle2Stats,
 			                                                   confAddr, initialSubject, 4, FALSE);
 
+			char *berthe_proxy_contact_str = linphone_address_as_string(
+			    linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(berthe.getLc())));
 			ms_message("Enabling network of core %s (contact %s)", linphone_core_get_identity(berthe.getLc()),
-			           linphone_address_as_string(
-			               linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(berthe.getLc()))));
+			           berthe_proxy_contact_str);
+			ms_free(berthe_proxy_contact_str);
 			linphone_core_set_network_reachable(berthe.getLc(), TRUE);
 			BC_ASSERT_TRUE(wait_for_list(coresList, &berthe.getStats().number_of_LinphoneRegistrationOk,
 			                             initialBertheStats.number_of_LinphoneRegistrationOk + 1,
diff --git a/tester/local_secure_chat_tester.cpp b/tester/local_secure_chat_tester.cpp
index 50821523be219a1e2017ecc70ae90974a8a900f0..1e17d89792df643a714eb4b8f84abeff45a787bd 100644
--- a/tester/local_secure_chat_tester.cpp
+++ b/tester/local_secure_chat_tester.cpp
@@ -362,12 +362,9 @@ static test_t local_conference_secure_chat_tests[] = {
     TEST_ONE_TAG("Secure Group chat with client restart",
                  LinphoneTest::secure_group_chat_room_with_client_restart,
                  "LeaksMemory"), /* beacause of coreMgr restart*/
-    TEST_ONE_TAG("Secure group chat with INVITE session error",
-                 LinphoneTest::secure_group_chat_room_with_invite_error,
-                 "LeaksMemory"), /* because of network up and down */
-    TEST_ONE_TAG("Secure group chat with SUBSCRIBE session error",
-                 LinphoneTest::secure_group_chat_room_with_subscribe_error,
-                 "LeaksMemory"), /* because of network up and down */
+    TEST_NO_TAG("Secure group chat with INVITE session error", LinphoneTest::secure_group_chat_room_with_invite_error),
+    TEST_NO_TAG("Secure group chat with SUBSCRIBE session error",
+                LinphoneTest::secure_group_chat_room_with_subscribe_error),
     TEST_ONE_TAG("Secure group chat with chat room deleted before server restart",
                  LinphoneTest::secure_group_chat_room_with_chat_room_deleted_before_server_restart,
                  "LeaksMemory"), /* because of network up and down */
diff --git a/tester/message_tester.c b/tester/message_tester.c
index 5fa3cad6179eafe1578f9bc39ecc4f229046e996..786b5bf2d22bd9127efbaae7045b442c1b75c6eb 100644
--- a/tester/message_tester.c
+++ b/tester/message_tester.c
@@ -1685,11 +1685,11 @@ static void message_with_voice_recording_base(bool_t create_message_from_recorde
 
 	BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageDelivered, 1));
 	BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1));
-	BC_ASSERT_PTR_NOT_NULL(marie->stat.last_received_chat_message);
+	LinphoneChatMessage *marie_msg = marie->stat.last_received_chat_message;
+	BC_ASSERT_PTR_NOT_NULL(marie_msg);
 
-	if (marie->stat.last_received_chat_message != NULL) {
-		LinphoneContent *content =
-		    (LinphoneContent *)(linphone_chat_message_get_contents(marie->stat.last_received_chat_message)->data);
+	if (marie_msg != NULL) {
+		LinphoneContent *content = (LinphoneContent *)(linphone_chat_message_get_contents(marie_msg)->data);
 		BC_ASSERT_EQUAL(linphone_content_get_file_duration(content), duration, int, "%d");
 		BC_ASSERT_STRING_EQUAL(linphone_content_get_type(content), "audio");
 		BC_ASSERT_STRING_EQUAL(linphone_content_get_subtype(content), "wav");