[frameworks/kdav] /: Port network management from KIO to QNAM
Kevin Ottens <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 96c39a58a16b6ac6f703e1f7a0a9e487728a8944 by Kevin Ottens, on behalf of Carl Schwan. Committed on 28/07/2026 at 19:47. Pushed by ervin into branch 'master'. Port network management from KIO to QNAM Allow to remove one abstraction layer as KIO is using QNAM in the background. Also this move KDAV from a tier 3 framework to a tier 2 framework Signed-off-by: Carl Schwan <[email protected]> M +2 -2 CMakeLists.txt M +2 -2 metainfo.yaml M +1 -1 src/CMakeLists.txt M +18 -22 src/common/davcollectioncreatejob.cpp M +15 -17 src/common/davcollectiondeletejob.cpp M +13 -16 src/common/davcollectionmodifyjob.cpp M +16 -19 src/common/davcollectionsfetchjob.cpp M +1 -10 src/common/daverror.cpp M +25 -33 src/common/davitemcreatejob.cpp M +17 -19 src/common/davitemdeletejob.cpp M +21 -38 src/common/davitemfetchjob.cpp M +22 -32 src/common/davitemmodifyjob.cpp M +14 -17 src/common/davitemsfetchjob.cpp M +22 -28 src/common/davitemslistjob.cpp M +48 -31 src/common/davmanager.cpp M +28 -18 src/common/davmanager_p.h M +13 -23 src/common/davprincipalhomesetsfetchjob.cpp M +33 -61 src/common/davprincipalsearchjob.cpp https://invent.kde.org/frameworks/kdav/-/commit/96c39a58a16b6ac6f703e1f7a0a9e487728a8944 diff --git a/CMakeLists.txt b/CMakeLists.txt index e3a61e3..edcac25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,9 +26,9 @@ include(ECMGenerateQDoc) set(REQUIRED_QT_VERSION 6.9.0) -find_package(Qt6 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core Gui Test) +find_package(Qt6 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core Gui Network Test Xml) -find_package(KF6 ${KF_DEP_VERSION} REQUIRED CoreAddons KIO I18n) +find_package(KF6 ${KF_DEP_VERSION} REQUIRED CoreAddons I18n) # setup lib diff --git a/metainfo.yaml b/metainfo.yaml index 83c1279..a783f69 100644 --- a/metainfo.yaml +++ b/metainfo.yaml @@ -1,7 +1,7 @@ maintainer: fancyname: KDAV description: An DAV protocol implementation with KJobs -tier: 3 +tier: 2 type: functional platforms: - name: All @@ -14,4 +14,4 @@ cmakename: KF6DAV public_lib: true group: Frameworks -subgroup: Tier 3 +subgroup: Tier 2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 547c7ce..49fbd48 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -149,7 +149,7 @@ PUBLIC PRIVATE Qt6::Xml Qt6::Gui - KF6::KIOCore + Qt6::Network KF6::I18n ) diff --git a/src/common/davcollectioncreatejob.cpp b/src/common/davcollectioncreatejob.cpp index c8ea4d4..08f81ea 100644 --- a/src/common/davcollectioncreatejob.cpp +++ b/src/common/davcollectioncreatejob.cpp @@ -9,10 +9,11 @@ #include "daverror.h" #include "davmanager_p.h" -#include <KIO/DavJob> -#include <KJob> #include <QColor> +#include <QNetworkReply> #include <QXmlStreamWriter> +#include <qnetworkreply.h> +#include <qnetworkrequest.h> using namespace KDAV; using namespace Qt::StringLiterals; @@ -22,7 +23,7 @@ namespace KDAV class DavCollectionCreateJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); DavCollection mCollection; int mRedirectCount = 0; @@ -54,10 +55,12 @@ void DavCollectionCreateJob::start() QXmlStreamWriter writer(&output); writer.setAutoFormatting(true); protocol->writeMkCol(writer, d->mCollection); + Q_ASSERT(output.startsWith(QStringLiteral("<?xml version=\"1.0\"?>\n"))); + output = output.mid(22); - auto job = DavManager::self()->createMkColJob(collectionUrl(), output); - connect(job, &KJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkReply *reply = DavManager::self()->createMkColJob(d->mCollection.url().url(), output); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } @@ -73,38 +76,31 @@ QUrl DavCollectionCreateJob::collectionUrl() const return d->mCollection.url().url(); } -void DavCollectionCreateJobPrivate::davJobFinished(KJob *job) +void DavCollectionCreateJobPrivate::davJobFinished(QNetworkReply *reply) { Q_Q(DavCollectionCreateJob); - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); - const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (davJob->error() || responseCode >= 400) { + if (reply->error() != QNetworkReply::NoError || responseCode >= 400) { setLatestResponseCode(responseCode); setError(ERR_COLLECTIONCREATE); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); emitResult(); return; } // The 'Location:' HTTP header is used to indicate the new URL - const QStringList allHeaders = davJob->queryMetaData(QStringLiteral("HTTP-Headers")).split(QLatin1Char('\n')); - QString location; - for (const QString &header : allHeaders) { - if (header.startsWith(QLatin1String("location:"), Qt::CaseInsensitive)) { - location = header.section(QLatin1Char(' '), 1); - } - } + const auto location = reply->header(QNetworkRequest::LocationHeader).toString(); QUrl url; if (location.isEmpty()) { - url = davJob->url(); + url = reply->url(); } else if (location.startsWith(QLatin1Char('/'))) { - url = davJob->url(); + url = reply->url(); url.setPath(location, QUrl::TolerantMode); } else { url = QUrl::fromUserInput(location); diff --git a/src/common/davcollectiondeletejob.cpp b/src/common/davcollectiondeletejob.cpp index b1dcc50..bb3ba03 100644 --- a/src/common/davcollectiondeletejob.cpp +++ b/src/common/davcollectiondeletejob.cpp @@ -8,9 +8,10 @@ #include "davjobbase_p.h" #include "daverror.h" +#include "davmanager_p.h" -#include <KIO/DeleteJob> -#include <KIO/Job> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; @@ -19,7 +20,7 @@ namespace KDAV class DavCollectionDeleteJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); DavUrl mUrl; }; @@ -35,29 +36,26 @@ DavCollectionDeleteJob::DavCollectionDeleteJob(const DavUrl &url, QObject *paren void DavCollectionDeleteJob::start() { Q_D(DavCollectionDeleteJob); - KIO::DeleteJob *job = KIO::del(d->mUrl.url(), KIO::HideProgressInfo | KIO::DefaultFlags); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + QNetworkRequest request(d->mUrl.url()); + request.setHeader(QNetworkRequest::UserAgentHeader, DavManager::self()->userAgent()); - connect(job, &KIO::DeleteJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkReply *reply = DavManager::self()->networkAccessManager()->deleteResource(request); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } -void DavCollectionDeleteJobPrivate::davJobFinished(KJob *job) +void DavCollectionDeleteJobPrivate::davJobFinished(QNetworkReply *reply) { - KIO::DeleteJob *deleteJob = qobject_cast<KIO::DeleteJob *>(job); + reply->deleteLater(); - if (deleteJob->error() && deleteJob->error() != KIO::ERR_NO_CONTENT) { - const int responseCode = deleteJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // - ? 0 - : deleteJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + if (reply->error() != QNetworkReply::NoError) { + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); setLatestResponseCode(responseCode); setError(ERR_COLLECTIONDELETE); - setJobErrorText(deleteJob->errorText()); - setJobError(deleteJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); } diff --git a/src/common/davcollectionmodifyjob.cpp b/src/common/davcollectionmodifyjob.cpp index 75951d2..dc146f8 100644 --- a/src/common/davcollectionmodifyjob.cpp +++ b/src/common/davcollectionmodifyjob.cpp @@ -11,8 +11,8 @@ #include "daverror.h" #include "utils_p.h" -#include <KIO/DavJob> -#include <KIO/Job> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; @@ -21,7 +21,7 @@ namespace KDAV class DavCollectionModifyJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); DavUrl mUrl; QDomDocument mQuery; @@ -107,32 +107,29 @@ void DavCollectionModifyJob::start() } } - KIO::DavJob *job = DavManager::self()->createPropPatchJob(d->mUrl.url(), mQuery.toString()); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - connect(job, &KIO::DavJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkReply *reply = DavManager::self()->createPropPatchJob(d->mUrl.url(), mQuery.toString()); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } -void DavCollectionModifyJobPrivate::davJobFinished(KJob *job) +void DavCollectionModifyJobPrivate::davJobFinished(QNetworkReply *reply) { - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); - const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx - if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + if (reply->error() != QNetworkReply::NoError || (responseCode >= 400 && responseCode < 600)) { setLatestResponseCode(responseCode); setError(ERR_COLLECTIONMODIFY); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); emitResult(); return; } QDomDocument response; - response.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing); + response.setContent(reply->readAll(), QDomDocument::ParseOption::UseNamespaceProcessing); QDomElement responseElement = Utils::firstChildElementNS(response.documentElement(), QStringLiteral("DAV:"), QStringLiteral("response")); bool hasError = false; diff --git a/src/common/davcollectionsfetchjob.cpp b/src/common/davcollectionsfetchjob.cpp index 3ecd06d..ce84441 100644 --- a/src/common/davcollectionsfetchjob.cpp +++ b/src/common/davcollectionsfetchjob.cpp @@ -15,11 +15,11 @@ #include "libkdav_debug.h" #include <KDAV/DavPushSupport> -#include <KIO/DavJob> -#include <KIO/Job> #include <QBuffer> #include <QColor> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; @@ -29,7 +29,7 @@ class DavCollectionsFetchJobPrivate : public DavJobBasePrivate { public: void principalFetchFinished(KJob *job); - void collectionsFetchFinished(KJob *job); + void collectionsFetchFinished(QNetworkReply *reply, const QUrl &requestUrl); void doCollectionsFetch(const QUrl &url); void subjobFinished(); @@ -80,11 +80,10 @@ void DavCollectionsFetchJobPrivate::doCollectionsFetch(const QUrl &url) const QDomDocument collectionQuery = DavManager::davProtocol(mUrl.protocol())->collectionsQuery()->buildQuery(); - KIO::DavJob *job = DavManager::self()->createPropFindJob(url, collectionQuery.toString()); - QObject::connect(job, &KIO::DavJob::result, q_ptr, [this](KJob *job) { - collectionsFetchFinished(job); + QNetworkReply *reply = DavManager::self()->createPropFindJob(url, collectionQuery.toString()); + QObject::connect(reply, &QNetworkReply::finished, q_ptr, [this, reply, url]() { + collectionsFetchFinished(reply, url); }); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); } void DavCollectionsFetchJobPrivate::principalFetchFinished(KJob *job) @@ -134,16 +133,14 @@ void DavCollectionsFetchJobPrivate::principalFetchFinished(KJob *job) } } -void DavCollectionsFetchJobPrivate::collectionsFetchFinished(KJob *job) +void DavCollectionsFetchJobPrivate::collectionsFetchFinished(QNetworkReply *reply, const QUrl &requestUrl) { Q_Q(DavCollectionsFetchJob); - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); - const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx - if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { - if (davJob->url() != mUrl.url()) { + if (reply->error() != QNetworkReply::NoError || (responseCode >= 400 && responseCode < 600)) { + if (requestUrl != mUrl.url()) { // Retry as if the initial URL was a calendar URL. // We can end up here when retrieving a homeset on // which a PROPFIND resulted in an error @@ -154,8 +151,8 @@ void DavCollectionsFetchJobPrivate::collectionsFetchFinished(KJob *job) setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); } else { // For use in the collectionDiscovered() signal @@ -164,8 +161,9 @@ void DavCollectionsFetchJobPrivate::collectionsFetchFinished(KJob *job) const QString jobUrl = _jobUrl.toDisplayString(); // Validate that we got a valid PROPFIND response + const QByteArray resp = reply->readAll(); QDomDocument response; - response.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing); + response.setContent(resp, QDomDocument::ParseOption::UseNamespaceProcessing); QDomElement rootElement = response.documentElement(); if (rootElement.tagName().compare(QLatin1String("multistatus"), Qt::CaseInsensitive) != 0) { setError(ERR_COLLECTIONFETCH); @@ -174,7 +172,6 @@ void DavCollectionsFetchJobPrivate::collectionsFetchFinished(KJob *job) return; } - QByteArray resp = davJob->responseData(); QDomDocument document; if (!document.setContent(resp, QDomDocument::ParseOption::UseNamespaceProcessing)) { setError(ERR_COLLECTIONFETCH); @@ -253,7 +250,7 @@ void DavCollectionsFetchJobPrivate::collectionsFetchFinished(KJob *job) href.append(QLatin1Char('/')); } - QUrl url = davJob->url(); + QUrl url = requestUrl; url.setUserInfo(QString()); if (href.startsWith(QLatin1Char('/'))) { // href is only a path, use request url to complete diff --git a/src/common/daverror.cpp b/src/common/daverror.cpp index cb1aba8..2e135f8 100644 --- a/src/common/daverror.cpp +++ b/src/common/daverror.cpp @@ -7,9 +7,6 @@ #include "daverror.h" #include <KLocalizedString> -#include <KIO/Global> -#include <KIO/Job> - using namespace KDAV; namespace KDAV @@ -66,13 +63,7 @@ int Error::responseCode() const QString KDAV::Error::translatedJobError() const { - QString err; - if (d->mJobErrorCode > 0 && d->mJobErrorCode != KIO::ERR_WORKER_DEFINED) { - err = KIO::buildErrorString(d->mJobErrorCode, d->mErrorText); - } else { - err = d->mErrorText; - } - return err; + return d->mErrorText; } QString Error::errorText() const diff --git a/src/common/davitemcreatejob.cpp b/src/common/davitemcreatejob.cpp index f7d05ae..b54ac55 100644 --- a/src/common/davitemcreatejob.cpp +++ b/src/common/davitemcreatejob.cpp @@ -9,18 +9,20 @@ #include "daverror.h" #include "davitemfetchjob.h" +#include "davmanager_p.h" -#include <KIO/DavJob> -#include <KIO/StoredTransferJob> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; +using namespace Qt::StringLiterals; namespace KDAV { class DavItemCreateJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); void itemRefreshed(KJob *job); DavItem mItem; @@ -40,20 +42,15 @@ DavItemCreateJob::DavItemCreateJob(const DavItem &item, QObject *parent) void DavItemCreateJob::start() { Q_D(DavItemCreateJob); - QString headers = QStringLiteral("Content-Type: "); - headers += d->mItem.contentType(); - headers += QLatin1String("\r\n"); - headers += QLatin1String("If-None-Match: *"); - - KIO::StoredTransferJob *job = KIO::storedPut(d->mItem.data(), itemUrl(), -1, KIO::HideProgressInfo | KIO::DefaultFlags); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - job->addMetaData(QStringLiteral("customHTTPHeader"), headers); - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); - job->setRedirectionHandlingEnabled(false); - - connect(job, &KIO::StoredTransferJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkRequest request(itemUrl()); + request.setHeader(QNetworkRequest::ContentTypeHeader, d->mItem.contentType()); + request.setHeader(QNetworkRequest::IfNoneMatchHeader, u"*"_s); + request.setHeader(QNetworkRequest::UserAgentHeader, DavManager::self()->userAgent()); + request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy); + + QNetworkReply *reply = DavManager::self()->networkAccessManager()->put(request, d->mItem.data()); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } @@ -69,17 +66,18 @@ QUrl DavItemCreateJob::itemUrl() const return d->mItem.url().url(); } -void DavItemCreateJobPrivate::davJobFinished(KJob *job) +void DavItemCreateJobPrivate::davJobFinished(QNetworkReply *reply) { Q_Q(DavItemCreateJob); - KIO::StoredTransferJob *storedJob = qobject_cast<KIO::StoredTransferJob *>(job); - const QString responseCodeStr = storedJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); - if (storedJob->error()) { + reply->deleteLater(); + + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (reply->error() != QNetworkReply::NoError) { setLatestResponseCode(responseCode); setError(ERR_ITEMCREATE); - setJobErrorText(storedJob->errorText()); - setJobError(storedJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); emitResult(); @@ -87,19 +85,13 @@ void DavItemCreateJobPrivate::davJobFinished(KJob *job) } // The 'Location:' HTTP header is used to indicate the new URL - const QStringList allHeaders = storedJob->queryMetaData(QStringLiteral("HTTP-Headers")).split(QLatin1Char('\n')); - QString location; - for (const QString &header : allHeaders) { - if (header.startsWith(QLatin1String("location:"), Qt::CaseInsensitive)) { - location = header.section(QLatin1Char(' '), 1); - } - } + const QString location = reply->header(QNetworkRequest::LocationHeader).toString(); QUrl url; if (location.isEmpty()) { - url = storedJob->url(); + url = reply->url(); } else if (location.startsWith(QLatin1Char('/'))) { - url = storedJob->url(); + url = reply->url(); url.setPath(location, QUrl::TolerantMode); } else { url = QUrl::fromUserInput(location); diff --git a/src/common/davitemdeletejob.cpp b/src/common/davitemdeletejob.cpp index 39f51d5..a627e0b 100644 --- a/src/common/davitemdeletejob.cpp +++ b/src/common/davitemdeletejob.cpp @@ -11,8 +11,8 @@ #include "davitemfetchjob.h" #include "davmanager_p.h" -#include <KIO/DeleteJob> -#include <KIO/Job> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; @@ -21,7 +21,7 @@ namespace KDAV class DavItemDeleteJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); void conflictingItemFetched(KJob *job); DavItem mItem; @@ -40,14 +40,13 @@ DavItemDeleteJob::DavItemDeleteJob(const DavItem &item, QObject *parent) void DavItemDeleteJob::start() { Q_D(DavItemDeleteJob); - KIO::DeleteJob *job = KIO::del(d->mItem.url().url(), KIO::HideProgressInfo | KIO::DefaultFlags); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("If-Match: ") + d->mItem.etag()); - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); - - connect(job, &KIO::DeleteJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkRequest request(d->mItem.url().url()); + request.setHeader(QNetworkRequest::IfMatchHeader, d->mItem.etag()); + request.setHeader(QNetworkRequest::UserAgentHeader, DavManager::self()->userAgent()); + + QNetworkReply *reply = DavManager::self()->networkAccessManager()->deleteResource(request); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } @@ -63,20 +62,19 @@ int DavItemDeleteJob::freshResponseCode() const return d->mFreshResponseCode; } -void DavItemDeleteJobPrivate::davJobFinished(KJob *job) +void DavItemDeleteJobPrivate::davJobFinished(QNetworkReply *reply) { - KIO::DeleteJob *deleteJob = qobject_cast<KIO::DeleteJob *>(job); + reply->deleteLater(); - if (deleteJob->error() && deleteJob->error() != KIO::ERR_NO_CONTENT) { - const int responseCode = deleteJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // - ? 0 - : deleteJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + if (reply->error() != QNetworkReply::NoError) { + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + // 404 and 410 mean the item is already gone, treat as success if (responseCode != 404 && responseCode != 410) { setLatestResponseCode(responseCode); setError(ERR_ITEMDELETE); - setJobErrorText(deleteJob->errorText()); - setJobError(deleteJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); } diff --git a/src/common/davitemfetchjob.cpp b/src/common/davitemfetchjob.cpp index 8365dfa..60c011c 100644 --- a/src/common/davitemfetchjob.cpp +++ b/src/common/davitemfetchjob.cpp @@ -8,9 +8,10 @@ #include "davjobbase_p.h" #include "daverror.h" +#include "davmanager_p.h" -#include <KIO/DavJob> -#include <KIO/StoredTransferJob> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; namespace KDAV @@ -18,27 +19,13 @@ namespace KDAV class DavItemFetchJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); DavUrl mUrl; DavItem mItem; }; } -static QString etagFromHeaders(const QString &headers) -{ - const QStringList allHeaders = headers.split(QLatin1Char('\n')); - - QString etag; - for (const QString &header : allHeaders) { - if (header.startsWith(QLatin1String("etag:"), Qt::CaseInsensitive)) { - etag = header.section(QLatin1Char(' '), 1); - } - } - - return etag; -} - DavItemFetchJob::DavItemFetchJob(const DavItem &item, QObject *parent) : DavJobBase(new DavItemFetchJobPrivate, parent) { @@ -49,17 +36,12 @@ DavItemFetchJob::DavItemFetchJob(const DavItem &item, QObject *parent) void DavItemFetchJob::start() { Q_D(DavItemFetchJob); - KIO::StoredTransferJob *job = KIO::storedGet(d->mItem.url().url(), KIO::Reload, KIO::HideProgressInfo | KIO::DefaultFlags); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - // Work around a strange bug in Zimbra (seen at least on CE 5.0.18) : if the user-agent - // contains "Mozilla", some strange debug data is displayed in the shared calendars. - // This kinda mess up the events parsing... - job->addMetaData(QStringLiteral("UserAgent"), QStringLiteral("KDE DAV groupware client")); - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); + QNetworkRequest request(d->mItem.url().url()); + request.setHeader(QNetworkRequest::UserAgentHeader, DavManager::self()->userAgent()); - connect(job, &KIO::StoredTransferJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkReply *reply = DavManager::self()->networkAccessManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } @@ -69,24 +51,25 @@ DavItem DavItemFetchJob::item() const return d->mItem; } -void DavItemFetchJobPrivate::davJobFinished(KJob *job) +void DavItemFetchJobPrivate::davJobFinished(QNetworkReply *reply) { - KIO::StoredTransferJob *storedJob = qobject_cast<KIO::StoredTransferJob *>(job); - const QString responseCodeStr = storedJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); setLatestResponseCode(responseCode); - if (storedJob->error()) { - setLatestResponseCode(responseCode); + if (reply->error() != QNetworkReply::NoError) { setError(ERR_PROBLEM_WITH_REQUEST); - setJobErrorText(storedJob->errorText()); - setJobError(storedJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); } else { - mItem.setData(storedJob->data()); - mItem.setContentType(storedJob->queryMetaData(QStringLiteral("content-type"))); - mItem.setEtag(etagFromHeaders(storedJob->queryMetaData(QStringLiteral("HTTP-Headers")))); + mItem.setData(reply->readAll()); + // Strip optional parameters like "; charset=utf-8" from the content type + const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString().section(QLatin1Char(';'), 0, 0).trimmed(); + mItem.setContentType(contentType); + // reply->header(QNetworkRequest::ETagHeader) returns invalid in the unit test + mItem.setEtag(QString::fromUtf8(reply->rawHeader("etag"))); } emitResult(); diff --git a/src/common/davitemmodifyjob.cpp b/src/common/davitemmodifyjob.cpp index 94aafa3..3965847 100644 --- a/src/common/davitemmodifyjob.cpp +++ b/src/common/davitemmodifyjob.cpp @@ -9,16 +9,19 @@ #include "daverror.h" #include "davitemfetchjob.h" +#include "davmanager_p.h" -#include <KIO/StoredTransferJob> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; + namespace KDAV { class DavItemModifyJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); void itemRefreshed(KJob *job); void conflictingItemFetched(KJob *job); @@ -40,19 +43,14 @@ DavItemModifyJob::DavItemModifyJob(const DavItem &item, QObject *parent) void DavItemModifyJob::start() { Q_D(DavItemModifyJob); - QString headers = QStringLiteral("Content-Type: "); - headers += d->mItem.contentType(); - headers += QLatin1String("\r\n"); - headers += QLatin1String("If-Match: ") + d->mItem.etag(); - - KIO::StoredTransferJob *job = KIO::storedPut(d->mItem.data(), itemUrl(), -1, KIO::HideProgressInfo | KIO::DefaultFlags); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - job->addMetaData(QStringLiteral("customHTTPHeader"), headers); - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); - - connect(job, &KIO::StoredTransferJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkRequest request(itemUrl()); + request.setHeader(QNetworkRequest::ContentTypeHeader, d->mItem.contentType()); + request.setHeader(QNetworkRequest::IfMatchHeader, d->mItem.etag()); + request.setHeader(QNetworkRequest::UserAgentHeader, DavManager::self()->userAgent()); + + QNetworkReply *reply = DavManager::self()->networkAccessManager()->put(request, d->mItem.data()); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } @@ -80,20 +78,18 @@ QUrl DavItemModifyJob::itemUrl() const return d->mItem.url().url(); } -void DavItemModifyJobPrivate::davJobFinished(KJob *job) +void DavItemModifyJobPrivate::davJobFinished(QNetworkReply *reply) { Q_Q(DavItemModifyJob); - KIO::StoredTransferJob *storedJob = qobject_cast<KIO::StoredTransferJob *>(job); + reply->deleteLater(); - if (storedJob->error()) { - const int responseCode = storedJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // - ? 0 - : storedJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + if (reply->error() != QNetworkReply::NoError) { + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); setLatestResponseCode(responseCode); setError(ERR_ITEMMODIFY); - setJobErrorText(storedJob->errorText()); - setJobError(storedJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); if (q->hasConflict()) { @@ -110,19 +106,13 @@ void DavItemModifyJobPrivate::davJobFinished(KJob *job) } // The 'Location:' HTTP header is used to indicate the new URL - const QStringList allHeaders = storedJob->queryMetaData(QStringLiteral("HTTP-Headers")).split(QLatin1Char('\n')); - QString location; - for (const QString &header : allHeaders) { - if (header.startsWith(QLatin1String("location:"), Qt::CaseInsensitive)) { - location = header.section(QLatin1Char(' '), 1); - } - } + const QString location = reply->header(QNetworkRequest::LocationHeader).toString(); QUrl url; if (location.isEmpty()) { - url = storedJob->url(); + url = reply->url(); } else if (location.startsWith(QLatin1Char('/'))) { - url = storedJob->url(); + url = reply->url(); url.setPath(location, QUrl::TolerantMode); } else { url = QUrl::fromUserInput(location); diff --git a/src/common/davitemsfetchjob.cpp b/src/common/davitemsfetchjob.cpp index 29a820b..efd9442 100644 --- a/src/common/davitemsfetchjob.cpp +++ b/src/common/davitemsfetchjob.cpp @@ -15,8 +15,8 @@ #include "davmultigetprotocol_p.h" #include "utils_p.h" -#include <KIO/DavJob> -#include <KIO/Job> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; @@ -25,7 +25,7 @@ namespace KDAV class DavItemsFetchJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); DavUrl mCollectionUrl; QStringList mUrls; @@ -59,10 +59,9 @@ void DavItemsFetchJob::start() // bug in Zoho Calendar which violates the RFC by honouring Depth: 0 // returning the collection resource itself instead of the explicitly // requested item hrefs. - KIO::DavJob *job = DavManager::self()->createReportJob(d->mCollectionUrl.url(), report.toString(), QStringLiteral("1")); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - connect(job, &KIO::DavJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkReply *reply = DavManager::self()->createReportJob(d->mCollectionUrl.url(), report.toString(), QStringLiteral("1")); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } @@ -83,18 +82,16 @@ DavItem DavItemsFetchJob::item(const QString &url) const return d->mItems.value(url); } -void DavItemsFetchJobPrivate::davJobFinished(KJob *job) +void DavItemsFetchJobPrivate::davJobFinished(QNetworkReply *reply) { - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); - const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx - if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + if (reply->error() != QNetworkReply::NoError || (responseCode >= 400 && responseCode < 600)) { setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); emitResult(); @@ -104,7 +101,7 @@ void DavItemsFetchJobPrivate::davJobFinished(KJob *job) const DavMultigetProtocol *protocol = static_cast<const DavMultigetProtocol *>(DavManager::davProtocol(mCollectionUrl.protocol())); QDomDocument document; - document.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing); + document.setContent(reply->readAll(), QDomDocument::ParseOption::UseNamespaceProcessing); const QDomElement documentElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); @@ -132,7 +129,7 @@ void DavItemsFetchJobPrivate::davJobFinished(KJob *job) const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); const QString href = hrefElement.text(); - QUrl url = davJob->url(); + QUrl url = reply->url(); if (href.startsWith(QLatin1Char('/'))) { // href is only a path, use request url to complete url.setPath(href, QUrl::TolerantMode); diff --git a/src/common/davitemslistjob.cpp b/src/common/davitemslistjob.cpp index 9cc4ca9..94154cf 100644 --- a/src/common/davitemslistjob.cpp +++ b/src/common/davitemslistjob.cpp @@ -15,9 +15,8 @@ #include "libkdav_debug.h" #include "utils_p.h" -#include <KIO/DavJob> -#include <KIO/Job> - +#include <QNetworkReply> +#include <QNetworkRequest> #include <set> using namespace KDAV; @@ -27,7 +26,7 @@ namespace KDAV class DavItemsListJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); DavUrl mUrl; std::shared_ptr<EtagCache> mEtagCache; @@ -86,20 +85,18 @@ void DavItemsListJob::start() if (d->mMimeTypes.isEmpty() || d->mMimeTypes.contains(mimeType)) { ++d->mSubJobCount; if (protocol->useReport()) { - KIO::DavJob *job = DavManager::self()->createReportJob(d->mUrl.url(), props.toString()); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - job->setProperty("davType", QStringLiteral("report")); - job->setProperty("itemsMimeType", mimeType); - connect(job, &KIO::DavJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkReply *reply = DavManager::self()->createReportJob(d->mUrl.url(), props.toString()); + reply->setProperty("davType", QStringLiteral("report")); + reply->setProperty("itemsMimeType", mimeType); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } else { - KIO::DavJob *job = DavManager::self()->createPropFindJob(d->mUrl.url(), props.toString()); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - job->setProperty("davType", QStringLiteral("propFind")); - job->setProperty("itemsMimeType", mimeType); - connect(job, &KIO::DavJob::result, this, [d](KJob *job) { - d->davJobFinished(job); + QNetworkReply *reply = DavManager::self()->createPropFindJob(d->mUrl.url(), props.toString()); + reply->setProperty("davType", QStringLiteral("propFind")); + reply->setProperty("itemsMimeType", mimeType); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->davJobFinished(reply); }); } } @@ -130,19 +127,16 @@ QStringList DavItemsListJob::deletedItems() const return d->mDeletedItems; } -void DavItemsListJobPrivate::davJobFinished(KJob *job) +void DavItemsListJobPrivate::davJobFinished(QNetworkReply *reply) { - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); - const int responseCode = davJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() // - ? 0 - : davJob->queryMetaData(QStringLiteral("responsecode")).toInt(); + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx - if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + if (reply->error() != QNetworkReply::NoError || (responseCode >= 400 && responseCode < 600)) { setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); } else { /* @@ -170,9 +164,9 @@ void DavItemsListJobPrivate::davJobFinished(KJob *job) * </multistatus> */ - const QString itemsMimeType = job->property("itemsMimeType").toString(); + const QString itemsMimeType = reply->property("itemsMimeType").toString(); QDomDocument document; - document.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing); + document.setContent(reply->readAll(), QDomDocument::ParseOption::UseNamespaceProcessing); const QDomElement documentElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); @@ -216,7 +210,7 @@ void DavItemsListJobPrivate::davJobFinished(KJob *job) const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); const QString href = hrefElement.text(); - QUrl url = davJob->url(); + QUrl url = reply->url(); url.setUserInfo(QString()); if (href.startsWith(QLatin1Char('/'))) { // href is only a path, use request url to complete diff --git a/src/common/davmanager.cpp b/src/common/davmanager.cpp index df9944b..210a342 100644 --- a/src/common/davmanager.cpp +++ b/src/common/davmanager.cpp @@ -10,15 +10,30 @@ #include "protocols/carddavprotocol_p.h" #include "protocols/groupdavprotocol_p.h" -#include <KIO/DavJob> - #include "libkdav_debug.h" +#include <QAuthenticator> +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> #include <QUrl> +#include <qnetworkreply.h> using namespace KDAV; +using namespace Qt::StringLiterals; + +DavManager::DavManager() + : mNam(std::make_unique<QNetworkAccessManager>()) +{ + QObject::connect(mNam.get(), &QNetworkAccessManager::authenticationRequired, [](QNetworkReply *reply, QAuthenticator *auth) { + const QUrl url = reply->request().url(); + if (!url.userName().isEmpty()) { + auth->setUser(url.userName()); + auth->setPassword(url.password()); + } + }); +} -DavManager::DavManager() = default; DavManager::~DavManager() = default; DavManager *DavManager::self() @@ -27,46 +42,40 @@ DavManager *DavManager::self() return &sSelf; } -KIO::DavJob *DavManager::createPropFindJob(const QUrl &url, const QString &document, const QString &depth) const +QNetworkReply *DavManager::createPropFindJob(const QUrl &url, const QString &document, const QString &depth) const { - KIO::DavJob *job = KIO::davPropFind(url, document, depth, KIO::HideProgressInfo | KIO::DefaultFlags); - - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); - job->setProperty("davDepth", QVariant::fromValue(depth)); - - return job; + return sendDavRequest("PROPFIND", url, document, depth); } -KIO::DavJob *DavManager::createReportJob(const QUrl &url, const QString &document, const QString &depth) const +QNetworkReply *DavManager::createReportJob(const QUrl &url, const QString &document, const QString &depth) const { - KIO::DavJob *job = KIO::davReport(url, document, depth, KIO::HideProgressInfo | KIO::DefaultFlags); + return sendDavRequest("REPORT", url, document, depth); +} - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); - job->setProperty("davDepth", QVariant::fromValue(depth)); +QNetworkReply *DavManager::createPropPatchJob(const QUrl &url, const QString &document) const +{ + return sendDavRequest("PROPPATCH", url, document); +} - return job; +QNetworkReply *DavManager::createMkColJob(const QUrl &url, const QString &document) const +{ + return sendDavRequest("MKCOL", url, document); } -KIO::DavJob *DavManager::createPropPatchJob(const QUrl &url, const QString &document) const +QNetworkAccessManager *DavManager::networkAccessManager() const { - KIO::DavJob *job = KIO::davPropPatch(url, document, KIO::HideProgressInfo | KIO::DefaultFlags); - const QString header = QStringLiteral("Content-Type: text/xml"); - job->addMetaData(QStringLiteral("customHTTPHeader"), header); - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); - return job; + return mNam.get(); } -KIO::DavJob *DavManager::createMkColJob(const QUrl &url, const QString &document) const +QNetworkReply *DavManager::sendDavRequest(const QByteArray &method, const QUrl &url, const QString &document, const QString &depth) const { - KIO::DavJob *job = KIO::davMkCol(url, document, KIO::HideProgressInfo | KIO::DefaultFlags); - const QString header = QStringLiteral("Content-Type: text/xml"); - job->addMetaData(QStringLiteral("customHTTPHeader"), header); - job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); - job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); - return job; + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, u"text/xml; charset=utf-8"_s); + if (!depth.isEmpty()) { + request.setRawHeader("Depth", depth.toUtf8()); + } + request.setHeader(QNetworkRequest::UserAgentHeader, userAgent()); + return mNam->sendCustomRequest(request, method, document.toUtf8()); } const DavProtocolBase *DavManager::davProtocol(Protocol protocol) @@ -91,3 +100,11 @@ const DavProtocolBase *DavManager::davProtocol(Protocol protocol) return d->mProtocols[protocol].get(); } + +QString DavManager::userAgent() const +{ + // Work around a strange bug in Zimbra (seen at least on CE 5.0.18) : if the user-agent + // contains "Mozilla", some strange debug data is displayed in the shared calendars. + // This kinda mess up the events parsing... + return u"KDE DAV groupware client"_s; +} diff --git a/src/common/davmanager_p.h b/src/common/davmanager_p.h index 29c9e3f..211517b 100644 --- a/src/common/davmanager_p.h +++ b/src/common/davmanager_p.h @@ -13,11 +13,8 @@ #include <memory> -namespace KIO -{ -class DavJob; -} - +class QNetworkAccessManager; +class QNetworkReply; class QUrl; namespace KDAV @@ -29,7 +26,7 @@ class DavProtocolBase; * \brief A factory class for handling DAV jobs. * * This class provides factory methods to create preconfigured - * low-level DAV jobs and has access to the global DAV protocol dialect + * low-level DAV network replies and has access to the global DAV protocol dialect * objects which abstract the access to the various DAV protocol dialects. */ class DavManager @@ -46,41 +43,51 @@ public: static DavManager *self(); /*! - * Returns a preconfigured DAV PROPFIND job. + * Sends a DAV PROPFIND request and returns the network reply. * - * \a url The target URL of the job. + * \a url The target URL of the request. * * \a document The query XML document. * * \a depth The Depth: value to send in the HTTP request */ - KIO::DavJob *createPropFindJob(const QUrl &url, const QString &document, const QString &depth = QStringLiteral("1")) const; + QNetworkReply *createPropFindJob(const QUrl &url, const QString &document, const QString &depth = QStringLiteral("1")) const; /*! - * Returns a preconfigured DAV REPORT job. + * Sends a DAV REPORT request and returns the network reply. * - * \a url The target URL of the job. + * \a url The target URL of the request. * \a document The query XML document. * \a depth The Depth: value to send in the HTTP request */ - KIO::DavJob *createReportJob(const QUrl &url, const QString &document, const QString &depth = QStringLiteral("1")) const; + QNetworkReply *createReportJob(const QUrl &url, const QString &document, const QString &depth = QStringLiteral("1")) const; /*! - * Returns a preconfigured DAV PROPPATCH job. + * Sends a DAV PROPPATCH request and returns the network reply. * - * \a url The target URL of the job. + * \a url The target URL of the request. * \a document The query XML document. */ - KIO::DavJob *createPropPatchJob(const QUrl &url, const QString &document) const; + QNetworkReply *createPropPatchJob(const QUrl &url, const QString &document) const; /*! - * Returns a preconfigured DAV MKCOL job. + * Returns a preconfigured DAV MKCOL reply. * - * \a url The target URL of the job. + * \a url The target URL of the request. * * \a document The query XML document. */ - KIO::DavJob *createMkColJob(const QUrl &url, const QString &document) const; + QNetworkReply *createMkColJob(const QUrl &url, const QString &document) const; + + /*! + * Returns the shared QNetworkAccessManager instance. + */ + QNetworkAccessManager *networkAccessManager() const; + + /*! + * Returns the user agent. + */ + QString userAgent() const; /*! * Returns the DAV protocol dialect object for the given DAV @p protocol. @@ -93,6 +100,9 @@ private: */ DavManager(); + QNetworkReply *sendDavRequest(const QByteArray &method, const QUrl &url, const QString &document, const QString &depth = {}) const; + + mutable std::unique_ptr<QNetworkAccessManager> mNam; std::unique_ptr<DavProtocolBase> mProtocols[3]; }; } diff --git a/src/common/davprincipalhomesetsfetchjob.cpp b/src/common/davprincipalhomesetsfetchjob.cpp index 04b6da7..7d95142 100644 --- a/src/common/davprincipalhomesetsfetchjob.cpp +++ b/src/common/davprincipalhomesetsfetchjob.cpp @@ -13,8 +13,8 @@ #include "protocolinfo.h" #include "utils_p.h" -#include <KIO/DavJob> -#include <KIO/Job> +#include <QNetworkReply> +#include <QNetworkRequest> using namespace KDAV; @@ -23,7 +23,7 @@ namespace KDAV class DavPrincipalHomeSetsFetchJobPrivate : public DavJobBasePrivate { public: - void davJobFinished(KJob *job); + void davJobFinished(QNetworkReply *reply); /* * Start the fetch process. * @@ -75,10 +75,9 @@ void DavPrincipalHomeSetsFetchJobPrivate::fetchHomeSets(bool homeSetsOnly) propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-URL"))); } - KIO::DavJob *job = DavManager::self()->createPropFindJob(mUrl.url(), document.toString(), QStringLiteral("0")); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - QObject::connect(job, &KIO::DavJob::result, q_ptr, [this](KJob *job) { - davJobFinished(job); + QNetworkReply *reply = DavManager::self()->createPropFindJob(mUrl.url(), document.toString(), QStringLiteral("0")); + QObject::connect(reply, &QNetworkReply::finished, q_ptr, [this, reply]() { + davJobFinished(reply); }); } @@ -88,25 +87,16 @@ QStringList DavPrincipalHomeSetsFetchJob::homeSets() const return d->mHomeSets; } -void DavPrincipalHomeSetsFetchJobPrivate::davJobFinished(KJob *job) +void DavPrincipalHomeSetsFetchJobPrivate::davJobFinished(QNetworkReply *reply) { - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); - const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); - - // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx - if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { - QString err; - if (davJob->error() && davJob->error() != KIO::ERR_WORKER_DEFINED) { - err = KIO::buildErrorString(davJob->error(), davJob->errorText()); - } else { - err = davJob->errorText(); - } + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (reply->error() != QNetworkReply::NoError || (responseCode >= 400 && responseCode < 600)) { setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); emitResult(); @@ -161,7 +151,7 @@ void DavPrincipalHomeSetsFetchJobPrivate::davJobFinished(KJob *job) // This is either given by current-user-principal or by principal-URL. QDomDocument document; - document.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing); + document.setContent(reply->readAll(), QDomDocument::ParseOption::UseNamespaceProcessing); const QDomElement multistatusElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(multistatusElement, QStringLiteral("DAV:"), QStringLiteral("response")); diff --git a/src/common/davprincipalsearchjob.cpp b/src/common/davprincipalsearchjob.cpp index d846838..7ce08ee 100644 --- a/src/common/davprincipalsearchjob.cpp +++ b/src/common/davprincipalsearchjob.cpp @@ -11,8 +11,8 @@ #include "davmanager_p.h" #include "utils_p.h" -#include <KIO/DavJob> -#include <KIO/Job> +#include <QNetworkReply> +#include <QNetworkRequest> #include <QUrl> @@ -24,8 +24,8 @@ class DavPrincipalSearchJobPrivate : public DavJobBasePrivate { public: void buildReportQuery(QDomDocument &query) const; - void principalCollectionSetSearchFinished(KJob *job); - void principalPropertySearchFinished(KJob *job); + void principalCollectionSetSearchFinished(QNetworkReply *reply); + void principalPropertySearchFinished(QNetworkReply *reply); DavUrl mUrl; DavPrincipalSearchJob::FilterType mType; @@ -86,38 +86,28 @@ void DavPrincipalSearchJob::start() QDomElement principalCollectionSet = query.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-collection-set")); prop.appendChild(principalCollectionSet); - KIO::DavJob *job = DavManager::self()->createPropFindJob(d->mUrl.url(), query.toString()); - job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - connect(job, &KIO::DavJob::result, this, [d](KJob *job) { - d->principalCollectionSetSearchFinished(job); + QNetworkReply *reply = DavManager::self()->createPropFindJob(d->mUrl.url(), query.toString()); + connect(reply, &QNetworkReply::finished, this, [d, reply]() { + d->principalCollectionSetSearchFinished(reply); }); - job->start(); } -void DavPrincipalSearchJobPrivate::principalCollectionSetSearchFinished(KJob *job) +void DavPrincipalSearchJobPrivate::principalCollectionSetSearchFinished(QNetworkReply *reply) { - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); - const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); - const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); - // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx - if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { + reply->deleteLater(); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (reply->error() != QNetworkReply::NoError || (responseCode >= 400 && responseCode < 600)) { setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); + setJobErrorText(reply->errorString()); + setJobError(reply->error()); setErrorTextFromDavError(); emitResult(); return; } - if (job->error()) { - setError(job->error()); - setErrorText(job->errorText()); - emitResult(); - return; - } - /* * Extract information from a document like the following: * @@ -139,7 +129,7 @@ void DavPrincipalSearchJobPrivate::principalCollectionSetSearchFinished(KJob *jo */ QDomDocument document; - document.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing); + document.setContent(reply->readAll(), QDomDocument::ParseOption::UseNamespaceProcessing); QDomElement documentElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); @@ -197,51 +187,33 @@ void DavPrincipalSearchJobPrivate::principalCollectionSetSearchFinished(KJob *jo QDomDocument principalPropertySearchQuery; buildReportQuery(principalPropertySearchQuery); - KIO::DavJob *reportJob = DavManager::self()->createReportJob(url, principalPropertySearchQuery.toString()); - reportJob->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); - QObject::connect(reportJob, &KIO::DavJob::result, q_ptr, [this](KJob *job) { - principalPropertySearchFinished(job); + QNetworkReply *reportReply = DavManager::self()->createReportJob(url, principalPropertySearchQuery.toString()); + QObject::connect(reportReply, &QNetworkReply::finished, q_ptr, [this, reportReply]() { + principalPropertySearchFinished(reportReply); }); ++mPrincipalPropertySearchSubJobCount; - reportJob->start(); } } -void DavPrincipalSearchJobPrivate::principalPropertySearchFinished(KJob *job) +void DavPrincipalSearchJobPrivate::principalPropertySearchFinished(QNetworkReply *reply) { + reply->deleteLater(); --mPrincipalPropertySearchSubJobCount; - if (job->error() && !mPrincipalPropertySearchSubJobSuccessful) { - setError(job->error()); - setErrorText(job->errorText()); - if (mPrincipalPropertySearchSubJobCount == 0) { - emitResult(); - } - return; - } - - KIO::DavJob *davJob = qobject_cast<KIO::DavJob *>(job); + const int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - const int responseCode = davJob->queryMetaData(QStringLiteral("responsecode")).toInt(); - - if (responseCode > 499 && responseCode < 600 && !mPrincipalPropertySearchSubJobSuccessful) { - // Server-side error, unrecoverable - setLatestResponseCode(responseCode); - setError(ERR_SERVER_UNRECOVERABLE); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); - setErrorTextFromDavError(); - if (mPrincipalPropertySearchSubJobCount == 0) { - emitResult(); + if (reply->error() != QNetworkReply::NoError || (responseCode >= 400 && responseCode < 600)) { + if (!mPrincipalPropertySearchSubJobSuccessful) { + setLatestResponseCode(responseCode); + if (responseCode >= 500) { + setError(ERR_SERVER_UNRECOVERABLE); + } else { + setError(ERR_PROBLEM_WITH_REQUEST); + } + setJobErrorText(reply->errorString()); + setJobError(reply->error()); + setErrorTextFromDavError(); } - return; - } else if (responseCode > 399 && responseCode < 500 && !mPrincipalPropertySearchSubJobSuccessful) { - setLatestResponseCode(responseCode); - setError(ERR_PROBLEM_WITH_REQUEST); - setJobErrorText(davJob->errorText()); - setJobError(davJob->error()); - setErrorTextFromDavError(); - if (mPrincipalPropertySearchSubJobCount == 0) { emitResult(); } @@ -269,7 +241,7 @@ void DavPrincipalSearchJobPrivate::principalPropertySearchFinished(KJob *job) */ QDomDocument document; - document.setContent(davJob->responseData(), QDomDocument::ParseOption::UseNamespaceProcessing); + document.setContent(reply->readAll(), QDomDocument::ParseOption::UseNamespaceProcessing); const QDomElement documentElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response"));