File indexing completed on 2023-09-24 04:08:37
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1999 Torben Weis <weis@kde.org> 0004 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org> 0005 SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-only 0008 */ 0009 0010 #include "kprotocolinfo_p.h" 0011 #include "kprotocolinfofactory_p.h" 0012 0013 #include <KPluginMetaData> 0014 0015 #include <QCoreApplication> 0016 #include <QDirIterator> 0017 #include <QStandardPaths> 0018 0019 #include "kiocoredebug.h" 0020 0021 Q_GLOBAL_STATIC(KProtocolInfoFactory, kProtocolInfoFactoryInstance) 0022 0023 KProtocolInfoFactory *KProtocolInfoFactory::self() 0024 { 0025 return kProtocolInfoFactoryInstance(); 0026 } 0027 0028 KProtocolInfoFactory::KProtocolInfoFactory() 0029 : m_cacheDirty(true) 0030 { 0031 } 0032 0033 KProtocolInfoFactory::~KProtocolInfoFactory() 0034 { 0035 QMutexLocker locker(&m_mutex); 0036 qDeleteAll(m_cache); 0037 m_cache.clear(); 0038 m_cacheDirty = true; 0039 } 0040 0041 QStringList KProtocolInfoFactory::protocols() 0042 { 0043 QMutexLocker locker(&m_mutex); 0044 0045 // fill cache, if not already done and use it 0046 fillCache(); 0047 return m_cache.keys(); 0048 } 0049 0050 QList<KProtocolInfoPrivate *> KProtocolInfoFactory::allProtocols() 0051 { 0052 QMutexLocker locker(&m_mutex); 0053 0054 // fill cache, if not already done and use it 0055 fillCache(); 0056 return m_cache.values(); 0057 } 0058 0059 KProtocolInfoPrivate *KProtocolInfoFactory::findProtocol(const QString &protocol) 0060 { 0061 Q_ASSERT(!protocol.isEmpty()); 0062 Q_ASSERT(!protocol.contains(QLatin1Char(':'))); 0063 0064 QMutexLocker locker(&m_mutex); 0065 0066 const bool filled = fillCache(); 0067 0068 KProtocolInfoPrivate *info = m_cache.value(protocol); 0069 if (!info && !filled) { 0070 // Unknown protocol! Maybe it just got installed and our cache is out of date? 0071 qCDebug(KIO_CORE) << "Refilling KProtocolInfoFactory cache in the hope to find" << protocol; 0072 m_cacheDirty = true; 0073 fillCache(); 0074 info = m_cache.value(protocol); 0075 } 0076 return info; 0077 } 0078 0079 bool KProtocolInfoFactory::fillCache() 0080 { 0081 // mutex MUST be locked from the outside! 0082 Q_ASSERT(!m_mutex.tryLock()); 0083 0084 // no work if filled 0085 if (!m_cacheDirty) { 0086 return false; 0087 } 0088 0089 qDeleteAll(m_cache); 0090 m_cache.clear(); 0091 0092 // first: search for meta data protocol info, that might be bundled with applications 0093 // we search in all library paths inside kf5/kio 0094 const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/kio")); 0095 for (const KPluginMetaData &md : plugins) { 0096 // get worker name & protocols it supports, if any 0097 const QString workerPath = md.fileName(); 0098 const QJsonObject protocols(md.rawData().value(QStringLiteral("KDE-KIO-Protocols")).toObject()); 0099 qCDebug(KIO_CORE) << workerPath << "supports protocols" << protocols.keys(); 0100 0101 // add all protocols, does nothing if object invalid 0102 for (auto it = protocols.begin(); it != protocols.end(); ++it) { 0103 // skip empty objects 0104 const QJsonObject protocol(it.value().toObject()); 0105 if (protocol.isEmpty()) { 0106 continue; 0107 } 0108 0109 // add to cache, skip double entries 0110 if (!m_cache.contains(it.key())) { 0111 m_cache.insert(it.key(), new KProtocolInfoPrivate(it.key(), workerPath, protocol)); 0112 } 0113 } 0114 } 0115 0116 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 84) 0117 // second: fallback to .protocol files 0118 const QStringList serviceDirs = 0119 QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kservices5"), QStandardPaths::LocateDirectory) 0120 << QCoreApplication::applicationDirPath() + QLatin1String("/kservices5"); 0121 for (const QString &serviceDir : serviceDirs) { 0122 QDirIterator it(serviceDir); 0123 while (it.hasNext()) { 0124 const QString file = it.next(); 0125 if (file.endsWith(QLatin1String(".protocol"))) { 0126 const QString prot = it.fileInfo().baseName(); 0127 // add to cache, skip double entries 0128 if (!m_cache.contains(prot)) { 0129 qCDebug(KIO_CORE) << "Loading deprecated protocol file, please port it to JSON metadata" << file; 0130 m_cache.insert(prot, new KProtocolInfoPrivate(file)); 0131 } 0132 } 0133 } 0134 } 0135 #endif 0136 0137 // all done, don't do it again 0138 m_cacheDirty = false; 0139 return true; 0140 }