1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999 Torben Weis <weis@kde.org>
4 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
5 SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-only
8*/
9
10#include "kprotocolinfo_p.h"
11#include "kprotocolinfofactory_p.h"
12
13#include <KPluginMetaData>
14
15#include <QCoreApplication>
16#include <QDirIterator>
17#include <QStandardPaths>
18
19#include "kiocoredebug.h"
20
21Q_GLOBAL_STATIC(KProtocolInfoFactory, kProtocolInfoFactoryInstance)
22
23KProtocolInfoFactory *KProtocolInfoFactory::self()
24{
25 return kProtocolInfoFactoryInstance();
26}
27
28KProtocolInfoFactory::KProtocolInfoFactory()
29 : m_cacheDirty(true)
30{
31}
32
33KProtocolInfoFactory::~KProtocolInfoFactory()
34{
35 QMutexLocker locker(&m_mutex);
36 qDeleteAll(c: m_cache);
37 m_cache.clear();
38}
39
40QStringList KProtocolInfoFactory::protocols()
41{
42 QMutexLocker locker(&m_mutex);
43
44 // fill cache, if not already done and use it
45 fillCache();
46 return m_cache.keys();
47}
48
49QList<KProtocolInfoPrivate *> KProtocolInfoFactory::allProtocols()
50{
51 QMutexLocker locker(&m_mutex);
52
53 // fill cache, if not already done and use it
54 fillCache();
55 return m_cache.values();
56}
57
58KProtocolInfoPrivate *KProtocolInfoFactory::findProtocol(const QString &protocol, bool updateCacheIfNotfound)
59{
60 Q_ASSERT(!protocol.isEmpty());
61 Q_ASSERT(!protocol.contains(QLatin1Char(':')));
62
63 QMutexLocker locker(&m_mutex);
64
65 const bool filled = fillCache();
66
67 KProtocolInfoPrivate *info = m_cache.value(key: protocol);
68 if (!info && !filled && updateCacheIfNotfound) {
69 // Unknown protocol! Maybe it just got installed and our cache is out of date?
70 qCDebug(KIO_CORE) << "Refilling KProtocolInfoFactory cache in the hope to find" << protocol;
71 m_cacheDirty = true;
72 fillCache();
73 info = m_cache.value(key: protocol);
74 }
75 return info;
76}
77
78bool KProtocolInfoFactory::fillCache()
79{
80 // mutex MUST be locked from the outside!
81 Q_ASSERT(!m_mutex.tryLock());
82
83 // no work if filled
84 if (!m_cacheDirty) {
85 return false;
86 }
87
88 qDeleteAll(c: m_cache);
89 m_cache.clear();
90
91 // first: search for meta data protocol info, that might be bundled with applications
92 // we search in all library paths inside kf5/kio
93 const QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/kio"));
94 for (const KPluginMetaData &md : plugins) {
95 // get worker name & protocols it supports, if any
96 const QString workerPath = md.fileName();
97 const QJsonObject protocols(md.rawData().value(QStringLiteral("KDE-KIO-Protocols")).toObject());
98 qCDebug(KIO_CORE) << workerPath << "supports protocols" << protocols.keys();
99
100 // add all protocols, does nothing if object invalid
101 for (auto it = protocols.begin(); it != protocols.end(); ++it) {
102 // skip empty objects
103 const QJsonObject protocol(it.value().toObject());
104 if (protocol.isEmpty()) {
105 continue;
106 }
107
108 // add to cache, skip double entries
109 if (!m_cache.contains(key: it.key())) {
110 m_cache.insert(key: it.key(), value: new KProtocolInfoPrivate(it.key(), workerPath, protocol));
111 }
112 }
113 }
114
115 // all done, don't do it again
116 m_cacheDirty = false;
117 return true;
118}
119

source code of kio/src/core/kprotocolinfofactory.cpp