File indexing completed on 2024-10-06 09:39:48
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2017 Elvis Angelaccio <elvis.angelaccio@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "kioexecd.h" 0009 #include "kioexecdadaptor.h" 0010 #include "kioexecdebug.h" 0011 0012 #include <KDirWatch> 0013 #include <KIO/CopyJob> 0014 #include <KLocalizedString> 0015 #include <KMessageBox> 0016 #include <KPluginFactory> 0017 0018 #include <QDir> 0019 #include <QFileInfo> 0020 #include <QStandardPaths> 0021 0022 static const int predefinedTimeout = 30000; // 30s 0023 0024 K_PLUGIN_CLASS_WITH_JSON(KIOExecd, "kioexecd.json") 0025 0026 KIOExecd::KIOExecd(QObject *parent, const QList<QVariant> &) 0027 : KDEDModule(parent) 0028 { 0029 qCDebug(KIOEXEC) << "kioexecd started"; 0030 0031 new KIOExecdAdaptor(this); 0032 m_watcher = new KDirWatch(this); 0033 0034 connect(m_watcher, &KDirWatch::dirty, this, &KIOExecd::slotDirty); 0035 connect(m_watcher, &KDirWatch::created, this, &KIOExecd::slotCreated); 0036 connect(m_watcher, &KDirWatch::deleted, this, &KIOExecd::slotDeleted); 0037 m_timer.setSingleShot(true); 0038 m_timer.setInterval(predefinedTimeout); 0039 connect(&m_timer, &QTimer::timeout, this, &KIOExecd::slotCheckDeletedFiles); 0040 } 0041 0042 KIOExecd::~KIOExecd() 0043 { 0044 // Remove the remaining temporary files and if possible their parent directories 0045 for (auto it = m_watched.constBegin(); it != m_watched.constEnd(); ++it) { 0046 QFileInfo info(it.key()); 0047 const auto parentDir = info.path(); 0048 qCDebug(KIOEXEC) << "About to delete" << parentDir << "containing" << info.fileName(); 0049 QFile::remove(it.key()); 0050 QDir().rmdir(parentDir); 0051 } 0052 } 0053 0054 void KIOExecd::watch(const QString &path, const QString &destUrl) 0055 { 0056 if (m_watched.contains(path)) { 0057 qCDebug(KIOEXEC) << "Already watching" << path; 0058 return; 0059 } 0060 0061 qCDebug(KIOEXEC) << "Going to watch" << path << "for changes, remote destination is" << destUrl; 0062 0063 // Watch the temporary file for modifications, creations or deletions 0064 m_watcher->addFile(path); 0065 m_watched.insert(path, QUrl(destUrl)); 0066 } 0067 0068 void KIOExecd::slotCreated(const QString &path) 0069 { 0070 m_deleted.remove(path); 0071 0072 // When the file is recreated, it is not signaled as dirty. 0073 slotDirty(path); 0074 } 0075 0076 void KIOExecd::slotDirty(const QString &path) 0077 { 0078 if (!m_watched.contains(path)) { 0079 return; 0080 } 0081 0082 const auto dest = m_watched.value(path); 0083 0084 const auto result = KMessageBox::questionTwoActions(nullptr, 0085 i18n("The file %1\nhas been modified. Do you want to upload the changes?", dest.toDisplayString()), 0086 i18n("File Changed"), 0087 KGuiItem(i18n("Upload")), 0088 KGuiItem(i18n("Do Not Upload"))); 0089 if (result != KMessageBox::PrimaryAction) { 0090 return; 0091 } 0092 0093 qCDebug(KIOEXEC) << "Uploading" << path << "to" << dest; 0094 auto job = KIO::copy(QUrl::fromLocalFile(path), dest); 0095 connect(job, &KJob::result, this, [](KJob *job) { 0096 if (job->error()) { 0097 KMessageBox::error(nullptr, job->errorString()); 0098 } 0099 }); 0100 } 0101 0102 void KIOExecd::slotDeleted(const QString &path) 0103 { 0104 if (!m_watched.contains(path)) { 0105 return; 0106 } 0107 0108 m_deleted.insert(path, QDateTime::currentDateTimeUtc()); 0109 m_timer.start(); 0110 } 0111 0112 void KIOExecd::slotCheckDeletedFiles() 0113 { 0114 const QDateTime currentDateTime = QDateTime::currentDateTimeUtc(); 0115 // check if the deleted (and not recreated) files where deleted 30s ago or more 0116 for (auto it = m_deleted.begin(); it != m_deleted.end();) { 0117 if (it.value().msecsTo(currentDateTime) >= predefinedTimeout) { 0118 qCDebug(KIOEXEC) << "Going to forget" << it.key(); 0119 m_watcher->removeFile(it.key()); 0120 m_watched.remove(it.key()); 0121 QFileInfo info(it.key()); 0122 const auto parentDir = info.path(); 0123 qCDebug(KIOEXEC) << "About to delete" << parentDir; 0124 QDir().rmdir(parentDir); 0125 it = m_deleted.erase(it); 0126 } else { 0127 ++it; 0128 } 0129 } 0130 if (!m_deleted.isEmpty()) { 0131 m_timer.start(); 0132 } 0133 } 0134 0135 #include "kioexecd.moc" 0136 #include "moc_kioexecd.cpp"