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 <QCoreApplication>
16 #include <QDebug>
17 #include <QFile>
18 #include <QPluginLoader>
19 #include <QSet>
20 #include <QTimer>
21 #include <QProcess>
22 #include <QAuthenticator>
23 #include <QNetworkProxy>
24 #include <QXmlStreamReader>
25 #include <QSignalMapper>
26 
27 #include "platformdependent.h"
28 #include "qtplatformdependent_p.h"
29 #include <QLibraryInfo>
30 
31 using namespace Attica;
32 
33 class ProviderManager::Private
34 {
35 public:
36  PlatformDependent *m_internals;
37  QHash<QUrl, Provider> m_providers;
38  QHash<QUrl, QUrl> m_providerTargets;
40  bool m_authenticationSuppressed;
41 
42  Private()
43  : m_internals(nullptr)
44  , m_authenticationSuppressed(false)
45  {
46  }
47  ~Private()
48  {
49  // do not delete m_internals: it is the root component of a plugin!
50  }
51 };
52 
53 PlatformDependent *ProviderManager::loadPlatformDependent(const ProviderFlags &flags)
54 {
55  if (flags & ProviderManager::DisablePlugins) {
56  return new QtPlatformDependent;
57  }
58 
59  QPluginLoader loader(QStringLiteral("attica_kde"));
60  PlatformDependent * ret = qobject_cast<PlatformDependent *>(loader.instance());
61 
62  return ret ? ret : new QtPlatformDependent;
63 }
64 
65 ProviderManager::ProviderManager(const ProviderFlags &flags)
66  : d(new Private)
67 {
68  d->m_internals = loadPlatformDependent(flags);
69  connect(d->m_internals->nam(), &QNetworkAccessManager::authenticationRequired, this, &ProviderManager::authenticate);
70 }
71 
73 {
74  QTimer::singleShot(0, this, &ProviderManager::slotLoadDefaultProvidersInternal);
75 }
76 
78 {
79  d->m_authenticationSuppressed = suppressed;
80 }
81 
83 {
84  d->m_providerTargets.clear();
85  d->m_providers.clear();
86 }
87 
88 void ProviderManager::slotLoadDefaultProvidersInternal()
89 {
90  const auto providerFiles = d->m_internals->getDefaultProviderFiles();
91  for (const QUrl &url : providerFiles) {
92  addProviderFile(url);
93  }
94  if (d->m_downloads.isEmpty()) {
95  Q_EMIT defaultProvidersLoaded();
96  }
97 }
98 
100 {
101  return d->m_internals->getDefaultProviderFiles();
102 }
103 
104 ProviderManager::~ProviderManager()
105 {
106  delete d;
107 }
108 
110 {
111  d->m_internals->addDefaultProviderFile(url);
112  addProviderFile(url);
113 }
114 
115 void ProviderManager::removeProviderFileFromDefaultProviders(const QUrl &url)
116 {
117  d->m_internals->removeDefaultProviderFile(url);
118 }
119 
120 void ProviderManager::addProviderFile(const QUrl &url)
121 {
122  if (url.isLocalFile()) {
123  QFile file(url.toLocalFile());
124  if (!file.open(QIODevice::ReadOnly)) {
125  qWarning() << "ProviderManager::addProviderFile: could not open provider file: " << url.toString();
126  return;
127  }
128  parseProviderFile(QLatin1String(file.readAll()), url);
129  } else {
130  if (!d->m_downloads.contains(url.toString())) {
131  QNetworkRequest req(url);
132  req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
133  QNetworkReply *reply = d->m_internals->get(req);
134  qCDebug(ATTICA) << "executing" << Utils::toString(reply->operation()) << "for" << reply->url();
135  connect(reply, &QNetworkReply::finished, this, [this, url]() {
136  fileFinished(url.toString());
137  });
138  d->m_downloads.insert(url.toString(), reply);
139  }
140  }
141 }
142 
143 void ProviderManager::fileFinished(const QString &url)
144 {
145  QNetworkReply *reply = d->m_downloads.take(url);
146  if (reply) {
147  if (reply->error())
148  Q_EMIT failedToLoad(QUrl(url), reply->error());
149  else
150  parseProviderFile(QLatin1String(reply->readAll()), QUrl(url));
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;
172  QString message;
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, Provider(d->m_internals, baseUrl, name, icon,
223  person, friendV, message, achievement, activity, content, fan, forum, knowledgebase,
224  event, comment, registerUrl));
225  d->m_providerTargets[url] = baseUrl;
226  Q_EMIT providerAdded(d->m_providers.value(baseUrl));
227  }
228  }
229  }
230 
231  if (xml.error() != QXmlStreamReader::NoError) {
232  qCDebug(ATTICA) << "error:" << xml.errorString() << "in" << url;
233  }
234 
235  if (d->m_downloads.isEmpty()) {
236  Q_EMIT defaultProvidersLoaded();
237  }
238 }
239 
241 {
242  return providerByUrl(d->m_providerTargets.value(url));
243 }
244 
246 {
247  return d->m_providers.value(url);
248 }
249 
251 {
252  return d->m_providers.values();
253 }
254 
255 #if ATTICA_BUILD_DEPRECATED_SINCE(5, 23)
256 bool ProviderManager::contains(const QString &provider) const
257 {
258  return d->m_providers.contains(QUrl(provider));
259 }
260 #endif
261 
262 QList<QUrl> ProviderManager::providerFiles() const
263 {
264  return d->m_providerTargets.keys();
265 }
266 
267 void ProviderManager::authenticate(QNetworkReply *reply, QAuthenticator *auth)
268 {
269  QUrl baseUrl;
270  const QList<QUrl> urls = d->m_providers.keys();
271  for (const QUrl &url : urls) {
272  if (url.isParentOf(reply->url())) {
273  baseUrl = url;
274  break;
275  }
276  }
277 
278  //qCDebug(ATTICA) << "ProviderManager::authenticate" << baseUrl;
279 
280  QString user;
281  QString password;
282  if (auth->user().isEmpty() && auth->password().isEmpty()) {
283  if (d->m_internals->hasCredentials(baseUrl)) {
284  if (d->m_internals->loadCredentials(baseUrl, user, password)) {
285  //qCDebug(ATTICA) << "ProviderManager::authenticate: loading authentication";
286  auth->setUser(user);
287  auth->setPassword(password);
288  return;
289  }
290  }
291  }
292 
293  if (!d->m_authenticationSuppressed && d->m_internals->askForCredentials(baseUrl, user, password)) {
294  //qCDebug(ATTICA) << "ProviderManager::authenticate: asking internals for new credentials";
295  //auth->setUser(user);
296  //auth->setPassword(password);
297  return;
298  }
299 
300  qWarning() << "ProviderManager::authenticate: No authentication credentials provided, aborting." << reply->url().toString();
301  Q_EMIT authenticationCredentialsMissing(d->m_providers.value(baseUrl));
302  reply->abort();
303 }
304 
305 void ProviderManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
306 {
307  Q_UNUSED(proxy)
308  Q_UNUSED(authenticator)
309 }
310 
311 void ProviderManager::initNetworkAccesssManager()
312 {
313  connect(d->m_internals->nam(), &QNetworkAccessManager::authenticationRequired, this, &ProviderManager::authenticate);
314  connect(d->m_internals->nam(), &QNetworkAccessManager::proxyAuthenticationRequired, this, &ProviderManager::proxyAuthenticationRequired);
315 }
316 
Provider providerByUrl(const QUrl &url) const
bool atEnd() const const
QString errorString() const const
void setPassword(const QString &password)
QString password() const const
QList< QUrl > defaultProviderFiles()
The list of provider files that get loaded by loadDefaultProviders.
void setAuthenticationSuppressed(bool suppressed)
Suppresses the authentication, so that the application can take care of authenticating itself...
QString name() const
A name for the provider that can be displayed to the user.
Definition: provider.cpp:249
QString toString() const const
void loadDefaultProviders()
Load available providers from configuration.
void authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
void addProviderFromXml(const QString &providerXml)
Parse a xml file containing a provider description.
QXmlStreamReader::Error error() const const
QStringRef value(const QString &namespaceUri, const QString &name) const const
Provider providerFor(const QUrl &url) const
bool isEmpty() const const
QString toString(QUrl::FormattingOptions options) const const
void addProviderFileToDefaultProviders(const QUrl &url)
Add a provider file to the default providers (xml that contains provider descriptions).
QString readElementText(QXmlStreamReader::ReadElementTextBehaviour behaviour)
bool isEmpty() const const
QByteArray readAll()
QString user() const const
void deleteLater()
QXmlStreamReader::TokenType readNext()
QString toLocalFile() const const
bool isParentOf(const QUrl &childUrl) const const
virtual void abort()=0
void clear()
Remove all providers and provider files that have been loaded.
QList< Provider > providers() const
QNetworkAccessManager::Operation operation() const const
bool isStartElement() const const
The Provider class represents one Open Collaboration Service provider.
Definition: provider.h:95
QUrl url() const const
void setAttribute(QNetworkRequest::Attribute code, const QVariant &value)
QNetworkReply::NetworkError error() const const
void setUser(const QString &user)
QXmlStreamAttributes attributes() const const
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
T qobject_cast(QObject *object)
QUrl baseUrl() const
A url that identifies this provider.
Definition: provider.cpp:213
QStringRef name() const const
bool contains(const QString &provider) const
bool isLocalFile() const const
bool isEndElement() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Jan 23 2021 03:59:45 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.