File indexing completed on 2024-05-05 12:12:13

0001 /*
0002     SPDX-FileCopyrightText: 2010 Grégory Oestreicher <greg@kamago.net>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "davcollectionmodifyjob.h"
0008 #include "davjobbase_p.h"
0009 #include "davmanager_p.h"
0010 
0011 #include "daverror.h"
0012 #include "utils_p.h"
0013 
0014 #include <KIO/DavJob>
0015 #include <KIO/Job>
0016 
0017 using namespace KDAV;
0018 
0019 namespace KDAV
0020 {
0021 class DavCollectionModifyJobPrivate : public DavJobBasePrivate
0022 {
0023 public:
0024     void davJobFinished(KJob *job);
0025 
0026     DavUrl mUrl;
0027     QDomDocument mQuery;
0028 
0029     QVector<QDomElement> mSetProperties;
0030     QVector<QDomElement> mRemoveProperties;
0031 };
0032 }
0033 
0034 DavCollectionModifyJob::DavCollectionModifyJob(const DavUrl &url, QObject *parent)
0035     : DavJobBase(new DavCollectionModifyJobPrivate, parent)
0036 {
0037     Q_D(DavCollectionModifyJob);
0038     d->mUrl = url;
0039 }
0040 
0041 void DavCollectionModifyJob::setProperty(const QString &prop, const QString &value, const QString &ns)
0042 {
0043     Q_D(DavCollectionModifyJob);
0044     QDomElement propElement;
0045 
0046     if (ns.isEmpty()) {
0047         propElement = d->mQuery.createElement(prop);
0048     } else {
0049         propElement = d->mQuery.createElementNS(ns, prop);
0050     }
0051 
0052     const QDomText textElement = d->mQuery.createTextNode(value);
0053     propElement.appendChild(textElement);
0054 
0055     d->mSetProperties << propElement;
0056 }
0057 
0058 void DavCollectionModifyJob::removeProperty(const QString &prop, const QString &ns)
0059 {
0060     Q_D(DavCollectionModifyJob);
0061     QDomElement propElement;
0062 
0063     if (ns.isEmpty()) {
0064         propElement = d->mQuery.createElement(prop);
0065     } else {
0066         propElement = d->mQuery.createElementNS(ns, prop);
0067     }
0068 
0069     d->mRemoveProperties << propElement;
0070 }
0071 
0072 void DavCollectionModifyJob::start()
0073 {
0074     Q_D(DavCollectionModifyJob);
0075     if (d->mSetProperties.isEmpty() && d->mRemoveProperties.isEmpty()) {
0076         setError(ERR_COLLECTIONMODIFY_NO_PROPERITES);
0077         d->setErrorTextFromDavError();
0078         emitResult();
0079         return;
0080     }
0081 
0082     QDomDocument mQuery;
0083     QDomElement propertyUpdateElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propertyupdate"));
0084     mQuery.appendChild(propertyUpdateElement);
0085 
0086     if (!d->mSetProperties.isEmpty()) {
0087         QDomElement setElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("set"));
0088         propertyUpdateElement.appendChild(setElement);
0089 
0090         QDomElement propElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
0091         setElement.appendChild(propElement);
0092 
0093         for (const QDomElement &element : std::as_const(d->mSetProperties)) {
0094             propElement.appendChild(element);
0095         }
0096     }
0097 
0098     if (!d->mRemoveProperties.isEmpty()) {
0099         QDomElement removeElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("remove"));
0100         propertyUpdateElement.appendChild(removeElement);
0101 
0102         QDomElement propElement = mQuery.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
0103         removeElement.appendChild(propElement);
0104 
0105         for (const QDomElement &element : std::as_const(d->mSetProperties)) {
0106             propElement.appendChild(element);
0107         }
0108     }
0109 
0110     KIO::DavJob *job = DavManager::self()->createPropPatchJob(d->mUrl.url(), mQuery.toString());
0111     job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
0112     connect(job, &KIO::DavJob::result, this, [d](KJob *job) {
0113         d->davJobFinished(job);
0114     });
0115 }
0116 
0117 void DavCollectionModifyJobPrivate::davJobFinished(KJob *job)
0118 {
0119     KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job);
0120     const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode"));
0121     const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt();
0122 
0123     // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx
0124     if (davJob->error() || (responseCode >= 400 && responseCode < 600)) {
0125         setLatestResponseCode(responseCode);
0126         setError(ERR_COLLECTIONMODIFY);
0127         setJobErrorText(davJob->errorText());
0128         setJobError(davJob->error());
0129         setErrorTextFromDavError();
0130         emitResult();
0131         return;
0132     }
0133 
0134     QDomDocument response;
0135     response.setContent(davJob->responseData(), true);
0136     QDomElement responseElement = Utils::firstChildElementNS(response.documentElement(), QStringLiteral("DAV:"), QStringLiteral("response"));
0137 
0138     bool hasError = false;
0139 
0140     // parse all propstats answers to get the eventual errors
0141     const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat"));
0142     for (int i = 0; i < propstats.length(); ++i) {
0143         const QDomElement propstatElement = propstats.item(i).toElement();
0144         const QDomElement statusElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("status"));
0145 
0146         const QString statusText = statusElement.text();
0147         if (statusText.contains(QLatin1String("200"))) {
0148             continue;
0149         } else {
0150             // Generic error
0151             hasError = true;
0152             break;
0153         }
0154     }
0155 
0156     if (hasError) {
0157         setError(ERR_COLLECTIONMODIFY_RESPONSE);
0158 
0159         // Trying to get more information about the error
0160         const QDomElement responseDescriptionElement =
0161             Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("responsedescription"));
0162         if (!responseDescriptionElement.isNull()) {
0163             setJobErrorText(responseDescriptionElement.text());
0164         }
0165         setErrorTextFromDavError();
0166     }
0167 
0168     emitResult();
0169 }
0170 
0171 #include "moc_davcollectionmodifyjob.cpp"