/* SPDX-FileCopyrightText: 2008, 2009 Fredrik Höglund SPDX-License-Identifier: LGPL-2.0-or-later */ #include "kio_desktop.h" #include #include #include #include #include #include #include #include #include #include #include "desktopnotifier_interface.h" #include "kded_interface.h" // Pseudo plugin class to embed meta data class KIOPluginForMetaData : public QObject { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kio.slave.desktop" FILE "desktop.json") }; extern "C" { int Q_DECL_EXPORT kdemain(int argc, char **argv) { // necessary to use other kio slaves QCoreApplication app(argc, argv); app.setApplicationName("kio_desktop"); // start the slave DesktopProtocol slave(argv[1], argv[2], argv[3]); slave.dispatchLoop(); return 0; } } DesktopProtocol::DesktopProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app) : KIO::ForwardingSlaveBase(protocol, pool, app) { checkLocalInstall(); org::kde::kded5 kded(QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QDBusConnection::sessionBus()); auto pending = kded.loadModule("desktopnotifier"); pending.waitForFinished(); } DesktopProtocol::~DesktopProtocol() { } void DesktopProtocol::checkLocalInstall() { #ifndef Q_OS_WIN // QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) returns the home dir // if the desktop folder doesn't exist, so verify its result QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); const QDir desktopDir(desktopPath); bool desktopIsEmpty; // Create the desktop folder if it doesn't exist if (!desktopDir.exists()) { ::mkdir(QFile::encodeName(desktopPath), S_IRWXU); desktopIsEmpty = true; } else desktopIsEmpty = desktopDir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot).isEmpty(); if (desktopIsEmpty) { // Copy the .directory file QFile::copy(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/directory.desktop")), desktopPath + "/.directory"); // Copy the desktop links QSet links; const auto dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/DesktopLinks"), QStandardPaths::LocateDirectory); for (const auto &dir : dirs) { const auto fileNames = QDir(dir).entryList({QStringLiteral("*.desktop")}); for (const auto &file : fileNames) { links += file; } } foreach (const QString &link, links) { const auto fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/DesktopLinks/%1").arg(link)); KDesktopFile file(fullPath); if (!file.desktopGroup().readEntry("Hidden", false)) QFile::copy(fullPath, QStringLiteral("%1/%2").arg(desktopPath, link)); } } #endif } bool DesktopProtocol::rewriteUrl(const QUrl &url, QUrl &newUrl) { QString oldPath = url.path(); // So that creating a new folder while at "desktop:" (without a '/' after ':') // doesn't create "/home/user/DesktopNew Folder" instead of "/home/user/Desktop/New Folder". if (oldPath.isEmpty() || !oldPath.startsWith(QLatin1Char('/'))) { oldPath.prepend(QLatin1Char('/')); } newUrl.setScheme(QStringLiteral("file")); const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); newUrl.setPath(desktopPath + oldPath); newUrl = newUrl.adjusted(QUrl::StripTrailingSlash); return true; } void DesktopProtocol::listDir(const QUrl &url) { KIO::ForwardingSlaveBase::listDir(url); QUrl actual; rewriteUrl(url, actual); org::kde::DesktopNotifier kded(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/desktopnotifier"), QDBusConnection::sessionBus()); kded.watchDir(actual.path()); } QString DesktopProtocol::desktopFile(KIO::UDSEntry &entry) const { const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME); if (name == QLatin1Char('.') || name == QLatin1String("..")) return QString(); QUrl url = processedUrl(); url.setPath(QStringLiteral("%1/%2").arg(url.path(), name)); if (entry.isDir()) { url.setPath(QStringLiteral("%1/.directory").arg(url.path())); if (!QFileInfo::exists(url.path())) return QString(); return url.path(); } if (KDesktopFile::isDesktopFile(url.path())) return url.path(); return QString(); } void DesktopProtocol::prepareUDSEntry(KIO::UDSEntry &entry, bool listing) const { ForwardingSlaveBase::prepareUDSEntry(entry, listing); const QString path = desktopFile(entry); if (!path.isEmpty()) { KDesktopFile file(path); const QString name = file.readName(); if (!name.isEmpty()) entry.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, name); if (!file.tryExec()) entry.replace(KIO::UDSEntry::UDS_HIDDEN, 1); } // Set a descriptive display name for the root item if (requestedUrl().path() == QLatin1String("/") && entry.stringValue(KIO::UDSEntry::UDS_NAME) == QLatin1Char('.')) { entry.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Desktop Folder")); } // Set the target URL to the local path QUrl localUrl(QUrl::fromLocalFile(entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH))); entry.replace(KIO::UDSEntry::UDS_TARGET_URL, localUrl.toString()); } void DesktopProtocol::rename(const QUrl &_src, const QUrl &_dest, KIO::JobFlags flags) { Q_UNUSED(flags) if (_src == _dest) { finished(); return; } QUrl src; rewriteUrl(_src, src); const QString srcPath = src.toLocalFile(); QUrl dest; rewriteUrl(_dest, dest); QString destPath = dest.toLocalFile(); QUrl reported_dest = _dest; if (KDesktopFile::isDesktopFile(srcPath)) { QString friendlyName; if (destPath.endsWith(QLatin1String(".desktop"))) { const QString fileName = dest.fileName(); friendlyName = KIO::decodeFileName(fileName.left(fileName.length() - 8)); } else { friendlyName = KIO::decodeFileName(dest.fileName()); destPath.append(QLatin1String(".desktop")); reported_dest.setPath(reported_dest.path().append(QLatin1String(".desktop"))); } // Update the value of the Name field in the file. KDesktopFile file(src.toLocalFile()); KConfigGroup cg(file.desktopGroup()); cg.writeEntry("Name", friendlyName); cg.writeEntry("Name", friendlyName, KConfigGroup::Persistent | KConfigGroup::Localized); cg.sync(); } if (QFile(srcPath).rename(destPath)) { org::kde::KDirNotify::emitFileRenamedWithLocalPath(_src, reported_dest, destPath); finished(); } else { error(KIO::ERR_CANNOT_RENAME, srcPath); } } void DesktopProtocol::virtual_hook(int id, void *data) { switch (id) { case SlaveBase::GetFileSystemFreeSpace: { QUrl *url = static_cast(data); fileSystemFreeSpace(*url); } break; default: SlaveBase::virtual_hook(id, data); } } void DesktopProtocol::fileSystemFreeSpace(const QUrl &url) { Q_UNUSED(url) const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); QStorageInfo storageInfo{desktopPath}; if (storageInfo.isValid() && storageInfo.isReady()) { setMetaData(QStringLiteral("total"), QString::number(storageInfo.bytesTotal())); setMetaData(QStringLiteral("available"), QString::number(storageInfo.bytesAvailable())); finished(); } else { error(KIO::ERR_CANNOT_STAT, desktopPath); } } #include "kio_desktop.moc"