From da2ea7d1147393c970b8b24029e1ee9d6bcc9cc7 Mon Sep 17 00:00:00 2001 From: Gaelle Braud Date: Tue, 5 Aug 2025 12:20:07 +0200 Subject: [PATCH] fix #LINQT-1799 secured status of conversation based on security level of all participants fix manage participants --- Linphone/core/chat/ChatCore.cpp | 83 +++++++++++++------ Linphone/core/chat/ChatCore.hpp | 10 +++ Linphone/core/participant/ParticipantCore.cpp | 7 +- Linphone/core/participant/ParticipantCore.hpp | 8 +- Linphone/view/Control/Button/LabelButton.qml | 1 - .../Control/Display/Chat/ChatListView.qml | 2 +- .../view/Page/Form/Chat/SelectedChatView.qml | 1 + .../Page/Layout/Chat/ConversationInfos.qml | 1 + .../Page/Layout/Chat/ManageParticipants.qml | 2 +- 9 files changed, 79 insertions(+), 36 deletions(-) diff --git a/Linphone/core/chat/ChatCore.cpp b/Linphone/core/chat/ChatCore.cpp index ee4bdb58d..7c3665cfa 100644 --- a/Linphone/core/chat/ChatCore.cpp +++ b/Linphone/core/chat/ChatCore.cpp @@ -135,6 +135,12 @@ ChatCore::ChatCore(const std::shared_ptr &chatRoom) : QObjec mEphemeralLifetime = chatRoom->ephemeralEnabled() ? chatRoom->getEphemeralLifetime() : 0; mIsMuted = chatRoom->getMuted(); mParticipants = buildParticipants(chatRoom); + + connect(this, &ChatCore::participantsChanged, this, [this] { + // refresh secured status of the chatroom + setIsSecured(computeSecuredStatus()); + }); + mIsSecured = computeSecuredStatus(); } ChatCore::~ChatCore() { @@ -186,6 +192,7 @@ void ChatCore::setSelf(QSharedPointer me) { }); mChatModelConnection->makeConnectToModel( &ChatModel::deleted, [this]() { mChatModelConnection->invokeToCore([this]() { emit deleted(); }); }); + mChatModelConnection->makeConnectToModel( &ChatModel::stateChanged, [this](const std::shared_ptr &chatRoom, linphone::ChatRoom::State newState) { @@ -196,6 +203,12 @@ void ChatCore::setSelf(QSharedPointer me) { setIsReadOnly(isReadOnly); }); }); + mChatModelConnection->makeConnectToModel( + &ChatModel::conferenceJoined, [this](const std::shared_ptr &chatRoom, + const std::shared_ptr &eventLog) { + auto participants = buildParticipants(chatRoom); + mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); }); + }); // Events (excluding messages) mChatModelConnection->makeConnectToModel( @@ -336,33 +349,24 @@ void ChatCore::setSelf(QSharedPointer me) { mChatModelConnection->invokeToCore([this, subject]() { setTitle(subject); }); }); - mChatModelConnection->makeConnectToModel(&ChatModel::participantAdded, - [this](const std::shared_ptr &chatRoom, - const std::shared_ptr &eventLog) { - auto participants = buildParticipants(chatRoom); - mChatModelConnection->invokeToCore([this, participants]() { - mParticipants = participants; - emit participantsChanged(); - }); - }); - mChatModelConnection->makeConnectToModel(&ChatModel::participantRemoved, - [this](const std::shared_ptr &chatRoom, - const std::shared_ptr &eventLog) { - auto participants = buildParticipants(chatRoom); - mChatModelConnection->invokeToCore([this, participants]() { - mParticipants = participants; - emit participantsChanged(); - }); - }); - mChatModelConnection->makeConnectToModel(&ChatModel::participantAdminStatusChanged, - [this](const std::shared_ptr &chatRoom, - const std::shared_ptr &eventLog) { - auto participants = buildParticipants(chatRoom); - mChatModelConnection->invokeToCore([this, participants]() { - mParticipants = participants; - emit participantsChanged(); - }); - }); + mChatModelConnection->makeConnectToModel( + &ChatModel::participantAdded, [this](const std::shared_ptr &chatRoom, + const std::shared_ptr &eventLog) { + auto participants = buildParticipants(chatRoom); + mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); }); + }); + mChatModelConnection->makeConnectToModel( + &ChatModel::participantRemoved, [this](const std::shared_ptr &chatRoom, + const std::shared_ptr &eventLog) { + auto participants = buildParticipants(chatRoom); + mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); }); + }); + mChatModelConnection->makeConnectToModel( + &ChatModel::participantAdminStatusChanged, [this](const std::shared_ptr &chatRoom, + const std::shared_ptr &eventLog) { + auto participants = buildParticipants(chatRoom); + mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); }); + }); mChatModelConnection->makeConnectToCore(&ChatCore::lRemoveParticipantAtIndex, [this](int index) { mChatModelConnection->invokeToModel([this, index]() { mChatModel->removeParticipantAtIndex(index); }); }); @@ -632,6 +636,25 @@ bool ChatCore::getMeAdmin() const { return mMeAdmin; } +bool ChatCore::isSecured() const { + return mIsSecured; +} + +void ChatCore::setIsSecured(bool secured) { + if (mIsSecured != secured) { + mIsSecured = secured; + emit isSecuredChanged(); + } +} + +bool ChatCore::computeSecuredStatus() const { + if (mParticipants.size() == 0) return false; + for (auto &participant : mParticipants) { + if (participant->getSecurityLevel() != LinphoneEnums::SecurityLevel::EndToEndEncryptedAndVerified) return false; + } + return true; +} + QVariantList ChatCore::getParticipantsGui() const { QVariantList result; for (auto participantCore : mParticipants) { @@ -649,6 +672,12 @@ QStringList ChatCore::getParticipantsAddresses() const { return result; } +void ChatCore::setParticipants(QList> participants) { + mustBeInMainThread(log().arg(Q_FUNC_INFO)); + mParticipants = participants; + emit participantsChanged(); +} + QList> ChatCore::buildParticipants(const std::shared_ptr &chatRoom) const { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); diff --git a/Linphone/core/chat/ChatCore.hpp b/Linphone/core/chat/ChatCore.hpp index fede2ce68..c2794ca3c 100644 --- a/Linphone/core/chat/ChatCore.hpp +++ b/Linphone/core/chat/ChatCore.hpp @@ -56,6 +56,7 @@ public: Q_PROPERTY(bool isGroupChat READ isGroupChat CONSTANT) Q_PROPERTY(bool isEncrypted READ isEncrypted CONSTANT) Q_PROPERTY(bool isReadOnly READ getIsReadOnly WRITE setIsReadOnly NOTIFY readOnlyChanged) + Q_PROPERTY(bool isSecured READ isSecured WRITE setIsSecured NOTIFY isSecuredChanged) Q_PROPERTY(QString sendingText READ getSendingText WRITE setSendingText NOTIFY sendingTextChanged) Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE lEnableEphemeral NOTIFY ephemeralEnabledChanged) Q_PROPERTY( @@ -119,6 +120,10 @@ public: bool getMeAdmin() const; void setMeAdmin(bool admin); + bool isSecured() const; + void setIsSecured(bool secured); + bool computeSecuredStatus() const; + QList> getEventLogList() const; void resetEventLogList(QList> list); void appendEventLogToEventLogList(QSharedPointer event); @@ -137,6 +142,7 @@ public: std::shared_ptr getModel() const; QSharedPointer> getChatModelConnection() const; + void setParticipants(QList> participants); QList> buildParticipants(const std::shared_ptr &chatRoom) const; QList> getParticipants() const; QVariantList getParticipantsGui() const; @@ -166,6 +172,7 @@ signals: void meAdminChanged(); void participantsChanged(); void fileListChanged(); + void isSecuredChanged(); void lDeleteMessage(ChatMessageGui *message); void lDelete(); @@ -203,6 +210,9 @@ private: bool mIsEncrypted = false; bool mIsReadOnly = false; bool mEphemeralEnabled = false; + // ChatRoom is secured if all its participants are + // EndToEndEncryptedAndVerified friends + bool mIsSecured = false; int mEphemeralLifetime = 0; QList> mFileList; bool mIsMuted = false; diff --git a/Linphone/core/participant/ParticipantCore.cpp b/Linphone/core/participant/ParticipantCore.cpp index cfea10294..68fc2ca19 100644 --- a/Linphone/core/participant/ParticipantCore.cpp +++ b/Linphone/core/participant/ParticipantCore.cpp @@ -53,6 +53,9 @@ ParticipantCore::ParticipantCore(const std::shared_ptr &p mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime()); mDisplayName = Utils::coreStringToAppString(participantAddress->getDisplayName()); if (mDisplayName.isEmpty()) mDisplayName = ToolModel::getDisplayName(participantAddress->clone()); + auto isFriend = ToolModel::findFriendByAddress(participantAddress->clone()); + mSecurityLevel = + isFriend ? LinphoneEnums::fromLinphone(isFriend->getSecurityLevel()) : LinphoneEnums::SecurityLevel::None; for (auto &device : participant->getDevices()) { auto name = Utils::coreStringToAppString(device->getName()); auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly()); @@ -76,7 +79,7 @@ void ParticipantCore::setSelf(QSharedPointer me) { connect(this, &ParticipantCore::sipAddressChanged, this, &ParticipantCore::updateIsMe); } -int ParticipantCore::getSecurityLevel() const { +LinphoneEnums::SecurityLevel ParticipantCore::getSecurityLevel() const { return mSecurityLevel; } @@ -165,7 +168,7 @@ void ParticipantCore::setIsFocus(const bool &focus) { } } -void ParticipantCore::setSecurityLevel(int level) { +void ParticipantCore::setSecurityLevel(LinphoneEnums::SecurityLevel level) { if (level != mSecurityLevel) { mSecurityLevel = level; emit securityLevelChanged(); diff --git a/Linphone/core/participant/ParticipantCore.hpp b/Linphone/core/participant/ParticipantCore.hpp index 5b6001ffe..2daf6101c 100644 --- a/Linphone/core/participant/ParticipantCore.hpp +++ b/Linphone/core/participant/ParticipantCore.hpp @@ -45,7 +45,7 @@ class ParticipantCore : public QObject, public AbstractObject { Q_PROPERTY(bool isMe READ isMe NOTIFY isMeChanged) Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT) Q_PROPERTY(bool focus READ isFocus CONSTANT) - Q_PROPERTY(int securityLevel READ getSecurityLevel NOTIFY securityLevelChanged) + Q_PROPERTY(LinphoneEnums::SecurityLevel securityLevel READ getSecurityLevel NOTIFY securityLevelChanged) Q_PROPERTY(int deviceCount READ getDeviceCount NOTIFY deviceCountChanged) Q_PROPERTY(QList devices READ getParticipantDevices NOTIFY deviceChanged) @@ -62,7 +62,7 @@ public: QDateTime getCreationTime() const; bool isAdmin() const; bool isFocus() const; - int getSecurityLevel() const; + LinphoneEnums::SecurityLevel getSecurityLevel() const; int getDeviceCount() const; bool isMe() const; @@ -75,7 +75,7 @@ public: void setCreationTime(const QDateTime &date); void setIsAdmin(const bool &status); void setIsFocus(const bool &focus); - void setSecurityLevel(int level); + void setSecurityLevel(LinphoneEnums::SecurityLevel level); QList getParticipantDevices(); @@ -116,7 +116,7 @@ private: QDateTime mCreationTime; bool mAdminStatus; bool mIsFocus; - int mSecurityLevel; + LinphoneEnums::SecurityLevel mSecurityLevel; bool mIsMe; DECLARE_ABSTRACT_OBJECT diff --git a/Linphone/view/Control/Button/LabelButton.qml b/Linphone/view/Control/Button/LabelButton.qml index 997509242..544303662 100644 --- a/Linphone/view/Control/Button/LabelButton.qml +++ b/Linphone/view/Control/Button/LabelButton.qml @@ -28,7 +28,6 @@ ColumnLayout { Text { id: text Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true text: labelButton.label font { pixelSize: Typography.p1.pixelSize diff --git a/Linphone/view/Control/Display/Chat/ChatListView.qml b/Linphone/view/Control/Display/Chat/ChatListView.qml index f79103f13..7887424c4 100644 --- a/Linphone/view/Control/Display/Chat/ChatListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatListView.qml @@ -176,7 +176,7 @@ ListView { property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.peerAddress) contact: contactObj?.value || null displayNameVal: contact ? undefined : modelData.core.avatarUri - secured: modelData.core.isEncrypted + secured: modelData.core.isSecured Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) // isConference: modelData.core.isConference diff --git a/Linphone/view/Page/Form/Chat/SelectedChatView.qml b/Linphone/view/Page/Form/Chat/SelectedChatView.qml index 963bb1149..b365ff671 100644 --- a/Linphone/view/Page/Form/Chat/SelectedChatView.qml +++ b/Linphone/view/Page/Form/Chat/SelectedChatView.qml @@ -93,6 +93,7 @@ FocusScope { property var contactObj: mainItem.chat ? UtilsCpp.findFriendByAddress(mainItem.chat?.core.peerAddress) : null contact: contactObj?.value || null displayNameVal: contact ? "" : mainItem.chat?.core.avatarUri + secured: mainItem.chat && mainItem.chat.core.isSecured Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) } diff --git a/Linphone/view/Page/Layout/Chat/ConversationInfos.qml b/Linphone/view/Page/Layout/Chat/ConversationInfos.qml index 3852a6262..1df08a46b 100644 --- a/Linphone/view/Page/Layout/Chat/ConversationInfos.qml +++ b/Linphone/view/Page/Layout/Chat/ConversationInfos.qml @@ -25,6 +25,7 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter contact: contactObj?.value || null displayNameVal: contact ? "" : mainItem.chatCore.avatarUri + secured: mainItem.chatGui && mainItem.chatGui.core.isSecured Layout.preferredWidth: Math.round(100 * DefaultStyle.dp) Layout.preferredHeight: Math.round(100 * DefaultStyle.dp) PopupButton { diff --git a/Linphone/view/Page/Layout/Chat/ManageParticipants.qml b/Linphone/view/Page/Layout/Chat/ManageParticipants.qml index 451422f5d..7782f3658 100644 --- a/Linphone/view/Page/Layout/Chat/ManageParticipants.qml +++ b/Linphone/view/Page/Layout/Chat/ManageParticipants.qml @@ -36,7 +36,7 @@ Rectangle { style: ButtonStyle.noBackground icon.source: AppIcons.leftArrow onClicked: { - mainItem.chatCore.participantsAddresses = manageParticipantsLayout.selectedParticipants + mainItem.chatCore.lSetParticipantsAddresses(manageParticipantsLayout.selectedParticipants) mainItem.done() } }