File indexing completed on 2024-04-21 03:53:53

0001 /*
0002     SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
0003 
0004     Based on DavItemsListJob:
0005     SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "davitemsfetchjob.h"
0011 #include "davjobbase_p.h"
0012 
0013 #include "daverror.h"
0014 #include "davmanager_p.h"
0015 #include "davmultigetprotocol_p.h"
0016 #include "utils_p.h"
0017 
0018 #include <KIO/DavJob>
0019 #include <KIO/Job>
0020 
0021 using namespace KDAV;
0022 
0023 namespace KDAV
0024 {
0025 class DavItemsFetchJobPrivate : public DavJobBasePrivate
0026 {
0027 public:
0028     void davJobFinished(KJob *job);
0029 
0030     DavUrl mCollectionUrl;
0031     QStringList mUrls;
0032     QMap<QString, DavItem> mItems;
0033 };
0034 }
0035 
0036 DavItemsFetchJob::DavItemsFetchJob(const DavUrl &collectionUrl, const QStringList &urls, QObject *parent)
0037     : DavJobBase(new DavItemsFetchJobPrivate, parent)
0038 {
0039     Q_D(DavItemsFetchJob);
0040     d->mCollectionUrl = collectionUrl;
0041     d->mUrls = urls;
0042 }
0043 
0044 void DavItemsFetchJob::start()
0045 {
0046     Q_D(DavItemsFetchJob);
0047     const DavMultigetProtocol *protocol = dynamic_cast<const DavMultigetProtocol *>(DavManager::davProtocol(d->mCollectionUrl.protocol()));
0048     if (!protocol) {
0049         setError(ERR_NO_MULTIGET);
0050         d->setErrorTextFromDavError();
0051         emitResult();
0052         return;
0053     }
0054 
0055     const QDomDocument report = protocol->itemsReportQuery(d->mUrls)->buildQuery();
0056     KIO::DavJob *job = DavManager::self()->createReportJob(d->mCollectionUrl.url(), report.toString(), QStringLiteral("0"));
0057     job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
0058     connect(job, &KIO::DavJob::result, this, [d](KJob *job) {
0059         d->davJobFinished(job);
0060     });
0061 }
0062 
0063 DavItem::List DavItemsFetchJob::items() const
0064 {
0065     Q_D(const DavItemsFetchJob);
0066     DavItem::List values;
0067     values.reserve(d->mItems.size());
0068     for (const auto &value : std::as_const(d->mItems)) {
0069         values << value;
0070     }
0071     return values;
0072 }
0073 
0074 DavItem DavItemsFetchJob::item(const QString &url) const
0075 {
0076     Q_D(const DavItemsFetchJob);
0077     return d->mItems.value(url);
0078 }
0079 
0080 void DavItemsFetchJobPrivate::davJobFinished(KJob *job)
0081 {
0082     KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job);
0083     const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode"));
0084     const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt();
0085 
0086     // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx
0087     if (davJob->error() || (responseCode >= 400 && responseCode < 600)) {
0088         setLatestResponseCode(responseCode);
0089         setError(ERR_PROBLEM_WITH_REQUEST);
0090         setJobErrorText(davJob->errorText());
0091         setJobError(davJob->error());
0092         setErrorTextFromDavError();
0093 
0094         emitResult();
0095         return;
0096     }
0097 
0098     const DavMultigetProtocol *protocol = static_cast<const DavMultigetProtocol *>(DavManager::davProtocol(mCollectionUrl.protocol()));
0099 
0100     QDomDocument document;
0101     document.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing);
0102     const QDomElement documentElement = document.documentElement();
0103 
0104     QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response"));
0105 
0106     while (!responseElement.isNull()) {
0107         QDomElement propstatElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("propstat"));
0108 
0109         if (propstatElement.isNull()) {
0110             responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
0111             continue;
0112         }
0113 
0114         // Check for errors
0115         const QDomElement statusElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("status"));
0116         if (!statusElement.text().contains(QLatin1String("200"))) {
0117             responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
0118             continue;
0119         }
0120 
0121         const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop"));
0122 
0123         DavItem item;
0124 
0125         // extract path
0126         const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href"));
0127         const QString href = hrefElement.text();
0128 
0129         QUrl url = davJob->url();
0130         if (href.startsWith(QLatin1Char('/'))) {
0131             // href is only a path, use request url to complete
0132             url.setPath(href, QUrl::TolerantMode);
0133         } else {
0134             // href is a complete url
0135             url = QUrl::fromUserInput(href);
0136         }
0137 
0138         auto _url = url;
0139         _url.setUserInfo(mCollectionUrl.url().userInfo());
0140         item.setUrl(DavUrl(_url, mCollectionUrl.protocol()));
0141 
0142         // extract ETag
0143         const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag"));
0144         item.setEtag(getetagElement.text());
0145 
0146         // extract content
0147         const QDomElement dataElement = Utils::firstChildElementNS(propElement, protocol->responseNamespace(), protocol->dataTagName());
0148 
0149         if (dataElement.isNull()) {
0150             responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
0151             continue;
0152         }
0153 
0154         const QByteArray data = dataElement.firstChild().toText().data().toUtf8();
0155         if (data.isEmpty()) {
0156             responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
0157             continue;
0158         }
0159 
0160         item.setData(data);
0161 
0162         mItems.insert(item.url().toDisplayString(), item);
0163         responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
0164     }
0165 
0166     emitResult();
0167 }
0168 
0169 #include "moc_davitemsfetchjob.cpp"