1/*
2 SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
3
4 Based on DavItemsListJob:
5 SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "davitemsfetchjob.h"
11#include "davjobbase_p.h"
12
13#include "daverror.h"
14#include "davmanager_p.h"
15#include "davmultigetprotocol_p.h"
16#include "utils_p.h"
17
18#include <KIO/DavJob>
19#include <KIO/Job>
20
21using namespace KDAV;
22
23namespace KDAV
24{
25class DavItemsFetchJobPrivate : public DavJobBasePrivate
26{
27public:
28 void davJobFinished(KJob *job);
29
30 DavUrl mCollectionUrl;
31 QStringList mUrls;
32 QMap<QString, DavItem> mItems;
33};
34}
35
36DavItemsFetchJob::DavItemsFetchJob(const DavUrl &collectionUrl, const QStringList &urls, QObject *parent)
37 : DavJobBase(new DavItemsFetchJobPrivate, parent)
38{
39 Q_D(DavItemsFetchJob);
40 d->mCollectionUrl = collectionUrl;
41 d->mUrls = urls;
42}
43
44void DavItemsFetchJob::start()
45{
46 Q_D(DavItemsFetchJob);
47 const DavMultigetProtocol *protocol = dynamic_cast<const DavMultigetProtocol *>(DavManager::davProtocol(protocol: d->mCollectionUrl.protocol()));
48 if (!protocol) {
49 setError(ERR_NO_MULTIGET);
50 d->setErrorTextFromDavError();
51 emitResult();
52 return;
53 }
54
55 const QDomDocument report = protocol->itemsReportQuery(urls: d->mUrls)->buildQuery();
56 KIO::DavJob *job = DavManager::self()->createReportJob(url: d->mCollectionUrl.url(), document: report.toString(), QStringLiteral("0"));
57 job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
58 connect(sender: job, signal: &KIO::DavJob::result, context: this, slot: [d](KJob *job) {
59 d->davJobFinished(job);
60 });
61}
62
63DavItem::List DavItemsFetchJob::items() const
64{
65 Q_D(const DavItemsFetchJob);
66 DavItem::List values;
67 values.reserve(asize: d->mItems.size());
68 for (const auto &value : std::as_const(t: d->mItems)) {
69 values << value;
70 }
71 return values;
72}
73
74DavItem DavItemsFetchJob::item(const QString &url) const
75{
76 Q_D(const DavItemsFetchJob);
77 return d->mItems.value(key: url);
78}
79
80void DavItemsFetchJobPrivate::davJobFinished(KJob *job)
81{
82 KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(object: job);
83 const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode"));
84 const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt();
85
86 // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx
87 if (davJob->error() || (responseCode >= 400 && responseCode < 600)) {
88 setLatestResponseCode(responseCode);
89 setError(ERR_PROBLEM_WITH_REQUEST);
90 setJobErrorText(davJob->errorText());
91 setJobError(davJob->error());
92 setErrorTextFromDavError();
93
94 emitResult();
95 return;
96 }
97
98 const DavMultigetProtocol *protocol = static_cast<const DavMultigetProtocol *>(DavManager::davProtocol(protocol: mCollectionUrl.protocol()));
99
100 QDomDocument document;
101 document.setContent(data: davJob->responseData(), options: QDomDocument::ParseOption::UseNamespaceProcessing);
102 const QDomElement documentElement = document.documentElement();
103
104 QDomElement responseElement = Utils::firstChildElementNS(parent: documentElement, QStringLiteral("DAV:"), QStringLiteral("response"));
105
106 while (!responseElement.isNull()) {
107 QDomElement propstatElement = Utils::firstChildElementNS(parent: responseElement, QStringLiteral("DAV:"), QStringLiteral("propstat"));
108
109 if (propstatElement.isNull()) {
110 responseElement = Utils::nextSiblingElementNS(element: responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
111 continue;
112 }
113
114 // Check for errors
115 const QDomElement statusElement = Utils::firstChildElementNS(parent: propstatElement, QStringLiteral("DAV:"), QStringLiteral("status"));
116 if (!statusElement.text().contains(s: QLatin1String("200"))) {
117 responseElement = Utils::nextSiblingElementNS(element: responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
118 continue;
119 }
120
121 const QDomElement propElement = Utils::firstChildElementNS(parent: propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop"));
122
123 DavItem item;
124
125 // extract path
126 const QDomElement hrefElement = Utils::firstChildElementNS(parent: responseElement, QStringLiteral("DAV:"), QStringLiteral("href"));
127 const QString href = hrefElement.text();
128
129 QUrl url = davJob->url();
130 if (href.startsWith(c: QLatin1Char('/'))) {
131 // href is only a path, use request url to complete
132 url.setPath(path: href, mode: QUrl::TolerantMode);
133 } else {
134 // href is a complete url
135 url = QUrl::fromUserInput(userInput: href);
136 }
137
138 auto _url = url;
139 _url.setUserInfo(userInfo: mCollectionUrl.url().userInfo());
140 item.setUrl(DavUrl(_url, mCollectionUrl.protocol()));
141
142 // extract ETag
143 const QDomElement getetagElement = Utils::firstChildElementNS(parent: propElement, QStringLiteral("DAV:"), QStringLiteral("getetag"));
144 item.setEtag(getetagElement.text());
145
146 // extract content
147 const QDomElement dataElement = Utils::firstChildElementNS(parent: propElement, namespaceUri: protocol->responseNamespace(), tagName: protocol->dataTagName());
148
149 if (dataElement.isNull()) {
150 responseElement = Utils::nextSiblingElementNS(element: responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
151 continue;
152 }
153
154 const QByteArray data = dataElement.firstChild().toText().data().toUtf8();
155 if (data.isEmpty()) {
156 responseElement = Utils::nextSiblingElementNS(element: responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
157 continue;
158 }
159
160 item.setData(data);
161
162 mItems.insert(key: item.url().toDisplayString(), value: item);
163 responseElement = Utils::nextSiblingElementNS(element: responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
164 }
165
166 emitResult();
167}
168
169#include "moc_davitemsfetchjob.cpp"
170

source code of kdav/src/common/davitemsfetchjob.cpp