Libkdav2

davprincipalhomesetsfetchjob.cpp
1 /*
2  Copyright (c) 2010 GrĂ©gory Oestreicher <[email protected]>
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 
19 #include "davprincipalhomesetsfetchjob.h"
20 
21 #include "davmanager.h"
22 #include "davprotocolbase.h"
23 #include "daverror.h"
24 #include "utils.h"
25 #include "davjob.h"
26 
27 using namespace KDAV2;
28 
30  : DavJobBase(parent), mUrl(url)
31 {
32 }
33 
35 {
36  fetchHomeSets(false);
37 }
38 
39 void DavPrincipalHomeSetsFetchJob::fetchHomeSets(bool homeSetsOnly)
40 {
41  QDomDocument document;
42 
43  QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind"));
44  document.appendChild(propfindElement);
45 
46  QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
47  propfindElement.appendChild(propElement);
48 
49  const QString homeSet = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSet();
50  const QString homeSetNS = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSetNS();
51  propElement.appendChild(document.createElementNS(homeSetNS, homeSet));
52 
53  if (!homeSetsOnly) {
54  propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-principal")));
55  propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-URL")));
56  }
57 
58  DavJob *job = DavManager::self()->createPropFindJob(mUrl.url(), document, QStringLiteral("0"));
59  connect(job, &DavJob::result, this, &DavPrincipalHomeSetsFetchJob::davJobFinished);
60 }
61 
63 {
64  return mHomeSets;
65 }
66 
67 QUrl DavPrincipalHomeSetsFetchJob::url() const
68 {
69  return mUrl.url();
70 }
71 void DavPrincipalHomeSetsFetchJob::davJobFinished(KJob *job)
72 {
73  auto davJob = static_cast<DavJob*>(job);
74  if (davJob->error()) {
75  setErrorFromJob(davJob);
76  emitResult();
77  return;
78  }
79 
80  /*
81  * Extract information from a document like the following (if no homeset is defined) :
82  *
83  * <D:multistatus xmlns:D="DAV:">
84  * <D:response xmlns:D="DAV:">
85  * <D:href xmlns:D="DAV:">/dav/</D:href>
86  * <D:propstat xmlns:D="DAV:">
87  * <D:status xmlns:D="DAV:">HTTP/1.1 200 OK</D:status>
88  * <D:prop xmlns:D="DAV:">
89  * <D:current-user-principal xmlns:D="DAV:">
90  * <D:href xmlns:D="DAV:">/principals/users/gdacoin/</D:href>
91  * </D:current-user-principal>
92  * </D:prop>
93  * </D:propstat>
94  * <D:propstat xmlns:D="DAV:">
95  * <D:status xmlns:D="DAV:">HTTP/1.1 404 Not Found</D:status>
96  * <D:prop xmlns:D="DAV:">
97  * <principal-URL xmlns="DAV:"/>
98  * <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav"/>
99  * </D:prop>
100  * </D:propstat>
101  * </D:response>
102  * </D:multistatus>
103  *
104  * Or like this (if the homeset is defined):
105  *
106  * <?xml version="1.0" encoding="utf-8" ?>
107  * <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
108  * <response>
109  * <href>/principals/users/greg%40kamago.net/</href>
110  * <propstat>
111  * <prop>
112  * <C:calendar-home-set>
113  * <href>/greg%40kamago.net/</href>
114  * </C:calendar-home-set>
115  * </prop>
116  * <status>HTTP/1.1 200 OK</status>
117  * </propstat>
118  * </response>
119  * </multistatus>
120  */
121 
122  mUrl.setUrl(davJob->url());
123  const QString homeSet = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSet();
124  const QString homeSetNS = DavManager::self()->davProtocol(mUrl.protocol())->principalHomeSetNS();
125  QString nextRoundHref; // The content of the href element that will be used if no homeset was found.
126  // This is either given by current-user-principal or by principal-URL.
127 
128  const QDomDocument document = davJob->response();
129  const QDomElement multistatusElement = document.documentElement();
130 
131  QDomElement responseElement = Utils::firstChildElementNS(multistatusElement, QStringLiteral("DAV:"), QStringLiteral("response"));
132  while (!responseElement.isNull()) {
133 
134  const QDomElement propstatElement = [&] {
135  // check for the valid propstat, without giving up on first error
136  const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat"));
137  for (int i = 0; i < propstats.length(); ++i) {
138  const QDomElement propstatCandidate = propstats.item(i).toElement();
139  const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status"));
140  if (statusElement.text().contains(QLatin1String("200"))) {
141  return propstatCandidate;
142  }
143  }
144  return QDomElement{};
145  }();
146 
147  if (propstatElement.isNull()) {
148  responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
149  continue;
150  }
151 
152  // extract home sets
153  const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop"));
154  const QDomElement homeSetElement = Utils::firstChildElementNS(propElement, homeSetNS, homeSet);
155 
156  if (!homeSetElement.isNull()) {
157  QDomElement hrefElement = Utils::firstChildElementNS(homeSetElement, QStringLiteral("DAV:"), QStringLiteral("href"));
158 
159  while (!hrefElement.isNull()) {
160  const QString href = hrefElement.text();
161  if (!mHomeSets.contains(href)) {
162  mHomeSets << href;
163  }
164 
165  hrefElement = Utils::nextSiblingElementNS(hrefElement, QStringLiteral("DAV:"), QStringLiteral("href"));
166  }
167  } else {
168  // Trying to get the principal url, given either by current-user-principal or principal-URL
169  QDomElement urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("current-user-principal"));
170  if (urlHolder.isNull()) {
171  urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("principal-URL"));
172  }
173 
174  if (!urlHolder.isNull()) {
175  // Getting the href that will be used for the next round
176  QDomElement hrefElement = Utils::firstChildElementNS(urlHolder, QStringLiteral("DAV:"), QStringLiteral("href"));
177  if (!hrefElement.isNull()) {
178  nextRoundHref = hrefElement.text();
179  }
180  }
181  }
182 
183  responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
184  }
185 
186  /*
187  * Now either we got one or more homesets, or we got an href for the next round
188  * or nothing can be found by this job.
189  * If we have homesets, we're done here and can notify the caller.
190  * Else we must ensure that we have an href for the next round.
191  */
192  if (!mHomeSets.isEmpty() || nextRoundHref.isEmpty()) {
193  emitResult();
194  } else {
195  QUrl nextRoundUrl(mUrl.url());
196 
197  if (nextRoundHref.startsWith(QLatin1Char('/'))) {
198  // nextRoundHref is only a path, use request url to complete
199  nextRoundUrl.setPath(nextRoundHref, QUrl::TolerantMode);
200  } else {
201  // href is a complete url
202  nextRoundUrl = QUrl::fromUserInput(nextRoundHref);
203  nextRoundUrl.setUserName(mUrl.url().userName());
204  nextRoundUrl.setPassword(mUrl.url().password());
205  }
206 
207  mUrl.setUrl(nextRoundUrl);
208  // And one more round, fetching only homesets
209  fetchHomeSets(true);
210  }
211 }
virtual QString principalHomeSet() const
Returns the home set that this protocol supports.
QString text() const const
QDomElement toElement() const const
static DavManager * self()
Returns the global instance of the DAV manager.
Definition: davmanager.cpp:52
QDomElement createElementNS(const QString &nsURI, const QString &qName)
const DavProtocolBase * davProtocol(Protocol protocol)
Returns the DAV protocol dialect object for the given DAV protocol.
Definition: davmanager.cpp:140
A helper class to combine url and protocol of a DAV url.
Definition: davurl.h:35
bool isNull() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
Protocol protocol() const
Returns the DAV protocol dialect that is used to retrieve the DAV object.
Definition: davurl.cpp:51
QString userName(QUrl::ComponentFormattingOptions options) const const
TolerantMode
QDomNodeList elementsByTagNameNS(const QString &nsURI, const QString &localName) const const
base class for the jobs used by the resource.
Definition: davjobbase.h:37
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QDomNode item(int index) const const
QStringList homeSets() const
Returns the found home sets.
virtual QString principalHomeSetNS() const
Returns the namespace of the home set.
bool isEmpty() const const
bool isEmpty() const const
QDomElement documentElement() const const
QDomElement KPIMKDAV2_EXPORT nextSiblingElementNS(const QDomElement &element, const QString &namespaceUri, const QString &tagName)
Returns the next sibling element of element that has the given tagName and is part of the namespaceUr...
Definition: utils.cpp:51
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QDomNode appendChild(const QDomNode &newChild)
void setErrorFromJob(DavJob *, ErrorNumber jobErrorCode=ERR_PROBLEM_WITH_REQUEST)
Set the error of this job from a failed DavJob (executed by this job).
Definition: davjobbase.cpp:99
void setUrl(const QUrl &url)
Sets the url that identifies the DAV object.
Definition: davurl.cpp:36
QString password(QUrl::ComponentFormattingOptions options) const const
void emitResult()
QDomElement KPIMKDAV2_EXPORT firstChildElementNS(const QDomElement &parent, const QString &namespaceUri, const QString &tagName)
Returns the first child element of parent that has the given tagName and is part of the namespaceUri.
Definition: utils.cpp:37
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
DavPrincipalHomeSetsFetchJob(const DavUrl &url, QObject *parent=nullptr)
Creates a new dav principals home sets fetch job.
QUrl url() const
Returns the url that identifies the DAV object.
Definition: davurl.cpp:41
int length() const const
DavJob * createPropFindJob(const QUrl &url, const QDomDocument &document, const QString &depth=QStringLiteral("1"))
Returns a preconfigured DAV PROPFIND job.
Definition: davmanager.cpp:66
QUrl fromUserInput(const QString &userInput)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Aug 15 2022 04:07:29 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.