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 | |
19 | using namespace KIO; |
20 | |
21 | namespace KIO |
22 | { |
23 | class WorkerConfigProtocol |
24 | { |
25 | public: |
26 | WorkerConfigProtocol() = default; |
27 | ~WorkerConfigProtocol() |
28 | { |
29 | delete configFile; |
30 | } |
31 | |
32 | WorkerConfigProtocol(const WorkerConfigProtocol &) = delete; |
33 | WorkerConfigProtocol &operator=(const WorkerConfigProtocol &) = delete; |
34 | |
35 | public: |
36 | MetaData global; |
37 | QHash<QString, MetaData> host; |
38 | KConfig *configFile; |
39 | }; |
40 | |
41 | static void readConfig(KConfig *config, const QString &group, MetaData *metaData) |
42 | { |
43 | *metaData += config->entryMap(aGroup: group); |
44 | } |
45 | |
46 | class WorkerConfigPrivate |
47 | { |
48 | public: |
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 | |
54 | public: |
55 | MetaData global; |
56 | QHash<QString, WorkerConfigProtocol *> protocol; |
57 | }; |
58 | |
59 | void 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 | |
67 | WorkerConfigProtocol *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 | |
81 | WorkerConfigProtocol *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 | |
90 | void 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 | |
124 | class WorkerConfigSingleton |
125 | { |
126 | public: |
127 | WorkerConfig instance; |
128 | }; |
129 | |
130 | template<typename T> |
131 | T *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"? |
141 | WorkerConfigSingleton *_workerConfigSelf() |
142 | { |
143 | return perThreadGlobalStatic<WorkerConfigSingleton>(); |
144 | } |
145 | |
146 | WorkerConfig *WorkerConfig::self() |
147 | { |
148 | return &_workerConfigSelf()->instance; |
149 | } |
150 | |
151 | WorkerConfig::WorkerConfig() |
152 | : d(new WorkerConfigPrivate) |
153 | { |
154 | d->readGlobalConfig(); |
155 | } |
156 | |
157 | WorkerConfig::~WorkerConfig() |
158 | { |
159 | qDeleteAll(c: d->protocol); |
160 | } |
161 | |
162 | void 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 | |
169 | void 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 | |
189 | MetaData 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 | |
208 | QString WorkerConfig::configData(const QString &protocol, const QString &host, const QString &key) |
209 | { |
210 | return configData(protocol, host).value(key); |
211 | } |
212 | |
213 | void 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 | |