Libkdav2

davprincipalhomesetsfetchjob.cpp
1/*
2 Copyright (c) 2010 Grégory Oestreicher <greg@kamago.net>
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
27using namespace KDAV2;
28
30 : DavJobBase(parent), mUrl(url)
31{
32}
33
35{
36 fetchHomeSets(false);
37}
38
39void 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
67QUrl DavPrincipalHomeSetsFetchJob::url() const
68{
69 return mUrl.url();
70}
71void 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}
base class for the jobs used by the resource.
Definition davjobbase.h:38
void setErrorFromJob(DavJob *, ErrorNumber jobErrorCode=ERR_PROBLEM_WITH_REQUEST)
Set the error of this job from a failed DavJob (executed by this job).
DavJob * createPropFindJob(const QUrl &url, const QDomDocument &document, const QString &depth=QStringLiteral("1"))
Returns a preconfigured DAV PROPFIND job.
static DavManager * self()
Returns the global instance of the DAV manager.
const DavProtocolBase * davProtocol(Protocol protocol)
Returns the DAV protocol dialect object for the given DAV protocol.
DavPrincipalHomeSetsFetchJob(const DavUrl &url, QObject *parent=nullptr)
Creates a new dav principals home sets fetch job.
QStringList homeSets() const
Returns the found home sets.
virtual QString principalHomeSetNS() const
Returns the namespace of the home set.
virtual QString principalHomeSet() const
Returns the home set that this protocol supports.
A helper class to combine url and protocol of a DAV url.
Definition davurl.h:36
QUrl url() const
Returns the url that identifies the DAV object.
Definition davurl.cpp:41
Protocol protocol() const
Returns the DAV protocol dialect that is used to retrieve the DAV object.
Definition davurl.cpp:51
void setUrl(const QUrl &url)
Sets the url that identifies the DAV object.
Definition davurl.cpp:36
void emitResult()
void result(KJob *job)
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
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
QDomElement createElementNS(const QString &nsURI, const QString &qName)
QDomElement documentElement() const const
QDomNodeList elementsByTagNameNS(const QString &nsURI, const QString &localName) const const
QString text() const const
QDomNode appendChild(const QDomNode &newChild)
bool isNull() const const
QDomElement toElement() const const
QDomNode item(int index) const const
int length() const const
bool isEmpty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
TolerantMode
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
QString password(ComponentFormattingOptions options) const const
QString userName(ComponentFormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:08:18 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.