Attica

providermanager.cpp
1 /*
2  This file is part of KDE.
3 
4  SPDX-FileCopyrightText: 2009 Eckhart Wörner <[email protected]>
5  SPDX-FileCopyrightText: 2009 Frederik Gladhorn <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
8 */
9 
10 #include "providermanager.h"
11 
12 #include "attica_debug.h"
13 #include "atticautils.h"
14 
15 #include <QAuthenticator>
16 #include <QCoreApplication>
17 #include <QDebug>
18 #include <QFile>
19 #include <QNetworkProxy>
20 #include <QPluginLoader>
21 #include <QSet>
22 #include <QSignalMapper>
23 #include <QTimer>
24 #include <QXmlStreamReader>
25 
26 #include "platformdependent.h"
27 #include "qtplatformdependent_p.h"
28 #include <QLibraryInfo>
29 
30 using namespace Attica;
31 
32 class Q_DECL_HIDDEN ProviderManager::Private
33 {
34 public:
35  PlatformDependent *m_internals;
36  QHash<QUrl, Provider> m_providers;
37  QHash<QUrl, QUrl> m_providerTargets;
39  bool m_authenticationSuppressed;
40 
41  Private()
42  : m_internals(nullptr)
43  , m_authenticationSuppressed(false)
44  {
45  }
46  ~Private()
47  {
48  // do not delete m_internals: it is the root component of a plugin!
49  }
50 };
51 
52 PlatformDependent *ProviderManager::loadPlatformDependent(const ProviderFlags &flags)
53 {
54  if (flags & ProviderManager::DisablePlugins) {
55  return new QtPlatformDependent;
56  }
57 
58  QPluginLoader loader(QStringLiteral("attica_kde"));
59  PlatformDependent *ret = qobject_cast<PlatformDependent *>(loader.instance());
60 
61  return ret ? ret : new QtPlatformDependent;
62 }
63 
64 ProviderManager::ProviderManager(const ProviderFlags &flags)
65  : d(new Private)
66 {
67  d->m_internals = loadPlatformDependent(flags);
68  connect(d->m_internals->nam(), &QNetworkAccessManager::authenticationRequired, this, &ProviderManager::authenticate);
69 }
70 
72 {
73  QTimer::singleShot(0, this, &ProviderManager::slotLoadDefaultProvidersInternal);
74 }
75 
77 {
78  d->m_authenticationSuppressed = suppressed;
79 }
80 
82 {
83  d->m_providerTargets.clear();
84  d->m_providers.clear();
85 }
86 
87 void ProviderManager::slotLoadDefaultProvidersInternal()
88 {
89  const auto providerFiles = d->m_internals->getDefaultProviderFiles();
90  for (const QUrl &url : providerFiles) {
91  addProviderFile(url);
92  }
93  if (d->m_downloads.isEmpty()) {
94  Q_EMIT defaultProvidersLoaded();
95  }
96 }
97 
99 {
100  return d->m_internals->getDefaultProviderFiles();
101 }
102 
103 ProviderManager::~ProviderManager()
104 {
105  delete d;
106 }
107 
109 {
110  d->m_internals->addDefaultProviderFile(url);
111  addProviderFile(url);
112 }
113 
114 void ProviderManager::removeProviderFileFromDefaultProviders(const QUrl &url)
115 {
116  d->m_internals->removeDefaultProviderFile(url);
117 }
118 
119 void ProviderManager::addProviderFile(const QUrl &url)
120 {
121  if (url.isLocalFile()) {
122  QFile file(url.toLocalFile());
123  if (!file.open(QIODevice::ReadOnly)) {
124  qWarning() << "ProviderManager::addProviderFile: could not open provider file: " << url.toString();
125  return;
126  }
127  parseProviderFile(QLatin1String(file.readAll()), url);
128  } else {
129  if (!d->m_downloads.contains(url.toString())) {
130  QNetworkRequest req(url);
131  req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
132  QNetworkReply *reply = d->m_internals->get(req);
133  qCDebug(ATTICA) << "executing" << Utils::toString(reply->operation()) << "for" << reply->url();
134  connect(reply, &QNetworkReply::finished, this, [this, url]() {
135  fileFinished(url.toString());
136  });
137  d->m_downloads.insert(url.toString(), reply);
138  }
139  }
140 }
141 
142 void ProviderManager::fileFinished(const QString &url)
143 {
144  QNetworkReply *reply = d->m_downloads.take(url);
145  if (reply) {
146  if (reply->error()) {
147  Q_EMIT failedToLoad(QUrl(url), reply->error());
148  } else {
149  parseProviderFile(QLatin1String(reply->readAll()), QUrl(url));
150  }
151  reply->deleteLater();
152  } else {
153  Q_EMIT failedToLoad(QUrl(url), QNetworkReply::UnknownNetworkError);
154  }
155 }
156 
158 {
159  parseProviderFile(providerXml, QUrl());
160 }
161 
162 void ProviderManager::parseProviderFile(const QString &xmlString, const QUrl &url)
163 {
164  QXmlStreamReader xml(xmlString);
165  while (!xml.atEnd() && xml.readNext()) {
166  if (xml.isStartElement() && xml.name() == QLatin1String("provider")) {
167  QUrl baseUrl;
168  QString name;
169  QUrl icon;
170  QString person;
171  QString friendV;
173  QString achievement;
174  QString activity;
175  QString content;
176  QString fan;
177  QString forum;
178  QString knowledgebase;
179  QString event;
180  QString comment;
181  QString registerUrl;
182 
183  while (!xml.atEnd() && xml.readNext()) {
184  if (xml.isStartElement()) {
185  if (xml.name() == QLatin1String("location")) {
186  baseUrl = QUrl(xml.readElementText());
187  } else if (xml.name() == QLatin1String("name")) {
188  name = xml.readElementText();
189  } else if (xml.name() == QLatin1String("icon")) {
190  icon = QUrl(xml.readElementText());
191  } else if (xml.name() == QLatin1String("person")) {
192  person = xml.attributes().value(QLatin1String("ocsversion")).toString();
193  } else if (xml.name() == QLatin1String("friend")) {
194  friendV = xml.attributes().value(QLatin1String("ocsversion")).toString();
195  } else if (xml.name() == QLatin1String("message")) {
196  message = xml.attributes().value(QLatin1String("ocsversion")).toString();
197  } else if (xml.name() == QLatin1String("achievement")) {
198  achievement = xml.attributes().value(QLatin1String("ocsversion")).toString();
199  } else if (xml.name() == QLatin1String("activity")) {
200  activity = xml.attributes().value(QLatin1String("ocsversion")).toString();
201  } else if (xml.name() == QLatin1String("content")) {
202  content = xml.attributes().value(QLatin1String("ocsversion")).toString();
203  } else if (xml.name() == QLatin1String("fan")) {
204  fan = xml.attributes().value(QLatin1String("ocsversion")).toString();
205  } else if (xml.name() == QLatin1String("forum")) {
206  forum = xml.attributes().value(QLatin1String("ocsversion")).toString();
207  } else if (xml.name() == QLatin1String("knowledgebase")) {
208  knowledgebase = xml.attributes().value(QLatin1String("ocsversion")).toString();
209  } else if (xml.name() == QLatin1String("event")) {
210  event = xml.attributes().value(QLatin1String("ocsversion")).toString();
211  } else if (xml.name() == QLatin1String("comment")) {
212  comment = xml.attributes().value(QLatin1String("ocsversion")).toString();
213  } else if (xml.name() == QLatin1String("register")) {
214  registerUrl = xml.readElementText();
215  }
216  } else if (xml.isEndElement() && xml.name() == QLatin1String("provider")) {
217  break;
218  }
219  }
220  if (!baseUrl.isEmpty()) {
221  // qCDebug(ATTICA) << "Adding provider" << baseUrl;
222  d->m_providers.insert(baseUrl,
223  Provider(d->m_internals,
224  baseUrl,
225  name,
226  icon,
227  person,
228  friendV,
229  message,
230  achievement,
231  activity,
232  content,
233  fan,
234  forum,
235  knowledgebase,
236  event,
237  comment,
238  registerUrl));
239  d->m_providerTargets[url] = baseUrl;
240  Q_EMIT providerAdded(d->m_providers.value(baseUrl));
241  }
242  }
243  }
244 
245  if (xml.error() != QXmlStreamReader::NoError) {
246  qCDebug(ATTICA) << "error:" << xml.errorString() << "in" << url;
247  }
248 
249  if (d->m_downloads.isEmpty()) {
250  Q_EMIT defaultProvidersLoaded();
251  }
252 }
253 
255 {
256  return providerByUrl(d->m_providerTargets.value(url));
257 }
258 
260 {
261  return d->m_providers.value(url);
262 }
263 
265 {
266  return d->m_providers.values();
267 }
268 
269 #if ATTICA_BUILD_DEPRECATED_SINCE(5, 23)
270 bool ProviderManager::contains(const QString &provider) const
271 {
272  return d->m_providers.contains(QUrl(provider));
273 }
274 #endif
275 
276 QList<QUrl> ProviderManager::providerFiles() const
277 {
278  return d->m_providerTargets.keys();
279 }
280 
281 void ProviderManager::authenticate(QNetworkReply *reply, QAuthenticator *auth)
282 {
283  QUrl baseUrl;
284  const QList<QUrl> urls = d->m_providers.keys();
285  for (const QUrl &url : urls) {
286  if (url.isParentOf(reply->url())) {
287  baseUrl = url;
288  break;
289  }
290  }
291 
292  // qCDebug(ATTICA) << "ProviderManager::authenticate" << baseUrl;
293 
294  QString user;
295  QString password;
296  if (auth->user().isEmpty() && auth->password().isEmpty()) {
297  if (d->m_internals->hasCredentials(baseUrl)) {
298  if (d->m_internals->loadCredentials(baseUrl, user, password)) {
299  // qCDebug(ATTICA) << "ProviderManager::authenticate: loading authentication";
300  auth->setUser(user);
301  auth->setPassword(password);
302  return;
303  }
304  }
305  }
306 
307  if (!d->m_authenticationSuppressed && d->m_internals->askForCredentials(baseUrl, user, password)) {
308  // qCDebug(ATTICA) << "ProviderManager::authenticate: asking internals for new credentials";
309  // auth->setUser(user);
310  // auth->setPassword(password);
311  return;
312  }
313 
314  qWarning() << "ProviderManager::authenticate: No authentication credentials provided, aborting." << reply->url().toString();
315  Q_EMIT authenticationCredentialsMissing(d->m_providers.value(baseUrl));
316  reply->abort();
317 }
318 
319 void ProviderManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
320 {
321  Q_UNUSED(proxy)
322  Q_UNUSED(authenticator)
323 }
324 
325 void ProviderManager::initNetworkAccesssManager()
326 {
327  connect(d->m_internals->nam(), &QNetworkAccessManager::authenticationRequired, this, &ProviderManager::authenticate);
328  connect(d->m_internals->nam(), &QNetworkAccessManager::proxyAuthenticationRequired, this, &ProviderManager::proxyAuthenticationRequired);
329 }
330 
331 #include "moc_providermanager.cpp"
void addProviderFileToDefaultProviders(const QUrl &url)
Add a provider file to the default providers (xml that contains provider descriptions).
QList< Provider > providers() const
bool isParentOf(const QUrl &childUrl) const const
QString user() const const
Provider providerFor(const QUrl &url) const
void setPassword(const QString &password)
Q_EMITQ_EMIT
void setUser(const QString &user)
void setAuthenticationSuppressed(bool suppressed)
Suppresses the authentication, so that the application can take care of authenticating itself.
QNetworkReply::NetworkError error() const const
QNetworkAccessManager::Operation operation() const const
bool contains(const QString &provider) const
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
void authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Provider providerByUrl(const QUrl &url) const
QUrl url() const const
void deleteLater()
QString toString(QUrl::FormattingOptions options) const const
virtual bool event(QEvent *e)
bool isEmpty() const const
void clear()
Remove all providers and provider files that have been loaded.
bool isEmpty() const const
void loadDefaultProviders()
Load available providers from configuration.
QString toLocalFile() const const
QList< QUrl > defaultProviderFiles()
The list of provider files that get loaded by loadDefaultProviders.
bool isLocalFile() const const
The Attica namespace,.
QByteArray readAll()
void addProviderFromXml(const QString &providerXml)
Parse a xml file containing a provider description.
QString password() const const
QString message
virtual void abort()=0
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Nov 29 2023 04:07:39 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.