File indexing completed on 2024-05-12 17:09:48
0001 /* 0002 SPDX-FileCopyrightText: 2008, 2009 Fredrik Höglund <fredrik@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "kio_desktop.h" 0008 0009 #include <KConfigGroup> 0010 #include <KDesktopFile> 0011 #include <KDirNotify> 0012 #include <KLocalizedString> 0013 0014 #include <QCoreApplication> 0015 #include <QDir> 0016 #include <QFile> 0017 #include <QStandardPaths> 0018 #include <QStorageInfo> 0019 0020 #include "desktopnotifier_interface.h" 0021 #include "kded_interface.h" 0022 0023 // Pseudo plugin class to embed meta data 0024 class KIOPluginForMetaData : public QObject 0025 { 0026 Q_OBJECT 0027 Q_PLUGIN_METADATA(IID "org.kde.kio.worker.desktop" FILE "desktop.json") 0028 }; 0029 0030 extern "C" { 0031 int Q_DECL_EXPORT kdemain(int argc, char **argv) 0032 { 0033 // necessary to use other kio workers 0034 QCoreApplication app(argc, argv); 0035 app.setApplicationName("kio_desktop"); 0036 0037 // start the worker 0038 DesktopProtocol worker(argv[1], argv[2], argv[3]); 0039 worker.dispatchLoop(); 0040 return 0; 0041 } 0042 } 0043 0044 DesktopProtocol::DesktopProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app) 0045 : KIO::ForwardingWorkerBase(protocol, pool, app) 0046 { 0047 checkLocalInstall(); 0048 0049 org::kde::kded5 kded(QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QDBusConnection::sessionBus()); 0050 auto pending = kded.loadModule("desktopnotifier"); 0051 pending.waitForFinished(); 0052 } 0053 0054 DesktopProtocol::~DesktopProtocol() 0055 { 0056 } 0057 0058 void DesktopProtocol::checkLocalInstall() 0059 { 0060 #ifndef Q_OS_WIN 0061 // QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) returns the home dir 0062 // if the desktop folder doesn't exist, so verify its result 0063 QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); 0064 0065 const QDir desktopDir(desktopPath); 0066 bool desktopIsEmpty; 0067 0068 // Create the desktop folder if it doesn't exist 0069 if (!desktopDir.exists()) { 0070 ::mkdir(QFile::encodeName(desktopPath), S_IRWXU); 0071 desktopIsEmpty = true; 0072 } else 0073 desktopIsEmpty = desktopDir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot).isEmpty(); 0074 0075 if (desktopIsEmpty) { 0076 // Copy the .directory file 0077 QFile::copy(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/directory.desktop")), desktopPath + "/.directory"); 0078 0079 // Copy the desktop links 0080 QSet<QString> links; 0081 const auto dirs = 0082 QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/DesktopLinks"), QStandardPaths::LocateDirectory); 0083 for (const auto &dir : dirs) { 0084 const auto fileNames = QDir(dir).entryList({QStringLiteral("*.desktop")}); 0085 for (const auto &file : fileNames) { 0086 links += file; 0087 } 0088 } 0089 0090 foreach (const QString &link, links) { 0091 const auto fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/DesktopLinks/%1").arg(link)); 0092 KDesktopFile file(fullPath); 0093 if (!file.desktopGroup().readEntry("Hidden", false)) 0094 QFile::copy(fullPath, QStringLiteral("%1/%2").arg(desktopPath, link)); 0095 } 0096 } 0097 #endif 0098 } 0099 0100 bool DesktopProtocol::rewriteUrl(const QUrl &url, QUrl &newUrl) 0101 { 0102 QString oldPath = url.path(); 0103 // So that creating a new folder while at "desktop:" (without a '/' after ':') 0104 // doesn't create "/home/user/DesktopNew Folder" instead of "/home/user/Desktop/New Folder". 0105 if (oldPath.isEmpty() || !oldPath.startsWith(QLatin1Char('/'))) { 0106 oldPath.prepend(QLatin1Char('/')); 0107 } 0108 0109 newUrl.setScheme(QStringLiteral("file")); 0110 const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); 0111 newUrl.setPath(desktopPath + oldPath); 0112 newUrl = newUrl.adjusted(QUrl::StripTrailingSlash); 0113 0114 return true; 0115 } 0116 0117 KIO::WorkerResult DesktopProtocol::listDir(const QUrl &url) 0118 { 0119 KIO::WorkerResult res = KIO::ForwardingWorkerBase::listDir(url); 0120 0121 QUrl actual; 0122 rewriteUrl(url, actual); 0123 0124 org::kde::DesktopNotifier kded(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/desktopnotifier"), QDBusConnection::sessionBus()); 0125 kded.watchDir(actual.path()); 0126 0127 return res; 0128 } 0129 0130 QString DesktopProtocol::desktopFile(KIO::UDSEntry &entry) const 0131 { 0132 const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME); 0133 if (name == QLatin1Char('.') || name == QLatin1String("..")) 0134 return QString(); 0135 0136 QUrl url = processedUrl(); 0137 url.setPath(QStringLiteral("%1/%2").arg(url.path(), name)); 0138 0139 if (entry.isDir()) { 0140 url.setPath(QStringLiteral("%1/.directory").arg(url.path())); 0141 if (!QFileInfo::exists(url.path())) 0142 return QString(); 0143 0144 return url.path(); 0145 } 0146 0147 if (KDesktopFile::isDesktopFile(url.path())) 0148 return url.path(); 0149 0150 return QString(); 0151 } 0152 0153 void DesktopProtocol::adjustUDSEntry(KIO::UDSEntry &entry, UDSEntryCreationMode creationMode) const 0154 { 0155 KIO::ForwardingWorkerBase::adjustUDSEntry(entry, creationMode); 0156 const QString path = desktopFile(entry); 0157 0158 if (!path.isEmpty()) { 0159 KDesktopFile file(path); 0160 0161 const QString name = file.readName(); 0162 if (!name.isEmpty()) 0163 entry.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, name); 0164 0165 if (!file.tryExec()) 0166 entry.replace(KIO::UDSEntry::UDS_HIDDEN, 1); 0167 } 0168 0169 // Set a descriptive display name for the root item 0170 if (requestedUrl().path() == QLatin1String("/") && entry.stringValue(KIO::UDSEntry::UDS_NAME) == QLatin1Char('.')) { 0171 entry.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Desktop Folder")); 0172 } 0173 0174 // Set the target URL to the local path 0175 QUrl localUrl(QUrl::fromLocalFile(entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH))); 0176 entry.replace(KIO::UDSEntry::UDS_TARGET_URL, localUrl.toString()); 0177 } 0178 0179 KIO::WorkerResult DesktopProtocol::rename(const QUrl &_src, const QUrl &_dest, KIO::JobFlags flags) 0180 { 0181 Q_UNUSED(flags) 0182 0183 if (_src == _dest) { 0184 return KIO::WorkerResult::pass(); 0185 } 0186 0187 QUrl src; 0188 rewriteUrl(_src, src); 0189 const QString srcPath = src.toLocalFile(); 0190 0191 QUrl dest; 0192 rewriteUrl(_dest, dest); 0193 QString destPath = dest.toLocalFile(); 0194 QUrl reported_dest = _dest; 0195 0196 if (KDesktopFile::isDesktopFile(srcPath)) { 0197 QString friendlyName; 0198 0199 if (destPath.endsWith(QLatin1String(".desktop"))) { 0200 const QString fileName = dest.fileName(); 0201 friendlyName = KIO::decodeFileName(fileName.left(fileName.length() - 8)); 0202 } else { 0203 friendlyName = KIO::decodeFileName(dest.fileName()); 0204 destPath.append(QLatin1String(".desktop")); 0205 reported_dest.setPath(reported_dest.path().append(QLatin1String(".desktop"))); 0206 } 0207 0208 // Update the value of the Name field in the file. 0209 KDesktopFile file(src.toLocalFile()); 0210 KConfigGroup cg(file.desktopGroup()); 0211 cg.writeEntry("Name", friendlyName); 0212 cg.writeEntry("Name", friendlyName, KConfigGroup::Persistent | KConfigGroup::Localized); 0213 cg.sync(); 0214 } 0215 0216 if (QFile(srcPath).rename(destPath)) { 0217 org::kde::KDirNotify::emitFileRenamedWithLocalPath(_src, reported_dest, destPath); 0218 return KIO::WorkerResult::pass(); 0219 } else { 0220 return KIO::WorkerResult::fail(KIO::ERR_CANNOT_RENAME, srcPath); 0221 } 0222 } 0223 0224 KIO::WorkerResult DesktopProtocol::fileSystemFreeSpace(const QUrl &url) 0225 { 0226 Q_UNUSED(url) 0227 0228 const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); 0229 QStorageInfo storageInfo{desktopPath}; 0230 if (storageInfo.isValid() && storageInfo.isReady()) { 0231 setMetaData(QStringLiteral("total"), QString::number(storageInfo.bytesTotal())); 0232 setMetaData(QStringLiteral("available"), QString::number(storageInfo.bytesAvailable())); 0233 return KIO::WorkerResult::pass(); 0234 } else { 0235 return KIO::WorkerResult::fail(KIO::ERR_CANNOT_STAT, desktopPath); 0236 } 0237 } 0238 0239 #include "kio_desktop.moc"