diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c37cbf70..4d91f4bc 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,227 +1,226 @@ set(Ruqola_ddpapi_SRCS ddpapi/ddpclient.cpp ) set (Ruqola_model_core_srcs model/messagemodel.cpp model/roommodel.cpp model/roomfilterproxymodel.cpp model/usersforroommodel.cpp model/usersforroomfilterproxymodel.cpp model/usersmodel.cpp model/usercompleterfilterproxymodel.cpp model/usercompletermodel.cpp model/statusmodel.cpp model/filesforroommodel.cpp model/filesforroomfilterproxymodel.cpp model/searchchannelmodel.cpp model/searchchannelfilterproxymodel.cpp model/inputcompletermodel.cpp model/loginmethodmodel.cpp model/searchmessagemodel.cpp model/searchmessagefilterproxymodel.cpp model/rocketchataccountmodel.cpp model/rocketchataccountfilterproxymodel.cpp model/emoticonmodel.cpp model/notificationpreferencemodel.cpp model/notificationdesktopdurationpreferencemodel.cpp model/notificationdesktopsoundpreferencemodel.cpp model/discussionsmodel.cpp model/discussionsfilterproxymodel.cpp model/threadsmodel.cpp model/threadsfilterproxymodel.cpp model/emoticoncategoriesmodel.cpp model/threadmessagemodel.cpp model/listmessagesmodel.cpp model/listmessagesmodelfilterproxymodel.cpp model/autotranslatelanguagesmodel.cpp ) set(Ruqola_plugins_srcs plugins/pluginauthenticationinterface.cpp plugins/pluginauthentication.cpp ) set(Ruqola_emoticons_srcs emoticons/emoji.cpp emoticons/emojimanager.cpp emoticons/unicodeemoticon.cpp emoticons/unicodeemoticonparser.cpp ) set(Ruqola_messages_srcs messages/message.cpp messages/messageattachment.cpp messages/messageurl.cpp messages/messagestarred.cpp messages/reactions.cpp messages/reaction.cpp messages/messagepinned.cpp messages/messagetranslation.cpp ) set(Ruqola_message_convertertextjob_SRCS convertertextjob/convertertextabstractjob.cpp convertertextjob/translatetextjob.cpp ) set(Ruqola_autotranslatelanguage_SRCS autotranslatelanguage.cpp autotranslatelanguages.cpp ) set (Ruqola_core_srcs ${Ruqola_autotranslatelanguage_SRCS} ${Ruqola_message_convertertextjob_SRCS} ${Ruqola_emoticons_srcs} ${Ruqola_messages_srcs} ${Ruqola_model_core_srcs} ${Ruqola_plugins_srcs} ${Ruqola_ddpapi_SRCS} authenticationinfo.cpp room.cpp roomwrapper.cpp notificationoptionswrapper.cpp ruqola.cpp ruqolautils.cpp rocketchatbackend.cpp messagequeue.cpp rocketchatmessage.cpp typingnotification.cpp changetemporarystatus.cpp user.cpp utils.cpp clipboardproxy.cpp otr.cpp otrmanager.cpp abstractwebsocket.cpp ruqolawebsocket.cpp rocketchataccount.cpp rocketchataccountsettings.cpp ruqolalogger.cpp ruqolaregisterengine.cpp ruqolaserverconfig.cpp rocketchatcache.cpp texthighlighter.cpp textconverter.cpp loadrecenthistorymanager.cpp file.cpp channel.cpp inputtextmanager.cpp authenticationmanager.cpp accountmanager.cpp managerdatapaths.cpp notificationoptions.cpp syntaxhighlightingmanager.cpp - copyfilejob.cpp receivetypingnotificationmanager.cpp serverconfiginfo.cpp notificationpreferences.cpp roles.cpp role.cpp avatarmanager.cpp discussion.cpp discussions.cpp threads.cpp emoticoncategory.cpp listmessages.cpp messagedownloadmanager.cpp fileattachments.cpp ) if (NOT WIN32) set(Ruqola_core_srcs ${Ruqola_core_srcs} unityservicemanager.cpp) endif() if (NOT ANDROID) list(APPEND Ruqola_core_srcs notification.cpp) endif() ecm_qt_declare_logging_category(Ruqola_core_srcs HEADER ruqola_debug.h IDENTIFIER RUQOLA_LOG CATEGORY_NAME org.kde.ruqola) ecm_qt_declare_logging_category(Ruqola_core_srcs HEADER ruqola_message_debug.h IDENTIFIER RUQOLA_MESSAGE_LOG CATEGORY_NAME org.kde.ruqola.message) ecm_qt_declare_logging_category(Ruqola_core_srcs HEADER ruqola_ddpapi_debug.h IDENTIFIER RUQOLA_DDPAPI_LOG CATEGORY_NAME org.kde.ruqola.ddpapi) ecm_qt_declare_logging_category(Ruqola_core_srcs HEADER ruqola_ddpapi_command_debug.h IDENTIFIER RUQOLA_DDPAPI_COMMAND_LOG CATEGORY_NAME org.kde.ruqola.ddpapi.command) ecm_qt_declare_logging_category(Ruqola_core_srcs HEADER ruqola_unknown_collectiontype_debug.h IDENTIFIER RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG CATEGORY_NAME org.kde.ruqola.ddp.collectiontype) qt5_add_resources(libruqolacore_RSC ruqolacore.qrc) add_library(libruqolacore ${Ruqola_core_srcs} ${libruqolacore_RSC}) generate_export_header(libruqolacore BASE_NAME libruqolacore) target_link_libraries(libruqolacore Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick Qt5::WebSockets Qt5::Network Qt5::NetworkAuth KF5::CoreAddons KF5::I18n KF5::Notifications KF5::SyntaxHighlighting librocketchatrestapi-qt5 ) if (NOT WIN32) target_link_libraries(libruqolacore Qt5::DBus) endif() if (WIN32 OR APPLE) target_link_libraries(libruqolacore KF5::IconThemes) endif() if (Qt5Keychain_FOUND) target_link_libraries(libruqolacore qt5keychain) target_include_directories(libruqolacore PRIVATE ${QTKEYCHAIN_INCLUDE_DIRS}) endif() set_target_properties(libruqolacore PROPERTIES OUTPUT_NAME ruqolacore VERSION ${RUQOLA_LIB_VERSION} SOVERSION ${RUQOLA_LIB_SOVERSION} ) if (BUILD_TESTING) add_subdirectory(autotests) endif() install(TARGETS libruqolacore ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) if (ANDROID) install(FILES ruqolacore-android-dependencies.xml DESTINATION ${KDE_INSTALL_LIBDIR}) endif() diff --git a/src/core/copyfilejob.cpp b/src/core/copyfilejob.cpp deleted file mode 100644 index 27e26b64..00000000 --- a/src/core/copyfilejob.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (c) 2018-2020 Laurent Montel - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License or - ( at your option ) version 3 or, at the discretion of KDE e.V. - ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "copyfilejob.h" -#include "ruqola_debug.h" -#include - -CopyFileJob::CopyFileJob(QObject *parent) - : KJob(parent) -{ -} - -void CopyFileJob::start() -{ - if (mLocalFile.isEmpty() || mCachedFile.isEmpty()) { - qCWarning(RUQOLA_LOG) << " localfile or cachedfile not defined"; - } else { - QFile f(mCachedFile); - if (!f.copy(mLocalFile)) { - qCWarning(RUQOLA_LOG) << "Impossible to copy " << mCachedFile << " to " << mLocalFile; - } - } -} - -void CopyFileJob::setLocalFile(const QString &localFile) -{ - mLocalFile = localFile; -} - -void CopyFileJob::setCachedFile(const QString &cachedFile) -{ - mCachedFile = cachedFile; -} diff --git a/src/core/copyfilejob.h b/src/core/copyfilejob.h deleted file mode 100644 index 8e02d1de..00000000 --- a/src/core/copyfilejob.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright (c) 2018-2020 Laurent Montel - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License or - ( at your option ) version 3 or, at the discretion of KDE e.V. - ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef COPYFILEJOB_H -#define COPYFILEJOB_H - -#include - -class CopyFileJob : public KJob -{ - Q_OBJECT -public: - explicit CopyFileJob(QObject *parent = nullptr); - ~CopyFileJob() override = default; - - void start() override; - - void setLocalFile(const QString &localFile); - - void setCachedFile(const QString &cachedFile); - -private: - Q_DISABLE_COPY(CopyFileJob) - QString mLocalFile; - QString mCachedFile; -}; - -#endif // COPYFILEJOB_H diff --git a/src/core/rocketchatcache.cpp b/src/core/rocketchatcache.cpp index d1ed6b14..b62498d0 100644 --- a/src/core/rocketchatcache.cpp +++ b/src/core/rocketchatcache.cpp @@ -1,212 +1,211 @@ /* Copyright (c) 2018-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "rocketchataccount.h" #include "rocketchatcache.h" #include "ruqola_debug.h" #include "managerdatapaths.h" #include "restapirequest.h" #include "avatarmanager.h" -#include "copyfilejob.h" #include #include #include RocketChatCache::RocketChatCache(RocketChatAccount *account, QObject *parent) : QObject(parent) , mAccount(account) { mAvatarManager = new AvatarManager(mAccount, this); connect(mAvatarManager, &AvatarManager::insertAvatarUrl, this, &RocketChatCache::insertAvatarUrl); loadAvatarCache(); connect(mAccount->restApi(), &RocketChatRestApi::RestApiRequest::downloadFileDone, this, &RocketChatCache::slotDataDownloaded); } RocketChatCache::~RocketChatCache() { QSettings settings; settings.beginGroup(QStringLiteral("Avatar")); QHash::const_iterator i = mUserAvatarUrl.constBegin(); while (i != mUserAvatarUrl.constEnd()) { settings.setValue(i.key(), i.value().toString()); ++i; } settings.endGroup(); } bool RocketChatCache::fileInCache(const QUrl &url) { const QFileInfo f(fileCachePath(url)); return f.exists(); } QString RocketChatCache::fileCachePath(const QUrl &url) { QString cachePath = ManagerDataPaths::self()->path(ManagerDataPaths::Cache, mAccount->accountName()); cachePath += QLatin1Char('/') + url.path(); return cachePath; } void RocketChatCache::slotDataDownloaded(const QByteArray &data, const QUrl &url, bool storeInCache, const QUrl &localFileUrl) { mFileInDownload.remove(url.path()); const QString newPath = storeInCache ? fileCachePath(url) : localFileUrl.toLocalFile(); //Split between image/video/audio const QUrl urldir = QUrl::fromUserInput(newPath).adjusted(QUrl::RemoveFilename); QDir().mkpath(urldir.toLocalFile()); QFile file(newPath); if (file.open(QIODevice::ReadWrite)) { file.write(data); file.close(); Q_EMIT fileDownloaded(url.path(), QUrl::fromLocalFile(newPath)); } else { qCWarning(RUQOLA_LOG) <<" Error !" << file.errorString(); } } void RocketChatCache::loadAvatarCache() { QSettings settings; settings.beginGroup(QStringLiteral("Avatar")); const QStringList keys = settings.childKeys(); for (const QString &key : keys) { mUserAvatarUrl[key] = QUrl(settings.value(key).toString()); } settings.endGroup(); } void RocketChatCache::downloadFile(const QString &url, const QUrl &localFile, bool storeInCache) { - if (fileInCache(QUrl(url))) { - auto *job = new CopyFileJob(this); - job->setCachedFile(fileCachePath(QUrl(url))); - job->setLocalFile(localFile.toString()); - job->start(); + QFile f(fileCachePath(QUrl(url))); + if (f.exists()) { + if (!f.copy(localFile.toLocalFile())) { + qCWarning(RUQOLA_LOG) << "Impossible to copy" << f.fileName() << "to" << localFile; + } } else { - //Redownload it. TODO inform user ? - //FIXME we don't use localfile! + // Not in cache. We need to download it (e.g. file attachment). const QUrl clickedUrl = generateDownloadFile(url); mAccount->restApi()->downloadFile(clickedUrl, QStringLiteral("text/plain"), storeInCache, localFile); + // this will call slotDataDownloaded } } QUrl RocketChatCache::attachmentUrl(const QString &url) { const QString cachePath = fileCachePath(QUrl(url)); if (QFileInfo::exists(cachePath)) { // QML wants a QUrl here. The widgets code would be simpler with just a QString path. return QUrl::fromLocalFile(cachePath); } else { downloadFileFromServer(url); } return {}; } void RocketChatCache::downloadAvatarFromServer(const QString &userId) { mAvatarManager->insertInDownloadQueue(userId); } void RocketChatCache::downloadFileFromServer(const QString &filename) { if (!mFileInDownload.contains(filename)) { mFileInDownload.insert(filename); mAccount->restApi()->downloadFile(generateDownloadFile(filename)); // this will call slotDataDownloaded } } QUrl RocketChatCache::generateDownloadFile(const QString &url) { if (url.startsWith(QLatin1String("https:")) || url.startsWith(QLatin1String("http:"))) { return QUrl(url); } QString tmpUrl = mAccount->settings()->serverUrl(); if (!tmpUrl.startsWith(QLatin1String("https://"))) { tmpUrl = QLatin1String("https://") + tmpUrl; } const QUrl downloadFileUrl = QUrl::fromUserInput(tmpUrl + url); return downloadFileUrl; } QString RocketChatCache::avatarUrlFromCacheOnly(const QString &userId) { const QUrl avatarUrl = mUserAvatarUrl.value(userId); if (!avatarUrl.isEmpty() && fileInCache(avatarUrl)) { const QString url = QUrl::fromLocalFile(fileCachePath(avatarUrl)).toString(); qCDebug(RUQOLA_LOG) << " Use image in cache" << url << " userId " << userId << " mUserAvatarUrl.value(userId) "<< mUserAvatarUrl.value(userId); return url; } return {}; } QString RocketChatCache::avatarUrl(const QString &userId) { //avoid to call this method several time. if (!mUserAvatarUrl.contains(userId)) { insertAvatarUrl(userId, QUrl()); downloadAvatarFromServer(userId); return {}; } else { const QUrl valueUrl = mUserAvatarUrl.value(userId); if (!valueUrl.isEmpty() && fileInCache(valueUrl)) { const QString url = QUrl::fromLocalFile(fileCachePath(valueUrl)).toString(); //qDebug() << " Use image in cache" << url << " userId " << userId << " mUserAvatarUrl.value(userId) "<< mUserAvatarUrl.value(userId); return url; } else { downloadAvatarFromServer(userId); } return {}; } } void RocketChatCache::insertAvatarUrl(const QString &userId, const QUrl &url) { mUserAvatarUrl.insert(userId, url); if (!url.isEmpty() && !fileInCache(url)) { mAccount->restApi()->downloadFile(url); // this will call slotDataDownloaded } } QString RocketChatCache::recordingVideoPath(const QString &accountName) const { const QString path = ManagerDataPaths::self()->path(ManagerDataPaths::Video, accountName); QDir directory(path); if (!directory.mkpath(path)) { qCWarning(RUQOLA_LOG) << "Unable to create folder: " << path; return QString(); } const QString filePath = path + QLatin1Char('/') + QString::number(QDateTime::currentDateTime().toMSecsSinceEpoch()) + QStringLiteral(".mp4"); return filePath; } QString RocketChatCache::recordingImagePath(const QString &accountName) const { const QString path = ManagerDataPaths::self()->path(ManagerDataPaths::Picture, accountName); QDir directory(path); if (!directory.mkpath(path)) { qCWarning(RUQOLA_LOG) << "Unable to create folder: " << path; return QString(); } const QString filePath = path + QLatin1Char('/') + QString::number(QDateTime::currentDateTime().toMSecsSinceEpoch()) + QStringLiteral(".jpg"); return filePath; }