1// -*- c++ -*-
2/*
3 This file is part of the KDE libraries
4 SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#include "workerconfig.h"
10
11#include <QHash>
12#include <QThreadStorage>
13
14#include <KConfig>
15#include <KSharedConfig>
16#include <kprotocolinfo.h>
17#include <kprotocolmanager.h>
18
19using namespace KIO;
20
21namespace KIO
22{
23class WorkerConfigProtocol
24{
25public:
26 WorkerConfigProtocol() = default;
27 ~WorkerConfigProtocol()
28 {
29 delete configFile;
30 }
31
32 WorkerConfigProtocol(const WorkerConfigProtocol &) = delete;
33 WorkerConfigProtocol &operator=(const WorkerConfigProtocol &) = delete;
34
35public:
36 MetaData global;
37 QHash<QString, MetaData> host;
38 KConfig *configFile;
39};
40
41static void readConfig(KConfig *config, const QString &group, MetaData *metaData)
42{
43 *metaData += config->entryMap(aGroup: group);
44}
45
46class WorkerConfigPrivate
47{
48public:
49 void readGlobalConfig();
50 WorkerConfigProtocol *readProtocolConfig(const QString &_protocol);
51 WorkerConfigProtocol *findProtocolConfig(const QString &_protocol);
52 void readConfigProtocolHost(const QString &_protocol, WorkerConfigProtocol *scp, const QString &host);
53
54public:
55 MetaData global;
56 QHash<QString, WorkerConfigProtocol *> protocol;
57};
58
59void WorkerConfigPrivate::readGlobalConfig()
60{
61 global.clear();
62 // Read stuff...
63 readConfig(config: KSharedConfig::openConfig().data(), QStringLiteral("Socks"), metaData: &global); // Socks settings.
64 global += KProtocolManager::entryMap(QStringLiteral("<default>"));
65}
66
67WorkerConfigProtocol *WorkerConfigPrivate::readProtocolConfig(const QString &_protocol)
68{
69 WorkerConfigProtocol *scp = protocol.value(key: _protocol, defaultValue: nullptr);
70 if (!scp) {
71 QString filename = KProtocolInfo::config(protocol: _protocol);
72 scp = new WorkerConfigProtocol;
73 scp->configFile = new KConfig(filename, KConfig::NoGlobals);
74 protocol.insert(key: _protocol, value: scp);
75 }
76 // Read global stuff...
77 readConfig(config: scp->configFile, QStringLiteral("<default>"), metaData: &(scp->global));
78 return scp;
79}
80
81WorkerConfigProtocol *WorkerConfigPrivate::findProtocolConfig(const QString &_protocol)
82{
83 WorkerConfigProtocol *scp = protocol.value(key: _protocol, defaultValue: nullptr);
84 if (!scp) {
85 scp = readProtocolConfig(_protocol);
86 }
87 return scp;
88}
89
90void WorkerConfigPrivate::readConfigProtocolHost(const QString &, WorkerConfigProtocol *scp, const QString &host)
91{
92 MetaData metaData;
93 scp->host.insert(key: host, value: metaData);
94
95 // Read stuff
96 // Break host into domains
97 QString domain = host;
98
99 if (!domain.contains(c: QLatin1Char('.'))) {
100 // Host without domain.
101 if (scp->configFile->hasGroup(QStringLiteral("<local>"))) {
102 readConfig(config: scp->configFile, QStringLiteral("<local>"), metaData: &metaData);
103 scp->host.insert(key: host, value: metaData);
104 }
105 }
106
107 int pos = 0;
108 do {
109 pos = host.lastIndexOf(c: QLatin1Char('.'), from: pos - 1);
110
111 if (pos < 0) {
112 domain = host;
113 } else {
114 domain = host.mid(position: pos + 1);
115 }
116
117 if (scp->configFile->hasGroup(group: domain)) {
118 readConfig(config: scp->configFile, group: domain.toLower(), metaData: &metaData);
119 scp->host.insert(key: host, value: metaData);
120 }
121 } while (pos > 0);
122}
123
124class WorkerConfigSingleton
125{
126public:
127 WorkerConfig instance;
128};
129
130template<typename T>
131T *perThreadGlobalStatic()
132{
133 static QThreadStorage<T *> s_storage;
134 if (!s_storage.hasLocalData()) {
135 s_storage.setLocalData(new T);
136 }
137 return s_storage.localData();
138}
139// Q_GLOBAL_STATIC(WorkerConfigSingleton, _self)
140// TODO: export symbol here, or make compile unit local by "static"?
141WorkerConfigSingleton *_workerConfigSelf()
142{
143 return perThreadGlobalStatic<WorkerConfigSingleton>();
144}
145
146WorkerConfig *WorkerConfig::self()
147{
148 return &_workerConfigSelf()->instance;
149}
150
151WorkerConfig::WorkerConfig()
152 : d(new WorkerConfigPrivate)
153{
154 d->readGlobalConfig();
155}
156
157WorkerConfig::~WorkerConfig()
158{
159 qDeleteAll(c: d->protocol);
160}
161
162void WorkerConfig::setConfigData(const QString &protocol, const QString &host, const QString &key, const QString &value)
163{
164 MetaData config;
165 config.insert(key, value);
166 setConfigData(protocol, host, config);
167}
168
169void WorkerConfig::setConfigData(const QString &protocol, const QString &host, const MetaData &config)
170{
171 if (protocol.isEmpty()) {
172 d->global += config;
173 } else {
174 WorkerConfigProtocol *scp = d->findProtocolConfig(protocol: protocol);
175 if (host.isEmpty()) {
176 scp->global += config;
177 } else {
178 if (!scp->host.contains(key: host)) {
179 d->readConfigProtocolHost(protocol, scp, host);
180 }
181
182 MetaData hostConfig = scp->host.value(key: host);
183 hostConfig += config;
184 scp->host.insert(key: host, value: hostConfig);
185 }
186 }
187}
188
189MetaData WorkerConfig::configData(const QString &protocol, const QString &host)
190{
191 MetaData config = d->global;
192 WorkerConfigProtocol *scp = d->findProtocolConfig(protocol: protocol);
193 config += scp->global;
194 if (host.isEmpty()) {
195 return config;
196 }
197
198 if (!scp->host.contains(key: host)) {
199 d->readConfigProtocolHost(protocol, scp, host);
200 Q_EMIT configNeeded(protocol, host);
201 }
202 MetaData hostConfig = scp->host.value(key: host);
203 config += hostConfig;
204
205 return config;
206}
207
208QString WorkerConfig::configData(const QString &protocol, const QString &host, const QString &key)
209{
210 return configData(protocol, host).value(key);
211}
212
213void WorkerConfig::reset()
214{
215 qDeleteAll(c: d->protocol);
216 d->protocol.clear();
217 d->readGlobalConfig();
218}
219
220}
221
222#include "moc_workerconfig.cpp"
223

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