From 6f1c065ea6c899fc7d5abcde2d485d6a4064ef90 Mon Sep 17 00:00:00 2001
From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com>
Date: Thu, 6 Mar 2025 13:14:37 +0100
Subject: [PATCH] Add getter of the account's CCMP user ID Update organizer's
 conference informations with the CCMP user ID of the participants upon
 reception of the HTTP response

---
 include/linphone/api/c-account-params.h      |  7 ++++
 include/linphone/api/c-participant-info.h    |  6 +++
 src/account/account-params.cpp               | 21 +++++++---
 src/account/account-params.h                 |  2 +
 src/c-wrapper/api/c-account-params.cpp       |  6 ++-
 src/c-wrapper/api/c-participant-info.cpp     |  7 +++-
 src/conference/ccmp-conference-scheduler.cpp | 37 +++++++++++++++-
 src/conference/conference-scheduler.cpp      |  6 ++-
 src/conference/conference-scheduler.h        |  1 +
 src/conference/participant-info.cpp          | 15 +++++++
 src/conference/participant-info.h            |  3 ++
 tester/audio_video_conference_tester.c       | 44 ++++++++++++++------
 12 files changed, 133 insertions(+), 22 deletions(-)

diff --git a/include/linphone/api/c-account-params.h b/include/linphone/api/c-account-params.h
index 0eb3f9f917..41efd1d006 100644
--- a/include/linphone/api/c-account-params.h
+++ b/include/linphone/api/c-account-params.h
@@ -707,6 +707,13 @@ linphone_account_params_get_conference_factory_address(const LinphoneAccountPara
 LINPHONE_PUBLIC const LinphoneAddress *
 linphone_account_params_get_audio_video_conference_factory_address(const LinphoneAccountParams *params);
 
+/**
+ * Get the CCMP user ID.
+ * @param params The #LinphoneAccountParams object @notnil
+ * @return The ID of the CCMP user. @maybenil
+ */
+LINPHONE_PUBLIC const char *linphone_account_params_get_ccmp_user_id(const LinphoneAccountParams *params);
+
 /**
  * Get the CCMP server address.
  * @param params The #LinphoneAccountParams object @notnil
diff --git a/include/linphone/api/c-participant-info.h b/include/linphone/api/c-participant-info.h
index 025559035a..3f8366542d 100644
--- a/include/linphone/api/c-participant-info.h
+++ b/include/linphone/api/c-participant-info.h
@@ -118,6 +118,12 @@ LINPHONE_PUBLIC bool_t linphone_participant_info_has_parameter(const LinphonePar
 LINPHONE_PUBLIC void linphone_participant_info_remove_parameter(LinphoneParticipantInfo *participant_info,
                                                                 const char *name);
 
+/**
+ * Get the CCMP uri of the object #LinphoneParticipantInfo.
+ * @param participant_info The #LinphoneParticipantInfo object. @notnil
+ * @return the CCMP uri of the #LinphoneParticipantInfo or NULL. @maybenil
+ */
+LINPHONE_PUBLIC const char *linphone_participant_info_get_ccmp_uri(const LinphoneParticipantInfo *participant_info);
 /**
  * @}
  */
diff --git a/src/account/account-params.cpp b/src/account/account-params.cpp
index 6b602b2e19..225b321f8d 100644
--- a/src/account/account-params.cpp
+++ b/src/account/account-params.cpp
@@ -168,7 +168,6 @@ AccountParams::AccountParams(LinphoneCore *lc, bool useDefaultValues) {
 
 	mCcmpServerUrl =
 	    useDefaultValues ? linphone_config_get_default_string(lc->config, "proxy", "ccmp_server_url", "") : "";
-	mCcmpUserId = useDefaultValues ? linphone_config_get_default_string(lc->config, "proxy", "ccmp_user_id", "") : "";
 
 	if (lc && lc->push_config) {
 		mPushNotificationConfig = PushNotificationConfig::toCpp(lc->push_config)->clone();
@@ -336,7 +335,6 @@ AccountParams::AccountParams(LinphoneCore *lc, int index) : AccountParams(lc, fa
 	}
 
 	mCcmpServerUrl = linphone_config_get_string(config, key, "ccmp_server_url", "");
-	mCcmpUserId = linphone_config_get_default_string(config, key, "ccmp_user_id", "");
 
 	mRtpBundleEnabled = !!linphone_config_get_bool(config, key, "rtp_bundle", linphone_core_rtp_bundle_enabled(lc));
 	mRtpBundleAssumption = !!linphone_config_get_bool(config, key, "rtp_bundle_assumption", FALSE);
@@ -484,6 +482,10 @@ AccountParams::~AccountParams() {
 		ms_free(mCcmpServerUrlCstr);
 		mCcmpServerUrlCstr = nullptr;
 	}
+	if (mCcmpUserIdCstr) {
+		ms_free(mCcmpUserIdCstr);
+		mCcmpUserIdCstr = nullptr;
+	}
 	if (mPushNotificationConfig) mPushNotificationConfig->unref();
 	if (mRoutesCString) {
 		bctbx_list_free_with_data(mRoutesCString, (bctbx_list_free_func)bctbx_free);
@@ -888,6 +890,18 @@ std::shared_ptr<const Address> AccountParams::getAudioVideoConferenceFactoryAddr
 	return mAudioVideoConferenceFactoryAddress;
 }
 
+const char *AccountParams::getCcmpUserIdCstr() const {
+	const auto &userId = getCcmpUserId();
+	if (mCcmpUserIdCstr) {
+		ms_free(mCcmpUserIdCstr);
+		mCcmpUserIdCstr = nullptr;
+	}
+	if (!userId.empty()) {
+		mCcmpUserIdCstr = ms_strdup(userId.c_str());
+	}
+	return mCcmpUserIdCstr;
+}
+
 const std::string &AccountParams::getCcmpUserId() const {
 	if (mCcmpUserId.empty()) {
 		mCcmpUserId = Utils::getXconId(mIdentityAddress);
@@ -1215,9 +1229,6 @@ void AccountParams::writeToConfigFile(LinphoneConfig *config, int index) {
 	if (!mCcmpServerUrl.empty()) {
 		linphone_config_set_string(config, key, "ccmp_server_url", mCcmpServerUrl.c_str());
 	}
-	if (!mCcmpUserId.empty()) {
-		linphone_config_set_string(config, key, "ccmp_user_id", mCcmpUserId.c_str());
-	}
 
 	linphone_config_set_int(config, key, "rtp_bundle", mRtpBundleEnabled);
 	linphone_config_set_int(config, key, "rtp_bundle_assumption", mRtpBundleAssumption);
diff --git a/src/account/account-params.h b/src/account/account-params.h
index fb14d4bdd5..c67ff580ff 100644
--- a/src/account/account-params.h
+++ b/src/account/account-params.h
@@ -135,6 +135,7 @@ public:
 	std::shared_ptr<const Address> getAudioVideoConferenceFactoryAddress() const;
 	const char *getCcmpServerUrlCstr() const;
 	const std::string &getCcmpServerUrl() const;
+	const char *getCcmpUserIdCstr() const;
 	const std::string &getCcmpUserId() const;
 	const std::string &getFileTransferServer() const;
 	const std::string &getIdentity() const;
@@ -206,6 +207,7 @@ private:
 	mutable char *mMwiServerAddressCstr = nullptr;
 	mutable char *mVoicemailAddressCstr = nullptr;
 	mutable char *mCcmpServerUrlCstr = nullptr;
+	mutable char *mCcmpUserIdCstr = nullptr;
 
 	std::string mInternationalPrefix;
 	std::string mInternationalPrefixIsoCountryCode;
diff --git a/src/c-wrapper/api/c-account-params.cpp b/src/c-wrapper/api/c-account-params.cpp
index cc603a49ea..c1a1b3c8de 100644
--- a/src/c-wrapper/api/c-account-params.cpp
+++ b/src/c-wrapper/api/c-account-params.cpp
@@ -350,6 +350,10 @@ linphone_account_params_get_audio_video_conference_factory_address(const Linphon
 	return address != nullptr ? address->toC() : nullptr;
 }
 
+const char *linphone_account_params_get_ccmp_user_id(const LinphoneAccountParams *params) {
+	return AccountParams::toCpp(params)->getCcmpUserIdCstr();
+}
+
 void linphone_account_params_set_ccmp_server_url(LinphoneAccountParams *params, const char *url) {
 	AccountParams::toCpp(params)->setCcmpServerUrl(L_C_TO_STRING(url));
 }
@@ -524,4 +528,4 @@ void linphone_account_params_set_supported_tags_list(LinphoneAccountParams *para
 		supportedTagsList.push_back(string((char *)tag->data));
 	}
 	AccountParams::toCpp(params)->setSupportedTagsList(supportedTagsList);
-}
\ No newline at end of file
+}
diff --git a/src/c-wrapper/api/c-participant-info.cpp b/src/c-wrapper/api/c-participant-info.cpp
index 5bf965e5cd..ec3f2030d8 100644
--- a/src/c-wrapper/api/c-participant-info.cpp
+++ b/src/c-wrapper/api/c-participant-info.cpp
@@ -81,7 +81,10 @@ bool_t linphone_participant_info_has_parameter(const LinphoneParticipantInfo *pa
 	return (bool_t)ParticipantInfo::toCpp(participant_info)->hasParameter(L_C_TO_STRING(name));
 }
 
-LINPHONE_PUBLIC void linphone_participant_info_remove_parameter(LinphoneParticipantInfo *participant_info,
-                                                                const char *name) {
+void linphone_participant_info_remove_parameter(LinphoneParticipantInfo *participant_info, const char *name) {
 	ParticipantInfo::toCpp(participant_info)->removeParameter(L_C_TO_STRING(name));
 }
+
+const char *linphone_participant_info_get_ccmp_uri(const LinphoneParticipantInfo *participant_info) {
+	return ParticipantInfo::toCpp(participant_info)->getCcmpUriCstr();
+}
diff --git a/src/conference/ccmp-conference-scheduler.cpp b/src/conference/ccmp-conference-scheduler.cpp
index d7f6019965..97f079034c 100644
--- a/src/conference/ccmp-conference-scheduler.cpp
+++ b/src/conference/ccmp-conference-scheduler.cpp
@@ -196,7 +196,7 @@ void CCMPConferenceScheduler::createOrUpdateConference(const std::shared_ptr<Con
 	}
 
 	// Conference user ID
-	std::string organizerXconUserId = Utils::getXconId(creator);
+	std::string organizerXconUserId = accountParams->getCcmpUserId();
 	if (organizerXconUserId.empty()) {
 		lError() << "Aborting creation of conference using conference scheduler [" << this
 		         << "] because the CCMP user id of the creator " << *creator << " cannot be found";
@@ -288,6 +288,41 @@ void CCMPConferenceScheduler::handleResponse(void *ctx, const HttpResponse &even
 							conferenceAddress = Address::create(uriEntry.front().getUri());
 						}
 					}
+					auto &users = confInfo->getUsers();
+					if (users.present()) {
+						auto info = ccmpScheduler->getInfo()->clone()->toSharedPtr();
+						for (auto &user : users->getUser()) {
+							auto ccmpUri = user.getEntity().get();
+							auto &associatedAors = user.getAssociatedAors();
+							std::shared_ptr<const Address> address;
+							if (associatedAors.present()) {
+								for (auto &aor : associatedAors->getEntry()) {
+									auto tmpAddress = Address::create(aor.getUri());
+									if (tmpAddress) {
+										address = tmpAddress;
+									}
+								}
+							}
+							if (address) {
+								auto participantInfo = info->findParticipant(address);
+								if (participantInfo) {
+									auto updatedParticipantInfo = participantInfo->clone()->toSharedPtr();
+									updatedParticipantInfo->setCcmpUri(ccmpUri);
+									info->updateParticipant(updatedParticipantInfo);
+								} else if (address->weakEqual(*info->getOrganizerAddress())) {
+									auto updatedOrganizerInfo = info->getOrganizer()->clone()->toSharedPtr();
+									updatedOrganizerInfo->setCcmpUri(ccmpUri);
+									info->setOrganizer(updatedOrganizerInfo);
+								} else {
+									lError()
+									    << "Unable to find participant or organizer with address " << *address
+									    << " among those in the list sent to the CCMP server by conference scheduler ["
+									    << ccmpScheduler << "]";
+								}
+							}
+						}
+						ccmpScheduler->updateInfo(info);
+					}
 				}
 			} catch (const std::bad_cast &e) {
 				lError() << "Error while casting parsed CCMP response in conference scheduler [" << ccmpScheduler
diff --git a/src/conference/conference-scheduler.cpp b/src/conference/conference-scheduler.cpp
index fc3326854d..b88d6b557e 100644
--- a/src/conference/conference-scheduler.cpp
+++ b/src/conference/conference-scheduler.cpp
@@ -209,6 +209,10 @@ void ConferenceScheduler::setInfo(const std::shared_ptr<ConferenceInfo> &info) {
 	createOrUpdateConference(mConferenceInfo);
 }
 
+void ConferenceScheduler::updateInfo(const std::shared_ptr<ConferenceInfo> &info) {
+	mConferenceInfo = info->clone()->toSharedPtr();
+}
+
 void ConferenceScheduler::onChatMessageStateChanged(const shared_ptr<ChatMessage> &message, ChatMessage::State state) {
 	shared_ptr<AbstractChatRoom> chatRoom = message->getChatRoom();
 	auto participantAddress = message->getRecipientAddress();
@@ -293,7 +297,7 @@ void ConferenceScheduler::setConferenceAddress(const std::shared_ptr<Address> &c
 	auto &mainDb = getCore()->getPrivate()->mainDb;
 	if (mainDb) {
 		lInfo() << "[Conference Scheduler] [" << this << "] Conference address " << *conferenceAddress
-		        << " is known, inserting conference info in database";
+		        << " is known, inserting conference info [" << mConferenceInfo << "] in database";
 		error = (mainDb->insertConferenceInfo(mConferenceInfo) < 0);
 	}
 #endif
diff --git a/src/conference/conference-scheduler.h b/src/conference/conference-scheduler.h
index 0b44d2f8b6..22496d998b 100644
--- a/src/conference/conference-scheduler.h
+++ b/src/conference/conference-scheduler.h
@@ -62,6 +62,7 @@ public:
 	const std::shared_ptr<ConferenceInfo> getInfo() const;
 	void cancelConference(const std::shared_ptr<ConferenceInfo> &info);
 	void setInfo(const std::shared_ptr<ConferenceInfo> &info);
+	void updateInfo(const std::shared_ptr<ConferenceInfo> &info);
 
 	void setConferenceAddress(const std::shared_ptr<Address> &conferenceAddress);
 
diff --git a/src/conference/participant-info.cpp b/src/conference/participant-info.cpp
index 21ec2111c2..36d650eb0b 100644
--- a/src/conference/participant-info.cpp
+++ b/src/conference/participant-info.cpp
@@ -37,6 +37,10 @@ ParticipantInfo::ParticipantInfo(const std::shared_ptr<const Address> &address)
 }
 
 ParticipantInfo::~ParticipantInfo() {
+	if (mCcmpUriCstr) {
+		ms_free(mCcmpUriCstr);
+		mCcmpUriCstr = nullptr;
+	}
 }
 
 ParticipantInfo *ParticipantInfo::clone() const {
@@ -71,6 +75,17 @@ void ParticipantInfo::setCcmpUri(const std::string &ccmpUri) {
 	mCcmpUri = ccmpUri;
 };
 
+const char *ParticipantInfo::getCcmpUriCstr() const {
+	if (mCcmpUriCstr) {
+		ms_free(mCcmpUriCstr);
+		mCcmpUriCstr = nullptr;
+	}
+	if (!mCcmpUri.empty()) {
+		mCcmpUriCstr = ms_strdup(mCcmpUri.c_str());
+	}
+	return mCcmpUriCstr;
+};
+
 std::string ParticipantInfo::getCcmpUri() const {
 	return mCcmpUri;
 };
diff --git a/src/conference/participant-info.h b/src/conference/participant-info.h
index 2173b10150..f642783d31 100644
--- a/src/conference/participant-info.h
+++ b/src/conference/participant-info.h
@@ -51,6 +51,7 @@ public:
 
 	void setCcmpUri(const std::string &ccmpUri);
 	std::string getCcmpUri() const;
+	const char *getCcmpUriCstr() const;
 
 	void setRole(Participant::Role role);
 	Participant::Role getRole() const;
@@ -78,6 +79,8 @@ private:
 	Participant::Role mRole = Participant::Role::Unknown;
 	int mSequence = -1;
 	participant_params_t mParameters;
+
+	mutable char *mCcmpUriCstr = nullptr;
 };
 
 inline std::ostream &operator<<(std::ostream &ostr, const ParticipantInfo &participantInfo) {
diff --git a/tester/audio_video_conference_tester.c b/tester/audio_video_conference_tester.c
index 55abb9f189..53f488506d 100644
--- a/tester/audio_video_conference_tester.c
+++ b/tester/audio_video_conference_tester.c
@@ -3371,9 +3371,16 @@ static void simple_ccmp_conference_base(bool_t update_conference, bool_t cancel_
 	coresList = bctbx_list_append(coresList, michelle->lc);
 
 	LinphoneAccount *marie_account = linphone_core_get_default_account(marie->lc);
-	LinphoneAccountParams *account_params =
-	    marie_account ? linphone_account_params_clone(linphone_account_get_params(marie_account)) : NULL;
-	if (account_params) {
+	BC_ASSERT_PTR_NOT_NULL(marie_account);
+	const LinphoneAccountParams *marie_account_params =
+	    marie_account ? linphone_account_get_params(marie_account) : NULL;
+	BC_ASSERT_PTR_NOT_NULL(marie_account_params);
+	LinphoneAddress *marie_identity = NULL;
+	if (marie_account_params) {
+		marie_identity = linphone_address_clone(marie_account_params
+		                                            ? linphone_account_params_get_identity_address(marie_account_params)
+		                                            : marie->identity);
+		LinphoneAccountParams *account_params = linphone_account_params_clone(marie_account_params);
 		linphone_account_params_set_ccmp_server_url(account_params, ccmp_server_url);
 		linphone_account_set_params(marie_account, account_params);
 		linphone_account_params_unref(account_params);
@@ -3389,11 +3396,7 @@ static void simple_ccmp_conference_base(bool_t update_conference, bool_t cancel_
 	linphone_conference_scheduler_cbs_unref(cbs);
 
 	LinphoneConferenceInfo *conf_info = linphone_conference_info_new();
-	LinphoneAddress *organizer_address =
-	    marie_account ? linphone_address_clone(
-	                        linphone_account_params_get_identity_address(linphone_account_get_params(marie_account)))
-	                  : linphone_address_clone(marie->identity);
-	linphone_conference_info_set_organizer(conf_info, organizer_address);
+	linphone_conference_info_set_organizer(conf_info, marie_identity);
 	bctbx_list_t *participants_info = NULL;
 	add_participant_info_to_list(&participants_info, pauline->identity, LinphoneParticipantRoleSpeaker, -1);
 	add_participant_info_to_list(&participants_info, laure->identity, LinphoneParticipantRoleListener, -1);
@@ -3449,6 +3452,23 @@ static void simple_ccmp_conference_base(bool_t update_conference, bool_t cancel_
 				linphone_conference_info_check_participant(info, mgr->identity, 0);
 			}
 		}
+		const bctbx_list_t *participant_infos = linphone_conference_info_get_participant_infos(info);
+		for (const bctbx_list_t *it = participant_infos; it; it = bctbx_list_next(it)) {
+			LinphoneParticipantInfo *participant_info = (LinphoneParticipantInfo *)bctbx_list_get_data(it);
+			BC_ASSERT_PTR_NOT_NULL(linphone_participant_info_get_ccmp_uri(participant_info));
+		}
+
+		const LinphoneParticipantInfo *organizer_info = linphone_conference_info_get_organizer_info(info);
+		BC_ASSERT_PTR_NOT_NULL(organizer_info);
+		if (organizer_info) {
+			const char *organizer_ccmp_uri = linphone_participant_info_get_ccmp_uri(organizer_info);
+			BC_ASSERT_PTR_NOT_NULL(organizer_ccmp_uri);
+			if (organizer_ccmp_uri) {
+				marie_account_params = marie_account ? linphone_account_get_params(marie_account) : NULL;
+				BC_ASSERT_STRING_EQUAL(organizer_ccmp_uri,
+				                       linphone_account_params_get_ccmp_user_id(marie_account_params));
+			}
+		}
 		linphone_conference_info_unref(info);
 	}
 
@@ -3494,7 +3514,7 @@ static void simple_ccmp_conference_base(bool_t update_conference, bool_t cancel_
 					LinphoneConferenceInfo *conf_info_in_db =
 					    linphone_core_find_conference_information_from_uri(mgr->lc, conference_address);
 					if (BC_ASSERT_PTR_NOT_NULL(conf_info_in_db)) {
-						check_conference_info_members(conf_info_in_db, uid, conference_address, organizer_address,
+						check_conference_info_members(conf_info_in_db, uid, conference_address, marie_identity,
 						                              participants_info, start_time, duration, subject, description, 0,
 						                              LinphoneConferenceInfoStateNew,
 						                              LinphoneConferenceSecurityLevelNone, TRUE, TRUE, TRUE, FALSE);
@@ -3629,7 +3649,7 @@ static void simple_ccmp_conference_base(bool_t update_conference, bool_t cancel_
 								exp_state = LinphoneConferenceInfoStateUpdated;
 							}
 
-							check_conference_info_members(conf_info_in_db, uid2, conference_address, organizer_address,
+							check_conference_info_members(conf_info_in_db, uid2, conference_address, marie_identity,
 							                              participants_info, start_time, duration, subject, description,
 							                              (mgr == michelle) ? 0 : 1, exp_state,
 							                              LinphoneConferenceSecurityLevelNone, TRUE, TRUE, TRUE, FALSE);
@@ -3746,7 +3766,7 @@ static void simple_ccmp_conference_base(bool_t update_conference, bool_t cancel_
 							} else {
 								ics_sequence = 2;
 							}
-							check_conference_info_members(conf_info_in_db, uid2, conference_address, organizer_address,
+							check_conference_info_members(conf_info_in_db, uid2, conference_address, marie_identity,
 							                              NULL, start_time, duration, subject, description,
 							                              ics_sequence, exp_state, LinphoneConferenceSecurityLevelNone,
 							                              TRUE, TRUE, TRUE, FALSE);
@@ -3834,7 +3854,7 @@ static void simple_ccmp_conference_base(bool_t update_conference, bool_t cancel_
 
 end:
 	if (conference_scheduler) linphone_conference_scheduler_unref(conference_scheduler);
-	if (organizer_address) linphone_address_unref(organizer_address);
+	if (marie_identity) linphone_address_unref(marie_identity);
 	if (conference_address) linphone_address_unref(conference_address);
 	if (conference_address_str) bctbx_free(conference_address_str);
 	bctbx_list_free_with_data(participants_info, (bctbx_list_free_func)linphone_participant_info_unref);
-- 
GitLab