File indexing completed on 2024-04-14 03:52:57

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 }
0039 
0040 QStringList KProtocolInfoFactory::protocols()
0041 {
0042     QMutexLocker locker(&m_mutex);
0043 
0044     // fill cache, if not already done and use it
0045     fillCache();
0046     return m_cache.keys();
0047 }
0048 
0049 QList<KProtocolInfoPrivate *> KProtocolInfoFactory::allProtocols()
0050 {
0051     QMutexLocker locker(&m_mutex);
0052 
0053     // fill cache, if not already done and use it
0054     fillCache();
0055     return m_cache.values();
0056 }
0057 
0058 KProtocolInfoPrivate *KProtocolInfoFactory::findProtocol(const QString &protocol, bool updateCacheIfNotfound)
0059 {
0060     Q_ASSERT(!protocol.isEmpty());
0061     Q_ASSERT(!protocol.contains(QLatin1Char(':')));
0062 
0063     QMutexLocker locker(&m_mutex);
0064 
0065     const bool filled = fillCache();
0066 
0067     KProtocolInfoPrivate *info = m_cache.value(protocol);
0068     if (!info && !filled && updateCacheIfNotfound) {
0069         // Unknown protocol! Maybe it just got installed and our cache is out of date?
0070         qCDebug(KIO_CORE) << "Refilling KProtocolInfoFactory cache in the hope to find" << protocol;
0071         m_cacheDirty = true;
0072         fillCache();
0073         info = m_cache.value(protocol);
0074     }
0075     return info;
0076 }
0077 
0078 bool KProtocolInfoFactory::fillCache()
0079 {
0080     // mutex MUST be locked from the outside!
0081     Q_ASSERT(!m_mutex.tryLock());
0082 
0083     // no work if filled
0084     if (!m_cacheDirty) {
0085         return false;
0086     }
0087 
0088     qDeleteAll(m_cache);
0089     m_cache.clear();
0090 
0091     // first: search for meta data protocol info, that might be bundled with applications
0092     // we search in all library paths inside kf5/kio
0093     const QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/kio"));
0094     for (const KPluginMetaData &md : plugins) {
0095         // get worker name & protocols it supports, if any
0096         const QString workerPath = md.fileName();
0097         const QJsonObject protocols(md.rawData().value(QStringLiteral("KDE-KIO-Protocols")).toObject());
0098         qCDebug(KIO_CORE) << workerPath << "supports protocols" << protocols.keys();
0099 
0100         // add all protocols, does nothing if object invalid
0101         for (auto it = protocols.begin(); it != protocols.end(); ++it) {
0102             // skip empty objects
0103             const QJsonObject protocol(it.value().toObject());
0104             if (protocol.isEmpty()) {
0105                 continue;
0106             }
0107 
0108             // add to cache, skip double entries
0109             if (!m_cache.contains(it.key())) {
0110                 m_cache.insert(it.key(), new KProtocolInfoPrivate(it.key(), workerPath, protocol));
0111             }
0112         }
0113     }
0114 
0115     // all done, don't do it again
0116     m_cacheDirty = false;
0117     return true;
0118 }