File indexing completed on 2024-04-28 15:26:37

0001 // -*- c++ -*-
0002 /*
0003     This file is part of the KDE libraries
0004     SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "workerconfig.h"
0010 
0011 #include <QHash>
0012 #include <QThreadStorage>
0013 
0014 #include <KConfig>
0015 #include <KSharedConfig>
0016 #include <kprotocolinfo.h>
0017 #include <kprotocolmanager.h>
0018 
0019 using namespace KIO;
0020 
0021 namespace KIO
0022 {
0023 class WorkerConfigProtocol
0024 {
0025 public:
0026     WorkerConfigProtocol() = default;
0027     ~WorkerConfigProtocol()
0028     {
0029         delete configFile;
0030     }
0031 
0032     WorkerConfigProtocol(const WorkerConfigProtocol &) = delete;
0033     WorkerConfigProtocol &operator=(const WorkerConfigProtocol &) = delete;
0034 
0035 public:
0036     MetaData global;
0037     QHash<QString, MetaData> host;
0038     KConfig *configFile;
0039 };
0040 
0041 static void readConfig(KConfig *config, const QString &group, MetaData *metaData)
0042 {
0043     *metaData += config->entryMap(group);
0044 }
0045 
0046 class WorkerConfigPrivate
0047 {
0048 public:
0049     void readGlobalConfig();
0050     WorkerConfigProtocol *readProtocolConfig(const QString &_protocol);
0051     WorkerConfigProtocol *findProtocolConfig(const QString &_protocol);
0052     void readConfigProtocolHost(const QString &_protocol, WorkerConfigProtocol *scp, const QString &host);
0053 
0054 public:
0055     MetaData global;
0056     QHash<QString, WorkerConfigProtocol *> protocol;
0057 };
0058 
0059 void WorkerConfigPrivate::readGlobalConfig()
0060 {
0061     global.clear();
0062     // Read stuff...
0063     readConfig(KSharedConfig::openConfig().data(), QStringLiteral("Socks"), &global); // Socks settings.
0064     global += KProtocolManager::entryMap(QStringLiteral("<default>"));
0065 }
0066 
0067 WorkerConfigProtocol *WorkerConfigPrivate::readProtocolConfig(const QString &_protocol)
0068 {
0069     WorkerConfigProtocol *scp = protocol.value(_protocol, nullptr);
0070     if (!scp) {
0071         QString filename = KProtocolInfo::config(_protocol);
0072         scp = new WorkerConfigProtocol;
0073         scp->configFile = new KConfig(filename, KConfig::NoGlobals);
0074         protocol.insert(_protocol, scp);
0075     }
0076     // Read global stuff...
0077     readConfig(scp->configFile, QStringLiteral("<default>"), &(scp->global));
0078     return scp;
0079 }
0080 
0081 WorkerConfigProtocol *WorkerConfigPrivate::findProtocolConfig(const QString &_protocol)
0082 {
0083     WorkerConfigProtocol *scp = protocol.value(_protocol, nullptr);
0084     if (!scp) {
0085         scp = readProtocolConfig(_protocol);
0086     }
0087     return scp;
0088 }
0089 
0090 void WorkerConfigPrivate::readConfigProtocolHost(const QString &, WorkerConfigProtocol *scp, const QString &host)
0091 {
0092     MetaData metaData;
0093     scp->host.insert(host, metaData);
0094 
0095     // Read stuff
0096     // Break host into domains
0097     QString domain = host;
0098 
0099     if (!domain.contains(QLatin1Char('.'))) {
0100         // Host without domain.
0101         if (scp->configFile->hasGroup("<local>")) {
0102             readConfig(scp->configFile, QStringLiteral("<local>"), &metaData);
0103             scp->host.insert(host, metaData);
0104         }
0105     }
0106 
0107     int pos = 0;
0108     do {
0109         pos = host.lastIndexOf(QLatin1Char('.'), pos - 1);
0110 
0111         if (pos < 0) {
0112             domain = host;
0113         } else {
0114             domain = host.mid(pos + 1);
0115         }
0116 
0117         if (scp->configFile->hasGroup(domain)) {
0118             readConfig(scp->configFile, domain.toLower(), &metaData);
0119             scp->host.insert(host, metaData);
0120         }
0121     } while (pos > 0);
0122 }
0123 
0124 class WorkerConfigSingleton
0125 {
0126 public:
0127     WorkerConfig instance;
0128 };
0129 
0130 template<typename T>
0131 T *perThreadGlobalStatic()
0132 {
0133     static QThreadStorage<T *> s_storage;
0134     if (!s_storage.hasLocalData()) {
0135         s_storage.setLocalData(new T);
0136     }
0137     return s_storage.localData();
0138 }
0139 // Q_GLOBAL_STATIC(WorkerConfigSingleton, _self)
0140 // TODO: export symbol here, or make compile unit local by "static"?
0141 WorkerConfigSingleton *_workerConfigSelf()
0142 {
0143     return perThreadGlobalStatic<WorkerConfigSingleton>();
0144 }
0145 
0146 WorkerConfig *WorkerConfig::self()
0147 {
0148     return &_workerConfigSelf()->instance;
0149 }
0150 
0151 WorkerConfig::WorkerConfig()
0152     : d(new WorkerConfigPrivate)
0153 {
0154     d->readGlobalConfig();
0155 }
0156 
0157 WorkerConfig::~WorkerConfig()
0158 {
0159     qDeleteAll(d->protocol);
0160 }
0161 
0162 void WorkerConfig::setConfigData(const QString &protocol, const QString &host, const QString &key, const QString &value)
0163 {
0164     MetaData config;
0165     config.insert(key, value);
0166     setConfigData(protocol, host, config);
0167 }
0168 
0169 void WorkerConfig::setConfigData(const QString &protocol, const QString &host, const MetaData &config)
0170 {
0171     if (protocol.isEmpty()) {
0172         d->global += config;
0173     } else {
0174         WorkerConfigProtocol *scp = d->findProtocolConfig(protocol);
0175         if (host.isEmpty()) {
0176             scp->global += config;
0177         } else {
0178             if (!scp->host.contains(host)) {
0179                 d->readConfigProtocolHost(protocol, scp, host);
0180             }
0181 
0182             MetaData hostConfig = scp->host.value(host);
0183             hostConfig += config;
0184             scp->host.insert(host, hostConfig);
0185         }
0186     }
0187 }
0188 
0189 MetaData WorkerConfig::configData(const QString &protocol, const QString &host)
0190 {
0191     MetaData config = d->global;
0192     WorkerConfigProtocol *scp = d->findProtocolConfig(protocol);
0193     config += scp->global;
0194     if (host.isEmpty()) {
0195         return config;
0196     }
0197 
0198     if (!scp->host.contains(host)) {
0199         d->readConfigProtocolHost(protocol, scp, host);
0200         Q_EMIT configNeeded(protocol, host);
0201     }
0202     MetaData hostConfig = scp->host.value(host);
0203     config += hostConfig;
0204 
0205     return config;
0206 }
0207 
0208 QString WorkerConfig::configData(const QString &protocol, const QString &host, const QString &key)
0209 {
0210     return configData(protocol, host).value(key);
0211 }
0212 
0213 void WorkerConfig::reset()
0214 {
0215     qDeleteAll(d->protocol);
0216     d->protocol.clear();
0217     d->readGlobalConfig();
0218 }
0219 
0220 }
0221 
0222 #include "moc_workerconfig.cpp"