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"