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 | |
21 | using namespace KDAV; |
22 | |
23 | namespace KDAV |
24 | { |
25 | class DavItemsFetchJobPrivate : public DavJobBasePrivate |
26 | { |
27 | public: |
28 | void davJobFinished(KJob *job); |
29 | |
30 | DavUrl mCollectionUrl; |
31 | QStringList mUrls; |
32 | QMap<QString, DavItem> mItems; |
33 | }; |
34 | } |
35 | |
36 | DavItemsFetchJob::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 | |
44 | void 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 | |
63 | DavItem::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 | |
74 | DavItem DavItemsFetchJob::item(const QString &url) const |
75 | { |
76 | Q_D(const DavItemsFetchJob); |
77 | return d->mItems.value(key: url); |
78 | } |
79 | |
80 | void 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 | |