fix #LINQT-1799 secured status of conversation based on security level of all participants

fix manage participants
This commit is contained in:
Gaelle Braud 2025-08-05 12:20:07 +02:00
parent a7f3476568
commit da2ea7d114
9 changed files with 79 additions and 36 deletions

View file

@ -135,6 +135,12 @@ ChatCore::ChatCore(const std::shared_ptr<linphone::ChatRoom> &chatRoom) : QObjec
mEphemeralLifetime = chatRoom->ephemeralEnabled() ? chatRoom->getEphemeralLifetime() : 0; mEphemeralLifetime = chatRoom->ephemeralEnabled() ? chatRoom->getEphemeralLifetime() : 0;
mIsMuted = chatRoom->getMuted(); mIsMuted = chatRoom->getMuted();
mParticipants = buildParticipants(chatRoom); mParticipants = buildParticipants(chatRoom);
connect(this, &ChatCore::participantsChanged, this, [this] {
// refresh secured status of the chatroom
setIsSecured(computeSecuredStatus());
});
mIsSecured = computeSecuredStatus();
} }
ChatCore::~ChatCore() { ChatCore::~ChatCore() {
@ -186,6 +192,7 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
}); });
mChatModelConnection->makeConnectToModel( mChatModelConnection->makeConnectToModel(
&ChatModel::deleted, [this]() { mChatModelConnection->invokeToCore([this]() { emit deleted(); }); }); &ChatModel::deleted, [this]() { mChatModelConnection->invokeToCore([this]() { emit deleted(); }); });
mChatModelConnection->makeConnectToModel( mChatModelConnection->makeConnectToModel(
&ChatModel::stateChanged, &ChatModel::stateChanged,
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom, linphone::ChatRoom::State newState) { [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom, linphone::ChatRoom::State newState) {
@ -196,6 +203,12 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
setIsReadOnly(isReadOnly); setIsReadOnly(isReadOnly);
}); });
}); });
mChatModelConnection->makeConnectToModel(
&ChatModel::conferenceJoined, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<const linphone::EventLog> &eventLog) {
auto participants = buildParticipants(chatRoom);
mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); });
});
// Events (excluding messages) // Events (excluding messages)
mChatModelConnection->makeConnectToModel( mChatModelConnection->makeConnectToModel(
@ -336,33 +349,24 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
mChatModelConnection->invokeToCore([this, subject]() { setTitle(subject); }); mChatModelConnection->invokeToCore([this, subject]() { setTitle(subject); });
}); });
mChatModelConnection->makeConnectToModel(&ChatModel::participantAdded, mChatModelConnection->makeConnectToModel(
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom, &ChatModel::participantAdded, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<const linphone::EventLog> &eventLog) { const std::shared_ptr<const linphone::EventLog> &eventLog) {
auto participants = buildParticipants(chatRoom); auto participants = buildParticipants(chatRoom);
mChatModelConnection->invokeToCore([this, participants]() { mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); });
mParticipants = participants; });
emit participantsChanged(); mChatModelConnection->makeConnectToModel(
}); &ChatModel::participantRemoved, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
}); const std::shared_ptr<const linphone::EventLog> &eventLog) {
mChatModelConnection->makeConnectToModel(&ChatModel::participantRemoved, auto participants = buildParticipants(chatRoom);
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom, mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); });
const std::shared_ptr<const linphone::EventLog> &eventLog) { });
auto participants = buildParticipants(chatRoom); mChatModelConnection->makeConnectToModel(
mChatModelConnection->invokeToCore([this, participants]() { &ChatModel::participantAdminStatusChanged, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
mParticipants = participants; const std::shared_ptr<const linphone::EventLog> &eventLog) {
emit participantsChanged(); auto participants = buildParticipants(chatRoom);
}); mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); });
}); });
mChatModelConnection->makeConnectToModel(&ChatModel::participantAdminStatusChanged,
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<const linphone::EventLog> &eventLog) {
auto participants = buildParticipants(chatRoom);
mChatModelConnection->invokeToCore([this, participants]() {
mParticipants = participants;
emit participantsChanged();
});
});
mChatModelConnection->makeConnectToCore(&ChatCore::lRemoveParticipantAtIndex, [this](int index) { mChatModelConnection->makeConnectToCore(&ChatCore::lRemoveParticipantAtIndex, [this](int index) {
mChatModelConnection->invokeToModel([this, index]() { mChatModel->removeParticipantAtIndex(index); }); mChatModelConnection->invokeToModel([this, index]() { mChatModel->removeParticipantAtIndex(index); });
}); });
@ -632,6 +636,25 @@ bool ChatCore::getMeAdmin() const {
return mMeAdmin; 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 ChatCore::getParticipantsGui() const {
QVariantList result; QVariantList result;
for (auto participantCore : mParticipants) { for (auto participantCore : mParticipants) {
@ -649,6 +672,12 @@ QStringList ChatCore::getParticipantsAddresses() const {
return result; return result;
} }
void ChatCore::setParticipants(QList<QSharedPointer<ParticipantCore>> participants) {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
mParticipants = participants;
emit participantsChanged();
}
QList<QSharedPointer<ParticipantCore>> QList<QSharedPointer<ParticipantCore>>
ChatCore::buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom) const { ChatCore::buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom) const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));

