File indexing completed on 2024-05-12 17:09:47
0001 /* 0002 SPDX-FileCopyrightText: 2003 Joseph Wenninger <jowenn@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <KIO/WorkerBase> 0008 #include <KLocalizedString> 0009 #include <KService> 0010 #include <KServiceGroup> 0011 #include <sys/stat.h> 0012 #include <time.h> 0013 0014 #include <QStandardPaths> 0015 #include <QUrl> 0016 #include <kio_version.h> 0017 0018 // Pseudo plugin class to embed meta data 0019 class KIOPluginForMetaData : public QObject 0020 { 0021 Q_OBJECT 0022 Q_PLUGIN_METADATA(IID "org.kde.kio.worker.applications" FILE "applications.json") 0023 }; 0024 0025 class ApplicationsProtocol : public KIO::WorkerBase 0026 { 0027 public: 0028 enum RunMode { 0029 ProgramsMode, 0030 ApplicationsMode, 0031 }; 0032 ApplicationsProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app); 0033 ~ApplicationsProtocol() override; 0034 KIO::WorkerResult get(const QUrl &url) override; 0035 KIO::WorkerResult stat(const QUrl &url) override; 0036 KIO::WorkerResult listDir(const QUrl &url) override; 0037 0038 private: 0039 RunMode m_runMode; 0040 }; 0041 0042 extern "C" { 0043 Q_DECL_EXPORT int kdemain(int argc, char **argv) 0044 { 0045 QCoreApplication app(argc, argv); 0046 app.setApplicationName("kio_applications"); 0047 0048 ApplicationsProtocol worker(argv[1], argv[2], argv[3]); 0049 worker.dispatchLoop(); 0050 return 0; 0051 } 0052 } 0053 0054 static void createFileEntry(KIO::UDSEntry &entry, const KService::Ptr &service, const QUrl &parentUrl) 0055 { 0056 entry.clear(); 0057 entry.fastInsert(KIO::UDSEntry::UDS_NAME, KIO::encodeFileName(service->name())); 0058 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); 0059 const QString fileUrl = parentUrl.url() + '/' + service->desktopEntryName(); 0060 entry.fastInsert(KIO::UDSEntry::UDS_URL, fileUrl); 0061 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0500); 0062 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("application/x-desktop")); 0063 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, 0); 0064 const QString localPath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, QStringLiteral("%1.desktop").arg(service->desktopEntryName())); 0065 entry.fastInsert(KIO::UDSEntry::UDS_LOCAL_PATH, localPath); 0066 entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, time(nullptr)); 0067 entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, service->icon()); 0068 } 0069 0070 static void createDirEntry(KIO::UDSEntry &entry, const QString &name, const QString &url, const QString &mime, const QString &iconName) 0071 { 0072 entry.clear(); 0073 entry.fastInsert(KIO::UDSEntry::UDS_NAME, name); 0074 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0075 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0500); 0076 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, mime); 0077 if (!url.isEmpty()) 0078 entry.fastInsert(KIO::UDSEntry::UDS_URL, url); 0079 entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, iconName); 0080 } 0081 0082 ApplicationsProtocol::ApplicationsProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app) 0083 : WorkerBase(protocol, pool, app) 0084 { 0085 // Adjusts which part of the K Menu to virtualize. 0086 if (protocol == "programs") 0087 m_runMode = ProgramsMode; 0088 else // if (protocol == "applications") 0089 m_runMode = ApplicationsMode; 0090 } 0091 0092 ApplicationsProtocol::~ApplicationsProtocol() 0093 { 0094 } 0095 0096 KIO::WorkerResult ApplicationsProtocol::get(const QUrl &url) 0097 { 0098 KService::Ptr service = KService::serviceByDesktopName(url.fileName()); 0099 if (service && service->isValid()) { 0100 const QString localPath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, QStringLiteral("%1.desktop").arg(service->desktopEntryName())); 0101 QUrl redirUrl(QUrl::fromLocalFile(localPath)); 0102 redirection(redirUrl); 0103 return KIO::WorkerResult::pass(); 0104 } else { 0105 return KIO::WorkerResult::fail(KIO::ERR_IS_DIRECTORY, url.toDisplayString()); 0106 } 0107 } 0108 0109 KIO::WorkerResult ApplicationsProtocol::stat(const QUrl &url) 0110 { 0111 KIO::UDSEntry entry; 0112 0113 QString servicePath(url.path()); 0114 if (!servicePath.endsWith('/')) 0115 servicePath.append('/'); 0116 servicePath.remove(0, 1); // remove starting '/' 0117 0118 KServiceGroup::Ptr grp = KServiceGroup::group(servicePath); 0119 0120 if (grp && grp->isValid()) { 0121 createDirEntry(entry, 0122 ((m_runMode == ApplicationsMode) ? i18n("Applications") : i18n("Programs")), 0123 url.url(), 0124 QStringLiteral("inode/directory"), 0125 grp->icon()); 0126 } else { 0127 KService::Ptr service = KService::serviceByDesktopName(url.fileName()); 0128 if (service && service->isValid()) { 0129 createFileEntry(entry, service, url); 0130 } else { 0131 return KIO::WorkerResult::fail(KIO::ERR_WORKER_DEFINED, i18n("Unknown application folder")); 0132 } 0133 } 0134 0135 statEntry(entry); 0136 return KIO::WorkerResult::pass(); 0137 } 0138 0139 KIO::WorkerResult ApplicationsProtocol::listDir(const QUrl &url) 0140 { 0141 QString groupPath = url.path(); 0142 if (!groupPath.endsWith('/')) 0143 groupPath.append('/'); 0144 groupPath.remove(0, 1); // remove starting '/' 0145 0146 KServiceGroup::Ptr grp = KServiceGroup::group(groupPath); 0147 0148 if (!grp || !grp->isValid()) { 0149 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, groupPath); 0150 } 0151 0152 unsigned int count = 0; 0153 KIO::UDSEntry entry; 0154 0155 foreach (const KSycocaEntry::Ptr &e, grp->entries(true, true)) { 0156 if (e->isType(KST_KServiceGroup)) { 0157 KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e.data())); 0158 0159 // qDebug() << "ADDING SERVICE GROUP WITH PATH " << g->relPath(); 0160 0161 // Avoid adding empty groups. 0162 KServiceGroup::Ptr subMenuRoot = KServiceGroup::group(g->relPath()); 0163 if (subMenuRoot->childCount() == 0) 0164 continue; 0165 0166 // Ignore dotfiles. 0167 if (g->name().startsWith('.')) 0168 continue; 0169 0170 QString relPath = g->relPath(); 0171 QUrl dirUrl = url; // preserve protocol, whether that's programs:/ or applications:/ 0172 dirUrl.setPath('/' + relPath); 0173 dirUrl = dirUrl.adjusted(QUrl::StripTrailingSlash); 0174 // qDebug() << "ApplicationsProtocol: adding entry" << dirUrl; 0175 createDirEntry(entry, g->caption(), dirUrl.url(), QStringLiteral("inode/directory"), g->icon()); 0176 } else { 0177 KService::Ptr service(static_cast<KService *>(e.data())); 0178 0179 // qDebug() << "the entry name is" << service->desktopEntryName() 0180 // << "with path" << service->entryPath(); 0181 0182 if (!service->isApplication()) // how could this happen? 0183 continue; 0184 createFileEntry(entry, service, url); 0185 } 0186 0187 listEntry(entry); 0188 count++; 0189 } 0190 0191 totalSize(count); 0192 return KIO::WorkerResult::pass(); 0193 } 0194 0195 #include "kio_applications.moc"