From a7ada2076a0315ba420b33b999e94d107879fa61 Mon Sep 17 00:00:00 2001
From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com>
Date: Mon, 24 Feb 2025 14:52:54 +0100
Subject: [PATCH] Create tchat within a conference only after receiving the
 NOTIFY full state

---
 src/conference/client-conference.cpp |  4 ++--
 src/db/main-db.cpp                   | 16 ++++++++--------
 tester/group_chat_tester.c           | 10 +++++++++-
 3 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/src/conference/client-conference.cpp b/src/conference/client-conference.cpp
index fdab0fca27..4f33d69ee6 100644
--- a/src/conference/client-conference.cpp
+++ b/src/conference/client-conference.cpp
@@ -195,11 +195,11 @@ void ClientConference::init(SalCallOp *op, BCTBX_UNUSED(ConferenceListener *conf
 	mPendingSubject = mConfParams->getUtf8Subject();
 	mConfParams->enableLocalParticipant(false);
 
-	if (mConfParams->chatEnabled()) {
 #ifdef HAVE_ADVANCED_IM
+	if (isChatOnly()) {
 		setChatRoom((new ClientChatRoom(core, getSharedFromThis()))->toSharedPtr());
-#endif // HAVE_ADVANCED_IM
 	}
+#endif // HAVE_ADVANCED_IM
 
 	if (supportsMedia()) {
 		getMe()->setAdmin((focusSession == nullptr) || (organizerAddress == nullptr) ||
diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp
index 0e6bd60b52..5bdf60abd6 100644
--- a/src/db/main-db.cpp
+++ b/src/db/main-db.cpp
@@ -6266,13 +6266,13 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() {
 				chatRoom->setUtf8Subject(subject);
 			} else if (backend == ChatParams::Backend::FlexisipChat) {
 #ifdef HAVE_ADVANCED_IM
+				const auto &localAddress = conferenceId.getLocalAddress();
 				unsigned int lastNotifyId = d->dbSession.getUnsignedInt(row, 7, 0);
 				list<shared_ptr<Participant>> participants = selectChatRoomParticipants(dbChatRoomId);
 				const auto meIt =
-				    std::find_if(participants.begin(), participants.end(),
-				                 [&localAddress = conferenceId.getLocalAddress()](const auto &participant) {
-					                 return (participant->getAddress()->weakEqual(*localAddress));
-				                 });
+				    std::find_if(participants.begin(), participants.end(), [&localAddress](const auto &participant) {
+					    return (participant->getAddress()->weakEqual(*localAddress));
+				    });
 				shared_ptr<Participant> me;
 				if (meIt != participants.end()) {
 					me = *meIt;
@@ -6310,8 +6310,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() {
 				std::shared_ptr<Conference> conference = nullptr;
 				if (serverMode) {
 					params->enableLocalParticipant(false);
-					conference =
-					    (new ServerConference(core, conferenceId.getLocalAddress(), nullptr, params))->toSharedPtr();
+					conference = (new ServerConference(core, localAddress, nullptr, params))->toSharedPtr();
 					conference->initFromDb(me, conferenceId, lastNotifyId, false);
 					chatRoom = conference->getChatRoom();
 					conference->setState(ConferenceInterface::State::Created);
@@ -6341,10 +6340,11 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() {
 						soci::rowset<soci::row> rows = (session->prepare << query, soci::use(dbChatRoomId));
 						for (const auto &row : rows) {
 							ConferenceId previousId = ConferenceId(Address::create(row.get<string>(0), true),
-							                                       conferenceId.getLocalAddress(), conferenceIdParams);
+							                                       localAddress, conferenceIdParams);
 							if (previousId != conferenceId) {
 								lInfo() << "Keeping around previous chat room ID [" << previousId
-								        << "] in case BYE is received for exhumed chat room [" << conferenceId << "]";
+								        << "] in case BYE is received for exhumed chat room " << *conference << " ["
+								        << conferenceId << "]";
 								auto clientChatRoom = dynamic_pointer_cast<ClientChatRoom>(chatRoom);
 								clientChatRoom->addConferenceIdToPreviousList(previousId);
 							}
diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c
index b03b0ea9e3..3f40af1945 100644
--- a/tester/group_chat_tester.c
+++ b/tester/group_chat_tester.c
@@ -322,7 +322,15 @@ void setup_chat_room_callbacks(LinphoneChatRoomCbs *cbs) {
 }
 
 void core_chat_room_state_changed(BCTBX_UNUSED(LinphoneCore *core), LinphoneChatRoom *cr, LinphoneChatRoomState state) {
-	if (state == LinphoneChatRoomStateInstantiated) {
+	const LinphoneConferenceParams *chat_params = linphone_chat_room_get_current_params(cr);
+	bool hasAudio = !!linphone_conference_params_audio_enabled(chat_params) ||
+	                !!linphone_conference_params_video_enabled(chat_params);
+	// When a chatroom is instantied as part of a conference, the first state it will be notifed is the Created state as
+	// the core waits for the full state to arrive before creating it. In fact, it may happen that a core wishes to
+	// create a conference with chat capabilities but the server doesn't supports it. The client would end up having a
+	// dangling tchat and needs to destroy it
+	if ((!hasAudio && (state == LinphoneChatRoomStateInstantiated)) ||
+	    (hasAudio && (state == LinphoneChatRoomStateCreated))) {
 		LinphoneChatRoomCbs *cbs = linphone_factory_create_chat_room_cbs(linphone_factory_get());
 		setup_chat_room_callbacks(cbs);
 		linphone_chat_room_add_callbacks(cr, cbs);
-- 
GitLab