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 | |
21 | Q_GLOBAL_STATIC(KProtocolInfoFactory, kProtocolInfoFactoryInstance) |
22 | |
23 | KProtocolInfoFactory *KProtocolInfoFactory::self() |
24 | { |
25 | return kProtocolInfoFactoryInstance(); |
26 | } |
27 | |
28 | KProtocolInfoFactory::KProtocolInfoFactory() |
29 | : m_cacheDirty(true) |
30 | { |
31 | } |
32 | |
33 | KProtocolInfoFactory::~KProtocolInfoFactory() |
34 | { |
35 | QMutexLocker locker(&m_mutex); |
36 | qDeleteAll(c: m_cache); |
37 | m_cache.clear(); |
38 | } |
39 | |
40 | QStringList 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 | |
49 | QList<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 | |
58 | KProtocolInfoPrivate *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 | |
78 | bool 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 | |