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

0001 /*
0002     SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "davitemmodifyjob.h"
0008 #include "davjobbase_p.h"
0009 
0010 #include "daverror.h"
0011 #include "davitemfetchjob.h"
0012 
0013 #include <KIO/StoredTransferJob>
0014 
0015 using namespace KDAV;
0016 namespace KDAV
0017 {
0018 class DavItemModifyJobPrivate : public DavJobBasePrivate
0019 {
0020 public:
0021     void davJobFinished(KJob *job);
0022     void itemRefreshed(KJob *job);
0023     void conflictingItemFetched(KJob *job);
0024 
0025     DavItem mItem;
0026     DavItem mFreshItem;
0027     int mFreshResponseCode = 0;
0028 
0029     Q_DECLARE_PUBLIC(DavItemModifyJob)
0030 };
0031 }
0032 
0033 DavItemModifyJob::DavItemModifyJob(const DavItem &item, QObject *parent)
0034     : DavJobBase(new DavItemModifyJobPrivate, parent)
0035 {
0036     Q_D(DavItemModifyJob);
0037     d->mItem = item;
0038 }
0039 
0040 void DavItemModifyJob::start()
0041 {
0042     Q_D(DavItemModifyJob);
0043     QString headers = QStringLiteral("Content-Type: ");
0044     headers += d->mItem.contentType();
0045     headers += QLatin1String("\r\n");
0046     headers += QLatin1String("If-Match: ") + d->mItem.etag();
0047 
0048     KIO::StoredTransferJob *job = KIO::storedPut(d->mItem.data(), itemUrl(), -1, KIO::HideProgressInfo | KIO::DefaultFlags);
0049     job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true"));
0050     job->addMetaData(QStringLiteral("customHTTPHeader"), headers);
0051     job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none"));
0052     job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true"));
0053 
0054     connect(job, &KIO::StoredTransferJob::result, this, [d](KJob *job) {
0055         d->davJobFinished(job);
0056     });
0057 }
0058 
0059 DavItem DavItemModifyJob::item() const
0060 {
0061     Q_D(const DavItemModifyJob);
0062     return d->mItem;
0063 }
0064 
0065 DavItem DavItemModifyJob::freshItem() const
0066 {
0067     Q_D(const DavItemModifyJob);
0068     return d->mFreshItem;
0069 }
0070 
0071 int DavItemModifyJob::freshResponseCode() const
0072 {
0073     Q_D(const DavItemModifyJob);
0074     return d->mFreshResponseCode;
0075 }
0076 
0077 QUrl DavItemModifyJob::itemUrl() const
0078 {
0079     Q_D(const DavItemModifyJob);
0080     return d->mItem.url().url();
0081 }
0082 
0083 void DavItemModifyJobPrivate::davJobFinished(KJob *job)
0084 {
0085     Q_Q(DavItemModifyJob);
0086     KIO::StoredTransferJob *storedJob = qobject_cast<KIO::StoredTransferJob *>(job);
0087 
0088     if (storedJob->error()) {
0089         const int responseCode = storedJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() //
0090             ? 0
0091             : storedJob->queryMetaData(QStringLiteral("responsecode")).toInt();
0092 
0093         setLatestResponseCode(responseCode);
0094         setError(ERR_ITEMMODIFY);
0095         setJobErrorText(storedJob->errorText());
0096         setJobError(storedJob->error());
0097         setErrorTextFromDavError();
0098 
0099         if (q->hasConflict()) {
0100             DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem);
0101             QObject::connect(fetchJob, &DavItemFetchJob::result, q, [this](KJob *job) {
0102                 conflictingItemFetched(job);
0103             });
0104             fetchJob->start();
0105         } else {
0106             emitResult();
0107         }
0108 
0109         return;
0110     }
0111 
0112     // The 'Location:' HTTP header is used to indicate the new URL
0113     const QStringList allHeaders = storedJob->queryMetaData(QStringLiteral("HTTP-Headers")).split(QLatin1Char('\n'));
0114     QString location;
0115     for (const QString &header : allHeaders) {
0116         if (header.startsWith(QLatin1String("location:"), Qt::CaseInsensitive)) {
0117             location = header.section(QLatin1Char(' '), 1);
0118         }
0119     }
0120 
0121     QUrl url;
0122     if (location.isEmpty()) {
0123         url = storedJob->url();
0124     } else if (location.startsWith(QLatin1Char('/'))) {
0125         url = storedJob->url();
0126         url.setPath(location, QUrl::TolerantMode);
0127     } else {
0128         url = QUrl::fromUserInput(location);
0129     }
0130 
0131     url.setUserInfo(q->itemUrl().userInfo());
0132     mItem.setUrl(DavUrl(url, mItem.url().protocol()));
0133 
0134     DavItemFetchJob *fetchJob = new DavItemFetchJob(mItem);
0135     QObject::connect(fetchJob, &DavItemFetchJob::result, q, [this](KJob *job) {
0136         itemRefreshed(job);
0137     });
0138     fetchJob->start();
0139 }
0140 
0141 void DavItemModifyJobPrivate::itemRefreshed(KJob *job)
0142 {
0143     if (!job->error()) {
0144         DavItemFetchJob *fetchJob = qobject_cast<DavItemFetchJob *>(job);
0145         mItem.setEtag(fetchJob->item().etag());
0146     } else {
0147         mItem.setEtag(QString());
0148     }
0149     emitResult();
0150 }
0151 
0152 void DavItemModifyJobPrivate::conflictingItemFetched(KJob *job)
0153 {
0154     DavItemFetchJob *fetchJob = qobject_cast<DavItemFetchJob *>(job);
0155     mFreshResponseCode = fetchJob->latestResponseCode();
0156 
0157     if (!job->error()) {
0158         mFreshItem = fetchJob->item();
0159     }
0160 
0161     emitResult();
0162 }
0163 
0164 #include "moc_davitemmodifyjob.cpp"