Libkdav2

davdiscoveryjob.cpp
1/*
2 Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com>
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 "davdiscoveryjob.h"
20
21#include "libkdav2_debug.h"
22#include "davmanager.h"
23#include "davprotocolbase.h"
24#include "daverror.h"
25#include "utils.h"
26#include "davjob.h"
27
28using namespace KDAV2;
29
30DavDiscoveryJob::DavDiscoveryJob(const DavUrl &davUrl, const QString &wellKnownSuffix, QObject *parent)
31 : DavJobBase(parent), mUrl(davUrl)
32{
33 auto url = davUrl.url();
34 if (!url.toString().contains("/.well-known/")) {
35 url.setPath(url.path() + "/.well-known/" + wellKnownSuffix);
36 mUrl.setUrl(url);
37 }
38}
39
41{
42 QDomDocument document;
43
44 QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind"));
46
47 QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
48 propfindElement.appendChild(propElement);
49
50 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-principal")));
51 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-URL")));
52
53 DavJob *job = DavManager::self()->createPropFindJob(mUrl.url(), document, QStringLiteral("0"));
54 connect(job, &DavJob::result, this, &DavDiscoveryJob::davJobFinished);
55}
56
58{
59 return mUrl.url();
60}
61
62void DavDiscoveryJob::davJobFinished(KJob *job)
63{
64 DavJob *davJob = static_cast<DavJob*>(job);
65
66 if (davJob->error()) {
67 //Retry on the root uri on 404, otherwise fail
68 if (davJob->httpStatusCode() == 404 && davJob->url().path() != QStringLiteral("/")) {
69 auto url = mUrl.url();
70 url.setPath("/");
71 mUrl.setUrl(url);
72 qCDebug(KDAV2_LOG) << "Retrying on root url" << url;
73 start();
74 return;
75 }
77 emitResult();
78 return;
79 }
80 mUrl.setUrl(davJob->url());
81
82 const QDomDocument document = davJob->response();
84
85
86 const QString principalHref = [&] {
87 QDomElement responseElement = Utils::firstChildElementNS(multistatusElement, QStringLiteral("DAV:"), QStringLiteral("response"));
88 while (!responseElement.isNull()) {
89
90 const QDomElement propstatElement = [&] {
91 // check for the valid propstat, without giving up on first error
92 const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat"));
93 for (int i = 0; i < propstats.length(); ++i) {
94 const QDomElement propstatCandidate = propstats.item(i).toElement();
95 const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status"));
96 if (statusElement.text().contains(QLatin1String("200"))) {
97 return propstatCandidate;
98 }
99 }
100 return QDomElement{};
101 }();
102
103 if (propstatElement.isNull()) {
104 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
105 continue;
106 }
107
108 // extract home sets
109 const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop"));
110
111 // Trying to get the principal url, given either by current-user-principal or principal-URL
112 QDomElement urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("current-user-principal"));
113 if (urlHolder.isNull()) {
114 urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("principal-URL"));
115 }
116
117 if (!urlHolder.isNull()) {
118 // Getting the href that will be used for the next round
119 const QDomElement hrefElement = Utils::firstChildElementNS(urlHolder, QStringLiteral("DAV:"), QStringLiteral("href"));
120 if (!hrefElement.isNull()) {
121 return hrefElement.text();
122 }
123 }
124
125 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
126 }
127 return QString{};
128 }();
129
130 QUrl principalUrl(mUrl.url());
131
132 if (principalHref.startsWith(QLatin1Char('/'))) {
133 // principalHref is only a path, use request url to complete
135 } else {
136 // href is a complete url
138 principalUrl.setUserName(mUrl.url().userName());
139 principalUrl.setPassword(mUrl.url().password());
140 }
141
142 mUrl.setUrl(principalUrl);
143 emitResult();
144}
void start() override
Starts the job.
DavDiscoveryJob(const DavUrl &url, const QString &wellKnownSuffix, QObject *parent=nullptr)
Discover the url of the server.
QUrl url() const
Returns the found principal url.
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.
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
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
QDomNode appendChild(const QDomNode &newChild)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
TolerantMode
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
QString password(ComponentFormattingOptions options) const const
QString path(ComponentFormattingOptions options) const const
void setPath(const QString &path, ParsingMode mode)
QString toString(FormattingOptions 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 Tue Mar 26 2024 11:13:28 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.