View file

@ -56,6 +56,7 @@ public:
Q_PROPERTY(bool isGroupChat READ isGroupChat CONSTANT) Q_PROPERTY(bool isGroupChat READ isGroupChat CONSTANT)
Q_PROPERTY(bool isEncrypted READ isEncrypted CONSTANT) Q_PROPERTY(bool isEncrypted READ isEncrypted CONSTANT)
Q_PROPERTY(bool isReadOnly READ getIsReadOnly WRITE setIsReadOnly NOTIFY readOnlyChanged) 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(QString sendingText READ getSendingText WRITE setSendingText NOTIFY sendingTextChanged)
Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE lEnableEphemeral NOTIFY ephemeralEnabledChanged) Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE lEnableEphemeral NOTIFY ephemeralEnabledChanged)
Q_PROPERTY( Q_PROPERTY(
@ -119,6 +120,10 @@ public:
bool getMeAdmin() const; bool getMeAdmin() const;
void setMeAdmin(bool admin); void setMeAdmin(bool admin);
bool isSecured() const;
void setIsSecured(bool secured);
bool computeSecuredStatus() const;
QList<QSharedPointer<EventLogCore>> getEventLogList() const; QList<QSharedPointer<EventLogCore>> getEventLogList() const;
void resetEventLogList(QList<QSharedPointer<EventLogCore>> list); void resetEventLogList(QList<QSharedPointer<EventLogCore>> list);
void appendEventLogToEventLogList(QSharedPointer<EventLogCore> event); void appendEventLogToEventLogList(QSharedPointer<EventLogCore> event);
@ -137,6 +142,7 @@ public:
std::shared_ptr<ChatModel> getModel() const; std::shared_ptr<ChatModel> getModel() const;
QSharedPointer<SafeConnection<ChatCore, ChatModel>> getChatModelConnection() const; QSharedPointer<SafeConnection<ChatCore, ChatModel>> getChatModelConnection() const;
void setParticipants(QList<QSharedPointer<ParticipantCore>> participants);
QList<QSharedPointer<ParticipantCore>> buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom) const; QList<QSharedPointer<ParticipantCore>> buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom) const;
QList<QSharedPointer<ParticipantCore>> getParticipants() const; QList<QSharedPointer<ParticipantCore>> getParticipants() const;
QVariantList getParticipantsGui() const; QVariantList getParticipantsGui() const;
@ -166,6 +172,7 @@ signals:
void meAdminChanged(); void meAdminChanged();
void participantsChanged(); void participantsChanged();
void fileListChanged(); void fileListChanged();
void isSecuredChanged();
void lDeleteMessage(ChatMessageGui *message); void lDeleteMessage(ChatMessageGui *message);
void lDelete(); void lDelete();
@ -203,6 +210,9 @@ private:
bool mIsEncrypted = false; bool mIsEncrypted = false;
bool mIsReadOnly = false; bool mIsReadOnly = false;
bool mEphemeralEnabled = false; bool mEphemeralEnabled = false;
// ChatRoom is secured if all its participants are
// EndToEndEncryptedAndVerified friends
bool mIsSecured = false;
int mEphemeralLifetime = 0; int mEphemeralLifetime = 0;
QList<QSharedPointer<ChatMessageContentCore>> mFileList; QList<QSharedPointer<ChatMessageContentCore>> mFileList;
bool mIsMuted = false; bool mIsMuted = false;

View file

