From c74654204af73edc5ea97a43981ff9981134908d Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Thu, 29 Apr 2021 15:14:50 +0200 Subject: [PATCH] secure first step --- linphone-app/CMakeLists.txt | 4 + linphone-app/src/app/App.cpp | 10 +- linphone-app/src/components/Components.hpp | 2 + .../src/components/calls/CallsListModel.cpp | 32 ++++ .../src/components/calls/CallsListModel.hpp | 1 + .../src/components/chat/ChatModel.cpp | 144 ++++++++++++++++- .../src/components/chat/ChatModel.hpp | 14 +- .../src/components/chat/ChatProxyModel.cpp | 28 +++- .../src/components/chat/ChatProxyModel.hpp | 18 ++- .../src/components/core/CoreHandlers.cpp | 4 +- .../src/components/core/CoreManager.cpp | 56 ++++++- .../src/components/core/CoreManager.hpp | 16 +- .../components/timeline/TimelineListModel.cpp | 148 ++++++++++++++++++ .../components/timeline/TimelineListModel.hpp | 54 +++++++ .../timeline/TimelineModel (copy).cpp | 102 ++++++++++++ .../timeline/TimelineModel (copy).hpp | 54 +++++++ .../src/components/timeline/TimelineModel.cpp | 84 +++------- .../src/components/timeline/TimelineModel.hpp | 59 ++++--- .../timeline/TimelineProxyModel.cpp | 54 +++++++ .../timeline/TimelineProxyModel.hpp | 45 ++++++ .../ui/modules/Linphone/Contact/Contact.qml | 12 +- .../ui/modules/Linphone/Timeline/Timeline.js | 12 +- .../ui/modules/Linphone/Timeline/Timeline.qml | 21 ++- linphone-app/ui/views/App/Main/Contacts.qml | 22 ++- .../ui/views/App/Main/Conversation.qml | 8 +- linphone-app/ui/views/App/Main/MainWindow.qml | 24 +-- 26 files changed, 899 insertions(+), 129 deletions(-) create mode 100644 linphone-app/src/components/timeline/TimelineListModel.cpp create mode 100644 linphone-app/src/components/timeline/TimelineListModel.hpp create mode 100644 linphone-app/src/components/timeline/TimelineModel (copy).cpp create mode 100644 linphone-app/src/components/timeline/TimelineModel (copy).hpp create mode 100644 linphone-app/src/components/timeline/TimelineProxyModel.cpp create mode 100644 linphone-app/src/components/timeline/TimelineProxyModel.hpp diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index d0c57033a..8d27697a4 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -165,6 +165,8 @@ set(SOURCES src/components/sound-player/SoundPlayer.cpp src/components/telephone-numbers/TelephoneNumbersModel.cpp src/components/timeline/TimelineModel.cpp + src/components/timeline/TimelineListModel.cpp + src/components/timeline/TimelineProxyModel.cpp src/components/url-handlers/UrlHandlers.cpp src/utils/LinphoneUtils.cpp src/utils/MediastreamerUtils.cpp @@ -241,6 +243,8 @@ set(HEADERS src/components/sound-player/SoundPlayer.hpp src/components/telephone-numbers/TelephoneNumbersModel.hpp src/components/timeline/TimelineModel.hpp + src/components/timeline/TimelineListModel.hpp + src/components/timeline/TimelineProxyModel.hpp src/components/url-handlers/UrlHandlers.hpp src/utils/LinphoneUtils.hpp src/utils/MediastreamerUtils.hpp diff --git a/linphone-app/src/app/App.cpp b/linphone-app/src/app/App.cpp index 487dfb451..01649ce7d 100644 --- a/linphone-app/src/app/App.cpp +++ b/linphone-app/src/app/App.cpp @@ -48,6 +48,10 @@ #include "utils/Utils.hpp" #include "components/other/desktop-tools/DesktopTools.hpp" +#include "components/timeline/TimelineModel.hpp" +#include "components/timeline/TimelineListModel.hpp" +#include "components/timeline/TimelineProxyModel.hpp" + // ============================================================================= using namespace std; @@ -581,6 +585,7 @@ void App::registerTypes () { qRegisterMetaType(); qRegisterMetaType>(); qRegisterMetaType > >(); + qRegisterMetaType>(); registerType("AssistantModel"); registerType("AuthenticationNotifier"); @@ -599,13 +604,14 @@ void App::registerTypes () { registerType("SipAddressesProxyModel"); registerType("SearchSipAddressesModel"); + registerType("TimelineProxyModel"); registerType("SoundPlayer"); registerType("TelephoneNumbersModel"); registerSingletonType("AudioCodecsModel"); registerSingletonType("OwnPresenceModel"); registerSingletonType("Presence"); - registerSingletonType("TimelineModel"); + //registerSingletonType("TimelineModel"); registerSingletonType("UrlHandlers"); registerSingletonType("VideoCodecsModel"); @@ -618,6 +624,7 @@ void App::registerTypes () { registerUncreatableType("LdapModel"); registerUncreatableType("SipAddressObserver"); registerUncreatableType("VcardModel"); + registerUncreatableType("TimelineModel"); } void App::registerSharedTypes () { @@ -632,6 +639,7 @@ void App::registerSharedTypes () { registerSharedSingletonType("ContactsListModel"); registerSharedSingletonType("ContactsImporterListModel"); registerSharedSingletonType("LdapListModel"); + registerSharedSingletonType("TimelineListModel"); } void App::registerToolTypes () { diff --git a/linphone-app/src/components/Components.hpp b/linphone-app/src/components/Components.hpp index 1569720ae..60cc7c5fc 100644 --- a/linphone-app/src/components/Components.hpp +++ b/linphone-app/src/components/Components.hpp @@ -59,6 +59,8 @@ #include "sound-player/SoundPlayer.hpp" #include "telephone-numbers/TelephoneNumbersModel.hpp" #include "timeline/TimelineModel.hpp" +#include "timeline/TimelineProxyModel.hpp" +#include "timeline/TimelineListModel.hpp" #include "url-handlers/UrlHandlers.hpp" #include "other/colors/Colors.hpp" diff --git a/linphone-app/src/components/calls/CallsListModel.cpp b/linphone-app/src/components/calls/CallsListModel.cpp index 55bd0b6f0..7d0f789c1 100644 --- a/linphone-app/src/components/calls/CallsListModel.cpp +++ b/linphone-app/src/components/calls/CallsListModel.cpp @@ -151,6 +151,38 @@ void CallsListModel::launchVideoCall (const QString &sipAddress) const { core->inviteAddressWithParams(address, params); } +bool CallsListModel::launchSecureChat (const QString &sipAddress) const { + shared_ptr core = CoreManager::getInstance()->getCore(); + shared_ptr address = core->interpretUrl(Utils::appStringToCoreString(sipAddress)); + if (!address) + return false; + + std::shared_ptr params = core->createDefaultChatRoomParams(); + std::list > participants; + std::shared_ptr localAddress; + participants.push_back(address); + auto proxy = core->getDefaultProxyConfig(); + params->enableEncryption(true); + + params->setSubject("This is Desktop test"); + params->setBackend(linphone::ChatRoomBackend::FlexisipChat); + params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime); + + std::shared_ptr chatRoom = core->createChatRoom(params, localAddress, participants); + /* + if( chatRoom!=nullptr){ + auto search = core->searchChatRoom(params, localAddress + , address + , participants); + if(search != chatRoom) + qWarning("toto"); + } + + + return chatRoom!=nullptr; + */ + return false; +} // ----------------------------------------------------------------------------- int CallsListModel::getRunningCallsNumber () const { diff --git a/linphone-app/src/components/calls/CallsListModel.hpp b/linphone-app/src/components/calls/CallsListModel.hpp index b5cf1d052..0edb7193c 100644 --- a/linphone-app/src/components/calls/CallsListModel.hpp +++ b/linphone-app/src/components/calls/CallsListModel.hpp @@ -44,6 +44,7 @@ public: Q_INVOKABLE void launchAudioCall (const QString &sipAddress, const QHash &headers = {}) const; Q_INVOKABLE void launchVideoCall (const QString &sipAddress) const; + Q_INVOKABLE bool launchSecureChat (const QString &sipAddress) const; Q_INVOKABLE int getRunningCallsNumber () const; diff --git a/linphone-app/src/components/chat/ChatModel.cpp b/linphone-app/src/components/chat/ChatModel.cpp index 478a665bb..887beb170 100644 --- a/linphone-app/src/components/chat/ChatModel.cpp +++ b/linphone-app/src/components/chat/ChatModel.cpp @@ -309,13 +309,58 @@ private: // ----------------------------------------------------------------------------- -ChatModel::ChatModel (const QString &peerAddress, const QString &localAddress) { +ChatModel::ChatModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure) { CoreManager *coreManager = CoreManager::getInstance(); mCoreHandlers = coreManager->getHandlers(); mMessageHandlers = make_shared(this); - setSipAddresses(peerAddress, localAddress); + shared_ptr core = CoreManager::getInstance()->getCore(); + shared_ptr factory(linphone::Factory::get()); + std::shared_ptr params = core->createDefaultChatRoomParams(); + std::list> participants; + + //params->enableEncryption(isSecure); + //if(isSecure){ + // params->setBackend(linphone::ChatRoomBackend::FlexisipChat); +// params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime); +// } + + mChatRoom = core->searchChatRoom(params, factory->createAddress(localAddress.toStdString()) + , factory->createAddress(peerAddress.toStdString()) + , participants); + /* + mChatRoom = core->getChatRoom( + factory->createAddress(peerAddress.toStdString()), + factory->createAddress(localAddress.toStdString()) + );*/ + Q_ASSERT(mChatRoom); + + handleIsComposingChanged(mChatRoom); + + // Get messages. + mEntries.clear(); + + QElapsedTimer timer; + timer.start(); + + for (auto &message : mChatRoom->getHistory(0)) + mEntries << qMakePair( + QVariantMap{ + { "type", EntryType::MessageEntry }, + { "timestamp", QDateTime::fromMSecsSinceEpoch(message->getTime() * 1000) } + }, + static_pointer_cast(message) + ); + + // Get calls. + if(!getIsSecure() ) + for (auto &callLog : core->getCallHistory(mChatRoom->getPeerAddress(), mChatRoom->getLocalAddress())) + insertCall(callLog); + + qInfo() << QStringLiteral("ChatModel (%1, %2) loaded in %3 milliseconds.") + .arg(peerAddress).arg(localAddress).arg(timer.elapsed()); + // Rebind lost handlers for(auto i = mEntries.begin() ; i != mEntries.end() ; ++i){ if(i->first["type"] == EntryType::MessageEntry){ @@ -330,7 +375,67 @@ ChatModel::ChatModel (const QString &peerAddress, const QString &localAddress) { QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &ChatModel::handleCallStateChanged); QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &ChatModel::handleIsComposingChanged); } + if(!mChatRoom) + qWarning("TOTO A"); +} + +ChatModel::ChatModel (std::shared_ptr chatRoom){ + CoreManager *coreManager = CoreManager::getInstance(); + mCoreHandlers = coreManager->getHandlers(); + mMessageHandlers = make_shared(this); + + shared_ptr core = CoreManager::getInstance()->getCore(); + shared_ptr factory(linphone::Factory::get()); + std::shared_ptr params = core->createDefaultChatRoomParams(); + std::list> participants; + + + mChatRoom = chatRoom; + + Q_ASSERT(mChatRoom); + + handleIsComposingChanged(mChatRoom); + + // Get messages. + mEntries.clear(); + + QElapsedTimer timer; + timer.start(); + + for (auto &message : mChatRoom->getHistory(0)) + mEntries << qMakePair( + QVariantMap{ + { "type", EntryType::MessageEntry }, + { "timestamp", QDateTime::fromMSecsSinceEpoch(message->getTime() * 1000) } + }, + static_pointer_cast(message) + ); + + // Get calls. + if(!getIsSecure() ) + for (auto &callLog : core->getCallHistory(mChatRoom->getPeerAddress(), mChatRoom->getLocalAddress())) + insertCall(callLog); + + + + + // Rebind lost handlers + for(auto i = mEntries.begin() ; i != mEntries.end() ; ++i){ + if(i->first["type"] == EntryType::MessageEntry){ + shared_ptr message = static_pointer_cast(i->second); + message->removeListener(mMessageHandlers);// Remove old listener if already exists + message->addListener(mMessageHandlers); + } + } + { + CoreHandlers *coreHandlers = mCoreHandlers.get(); + QObject::connect(coreHandlers, &CoreHandlers::messageReceived, this, &ChatModel::handleMessageReceived); + QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &ChatModel::handleCallStateChanged); + QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &ChatModel::handleIsComposingChanged); + } + if(!mChatRoom) + qWarning("TOTO B"); } ChatModel::~ChatModel () { @@ -407,20 +512,34 @@ QString ChatModel::getLocalAddress () const { ); } QString ChatModel::getFullPeerAddress () const { + if(!mChatRoom) + qWarning("TOTO Z"); return QString::fromStdString(mChatRoom->getPeerAddress()->asString()); } QString ChatModel::getFullLocalAddress () const { return QString::fromStdString(mChatRoom->getLocalAddress()->asString()); } -void ChatModel::setSipAddresses (const QString &peerAddress, const QString &localAddress) { +void ChatModel::setSipAddresses (const QString &peerAddress, const QString &localAddress, const bool& isSecure) { shared_ptr core = CoreManager::getInstance()->getCore(); shared_ptr factory(linphone::Factory::get()); + std::shared_ptr params = core->createDefaultChatRoomParams(); + std::list> participants; + //params->enableEncryption(isSecure); + //if(isSecure){ + // params->setBackend(linphone::ChatRoomBackend::FlexisipChat); +// params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime); +// } + + mChatRoom = core->searchChatRoom(params, factory->createAddress(localAddress.toStdString()) + , factory->createAddress(peerAddress.toStdString()) + , participants); + /* mChatRoom = core->getChatRoom( factory->createAddress(peerAddress.toStdString()), factory->createAddress(localAddress.toStdString()) - ); + );*/ Q_ASSERT(mChatRoom); handleIsComposingChanged(mChatRoom); @@ -441,14 +560,23 @@ void ChatModel::setSipAddresses (const QString &peerAddress, const QString &loca ); // Get calls. - for (auto &callLog : core->getCallHistory(mChatRoom->getPeerAddress(), mChatRoom->getLocalAddress())) - insertCall(callLog); + if(!getIsSecure() ) + for (auto &callLog : core->getCallHistory(mChatRoom->getPeerAddress(), mChatRoom->getLocalAddress())) + insertCall(callLog); qInfo() << QStringLiteral("ChatModel (%1, %2) loaded in %3 milliseconds.") .arg(peerAddress).arg(localAddress).arg(timer.elapsed()); + + if(!mChatRoom) + qWarning("TOTO C"); } +bool ChatModel::getIsSecure() const{ + return mChatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Encrypted + || mChatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Safe; +} + bool ChatModel::getIsRemoteComposing () const { return mIsRemoteComposing; } @@ -637,7 +765,9 @@ void ChatModel::resetMessageCount () { } emit messageCountReset(); } - +std::shared_ptr ChatModel::getChatRoom(){ + return mChatRoom; +} // ----------------------------------------------------------------------------- const ChatModel::ChatEntryData ChatModel::getFileMessageEntry (int id) { diff --git a/linphone-app/src/components/chat/ChatModel.hpp b/linphone-app/src/components/chat/ChatModel.hpp index b0d79b57f..4002ece96 100644 --- a/linphone-app/src/components/chat/ChatModel.hpp +++ b/linphone-app/src/components/chat/ChatModel.hpp @@ -73,7 +73,8 @@ public: }; Q_ENUM(MessageStatus); - ChatModel (const QString &peerAddress, const QString &localAddress); + ChatModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure); + ChatModel (std::shared_ptr chatRoom); ~ChatModel (); int rowCount (const QModelIndex &index = QModelIndex()) const override; @@ -88,6 +89,8 @@ public: QString getLocalAddress () const; QString getFullPeerAddress () const; QString getFullLocalAddress () const; + + bool getIsSecure() const; bool getIsRemoteComposing () const; @@ -111,6 +114,8 @@ public: void compose (); void resetMessageCount (); + + std::shared_ptr getChatRoom(); signals: bool isRemoteComposingChanged (bool status); @@ -128,7 +133,7 @@ signals: private: typedef QPair> ChatEntryData; - void setSipAddresses (const QString &peerAddress, const QString &localAddress); + void setSipAddresses (const QString &peerAddress, const QString &localAddress, const bool& isSecure); const ChatEntryData getFileMessageEntry (int id); @@ -144,10 +149,13 @@ private: bool mIsRemoteComposing = false; mutable QList mEntries; - std::shared_ptr mChatRoom; std::shared_ptr mCoreHandlers; std::shared_ptr mMessageHandlers; + + std::shared_ptr mChatRoom; }; +Q_DECLARE_METATYPE(std::shared_ptr); + #endif // CHAT_MODEL_H_ diff --git a/linphone-app/src/components/chat/ChatProxyModel.cpp b/linphone-app/src/components/chat/ChatProxyModel.cpp index 5796bdb2d..1e6bf522d 100644 --- a/linphone-app/src/components/chat/ChatProxyModel.cpp +++ b/linphone-app/src/components/chat/ChatProxyModel.cpp @@ -64,6 +64,7 @@ private: ChatProxyModel::ChatProxyModel (QObject *parent) : QSortFilterProxyModel(parent) { setSourceModel(new ChatModelFilter(this)); + mIsSecure = false; App *app = App::getInstance(); QObject::connect(app->getMainWindow(), &QWindow::activeChanged, this, [this]() { @@ -168,7 +169,7 @@ QString ChatProxyModel::getPeerAddress () const { void ChatProxyModel::setPeerAddress (const QString &peerAddress) { mPeerAddress = peerAddress; - reload(); + //reload(); } QString ChatProxyModel::getLocalAddress () const { @@ -177,7 +178,7 @@ QString ChatProxyModel::getLocalAddress () const { void ChatProxyModel::setLocalAddress (const QString &localAddress) { mLocalAddress = localAddress; - reload(); + //reload(); } QString ChatProxyModel::getFullPeerAddress () const { @@ -198,6 +199,14 @@ void ChatProxyModel::setFullLocalAddress (const QString &localAddress) { //reload(); } +int ChatProxyModel::getIsSecure () const { + return mChatModel ? mChatModel->getIsSecure() : -1; +} + +void ChatProxyModel::setIsSecure (const int &secure) { + mIsSecure = secure; +} + bool ChatProxyModel::getIsRemoteComposing () const { return mChatModel ? mChatModel->getIsRemoteComposing() : false; } @@ -218,7 +227,10 @@ void ChatProxyModel::reload () { QObject::disconnect(chatModel, &ChatModel::messageSent, this, &ChatProxyModel::handleMessageSent); } - mChatModel = CoreManager::getInstance()->getChatModel(mPeerAddress, mLocalAddress); + //mChatModel = CoreManager::getInstance()->getChatModel(mPeerAddress, mLocalAddress, mIsSecure); + //if(mChatRoom) + mChatModel = CoreManager::getInstance()->getChatModel(mChatRoom); + if (mChatModel) { @@ -235,6 +247,16 @@ void ChatProxyModel::resetMessageCount(){ mChatModel->resetMessageCount(); } } + +std::shared_ptr ChatProxyModel::getChatRoom () const{ + return mChatModel; + +} +void ChatProxyModel::setChatRoom (std::shared_ptr chatModel){ + mChatRoom = chatModel->getChatRoom(); + reload(); + emit chatRoomChanged(); +} // ----------------------------------------------------------------------------- static inline QWindow *getParentWindow (QObject *object) { diff --git a/linphone-app/src/components/chat/ChatProxyModel.hpp b/linphone-app/src/components/chat/ChatProxyModel.hpp index cfc4e7573..f5c891296 100644 --- a/linphone-app/src/components/chat/ChatProxyModel.hpp +++ b/linphone-app/src/components/chat/ChatProxyModel.hpp @@ -38,7 +38,11 @@ class ChatProxyModel : public QSortFilterProxyModel { Q_PROPERTY(QString localAddress READ getLocalAddress WRITE setLocalAddress NOTIFY localAddressChanged); Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress WRITE setFullPeerAddress NOTIFY fullPeerAddressChanged); Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress WRITE setFullLocalAddress NOTIFY fullLocalAddressChanged); + Q_PROPERTY(int isSecure READ getIsSecure WRITE setIsSecure NOTIFY isSecureChanged); + Q_PROPERTY(std::shared_ptr chatRoom READ getChatRoom WRITE setChatRoom NOTIFY chatRoomChanged); + //Q_PROPERTY(bool isSecure MEMBER mIsSecure NOTIFY isSecureChanged); Q_PROPERTY(bool isRemoteComposing READ getIsRemoteComposing NOTIFY isRemoteComposingChanged); + //Q_PROPERTY(bool isSecure READ getIsSecure NOTIFY isSecureChanged); Q_PROPERTY(QString cachedText READ getCachedText); public: @@ -62,13 +66,16 @@ public: Q_INVOKABLE void compose (const QString& text); Q_INVOKABLE void resetMessageCount(); - + signals: void peerAddressChanged (const QString &peerAddress); void localAddressChanged (const QString &localAddress); void fullPeerAddressChanged (const QString &fullPeerAddress); void fullLocalAddressChanged (const QString &fullLocalAddress); bool isRemoteComposingChanged (bool status); + bool isSecureChanged(bool secure); + + void chatRoomChanged(); void moreEntriesLoaded (int n); @@ -89,6 +96,12 @@ private: QString getFullLocalAddress () const; void setFullLocalAddress (const QString &localAddress); + + int getIsSecure () const; + void setIsSecure (const int &secure); + + std::shared_ptr getChatRoom () const; + void setChatRoom (std::shared_ptr chatRoom); bool getIsRemoteComposing () const; @@ -108,7 +121,10 @@ private: QString mLocalAddress; QString mFullPeerAddress; QString mFullLocalAddress; + int mIsSecure; static QString gCachedText; + std::shared_ptr mChatRoom; + std::shared_ptr mChatModel; diff --git a/linphone-app/src/components/core/CoreHandlers.cpp b/linphone-app/src/components/core/CoreHandlers.cpp index bf41cdca7..e33d67220 100644 --- a/linphone-app/src/components/core/CoreHandlers.cpp +++ b/linphone-app/src/components/core/CoreHandlers.cpp @@ -196,7 +196,9 @@ void CoreHandlers::onMessageReceived ( !app->hasFocus() || !CoreManager::getInstance()->chatModelExists( Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly()), - Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly()) + Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly()), + chatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Encrypted + || chatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Safe ) ) core->playLocal(Utils::appStringToCoreString(settingsModel->getChatNotificationSoundPath())); diff --git a/linphone-app/src/components/core/CoreManager.cpp b/linphone-app/src/components/core/CoreManager.cpp index fe3c9156d..9d8584fc7 100644 --- a/linphone-app/src/components/core/CoreManager.cpp +++ b/linphone-app/src/components/core/CoreManager.cpp @@ -38,6 +38,7 @@ #include "components/settings/AccountSettingsModel.hpp" #include "components/settings/SettingsModel.hpp" #include "components/sip-addresses/SipAddressesModel.hpp" +#include "components/timeline/TimelineListModel.hpp" #include "utils/Utils.hpp" @@ -106,6 +107,7 @@ void CoreManager::initCoreManager(){ mSettingsModel = new SettingsModel(this); mSipAddressesModel = new SipAddressesModel(this); mEventCountNotifier = new EventCountNotifier(this); + mTimelineListModel = new TimelineListModel(this); mEventCountNotifier->updateUnreadMessageCount(); QObject::connect(mEventCountNotifier, &EventCountNotifier::eventCountChanged,this, &CoreManager::eventCountChanged); migrate(); @@ -118,12 +120,12 @@ CoreManager *CoreManager::getInstance (){ return mInstance; } -shared_ptr CoreManager::getChatModel (const QString &peerAddress, const QString &localAddress) { +shared_ptr CoreManager::getChatModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure) { if (peerAddress.isEmpty() || localAddress.isEmpty()) return nullptr; // Create a new chat model. - QPair chatModelId{ peerAddress, localAddress }; + QPair> chatModelId{isSecure,{ peerAddress, localAddress }}; if (!mChatModels.contains(chatModelId)) { if ( !mCore->createAddress(peerAddress.toStdString()) || @@ -140,7 +142,7 @@ shared_ptr CoreManager::getChatModel (const QString &peerAddress, con delete chatModel; }; - shared_ptr chatModel(new ChatModel(peerAddress, localAddress), deleter); + shared_ptr chatModel(new ChatModel(peerAddress, localAddress, isSecure), deleter); mChatModels[chatModelId] = chatModel; emit chatModelCreated(chatModel); @@ -154,8 +156,46 @@ shared_ptr CoreManager::getChatModel (const QString &peerAddress, con return chatModel; } -bool CoreManager::chatModelExists (const QString &peerAddress, const QString &localAddress) { - return mChatModels.contains({ peerAddress, localAddress }); +shared_ptr CoreManager::getChatModel (std::shared_ptr chatRoom) { + if (!chatRoom) + return nullptr; + auto pc = chatRoom->getCurrentParams(); + for(auto it = mChatModels.begin() ; it != mChatModels.end() ; ++it) { + auto a = it->lock(); + auto pa = a->getChatRoom()->getCurrentParams(); + if( a->getChatRoom()->getConferenceAddress() == chatRoom->getConferenceAddress() + && a->getChatRoom()->getLocalAddress() == chatRoom->getLocalAddress() + && a->getChatRoom()->getPeerAddress() == chatRoom->getPeerAddress() + && a->getChatRoom()->getPeerAddress() == chatRoom->getPeerAddress() + && pa->encryptionEnabled() == pc->encryptionEnabled() + ){ + // Returns an existing chat model. + shared_ptr chatModel = a; + Q_CHECK_PTR(chatModel); + return chatModel; + } + } + + QPair> chatModelId{pc->encryptionEnabled(), + { QString::fromStdString(chatRoom->getPeerAddress()->asString()) + , QString::fromStdString(chatRoom->getLocalAddress()->asString()) }}; + + + auto deleter = [this, chatModelId](ChatModel *chatModel) { + bool removed = mChatModels.remove(chatModelId); + Q_ASSERT(removed); + chatModel->deleteLater(); + }; + + shared_ptr chatModel(new ChatModel(chatRoom), deleter); + mChatModels[chatModelId] = chatModel; + + emit chatModelCreated(chatModel); + + return chatModel; +} +bool CoreManager::chatModelExists (const QString &peerAddress, const QString &localAddress, const bool &isSecure) { + return mChatModels.contains({isSecure, { peerAddress, localAddress}}); } HistoryModel* CoreManager::getHistoryModel(){ @@ -275,6 +315,12 @@ void CoreManager::createLinphoneCore (const QString &configPath) { Paths::getFactoryConfigFilePath(), nullptr ); + // You only need to give your LIME server URL + mCore->setLimeX3DhServerUrl("https://lime.linphone.org/lime-server/lime-server.php"); + // and enable LIME on your core to use encryption. + mCore->enableLimeX3Dh(true); + // Now see the CoreService.CreateGroupChatRoom to see how to create a secure chat room + mCore->addListener(mHandlers); mCore->setVideoDisplayFilter("MSQOGL"); mCore->usePreviewWindow(true); diff --git a/linphone-app/src/components/core/CoreManager.hpp b/linphone-app/src/components/core/CoreManager.hpp index 261b85e22..f055e653b 100644 --- a/linphone-app/src/components/core/CoreManager.hpp +++ b/linphone-app/src/components/core/CoreManager.hpp @@ -43,6 +43,7 @@ class LdapListModel; class SettingsModel; class SipAddressesModel; class VcardModel; +class TimelineListModel; class CoreManager : public QObject { @@ -66,8 +67,9 @@ public: return mHandlers; } - std::shared_ptr getChatModel (const QString &peerAddress, const QString &localAddress); - bool chatModelExists (const QString &sipAddress, const QString &localAddress); + std::shared_ptr getChatModel (const QString &peerAddress, const QString &localAddress, const bool &isSecure); + std::shared_ptr getChatModel (std::shared_ptr chatRoom); + bool chatModelExists (const QString &sipAddress, const QString &localAddress, const bool &isSecure); HistoryModel* getHistoryModel(); @@ -101,8 +103,11 @@ public: Q_CHECK_PTR(mContactsImporterListModel); return mContactsImporterListModel; } - - + + TimelineListModel *getTimelineListModel () const { + Q_CHECK_PTR(mTimelineListModel); + return mTimelineListModel; + } SipAddressesModel *getSipAddressesModel () const { Q_CHECK_PTR(mSipAddressesModel); @@ -194,6 +199,7 @@ private: CallsListModel *mCallsListModel = nullptr; ContactsListModel *mContactsListModel = nullptr; ContactsImporterListModel *mContactsImporterListModel = nullptr; + TimelineListModel *mTimelineListModel = nullptr; SipAddressesModel *mSipAddressesModel = nullptr; SettingsModel *mSettingsModel = nullptr; @@ -201,7 +207,7 @@ private: EventCountNotifier *mEventCountNotifier = nullptr; - QHash, std::weak_ptr> mChatModels; + QHash >, std::weak_ptr> mChatModels; HistoryModel * mHistoryModel = nullptr; LdapListModel *mLdapListModel = nullptr; diff --git a/linphone-app/src/components/timeline/TimelineListModel.cpp b/linphone-app/src/components/timeline/TimelineListModel.cpp new file mode 100644 index 000000000..e92680cac --- /dev/null +++ b/linphone-app/src/components/timeline/TimelineListModel.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "components/core/CoreManager.hpp" +#include "components/settings/AccountSettingsModel.hpp" +#include "components/sip-addresses/SipAddressesModel.hpp" +#include "utils/Utils.hpp" + +#include "TimelineListModel.hpp" +#include "TimelineModel.hpp" + +#include + + +// ============================================================================= + +TimelineListModel::TimelineListModel (QObject *parent) : QAbstractListModel(parent) { + initTimeline(); +} + +// ----------------------------------------------------------------------------- +void TimelineListModel::reset(){ + initTimeline(); +} + +int TimelineListModel::rowCount (const QModelIndex &) const { + return mTimelines.count(); +} + +QHash TimelineListModel::roleNames () const { + QHash roles; + roles[Qt::DisplayRole] = "$timelines"; + return roles; +} + +QVariant TimelineListModel::data (const QModelIndex &index, int role) const { + int row = index.row(); + + if (!index.isValid() || row < 0 || row >= mTimelines.count()) + return QVariant(); + + if (role == Qt::DisplayRole) + return QVariant::fromValue(mTimelines[row]); + + return QVariant(); +} + +// ----------------------------------------------------------------------------- + + + +// ----------------------------------------------------------------------------- + +bool TimelineListModel::removeRow (int row, const QModelIndex &parent) { + return removeRows(row, 1, parent); +} + +bool TimelineListModel::removeRows (int row, int count, const QModelIndex &parent) { + int limit = row + count - 1; + + if (row < 0 || count < 0 || limit >= mTimelines.count()) + return false; + + beginRemoveRows(parent, row, limit); + + for (int i = 0; i < count; ++i) + delete mTimelines.takeAt(row); + + endRemoveRows(); + + return true; +} + + +// ----------------------------------------------------------------------------- + +void TimelineListModel::initTimeline () { + CoreManager *coreManager = CoreManager::getInstance(); + auto currentAddress = coreManager->getAccountSettingsModel()->getUsedSipAddress(); + + std::list> allChatRooms = coreManager->getCore()->getChatRooms(); + QList models; + for(auto itAllChatRooms = allChatRooms.begin() ; itAllChatRooms != allChatRooms.end() ; ++itAllChatRooms){ + if((*itAllChatRooms)->getMe()->getAddress()->weakEqual(currentAddress)){ + models << new TimelineModel(*itAllChatRooms); + } + } + //beginInsertRows(QModelIndex(), 0, models.count()-1); + + mTimelines = models; + + //endInsertRows(); + + /* + initSipAddressesFromChat(); + initSipAddressesFromCalls(); + initRefs(); + initSipAddressesFromContacts();*/ + + /* + auto bcSections = lConfig->getSectionsNamesList(); + // Loop on all sections and load configuration. If this is not a LDAP configuration, the model is discarded. + for(auto itSections = bcSections.begin(); itSections != bcSections.end(); ++itSections) { + TimelineModel * model = new TimelineModel(); + if(model->load(*itSections)){ + mTimelines.append(model); + }else + delete model; + } + */ +} +/* +// Create a new TimelineModel and put it in the list +void TimelineListModel::add(){ + int row = mTimelines.count(); + beginInsertRows(QModelIndex(), row, row); + auto model = new TimelineModel(); + model->init(); + mTimelines << model; + endInsertRows(); + resetInternalData(); +} +*/ +void TimelineListModel::remove (TimelineModel *model) { + /* + int index = mTimelines.indexOf(ldap); + if (index >=0){ + ldap->unsave(); + removeRow(index); + }*/ +} diff --git a/linphone-app/src/components/timeline/TimelineListModel.hpp b/linphone-app/src/components/timeline/TimelineListModel.hpp new file mode 100644 index 000000000..1525f958e --- /dev/null +++ b/linphone-app/src/components/timeline/TimelineListModel.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TIMELINE_LIST_MODEL_H_ +#define TIMELINE_LIST_MODEL_H_ + +#include + +class TimelineModel; +// ============================================================================= + +class TimelineListModel : public QAbstractListModel { + Q_OBJECT +public: + + TimelineListModel (QObject *parent = Q_NULLPTR); + + void reset(); + + int rowCount (const QModelIndex &index = QModelIndex()) const override; + + QHash roleNames () const override; + QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; + +// Remove a chatroom + Q_INVOKABLE void remove (TimelineModel *importer); + +private: + bool removeRow (int row, const QModelIndex &parent = QModelIndex()); + bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override; + + void initTimeline (); + + QList mTimelines; +}; + +#endif // TIMELINE_LIST_MODEL_H_ diff --git a/linphone-app/src/components/timeline/TimelineModel (copy).cpp b/linphone-app/src/components/timeline/TimelineModel (copy).cpp new file mode 100644 index 000000000..839ff6ba2 --- /dev/null +++ b/linphone-app/src/components/timeline/TimelineModel (copy).cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "components/core/CoreManager.hpp" +#include "components/settings/AccountSettingsModel.hpp" +#include "components/sip-addresses/SipAddressesModel.hpp" +#include "utils/Utils.hpp" + +#include "TimelineModel.hpp" + +#include + + +// ============================================================================= + +TimelineModel::TimelineModel (QObject *parent) : QSortFilterProxyModel(parent) { + CoreManager *coreManager = CoreManager::getInstance(); + AccountSettingsModel *accountSettingsModel = coreManager->getAccountSettingsModel(); + + QObject::connect(accountSettingsModel, &AccountSettingsModel::accountSettingsUpdated, this, [this]() { + handleLocalAddressChanged(CoreManager::getInstance()->getAccountSettingsModel()->getUsedSipAddressAsStringUriOnly()); + }); + QObject::connect(coreManager->getSipAddressesModel(), &SipAddressesModel::sipAddressReset, this, [this]() { + invalidate();// Invalidate and reload GUI if the model has been reset + }); + mLocalAddress = accountSettingsModel->getUsedSipAddressAsStringUriOnly(); + + setSourceModel(coreManager->getSipAddressesModel()); + sort(0); +} + +QHash TimelineModel::roleNames () const { + QHash roles; + roles[Qt::DisplayRole] = "$timelineEntry"; + return roles; +} + +// ----------------------------------------------------------------------------- + +static inline const QHash *getLocalToConferenceEntry (const QVariantMap &map) { + return map.value("__localToConferenceEntry").value(); +} + +QVariant TimelineModel::data (const QModelIndex &index, int role) const { + QVariantMap map(QSortFilterProxyModel::data(index, role).toMap()); + + auto localToConferenceEntry = getLocalToConferenceEntry(map); + auto it = localToConferenceEntry->find(getCleanedLocalAddress()); + if (it != localToConferenceEntry->end()) { + map["timestamp"] = it->timestamp; + map["isComposing"] = it->isComposing; + map["unreadMessageCount"] = it->unreadMessageCount; + map["missedCallCount"] = it->missedCallCount; + } + + return map; +} + +bool TimelineModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const { + const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + return getLocalToConferenceEntry(index.data().toMap())->contains(getCleanedLocalAddress()); +} + +bool TimelineModel::lessThan (const QModelIndex &left, const QModelIndex &right) const { +QString localAddress = getCleanedLocalAddress(); + const QDateTime &a(getLocalToConferenceEntry(sourceModel()->data(left).toMap())->find(localAddress)->timestamp); + const QDateTime &b(getLocalToConferenceEntry(sourceModel()->data(right).toMap())->find(localAddress)->timestamp); + return a > b; +} + +// ----------------------------------------------------------------------------- +QString TimelineModel::getLocalAddress () const +{ + return mLocalAddress; +} +QString TimelineModel::getCleanedLocalAddress () const +{ + return Utils::cleanSipAddress(mLocalAddress); +} +void TimelineModel::handleLocalAddressChanged (const QString &localAddress) { + if (mLocalAddress != localAddress) { + mLocalAddress = localAddress; + invalidate(); + } +} diff --git a/linphone-app/src/components/timeline/TimelineModel (copy).hpp b/linphone-app/src/components/timeline/TimelineModel (copy).hpp new file mode 100644 index 000000000..8777389af --- /dev/null +++ b/linphone-app/src/components/timeline/TimelineModel (copy).hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TIMELINE_MODEL_H_ +#define TIMELINE_MODEL_H_ + +#include +// ============================================================================= + +class TimelineModel : public QSortFilterProxyModel { + Q_OBJECT; + + Q_PROPERTY(QString localAddress READ getLocalAddress NOTIFY localAddressChanged); + +public: + TimelineModel (QObject *parent = Q_NULLPTR); + + QHash roleNames () const override; + +signals: + void localAddressChanged (const QString &localAddress); + +protected: + QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; + + bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override; + bool lessThan (const QModelIndex &left, const QModelIndex &right) const override; + + QString getLocalAddress () const; + QString getCleanedLocalAddress () const; + void handleLocalAddressChanged (const QString &localAddress); + +private: + QString mLocalAddress; +}; + +#endif // TIMELINE_MODEL_H_ diff --git a/linphone-app/src/components/timeline/TimelineModel.cpp b/linphone-app/src/components/timeline/TimelineModel.cpp index 839ff6ba2..30c3d669d 100644 --- a/linphone-app/src/components/timeline/TimelineModel.cpp +++ b/linphone-app/src/components/timeline/TimelineModel.cpp @@ -21,6 +21,7 @@ #include "components/core/CoreManager.hpp" #include "components/settings/AccountSettingsModel.hpp" #include "components/sip-addresses/SipAddressesModel.hpp" +#include "components/chat/ChatModel.hpp" #include "utils/Utils.hpp" #include "TimelineModel.hpp" @@ -30,73 +31,40 @@ // ============================================================================= -TimelineModel::TimelineModel (QObject *parent) : QSortFilterProxyModel(parent) { - CoreManager *coreManager = CoreManager::getInstance(); - AccountSettingsModel *accountSettingsModel = coreManager->getAccountSettingsModel(); - - QObject::connect(accountSettingsModel, &AccountSettingsModel::accountSettingsUpdated, this, [this]() { - handleLocalAddressChanged(CoreManager::getInstance()->getAccountSettingsModel()->getUsedSipAddressAsStringUriOnly()); - }); - QObject::connect(coreManager->getSipAddressesModel(), &SipAddressesModel::sipAddressReset, this, [this]() { - invalidate();// Invalidate and reload GUI if the model has been reset - }); - mLocalAddress = accountSettingsModel->getUsedSipAddressAsStringUriOnly(); - - setSourceModel(coreManager->getSipAddressesModel()); - sort(0); +TimelineModel::TimelineModel (std::shared_ptr chatRoom, QObject *parent) : QObject(parent) { + mChatModel = CoreManager::getInstance()->getChatModel(chatRoom); } -QHash TimelineModel::roleNames () const { - QHash roles; - roles[Qt::DisplayRole] = "$timelineEntry"; - return roles; +QString TimelineModel::getFullPeerAddress() const{ + return mChatModel->getFullPeerAddress(); +} +QString TimelineModel::getFullLocalAddress() const{ + return mChatModel->getLocalAddress(); } -// ----------------------------------------------------------------------------- -static inline const QHash *getLocalToConferenceEntry (const QVariantMap &map) { - return map.value("__localToConferenceEntry").value(); +QString TimelineModel::getUsername() const{ + std::string username = mChatModel->getChatRoom()->getSubject(); + if(username != ""){ + return QString::fromStdString(username); + } + username = mChatModel->getChatRoom()->getPeerAddress()->getDisplayName(); + if(username != "") + return QString::fromStdString(username); + username = mChatModel->getChatRoom()->getPeerAddress()->getUsername(); + if(username != "") + return QString::fromStdString(username); + return QString::fromStdString(mChatModel->getChatRoom()->getPeerAddress()->asStringUriOnly()); } -QVariant TimelineModel::data (const QModelIndex &index, int role) const { - QVariantMap map(QSortFilterProxyModel::data(index, role).toMap()); - - auto localToConferenceEntry = getLocalToConferenceEntry(map); - auto it = localToConferenceEntry->find(getCleanedLocalAddress()); - if (it != localToConferenceEntry->end()) { - map["timestamp"] = it->timestamp; - map["isComposing"] = it->isComposing; - map["unreadMessageCount"] = it->unreadMessageCount; - map["missedCallCount"] = it->missedCallCount; - } - - return map; +QString TimelineModel::getAvatar() const{ + return ""; } -bool TimelineModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const { - const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); - return getLocalToConferenceEntry(index.data().toMap())->contains(getCleanedLocalAddress()); +int TimelineModel::getPresenceStatus() const{ + return 0; } -bool TimelineModel::lessThan (const QModelIndex &left, const QModelIndex &right) const { -QString localAddress = getCleanedLocalAddress(); - const QDateTime &a(getLocalToConferenceEntry(sourceModel()->data(left).toMap())->find(localAddress)->timestamp); - const QDateTime &b(getLocalToConferenceEntry(sourceModel()->data(right).toMap())->find(localAddress)->timestamp); - return a > b; -} - -// ----------------------------------------------------------------------------- -QString TimelineModel::getLocalAddress () const -{ - return mLocalAddress; -} -QString TimelineModel::getCleanedLocalAddress () const -{ - return Utils::cleanSipAddress(mLocalAddress); -} -void TimelineModel::handleLocalAddressChanged (const QString &localAddress) { - if (mLocalAddress != localAddress) { - mLocalAddress = localAddress; - invalidate(); - } +std::shared_ptr TimelineModel::getChatRoom() const{ + return mChatModel; } diff --git a/linphone-app/src/components/timeline/TimelineModel.hpp b/linphone-app/src/components/timeline/TimelineModel.hpp index 8777389af..591cc32fb 100644 --- a/linphone-app/src/components/timeline/TimelineModel.hpp +++ b/linphone-app/src/components/timeline/TimelineModel.hpp @@ -23,32 +23,53 @@ #include // ============================================================================= +#include +#include -class TimelineModel : public QSortFilterProxyModel { - Q_OBJECT; +#include - Q_PROPERTY(QString localAddress READ getLocalAddress NOTIFY localAddressChanged); +#include "../contact/ContactModel.hpp" + +class ChatModel; + +class TimelineModel : public QObject { + Q_OBJECT public: - TimelineModel (QObject *parent = Q_NULLPTR); + TimelineModel (std::shared_ptr chatRoom, QObject *parent = Q_NULLPTR); + + Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged) + Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress NOTIFY fullLocalAddressChanged) + Q_PROPERTY(std::shared_ptr chatRoom READ getChatRoom CONSTANT) + +// Contact + Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged) + Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged) + Q_PROPERTY(QString avatar READ getAvatar NOTIFY avatarChanged) + Q_PROPERTY(int presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged) + + + QString getFullPeerAddress() const; + QString getFullLocalAddress() const; + + QString getUsername() const; + QString getAvatar() const; + int getPresenceStatus() const; + + + std::shared_ptr getChatRoom() const; - QHash roleNames () const override; + QDateTime mTimestamp; + std::shared_ptr mChatModel; + //std::shared_ptr mChatRoom; signals: - void localAddressChanged (const QString &localAddress); - -protected: - QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; - - bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override; - bool lessThan (const QModelIndex &left, const QModelIndex &right) const override; - - QString getLocalAddress () const; - QString getCleanedLocalAddress () const; - void handleLocalAddressChanged (const QString &localAddress); - -private: - QString mLocalAddress; + void fullPeerAddressChanged(); + void fullLocalAddressChanged(); + void usernameChanged(); + void avatarChanged(); + void presenceStatusChanged(); + }; #endif // TIMELINE_MODEL_H_ diff --git a/linphone-app/src/components/timeline/TimelineProxyModel.cpp b/linphone-app/src/components/timeline/TimelineProxyModel.cpp new file mode 100644 index 000000000..800a4d379 --- /dev/null +++ b/linphone-app/src/components/timeline/TimelineProxyModel.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "components/core/CoreManager.hpp" +#include "components/settings/AccountSettingsModel.hpp" +#include "components/sip-addresses/SipAddressesModel.hpp" +#include "utils/Utils.hpp" + +#include "TimelineProxyModel.hpp" +#include "TimelineListModel.hpp" +#include "TimelineModel.hpp" + +#include + + +// ============================================================================= + +// ----------------------------------------------------------------------------- + +TimelineProxyModel::TimelineProxyModel (QObject *parent) : QSortFilterProxyModel(parent) { + setSourceModel(CoreManager::getInstance()->getTimelineListModel()); + sort(0); +} + +// ----------------------------------------------------------------------------- + +bool TimelineProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const { + const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + return true; +} + +bool TimelineProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const { + const TimelineModel* a = sourceModel()->data(left).value(); + const TimelineModel* b = sourceModel()->data(right).value(); + + return a->mTimestamp <= b->mTimestamp; +} diff --git a/linphone-app/src/components/timeline/TimelineProxyModel.hpp b/linphone-app/src/components/timeline/TimelineProxyModel.hpp new file mode 100644 index 000000000..c5b8e3b94 --- /dev/null +++ b/linphone-app/src/components/timeline/TimelineProxyModel.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TIMELINE_PROXY_MODEL_H_ +#define TIMELINE_PROXY_MODEL_H_ + +#include +// ============================================================================= + +class TimelineProxyModel : public QSortFilterProxyModel { + Q_OBJECT; + + +public: + TimelineProxyModel (QObject *parent = Q_NULLPTR); + +protected: + + bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override; + bool lessThan (const QModelIndex &left, const QModelIndex &right) const override; + + QString getLocalAddress () const; + QString getCleanedLocalAddress () const; + void handleLocalAddressChanged (const QString &localAddress); + +}; + +#endif // TIMELINE_PROXY_MODEL_H_ diff --git a/linphone-app/ui/modules/Linphone/Contact/Contact.qml b/linphone-app/ui/modules/Linphone/Contact/Contact.qml index 2139eec6f..03abe44f1 100644 --- a/linphone-app/ui/modules/Linphone/Contact/Contact.qml +++ b/linphone-app/ui/modules/Linphone/Contact/Contact.qml @@ -19,8 +19,9 @@ Rectangle { // A entry from `SipAddressesModel` or an `SipAddressObserver`. property var entry + // entry should have these functions : presenceStatus, sipAddress, username, avatar (image) - readonly property var _contact: entry.contact + //readonly property var _contact: entry.contact // --------------------------------------------------------------------------- @@ -41,13 +42,15 @@ Rectangle { Layout.preferredHeight: ContactStyle.contentHeight Layout.preferredWidth: ContactStyle.contentHeight - image: _contact && _contact.vcard.avatar + //image: _contact && _contact.vcard.avatar + image: entry.avatar presenceLevel: entry.presenceStatus != null ? Presence.getPresenceLevel(entry.presenceStatus) : -1 - username: LinphoneUtils.getContactUsername(_contact || entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || '') + //username: LinphoneUtils.getContactUsername(_contact || entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || '') + username: entry.username } ContactDescription { @@ -57,7 +60,8 @@ Rectangle { Layout.fillWidth: true Layout.leftMargin: ContactStyle.spacing - sipAddress: entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || '' + //sipAddress: entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || '' + sipAddress: entry.sipAddress username: avatar.username } diff --git a/linphone-app/ui/modules/Linphone/Timeline/Timeline.js b/linphone-app/ui/modules/Linphone/Timeline/Timeline.js index c3b4f1398..7126aba38 100644 --- a/linphone-app/ui/modules/Linphone/Timeline/Timeline.js +++ b/linphone-app/ui/modules/Linphone/Timeline/Timeline.js @@ -26,6 +26,7 @@ // ============================================================================= function setSelectedEntry (peerAddress, localAddress) { + /* if (localAddress != null && localAddress !== Linphone.AccountSettingsModel.sipAddress) { resetSelectedEntry() return @@ -42,16 +43,19 @@ function setSelectedEntry (peerAddress, localAddress) { return } } + */ } function resetSelectedEntry () { + /* view.currentIndex = -1 - timeline._selectedSipAddress = '' + timeline._selectedSipAddress = ''*/ } // ----------------------------------------------------------------------------- function handleDataChanged (topLeft, bottomRight, roles) { + /* var index = view.currentIndex var model = timeline.model var sipAddress = timeline._selectedSipAddress @@ -62,18 +66,22 @@ function handleDataChanged (topLeft, bottomRight, roles) { ) { setSelectedEntry(sipAddress) } + */ } function handleRowsAboutToBeRemoved (parent, first, last) { + /* var index = view.currentIndex if (index >= first && index <= last) { view.currentIndex = -1 } + */ } function handleCountChanged (_) { + /* var sipAddress = timeline._selectedSipAddress if (sipAddress.length > 0) { setSelectedEntry(sipAddress) - } + }*/ } diff --git a/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml b/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml index fe90a60f0..3eb71ab70 100644 --- a/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml +++ b/linphone-app/ui/modules/Linphone/Timeline/Timeline.qml @@ -19,7 +19,8 @@ Rectangle { // --------------------------------------------------------------------------- - signal entrySelected (string entry) + //signal entrySelected (string entry) + signal entrySelected (TimelineModel entry) // --------------------------------------------------------------------------- @@ -62,7 +63,7 @@ Rectangle { anchors.fill:parent onClicked: { view.currentIndex = -1 - timeline.entrySelected('') + timeline.entrySelected('',false) } } @@ -117,7 +118,9 @@ Rectangle { : TimelineStyle.contact.backgroundColor.b ) displayUnreadMessageCount: SettingsModel.chatEnabled - entry: $timelineEntry + //entry: $timelineEntry + //entry: SipAddressesModel.getSipAddressObserver(modelData.fullPeerAddress, modelData.fullLocalAddress) + entry: modelData sipAddressColor: isSelected ? TimelineStyle.contact.sipAddress.color.selected : TimelineStyle.contact.sipAddress.color.normal @@ -128,10 +131,11 @@ Rectangle { Loader { anchors.fill: parent sourceComponent: TooltipArea { - text: $timelineEntry.timestamp.toLocaleString( - Qt.locale(App.locale), - Locale.ShortFormat - ) + + //text: $timelineEntry.timestamp.toLocaleString( + //Qt.locale(App.locale), + //Locale.ShortFormat + //) } } } @@ -140,7 +144,8 @@ Rectangle { anchors.fill: parent onClicked: { view.currentIndex = index - timeline.entrySelected($timelineEntry.sipAddress) + timeline.entrySelected(modelData) + //timeline.entrySelected($timelineEntry.sipAddress, $timelineEntry.isSecure) } } } diff --git a/linphone-app/ui/views/App/Main/Contacts.qml b/linphone-app/ui/views/App/Main/Contacts.qml index 553a3c9b6..0b1cdc130 100644 --- a/linphone-app/ui/views/App/Main/Contacts.qml +++ b/linphone-app/ui/views/App/Main/Contacts.qml @@ -148,6 +148,11 @@ ColumnLayout { icon: SettingsModel.chatEnabled && SettingsModel.showStartChatButton ? 'chat' : 'history' onClicked: actions.itemAt(2).open() } + + ActionButton { + icon: 'call_chat_unsecure' + onClicked: {console.log("A");actions.itemAt(3).open()} + } } ActionButton { @@ -176,8 +181,23 @@ ColumnLayout { peerAddress: sipAddress, localAddress: AccountSettingsModel.sipAddress, fullPeerAddress: sipAddress, - fullLocalAddress: AccountSettingsModel.fullSipAddress + fullLocalAddress: AccountSettingsModel.fullSipAddress, + secure:false }) + }, + function (sipAddress) { + console.log("B") + if(CallsListModel.launchSecureChat(sipAddress)){ + console.log("C") + window.setView('Conversation', { + peerAddress: sipAddress, + localAddress: AccountSettingsModel.sipAddress, + fullPeerAddress: sipAddress, + fullLocalAddress: AccountSettingsModel.fullSipAddress, + secure:true + }) + }else + console.log("D") } ] diff --git a/linphone-app/ui/views/App/Main/Conversation.qml b/linphone-app/ui/views/App/Main/Conversation.qml index c5b81b335..c2f7b55f6 100644 --- a/linphone-app/ui/views/App/Main/Conversation.qml +++ b/linphone-app/ui/views/App/Main/Conversation.qml @@ -17,6 +17,8 @@ ColumnLayout { property string localAddress property string fullPeerAddress property string fullLocalAddress + property int isSecure + property var chatRoom readonly property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver((fullPeerAddress?fullPeerAddress:peerAddress), (fullLocalAddress?fullLocalAddress:localAddress)) @@ -170,11 +172,13 @@ ColumnLayout { } resetMessageCount() } - + isSecure: conversation.isSecure + chatRoom: conversation.chatRoom peerAddress: conversation.peerAddress - localAddress: conversation.localAddress fullPeerAddress: conversation.fullPeerAddress fullLocalAddress: conversation.fullLocalAddress + localAddress: conversation.localAddress// Reload is done on localAddress. Use this order + } } diff --git a/linphone-app/ui/views/App/Main/MainWindow.qml b/linphone-app/ui/views/App/Main/MainWindow.qml index 8cbcfbadf..1ce1556a9 100644 --- a/linphone-app/ui/views/App/Main/MainWindow.qml +++ b/linphone-app/ui/views/App/Main/MainWindow.qml @@ -160,20 +160,23 @@ ApplicationWindow { window.setView('ContactEdit', { sipAddress: entry.sipAddress }) } else { window.setView('Conversation', { + isSecure: entry.isSecure, peerAddress: entry.sipAddress, - localAddress: AccountSettingsModel.sipAddress, fullPeerAddress: entry.fullSipAddress, - fullLocalAddress: AccountSettingsModel.fullSipAddress + fullLocalAddress: AccountSettingsModel.fullSipAddress, + localAddress: AccountSettingsModel.sipAddress + }) } } onLaunchCall: CallsListModel.launchAudioCall(sipAddress) onLaunchChat: window.setView('Conversation', { + isSecure:false, peerAddress: sipAddress, - localAddress: AccountSettingsModel.sipAddress, fullPeerAddress: sipAddress, - fullLocalAddress: AccountSettingsModel.fullSipAddress + fullLocalAddress: AccountSettingsModel.fullSipAddress, + localAddress: AccountSettingsModel.sipAddress }) onLaunchVideoCall: CallsListModel.launchVideoCall(sipAddress) @@ -259,13 +262,16 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true - model: TimelineModel + model: TimelineProxyModel{} onEntrySelected: (entry?setView('Conversation', { - peerAddress: entry, - localAddress: AccountSettingsModel.sipAddress, - fullPeerAddress: entry, - fullLocalAddress: AccountSettingsModel.fullSipAddress + isSecure:-1, + peerAddress: entry.fullPeerAddress, + fullPeerAddress: entry.fullPeerAddress, + fullLocalAddress: AccountSettingsModel.fullSipAddress, + localAddress: AccountSettingsModel.sipAddress, + chatRoom:entry.chatRoom + }): setView('HistoryView', {}) )