File indexing completed on 2024-09-08 12:12:30
0001 /* 0002 This file is part of KDE. 0003 0004 SPDX-FileCopyrightText: 2009 Eckhart Wörner <ewoerner@kde.org> 0005 SPDX-FileCopyrightText: 2009 Frederik Gladhorn <gladhorn@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0008 */ 0009 0010 #include "providermanager.h" 0011 0012 #include "attica_debug.h" 0013 #include "atticautils.h" 0014 0015 #include <QAuthenticator> 0016 #include <QCoreApplication> 0017 #include <QDebug> 0018 #include <QFile> 0019 #include <QNetworkProxy> 0020 #include <QPluginLoader> 0021 #include <QSet> 0022 #include <QSignalMapper> 0023 #include <QTimer> 0024 #include <QXmlStreamReader> 0025 0026 #include "platformdependent.h" 0027 #include "qtplatformdependent_p.h" 0028 #include <QLibraryInfo> 0029 0030 using namespace Attica; 0031 0032 class Q_DECL_HIDDEN ProviderManager::Private 0033 { 0034 public: 0035 PlatformDependent *m_internals; 0036 QHash<QUrl, Provider> m_providers; 0037 QHash<QUrl, QUrl> m_providerTargets; 0038 QHash<QString, QNetworkReply *> m_downloads; 0039 bool m_authenticationSuppressed; 0040 0041 Private() 0042 : m_internals(nullptr) 0043 , m_authenticationSuppressed(false) 0044 { 0045 } 0046 ~Private() 0047 { 0048 // do not delete m_internals: it is the root component of a plugin! 0049 } 0050 }; 0051 0052 PlatformDependent *ProviderManager::loadPlatformDependent(const ProviderFlags &flags) 0053 { 0054 if (flags & ProviderManager::DisablePlugins) { 0055 return new QtPlatformDependent; 0056 } 0057 0058 QPluginLoader loader(QStringLiteral("attica_kde")); 0059 PlatformDependent *ret = qobject_cast<PlatformDependent *>(loader.instance()); 0060 0061 return ret ? ret : new QtPlatformDependent; 0062 } 0063 0064 ProviderManager::ProviderManager(const ProviderFlags &flags) 0065 : d(new Private) 0066 { 0067 d->m_internals = loadPlatformDependent(flags); 0068 connect(d->m_internals->nam(), &QNetworkAccessManager::authenticationRequired, this, &ProviderManager::authenticate); 0069 } 0070 0071 void ProviderManager::loadDefaultProviders() 0072 { 0073 QTimer::singleShot(0, this, &ProviderManager::slotLoadDefaultProvidersInternal); 0074 } 0075 0076 void ProviderManager::setAuthenticationSuppressed(bool suppressed) 0077 { 0078 d->m_authenticationSuppressed = suppressed; 0079 } 0080 0081 void ProviderManager::clear() 0082 { 0083 d->m_providerTargets.clear(); 0084 d->m_providers.clear(); 0085 } 0086 0087 void ProviderManager::slotLoadDefaultProvidersInternal() 0088 { 0089 const auto providerFiles = d->m_internals->getDefaultProviderFiles(); 0090 for (const QUrl &url : providerFiles) { 0091 addProviderFile(url); 0092 } 0093 if (d->m_downloads.isEmpty()) { 0094 Q_EMIT defaultProvidersLoaded(); 0095 } 0096 } 0097 0098 QList<QUrl> ProviderManager::defaultProviderFiles() 0099 { 0100 return d->m_internals->getDefaultProviderFiles(); 0101 } 0102 0103 ProviderManager::~ProviderManager() 0104 { 0105 delete d; 0106 } 0107 0108 void ProviderManager::addProviderFileToDefaultProviders(const QUrl &url) 0109 { 0110 d->m_internals->addDefaultProviderFile(url); 0111 addProviderFile(url); 0112 } 0113 0114 void ProviderManager::removeProviderFileFromDefaultProviders(const QUrl &url) 0115 { 0116 d->m_internals->removeDefaultProviderFile(url); 0117 } 0118 0119 void ProviderManager::addProviderFile(const QUrl &url) 0120 { 0121 if (url.isLocalFile()) { 0122 QFile file(url.toLocalFile()); 0123 if (!file.open(QIODevice::ReadOnly)) { 0124 qWarning() << "ProviderManager::addProviderFile: could not open provider file: " << url.toString(); 0125 return; 0126 } 0127 parseProviderFile(QLatin1String(file.readAll()), url); 0128 } else { 0129 if (!d->m_downloads.contains(url.toString())) { 0130 QNetworkRequest req(url); 0131 req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); 0132 QNetworkReply *reply = d->m_internals->get(req); 0133 qCDebug(ATTICA) << "executing" << Utils::toString(reply->operation()) << "for" << reply->url(); 0134 connect(reply, &QNetworkReply::finished, this, [this, url]() { 0135 fileFinished(url.toString()); 0136 }); 0137 d->m_downloads.insert(url.toString(), reply); 0138 } 0139 } 0140 } 0141 0142 void ProviderManager::fileFinished(const QString &url) 0143 { 0144 QNetworkReply *reply = d->m_downloads.take(url); 0145 if (reply) { 0146 if (reply->error()) { 0147 Q_EMIT failedToLoad(QUrl(url), reply->error()); 0148 } else { 0149 parseProviderFile(QLatin1String(reply->readAll()), QUrl(url)); 0150 } 0151 reply->deleteLater(); 0152 } else { 0153 Q_EMIT failedToLoad(QUrl(url), QNetworkReply::UnknownNetworkError); 0154 } 0155 } 0156 0157 void ProviderManager::addProviderFromXml(const QString &providerXml) 0158 { 0159 parseProviderFile(providerXml, QUrl()); 0160 } 0161 0162 void ProviderManager::parseProviderFile(const QString &xmlString, const QUrl &url) 0163 { 0164 QXmlStreamReader xml(xmlString); 0165 while (!xml.atEnd() && xml.readNext()) { 0166 if (xml.isStartElement() && xml.name() == QLatin1String("provider")) { 0167 QUrl baseUrl; 0168 QString name; 0169 QUrl icon; 0170 QString person; 0171 QString friendV; 0172 QString message; 0173 QString achievement; 0174 QString activity; 0175 QString content; 0176 QString fan; 0177 QString forum; 0178 QString knowledgebase; 0179 QString event; 0180 QString comment; 0181 QString registerUrl; 0182 0183 while (!xml.atEnd() && xml.readNext()) { 0184 if (xml.isStartElement()) { 0185 if (xml.name() == QLatin1String("location")) { 0186 baseUrl = QUrl(xml.readElementText()); 0187 } else if (xml.name() == QLatin1String("name")) { 0188 name = xml.readElementText(); 0189 } else if (xml.name() == QLatin1String("icon")) { 0190 icon = QUrl(xml.readElementText()); 0191 } else if (xml.name() == QLatin1String("person")) { 0192 person = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0193 } else if (xml.name() == QLatin1String("friend")) { 0194 friendV = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0195 } else if (xml.name() == QLatin1String("message")) { 0196 message = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0197 } else if (xml.name() == QLatin1String("achievement")) { 0198 achievement = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0199 } else if (xml.name() == QLatin1String("activity")) { 0200 activity = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0201 } else if (xml.name() == QLatin1String("content")) { 0202 content = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0203 } else if (xml.name() == QLatin1String("fan")) { 0204 fan = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0205 } else if (xml.name() == QLatin1String("forum")) { 0206 forum = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0207 } else if (xml.name() == QLatin1String("knowledgebase")) { 0208 knowledgebase = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0209 } else if (xml.name() == QLatin1String("event")) { 0210 event = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0211 } else if (xml.name() == QLatin1String("comment")) { 0212 comment = xml.attributes().value(QLatin1String("ocsversion")).toString(); 0213 } else if (xml.name() == QLatin1String("register")) { 0214 registerUrl = xml.readElementText(); 0215 } 0216 } else if (xml.isEndElement() && xml.name() == QLatin1String("provider")) { 0217 break; 0218 } 0219 } 0220 if (!baseUrl.isEmpty()) { 0221 // qCDebug(ATTICA) << "Adding provider" << baseUrl; 0222 d->m_providers.insert(baseUrl, 0223 Provider(d->m_internals, 0224 baseUrl, 0225 name, 0226 icon, 0227 person, 0228 friendV, 0229 message, 0230 achievement, 0231 activity, 0232 content, 0233 fan, 0234 forum, 0235 knowledgebase, 0236 event, 0237 comment, 0238 registerUrl)); 0239 d->m_providerTargets[url] = baseUrl; 0240 Q_EMIT providerAdded(d->m_providers.value(baseUrl)); 0241 } 0242 } 0243 } 0244 0245 if (xml.error() != QXmlStreamReader::NoError) { 0246 qCDebug(ATTICA) << "error:" << xml.errorString() << "in" << url; 0247 } 0248 0249 if (d->m_downloads.isEmpty()) { 0250 Q_EMIT defaultProvidersLoaded(); 0251 } 0252 } 0253 0254 Provider ProviderManager::providerFor(const QUrl &url) const 0255 { 0256 return providerByUrl(d->m_providerTargets.value(url)); 0257 } 0258 0259 Provider ProviderManager::providerByUrl(const QUrl &url) const 0260 { 0261 return d->m_providers.value(url); 0262 } 0263 0264 QList<Provider> ProviderManager::providers() const 0265 { 0266 return d->m_providers.values(); 0267 } 0268 0269 #if ATTICA_BUILD_DEPRECATED_SINCE(5, 23) 0270 bool ProviderManager::contains(const QString &provider) const 0271 { 0272 return d->m_providers.contains(QUrl(provider)); 0273 } 0274 #endif 0275 0276 QList<QUrl> ProviderManager::providerFiles() const 0277 { 0278 return d->m_providerTargets.keys(); 0279 } 0280 0281 void ProviderManager::authenticate(QNetworkReply *reply, QAuthenticator *auth) 0282 { 0283 QUrl baseUrl; 0284 const QList<QUrl> urls = d->m_providers.keys(); 0285 for (const QUrl &url : urls) { 0286 if (url.isParentOf(reply->url())) { 0287 baseUrl = url; 0288 break; 0289 } 0290 } 0291 0292 // qCDebug(ATTICA) << "ProviderManager::authenticate" << baseUrl; 0293 0294 QString user; 0295 QString password; 0296 if (auth->user().isEmpty() && auth->password().isEmpty()) { 0297 if (d->m_internals->hasCredentials(baseUrl)) { 0298 if (d->m_internals->loadCredentials(baseUrl, user, password)) { 0299 // qCDebug(ATTICA) << "ProviderManager::authenticate: loading authentication"; 0300 auth->setUser(user); 0301 auth->setPassword(password); 0302 return; 0303 } 0304 } 0305 } 0306 0307 if (!d->m_authenticationSuppressed && d->m_internals->askForCredentials(baseUrl, user, password)) { 0308 // qCDebug(ATTICA) << "ProviderManager::authenticate: asking internals for new credentials"; 0309 // auth->setUser(user); 0310 // auth->setPassword(password); 0311 return; 0312 } 0313 0314 qWarning() << "ProviderManager::authenticate: No authentication credentials provided, aborting." << reply->url().toString(); 0315 Q_EMIT authenticationCredentialsMissing(d->m_providers.value(baseUrl)); 0316 reply->abort(); 0317 } 0318 0319 void ProviderManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator) 0320 { 0321 Q_UNUSED(proxy) 0322 Q_UNUSED(authenticator) 0323 } 0324 0325 void ProviderManager::initNetworkAccesssManager() 0326 { 0327 connect(d->m_internals->nam(), &QNetworkAccessManager::authenticationRequired, this, &ProviderManager::authenticate); 0328 connect(d->m_internals->nam(), &QNetworkAccessManager::proxyAuthenticationRequired, this, &ProviderManager::proxyAuthenticationRequired); 0329 } 0330 0331 #include "moc_providermanager.cpp"