diff --git a/linphone-app/src/app/paths/Paths.cpp b/linphone-app/src/app/paths/Paths.cpp index 4e39aabe6..7bb3a61b1 100644 --- a/linphone-app/src/app/paths/Paths.cpp +++ b/linphone-app/src/app/paths/Paths.cpp @@ -240,7 +240,7 @@ string Paths::getLogsDirPath () { } string Paths::getMessageHistoryFilePath () { - return getWritableFilePath(getAppMessageHistoryFilePath()); + return getReadableFilePath(getAppMessageHistoryFilePath());// No need to ensure that the file exists as this DB is deprecated } string Paths::getPackageDataDirPath () { @@ -300,10 +300,19 @@ static void migrateConfigurationFile (const QString &oldPath, const QString &new qWarning() << "Failed migration of" << oldPath << "to" << newPath; } } - -void Paths::migrate () { +void migrateFlatpakVersionFiles(){ +#ifdef Q_OS_LINUX +// Copy all files + QString flatpakPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.var/app/com.belledonnecommunications.linphone/data/linphone"; + if( QDir().exists(flatpakPath)){ + qInfo() << "Migrating data from Flatpak."; + Utils::copyDir(flatpakPath, QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); + } +#endif +} +void migrateGTKVersionFiles(){ QString newPath = getAppConfigFilePath(); - QString oldBaseDir = QSysInfo::productType() == QLatin1String("windows") + QString oldBaseDir = QSysInfo::productType() == QLatin1String("windows") ? QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) : QStandardPaths::writableLocation(QStandardPaths::HomeLocation); QString oldPath = oldBaseDir + "/.linphonerc"; @@ -329,3 +338,7 @@ void Paths::migrate () { if (!filePathExists(newPath) && filePathExists(oldPath)) migrateFile(oldPath, newPath); } +void Paths::migrate () { + migrateFlatpakVersionFiles(); // First, check Flatpak version as it is the earlier version + migrateGTKVersionFiles();// Then check old version for migration +} diff --git a/linphone-app/src/components/assistant/AssistantModel.cpp b/linphone-app/src/components/assistant/AssistantModel.cpp index 4bc0aac2c..c46056735 100644 --- a/linphone-app/src/components/assistant/AssistantModel.cpp +++ b/linphone-app/src/components/assistant/AssistantModel.cpp @@ -22,6 +22,7 @@ #include "components/core/CoreManager.hpp" #include "components/settings/AccountSettingsModel.hpp" #include "components/settings/SettingsModel.hpp" +#include "components/sip-addresses/SipAddressesModel.hpp" #include "utils/LinphoneUtils.hpp" #include "utils/Utils.hpp" @@ -55,9 +56,9 @@ private: linphone::AccountCreator::Status status, const string & ) override { - if (status == linphone::AccountCreator::Status::AccountCreated) + if (status == linphone::AccountCreator::Status::AccountCreated){ emit mAssistant->createStatusChanged(QString("")); - else { + }else { if (status == linphone::AccountCreator::Status::RequestFailed) emit mAssistant->createStatusChanged(tr("requestFailed")); else if (status == linphone::AccountCreator::Status::ServerError) @@ -74,6 +75,7 @@ private: ) override { if (status == linphone::AccountCreator::Status::AccountExist || status == linphone::AccountCreator::Status::AccountExistWithAlias) { createProxyConfig(creator); + CoreManager::getInstance()->getSipAddressesModel()->reset(); emit mAssistant->loginStatusChanged(QString("")); } else { if (status == linphone::AccountCreator::Status::RequestFailed) @@ -94,7 +96,7 @@ private: ) { if (creator->getEmail().empty()) createProxyConfig(creator); - + CoreManager::getInstance()->getSipAddressesModel()->reset(); emit mAssistant->activateStatusChanged(QString("")); } else { if (status == linphone::AccountCreator::Status::RequestFailed) @@ -111,6 +113,7 @@ private: ) override { if (status == linphone::AccountCreator::Status::AccountActivated) { createProxyConfig(creator); + CoreManager::getInstance()->getSipAddressesModel()->reset(); emit mAssistant->activateStatusChanged(QString("")); } else { if (status == linphone::AccountCreator::Status::RequestFailed) @@ -126,6 +129,7 @@ private: const string & ) override { if (status == linphone::AccountCreator::Status::RequestOk) { + CoreManager::getInstance()->getSipAddressesModel()->reset(); emit mAssistant->recoverStatusChanged(QString("")); } else { if (status == linphone::AccountCreator::Status::RequestFailed) diff --git a/linphone-app/src/components/core/CoreManager.cpp b/linphone-app/src/components/core/CoreManager.cpp index 9bd5452df..fa2a35c42 100644 --- a/linphone-app/src/components/core/CoreManager.cpp +++ b/linphone-app/src/components/core/CoreManager.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "config.h" @@ -210,7 +211,10 @@ void CoreManager::cleanLogs () const { void CoreManager::setDatabasesPaths () { SET_DATABASE_PATH(Friends, Paths::getFriendsListFilePath()); SET_DATABASE_PATH(CallLogs, Paths::getCallHistoryFilePath()); - SET_DATABASE_PATH(Chat, Paths::getMessageHistoryFilePath()); + if(QFile::exists(Utils::coreStringToAppString(Paths::getMessageHistoryFilePath()))){ + SET_DATABASE_PATH(Chat, Paths::getMessageHistoryFilePath());// Setting the message database let SDK to migrate data + QFile::remove(Utils::coreStringToAppString(Paths::getMessageHistoryFilePath())); + } } #undef SET_DATABASE_PATH diff --git a/linphone-app/src/components/sip-addresses/SipAddressesModel.cpp b/linphone-app/src/components/sip-addresses/SipAddressesModel.cpp index 822db8783..2a349b48c 100644 --- a/linphone-app/src/components/sip-addresses/SipAddressesModel.cpp +++ b/linphone-app/src/components/sip-addresses/SipAddressesModel.cpp @@ -71,10 +71,17 @@ SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(pare QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &SipAddressesModel::handleCallStateChanged); QObject::connect(coreHandlers, &CoreHandlers::presenceReceived, this, &SipAddressesModel::handlePresenceReceived); QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &SipAddressesModel::handleIsComposingChanged); + QObject::connect(coreHandlers, &CoreHandlers::registrationStateChanged, this, &SipAddressesModel::handleRegistrationStateChanged); } // ----------------------------------------------------------------------------- - +void SipAddressesModel::reset(){ + mPeerAddressToSipAddressEntry.clear(); + mRefs.clear(); + resetInternalData(); + initSipAddresses(); + emit sipAddressReset(); +} int SipAddressesModel::rowCount (const QModelIndex &) const { return mRefs.count(); } @@ -433,7 +440,15 @@ void SipAddressesModel::handleIsComposingChanged (const shared_ptr &proxyConfig, linphone::RegistrationState state){ + QString address = Utils::coreStringToAppString(proxyConfig->getIdentityAddress()->asStringUriOnly()); + if(!mRegistredProxies.contains(address) && state == linphone::RegistrationState::Ok)// This is a new state. + reset(); + else if( state == linphone::RegistrationState::Cleared){ + mRegistredProxies.removeAll(address); + reset(); + } +} // ----------------------------------------------------------------------------- void SipAddressesModel::addOrUpdateSipAddress (SipAddressEntry &sipAddressEntry, ContactModel *contact) { @@ -538,16 +553,25 @@ void SipAddressesModel::removeContactOfSipAddress (const QString &sipAddress) { void SipAddressesModel::initSipAddresses () { QElapsedTimer timer; timer.start(); + + auto proxies = CoreManager::getInstance()->getCore()->getProxyConfigList(); + foreach( auto proxy, proxies){ + QString address = Utils::coreStringToAppString(proxy->getIdentityAddress()->asStringUriOnly()); + if(proxy->getState() == linphone::RegistrationState::Ok && !mRegistredProxies.contains(address)){ + mRegistredProxies.push_back(address); + } + } - initSipAddressesFromChat(); - initSipAddressesFromCalls(); + initSipAddressesFromChat(mRegistredProxies); + initSipAddressesFromCalls(mRegistredProxies); initRefs(); initSipAddressesFromContacts(); qInfo() << "Sip addresses model initialized in:" << timer.elapsed() << "ms."; } -void SipAddressesModel::initSipAddressesFromChat () { +void SipAddressesModel::initSipAddressesFromChat (const QStringList &pRegistredProxies) { + for (const auto &chatRoom : CoreManager::getInstance()->getCore()->getChatRooms()) { list> history(chatRoom->getHistory(1)); if (history.empty()) @@ -556,52 +580,55 @@ void SipAddressesModel::initSipAddressesFromChat () { QString peerAddress(Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly())); QString localAddress(Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly())); - getSipAddressEntry(peerAddress)->localAddressToConferenceEntry[localAddress] = { - chatRoom->getUnreadMessagesCount(), - CoreManager::getInstance()->getMissedCallCount(peerAddress, localAddress), - false, - QDateTime::fromMSecsSinceEpoch(history.back()->getTime() * 1000) - }; + if(pRegistredProxies.contains(localAddress)){ + getSipAddressEntry(peerAddress)->localAddressToConferenceEntry[localAddress] = { + chatRoom->getUnreadMessagesCount(), + CoreManager::getInstance()->getMissedCallCount(peerAddress, localAddress), + false, + QDateTime::fromMSecsSinceEpoch(history.back()->getTime() * 1000) + }; + } } } -void SipAddressesModel::initSipAddressesFromCalls () { +void SipAddressesModel::initSipAddressesFromCalls (const QStringList &pRegistredProxies) { using ConferenceId = QPair; QSet conferenceDone; for (const auto &callLog : CoreManager::getInstance()->getCore()->getCallLogs()) { const QString peerAddress(Utils::coreStringToAppString(callLog->getRemoteAddress()->asStringUriOnly())); const QString localAddress(Utils::coreStringToAppString(callLog->getLocalAddress()->asStringUriOnly())); - - switch (callLog->getStatus()) { - case linphone::Call::Status::Aborted: - case linphone::Call::Status::EarlyAborted: + if(pRegistredProxies.contains(localAddress)){ + switch (callLog->getStatus()) { + case linphone::Call::Status::Aborted: + case linphone::Call::Status::EarlyAborted: return; // Ignore aborted calls. - case linphone::Call::Status::AcceptedElsewhere: - case linphone::Call::Status::DeclinedElsewhere: + case linphone::Call::Status::AcceptedElsewhere: + case linphone::Call::Status::DeclinedElsewhere: return; // Ignore accepted calls on other device. - case linphone::Call::Status::Success: - case linphone::Call::Status::Declined: + case linphone::Call::Status::Success: + case linphone::Call::Status::Declined: - case linphone::Call::Status::Missed: + case linphone::Call::Status::Missed: break; - } + } - ConferenceId conferenceId{ peerAddress, localAddress }; - if (conferenceDone.contains(conferenceId)) - continue; // Already used. - conferenceDone << conferenceId; + ConferenceId conferenceId{ peerAddress, localAddress }; + if (conferenceDone.contains(conferenceId)) + continue; // Already used. + conferenceDone << conferenceId; // The duration can be wrong if status is not success. - QDateTime timestamp(callLog->getStatus() == linphone::Call::Status::Success - ? QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000) - : QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000)); + QDateTime timestamp(callLog->getStatus() == linphone::Call::Status::Success + ? QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000) + : QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000)); - auto &localToConferenceEntry = getSipAddressEntry(peerAddress)->localAddressToConferenceEntry; - auto it = localToConferenceEntry.find(localAddress); - if (it == localToConferenceEntry.end()) - localToConferenceEntry[localAddress] = { 0,0, false, move(timestamp) }; - else if (it->timestamp.isNull() || timestamp > it->timestamp) - it->timestamp = move(timestamp); + auto &localToConferenceEntry = getSipAddressEntry(peerAddress)->localAddressToConferenceEntry; + auto it = localToConferenceEntry.find(localAddress); + if (it == localToConferenceEntry.end()) + localToConferenceEntry[localAddress] = { 0,0, false, move(timestamp) }; + else if (it->timestamp.isNull() || timestamp > it->timestamp) + it->timestamp = move(timestamp); + } } } diff --git a/linphone-app/src/components/sip-addresses/SipAddressesModel.hpp b/linphone-app/src/components/sip-addresses/SipAddressesModel.hpp index bd66688ce..c9466ade3 100644 --- a/linphone-app/src/components/sip-addresses/SipAddressesModel.hpp +++ b/linphone-app/src/components/sip-addresses/SipAddressesModel.hpp @@ -52,6 +52,8 @@ public: }; SipAddressesModel (QObject *parent = Q_NULLPTR); + + void reset(); int rowCount (const QModelIndex &index = QModelIndex()) const override; @@ -78,6 +80,8 @@ public: Q_INVOKABLE static QString cleanSipAddress (const QString &sipAddress); // --------------------------------------------------------------------------- +signals: + void sipAddressReset();// The model has been reset private: bool removeRow (int row, const QModelIndex &parent = QModelIndex()); @@ -104,6 +108,8 @@ private: void handleMessageSent (const std::shared_ptr &message); void handleIsComposingChanged (const std::shared_ptr &chatRoom); + + void handleRegistrationStateChanged( const std::shared_ptr &proxyConfig, linphone::RegistrationState state); // --------------------------------------------------------------------------- @@ -125,8 +131,8 @@ private: void initSipAddresses (); - void initSipAddressesFromChat (); - void initSipAddressesFromCalls (); + void initSipAddressesFromChat (const QStringList &pRegistredProxies);// Read chat logs and keep only for registred proxies + void initSipAddressesFromCalls (const QStringList &pRegistredProxies);// Read call logs and keep only for registred proxies void initSipAddressesFromContacts (); void initRefs (); @@ -143,7 +149,7 @@ private: it = mPeerAddressToSipAddressEntry.insert(peerAddress, { peerAddress, nullptr, Presence::Offline, {} }); return &(*it); } - + QStringList mRegistredProxies;// Storing registred proxies is used to avoid loosing logs when disconnected QHash mPeerAddressToSipAddressEntry; QList mRefs; diff --git a/linphone-app/src/components/timeline/TimelineModel.cpp b/linphone-app/src/components/timeline/TimelineModel.cpp index c24881b19..a93351cea 100644 --- a/linphone-app/src/components/timeline/TimelineModel.cpp +++ b/linphone-app/src/components/timeline/TimelineModel.cpp @@ -33,6 +33,9 @@ TimelineModel::TimelineModel (QObject *parent) : QSortFilterProxyModel(parent) { 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()); diff --git a/linphone-app/src/utils/Utils.cpp b/linphone-app/src/utils/Utils.cpp index 5a9cf11a0..b8cc27fed 100644 --- a/linphone-app/src/utils/Utils.cpp +++ b/linphone-app/src/utils/Utils.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include "Utils.hpp" @@ -355,3 +357,20 @@ QString Utils::getCountryName(const QLocale::Country& p_country) countryName = QLocale::countryToString(p_country); return countryName; } +// Copy a folder recursively without erasing old file +void Utils::copyDir(QString from, QString to) { + QDir dir; + dir.setPath(from); + from += QDir::separator(); + to += QDir::separator(); + foreach (QString copyFile, dir.entryList(QDir::Files)) {// Copy each files + QString toFile = to + copyFile; + if (!QFile::exists(toFile)) + QFile::copy(from+copyFile, toFile); + } + foreach (QString nextDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {// Copy folder + QString toDir = to + nextDir; + QDir().mkpath(toDir);// no need to check if dir exists + copyDir(from + nextDir, toDir);//Go up + } +} diff --git a/linphone-app/src/utils/Utils.hpp b/linphone-app/src/utils/Utils.hpp index 88e134846..cdc4b6044 100644 --- a/linphone-app/src/utils/Utils.hpp +++ b/linphone-app/src/utils/Utils.hpp @@ -98,6 +98,7 @@ namespace Utils { return connection; } QString getCountryName(const QLocale::Country& country); + void copyDir(QString from, QString to);// Copy a folder recursively without erasing old file } #endif // UTILS_H_