@ -53,6 +53,9 @@ ParticipantCore::ParticipantCore(const std::shared_ptr<linphone::Participant> &p
mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime()); mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime());
mDisplayName = Utils::coreStringToAppString(participantAddress->getDisplayName()); mDisplayName = Utils::coreStringToAppString(participantAddress->getDisplayName());
if (mDisplayName.isEmpty()) mDisplayName = ToolModel::getDisplayName(participantAddress->clone()); 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()) { for (auto &device : participant->getDevices()) {
auto name = Utils::coreStringToAppString(device->getName()); auto name = Utils::coreStringToAppString(device->getName());
auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly()); auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly());
@ -76,7 +79,7 @@ void ParticipantCore::setSelf(QSharedPointer<ParticipantCore> me) {
connect(this, &ParticipantCore::sipAddressChanged, this, &ParticipantCore::updateIsMe); connect(this, &ParticipantCore::sipAddressChanged, this, &ParticipantCore::updateIsMe);
} }
int ParticipantCore::getSecurityLevel() const { LinphoneEnums::SecurityLevel ParticipantCore::getSecurityLevel() const {
return mSecurityLevel; 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) { if (level != mSecurityLevel) {
mSecurityLevel = level; mSecurityLevel = level;
emit securityLevelChanged(); emit securityLevelChanged();

View file

@ -45,7 +45,7 @@ class ParticipantCore : public QObject, public AbstractObject {
Q_PROPERTY(bool isMe READ isMe NOTIFY isMeChanged) Q_PROPERTY(bool isMe READ isMe NOTIFY isMeChanged)
Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT) Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT)
Q_PROPERTY(bool focus READ isFocus 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(int deviceCount READ getDeviceCount NOTIFY deviceCountChanged)
Q_PROPERTY(QList<QVariant> devices READ getParticipantDevices NOTIFY deviceChanged) Q_PROPERTY(QList<QVariant> devices READ getParticipantDevices NOTIFY deviceChanged)
@ -62,7 +62,7 @@ public:
QDateTime getCreationTime() const; QDateTime getCreationTime() const;
bool isAdmin() const; bool isAdmin() const;
bool isFocus() const; bool isFocus() const;
int getSecurityLevel() const; LinphoneEnums::SecurityLevel getSecurityLevel() const;
int getDeviceCount() const; int getDeviceCount() const;
bool isMe() const; bool isMe() const;
@ -75,7 +75,7 @@ public:
void setCreationTime(const QDateTime &date); void setCreationTime(const QDateTime &date);
void setIsAdmin(const bool &status); void setIsAdmin(const bool &status);
void setIsFocus(const bool &focus); void setIsFocus(const bool &focus);
void setSecurityLevel(int level); void setSecurityLevel(LinphoneEnums::SecurityLevel level);
QList<QVariant> getParticipantDevices(); QList<QVariant> getParticipantDevices();
@ -116,7 +116,7 @@ private:
QDateTime mCreationTime; QDateTime mCreationTime;
bool mAdminStatus; bool mAdminStatus;
bool mIsFocus; bool mIsFocus;
int mSecurityLevel; LinphoneEnums::SecurityLevel mSecurityLevel;
bool mIsMe; bool mIsMe;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -28,7 +28,6 @@ ColumnLayout {
Text { Text {
id: text id: text
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
text: labelButton.label text: labelButton.label
font { font {
pixelSize: Typography.p1.pixelSize pixelSize: Typography.p1.pixelSize

View file

@ -176,7 +176,7 @@ ListView {
property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.peerAddress) property var contactObj: UtilsCpp.findFriendByAddress(modelData.core.peerAddress)
contact: contactObj?.value || null contact: contactObj?.value || null
displayNameVal: contact ? undefined : modelData.core.avatarUri displayNameVal: contact ? undefined : modelData.core.avatarUri
secured: modelData.core.isEncrypted secured: modelData.core.isSecured
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
// isConference: modelData.core.isConference // isConference: modelData.core.isConference

View file

@ -93,6 +93,7 @@ FocusScope {
property var contactObj: mainItem.chat ? UtilsCpp.findFriendByAddress(mainItem.chat?.core.peerAddress) : null property var contactObj: mainItem.chat ? UtilsCpp.findFriendByAddress(mainItem.chat?.core.peerAddress) : null
contact: contactObj?.value || null contact: contactObj?.value || null
displayNameVal: contact ? "" : mainItem.chat?.core.avatarUri displayNameVal: contact ? "" : mainItem.chat?.core.avatarUri
secured: mainItem.chat && mainItem.chat.core.isSecured
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp) Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp) Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
} }

View file

@ -25,6 +25,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
contact: contactObj?.value || null contact: contactObj?.value || null
displayNameVal: contact ? "" : mainItem.chatCore.avatarUri displayNameVal: contact ? "" : mainItem.chatCore.avatarUri
secured: mainItem.chatGui && mainItem.chatGui.core.isSecured
Layout.preferredWidth: Math.round(100 * DefaultStyle.dp) Layout.preferredWidth: Math.round(100 * DefaultStyle.dp)
Layout.preferredHeight: Math.round(100 * DefaultStyle.dp) Layout.preferredHeight: Math.round(100 * DefaultStyle.dp)
PopupButton { PopupButton {

View file

@ -36,7 +36,7 @@ Rectangle {
style: ButtonStyle.noBackground style: ButtonStyle.noBackground
icon.source: AppIcons.leftArrow icon.source: AppIcons.leftArrow
onClicked: { onClicked: {
mainItem.chatCore.participantsAddresses = manageParticipantsLayout.selectedParticipants mainItem.chatCore.lSetParticipantsAddresses(manageParticipantsLayout.selectedParticipants)
mainItem.done() mainItem.done()
} }
} }