[frameworks/kdav] /: Add fetching DavPush data in DavCollectionsFetchJob
Dominique MICHEL <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 69d31019eef975e0ad9661e7f367528ba7761b5f by Dominique MICHEL.
Committed on 24/07/2026 at 08:12.
Pushed by aloeil into branch 'master'.
Add fetching DavPush data in DavCollectionsFetchJob
M +19 -2 autotests/data/dataitemmultifetchjob-caldav-collections.txt
M +19 -2 autotests/data/davcollectionsfetchjob-caldav-color-collections.txt
M +4 -1 autotests/data/davcollectionsfetchjob-collection-homeset-404.txt
M +4 -1 autotests/data/davcollectionsfetchjob-fallback-404.txt
M +5 -0 autotests/davcollectionsmultifetchjobtest.cpp
M +16 -0 autotests/davcollectiontest.cpp
M +3 -0 src/CMakeLists.txt
M +12 -0 src/common/davcollection.cpp
M +15 -0 src/common/davcollection.h
M +7 -0 src/common/davcollectionsfetchjob.cpp
A +65 -0 src/common/davpushsupport.cpp [License: LGPL(v2.0+)]
A +82 -0 src/common/davpushsupport.h [License: LGPL(v2.0+)]
M +27 -0 src/common/utils.cpp
M +12 -0 src/common/utils_p.h
M +9 -1 src/protocols/caldavprotocol.cpp
https://invent.kde.org/frameworks/kdav/-/commit/69d31019eef975e0ad9661e7f367528ba7761b5f
diff --git a/autotests/data/dataitemmultifetchjob-caldav-collections.txt b/autotests/data/dataitemmultifetchjob-caldav-collections.txt
index dce8f56..2b44fa1 100644
--- a/autotests/data/dataitemmultifetchjob-caldav-collections.txt
+++ b/autotests/data/dataitemmultifetchjob-caldav-collections.txt
@@ -1,6 +1,6 @@
C: PROPFIND /caldav/dfaure%40example.com/ HTTP/1.1
B: <?xml version="1.0" encoding="utf-8"?>
-B: <propfind xmlns="DAV:">
+B: <propfind xmlns="DAV:" xmlns:P="https://bitfire.at/webdav-push">
B: <prop xmlns="DAV:">
B: <displayname xmlns="DAV:"/>
B: <resourcetype xmlns="DAV:"/>
@@ -8,6 +8,9 @@ B: <calendar-color xmlns="http://apple.com/ns/ical/"/>
B: <supported-calendar-component-set xmlns="urn:ietf:params:xml:ns:caldav"/>
B: <current-user-privilege-set xmlns="DAV:"/>
B: <getctag xmlns="http://calendarserver.org/ns/"/>
+B: <P:transports xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:topic xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:supported-triggers xmlns:P="https://bitfire.at/webdav-push"/>
B: </prop>
B: </propfind>
S: HTTP/1.0 207 Multi-Status
@@ -16,7 +19,7 @@ S: Last-Modified: Wed, 04 Jan 2017 18:26:47 GMT
S: DAV: 1, 3, extended-mkcol, access-control, calendarserver-principal-property-search, calendar-access, calendar-proxy, calendar-schedule, calendar-auto-schedule, addressbook, 2
S: Content-Type: application/xml; charset=utf-8
D: <?xml version="1.0" encoding="utf-8" ?>
-D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
+D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:P="https://bitfire.at/webdav-push">
D: <response xmlns="DAV:">
D: <href xmlns="DAV:">/caldav.php/test1.user/home/</href>
D: <propstat xmlns="DAV:">
@@ -40,6 +43,20 @@ D: <read xmlns="DAV:"/>
D: </privilege>
D: </current-user-privilege-set>
D: <getctag xmlns="http://calendarserver.org/ns/">12345</getctag>
+D: <P:transports>
+D: <P:web-push>
+D: <P:vapid-public-key type="p256ecdsa">TXlWYXBpZFB1YmxpY0tleQ</P:vapid-public-key>
+D: </P:web-push>
+D: </P:transports>
+D: <P:topic>MyTopic-1</P:topic>
+D: <P:supported-triggers>
+D: <P:content-update>
+D: <depth>1</depth>
+D: </P:content-update>
+D: <P:property-update>
+D: <depth>0</depth>
+D: </P:property-update>
+D: </P:supported-triggers>
D: </prop>
D: <status xmlns="DAV:">HTTP/1.1 200 OK</status>
D: </propstat>
diff --git a/autotests/data/davcollectionsfetchjob-caldav-color-collections.txt b/autotests/data/davcollectionsfetchjob-caldav-color-collections.txt
index 278475d..8824451 100644
--- a/autotests/data/davcollectionsfetchjob-caldav-color-collections.txt
+++ b/autotests/data/davcollectionsfetchjob-caldav-color-collections.txt
@@ -1,6 +1,6 @@
C: PROPFIND /caldav/dfaure%40example.com/ HTTP/1.1
B: <?xml version="1.0" encoding="utf-8"?>
-B: <propfind xmlns="DAV:">
+B: <propfind xmlns="DAV:" xmlns:P="https://bitfire.at/webdav-push">
B: <prop xmlns="DAV:">
B: <displayname xmlns="DAV:"/>
B: <resourcetype xmlns="DAV:"/>
@@ -8,12 +8,15 @@ B: <calendar-color xmlns="http://apple.com/ns/ical/"/>
B: <supported-calendar-component-set xmlns="urn:ietf:params:xml:ns:caldav"/>
B: <current-user-privilege-set xmlns="DAV:"/>
B: <getctag xmlns="http://calendarserver.org/ns/"/>
+B: <P:transports xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:topic xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:supported-triggers xmlns:P="https://bitfire.at/webdav-push"/>
B: </prop>
B: </propfind>
S: HTTP/1.0 207 Multi-Status
S: Content-Type: application/xml; charset=utf-8
D: <?xml version="1.0" encoding="utf-8" ?>
-D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:ical="http://apple.com/ns/ical/">
+D: <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:ical="http://apple.com/ns/ical/" xmlns:P="https://bitfire.at/webdav-push">
D: <response xmlns="DAV:">
D: <href xmlns="DAV:">/caldav.php/test1.user/home/</href>
D: <propstat xmlns="DAV:">
@@ -28,6 +31,20 @@ D: </resourcetype>
D: <displayname xmlns="DAV:">Color Calendar</displayname>
D: <ical:calendar-color xmlns:ical="http://apple.com/ns/ical/">#FF0000FF</ical:calendar-color>
D: <getctag xmlns="http://calendarserver.org/ns/">99999</getctag>
+D: <P:transports>
+D: <P:web-push>
+D: <P:vapid-public-key>MyVapidPublicKey</P:vapid-public-key>
+D: </P:web-push>
+D: </P:transports>
+D: <P:topic>MyTopic-1</P:topic>
+D: <P:supported-triggers>
+D: <P:content-update>
+D: <depth>1</depth>
+D: </P:content-update>
+D: <P:property-update>
+D: <depth>0</depth>
+D: </P:property-update>
+D: </P:supported-triggers>
D: </prop>
D: <status xmlns="DAV:">HTTP/1.1 200 OK</status>
D: </propstat>
diff --git a/autotests/data/davcollectionsfetchjob-collection-homeset-404.txt b/autotests/data/davcollectionsfetchjob-collection-homeset-404.txt
index 9b2e8e1..35a547f 100644
--- a/autotests/data/davcollectionsfetchjob-collection-homeset-404.txt
+++ b/autotests/data/davcollectionsfetchjob-collection-homeset-404.txt
@@ -1,6 +1,6 @@
C: PROPFIND /caldav/dfaure%40example.com/ HTTP/1.1
B: <?xml version="1.0" encoding="utf-8"?>
-B: <propfind xmlns="DAV:">
+B: <propfind xmlns="DAV:" xmlns:P="https://bitfire.at/webdav-push">
B: <prop xmlns="DAV:">
B: <displayname xmlns="DAV:"/>
B: <resourcetype xmlns="DAV:"/>
@@ -8,6 +8,9 @@ B: <calendar-color xmlns="http://apple.com/ns/ical/"/>
B: <supported-calendar-component-set xmlns="urn:ietf:params:xml:ns:caldav"/>
B: <current-user-privilege-set xmlns="DAV:"/>
B: <getctag xmlns="http://calendarserver.org/ns/"/>
+B: <P:transports xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:topic xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:supported-triggers xmlns:P="https://bitfire.at/webdav-push"/>
B: </prop>
B: </propfind>
S: HTTP/1.1 404 Not Found
diff --git a/autotests/data/davcollectionsfetchjob-fallback-404.txt b/autotests/data/davcollectionsfetchjob-fallback-404.txt
index 431dd26..1554d65 100644
--- a/autotests/data/davcollectionsfetchjob-fallback-404.txt
+++ b/autotests/data/davcollectionsfetchjob-fallback-404.txt
@@ -1,6 +1,6 @@
C: PROPFIND /caldav HTTP/1.1
B: <?xml version="1.0" encoding="utf-8"?>
-B: <propfind xmlns="DAV:">
+B: <propfind xmlns="DAV:" xmlns:P="https://bitfire.at/webdav-push">
B: <prop xmlns="DAV:">
B: <displayname xmlns="DAV:"/>
B: <resourcetype xmlns="DAV:"/>
@@ -8,6 +8,9 @@ B: <calendar-color xmlns="http://apple.com/ns/ical/"/>
B: <supported-calendar-component-set xmlns="urn:ietf:params:xml:ns:caldav"/>
B: <current-user-privilege-set xmlns="DAV:"/>
B: <getctag xmlns="http://calendarserver.org/ns/"/>
+B: <P:transports xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:topic xmlns:P="https://bitfire.at/webdav-push"/>
+B: <P:supported-triggers xmlns:P="https://bitfire.at/webdav-push"/>
B: </prop>
B: </propfind>
S: HTTP/1.1 404 Not Found
diff --git a/autotests/davcollectionsmultifetchjobtest.cpp b/autotests/davcollectionsmultifetchjobtest.cpp
index 6d895c2..66afeae 100644
--- a/autotests/davcollectionsmultifetchjobtest.cpp
+++ b/autotests/davcollectionsmultifetchjobtest.cpp
@@ -8,6 +8,7 @@
#include "fakeserver.h"
#include <KDAV/DavCollectionsMultiFetchJob>
+#include <KDAV/DavPushSupport>
#include <QSignalSpy>
#include <QTest>
@@ -60,6 +61,10 @@ void DavCollectionsMultiFetchJobTest::runSuccessfullTest()
QCOMPARE(calendar.url().url().path(), QStringLiteral("/caldav.php/test1.user/home/"));
QCOMPARE(calendar.CTag(), QStringLiteral("12345"));
QCOMPARE(calendar.privileges(), KDAV::Read);
+ auto davPush = KDAV::DavPushSupport();
+ davPush.setTopic(QStringLiteral("MyTopic-1"));
+ davPush.setVapidPublicKey("TXlWYXBpZFB1YmxpY0tleQ");
+ QCOMPARE(calendar.davPushSupport(), davPush);
const KDAV::DavCollection addressbook = collections.at(cardDavIdx);
QCOMPARE(addressbook.displayName(), QStringLiteral("My Address Book"));
diff --git a/autotests/davcollectiontest.cpp b/autotests/davcollectiontest.cpp
index ce28f99..67cbefb 100644
--- a/autotests/davcollectiontest.cpp
+++ b/autotests/davcollectiontest.cpp
@@ -7,6 +7,7 @@
#include "davcollectiontest.h"
#include <KDAV/DavCollection>
+#include <KDAV/DavPushSupport>
#include <KDAV/DavUrl>
#include <QColor>
@@ -22,6 +23,7 @@ void DavCollectionTest::createEmpty()
QCOMPARE(davCollection.color(), QColor());
QCOMPARE(davCollection.contentTypes(), KDAV::DavCollection::ContentTypes());
QCOMPARE(davCollection.privileges(), KDAV::Privileges());
+ QCOMPARE(davCollection.davPushSupport(), KDAV::DavPushSupport());
}
void DavCollectionTest::storeTest()
@@ -43,6 +45,11 @@ void DavCollectionTest::setTest()
{
QUrl url(QStringLiteral("test://me:pw@test"));
KDAV::DavUrl davUrl(url, KDAV::CardDav);
+
+ KDAV::DavPushSupport davPush{};
+ davPush.setVapidPublicKey("TXlWYXBpZFB1YmxpY0tleQ");
+ davPush.setTopic(QLatin1StringView("Topic"));
+
KDAV::DavCollection davCollection;
davCollection.setUrl(davUrl);
@@ -51,6 +58,7 @@ void DavCollectionTest::setTest()
davCollection.setColor(QColor(1, 2, 3));
davCollection.setContentTypes(KDAV::DavCollection::Events | KDAV::DavCollection::Todos);
davCollection.setPrivileges(KDAV::Read | KDAV::Write);
+ davCollection.setDavPushSupport(davPush);
QCOMPARE(davCollection.url().protocol(), KDAV::CardDav);
QCOMPARE(davCollection.url().url(), url);
@@ -59,6 +67,7 @@ void DavCollectionTest::setTest()
QCOMPARE(davCollection.color(), QColor(1, 2, 3));
QCOMPARE(davCollection.contentTypes(), KDAV::DavCollection::Events | KDAV::DavCollection::Todos);
QCOMPARE(davCollection.privileges(), KDAV::Read | KDAV::Write);
+ QCOMPARE(davCollection.davPushSupport(), davPush);
}
void DavCollectionTest::copyTest()
@@ -68,12 +77,17 @@ void DavCollectionTest::copyTest()
QUrl url(QStringLiteral("test://me:pw@test"));
KDAV::DavUrl davUrl(url, KDAV::CardDav);
+ KDAV::DavPushSupport davPush{};
+ davPush.setVapidPublicKey("TXlWYXBpZFB1YmxpY0tleQ");
+ davPush.setTopic(QLatin1StringView("Topic"));
+
davCollection.setUrl(davUrl);
davCollection.setCTag(QStringLiteral("ctag"));
davCollection.setDisplayName(QStringLiteral("myname"));
davCollection.setColor(QColor(1, 2, 3));
davCollection.setContentTypes(KDAV::DavCollection::Events | KDAV::DavCollection::Todos);
davCollection.setPrivileges(KDAV::Read | KDAV::Write);
+ davCollection.setDavPushSupport(davPush);
KDAV::DavCollection copy1(davCollection);
QCOMPARE(copy1.url().protocol(), davCollection.url().protocol());
@@ -83,6 +97,7 @@ void DavCollectionTest::copyTest()
QCOMPARE(copy1.color(), davCollection.color());
QCOMPARE(copy1.contentTypes(), davCollection.contentTypes());
QCOMPARE(copy1.privileges(), davCollection.privileges());
+ QCOMPARE(copy1.davPushSupport(), davPush);
KDAV::DavCollection copy2;
copy2 = davCollection;
@@ -94,6 +109,7 @@ void DavCollectionTest::copyTest()
QCOMPARE(copy2.color(), davCollection.color());
QCOMPARE(copy2.contentTypes(), davCollection.contentTypes());
QCOMPARE(copy2.privileges(), davCollection.privileges());
+ QCOMPARE(copy2.davPushSupport(), davPush);
}
QTEST_MAIN(DavCollectionTest)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fe910d4..547c7ce 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -14,6 +14,8 @@ set_target_properties(KF6DAV PROPERTIES
target_sources(KF6DAV PRIVATE
common/davcollection.cpp
common/davcollection.h
+ common/davpushsupport.cpp
+ common/davpushsupport.h
common/davcollectioncreatejob.cpp
common/davcollectioncreatejob.h
common/davcollectiondeletejob.cpp
@@ -80,6 +82,7 @@ ecm_generate_headers(KDAV_Camelcase_HEADERS
HEADER_NAMES
DavJobBase
DavCollection
+ DavPushSupport
DavCollectionDeleteJob
DavCollectionsFetchJob
DavCollectionCreateJob
diff --git a/src/common/davcollection.cpp b/src/common/davcollection.cpp
index 0ede17c..c25e011 100644
--- a/src/common/davcollection.cpp
+++ b/src/common/davcollection.cpp
@@ -7,6 +7,7 @@
#include "davcollection.h"
+#include "davpushsupport.h"
#include "davurl.h"
#include <QColor>
@@ -23,6 +24,7 @@ public:
QColor mColor;
Privileges mPrivileges;
QByteArray mTimeZone;
+ DavPushSupport mDavPushSupport;
};
DavCollection::DavCollection()
@@ -114,3 +116,13 @@ QByteArray DavCollection::timeZone() const
{
return d->mTimeZone;
}
+
+void DavCollection::setDavPushSupport(const DavPushSupport &pushSupport)
+{
+ d->mDavPushSupport = pushSupport;
+}
+
+DavPushSupport DavCollection::davPushSupport() const
+{
+ return d->mDavPushSupport;
+}
diff --git a/src/common/davcollection.h b/src/common/davcollection.h
index 4af1eca..2860a4a 100644
--- a/src/common/davcollection.h
+++ b/src/common/davcollection.h
@@ -21,6 +21,7 @@ class DavCollectionPrivate;
namespace KDAV
{
+class DavPushSupport;
class DavUrl;
}
@@ -170,6 +171,20 @@ public:
*/
[[nodiscard]] QByteArray timeZone() const;
+ /*!
+ * Sets the DavPushSupport on this calendar collection.
+ *
+ * \since 6.29
+ */
+ void setDavPushSupport(const DavPushSupport &pushSupport);
+
+ /*!
+ * Returns the DavPushSupport of this calendar collection, is Null if not set.
+ *
+ * \since 6.29
+ */
+ [[nodiscard]] DavPushSupport davPushSupport() const;
+
private:
QSharedDataPointer<DavCollectionPrivate> d;
};
diff --git a/src/common/davcollectionsfetchjob.cpp b/src/common/davcollectionsfetchjob.cpp
index 7de7251..3ecd06d 100644
--- a/src/common/davcollectionsfetchjob.cpp
+++ b/src/common/davcollectionsfetchjob.cpp
@@ -14,6 +14,7 @@
#include "utils_p.h"
#include "libkdav_debug.h"
+#include <KDAV/DavPushSupport>
#include <KIO/DavJob>
#include <KIO/Job>
@@ -335,6 +336,12 @@ void DavCollectionsFetchJobPrivate::collectionsFetchFinished(KJob *job)
collection.setPrivileges(privileges);
}
+ // Extract Dav Push notification information
+ auto pushSupport = Utils::extractDavPushSupport(propElement);
+ if (pushSupport) {
+ collection.setDavPushSupport(*pushSupport);
+ }
+
qCDebug(KDAV_LOG) << url.toDisplayString() << "PRIVS: " << collection.privileges();
mCollections << collection;
Q_EMIT q->collectionDiscovered(mUrl.protocol(), url.toDisplayString(), jobUrl);
diff --git a/src/common/davpushsupport.cpp b/src/common/davpushsupport.cpp
new file mode 100644
index 0000000..a9cb66f
--- /dev/null
+++ b/src/common/davpushsupport.cpp
@@ -0,0 +1,65 @@
+/*
+ SPDX-FileCopyrightText: 2026 Dominique Michel <[email protected]>
+
+ SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "davpushsupport.h"
+
+using namespace KDAV;
+
+class DavPushSupportPrivate : public QSharedData
+{
+public:
+ bool operator==(const DavPushSupportPrivate &rhs) const;
+
+public:
+ QString topic;
+ QByteArray vapidPublicKey;
+};
+
+bool DavPushSupportPrivate::operator==(const DavPushSupportPrivate &rhs) const
+{
+ return std::tie(topic, vapidPublicKey) == std::tie(rhs.topic, rhs.vapidPublicKey);
+}
+
+DavPushSupport::DavPushSupport()
+ : d(new DavPushSupportPrivate)
+{
+}
+
+DavPushSupport::DavPushSupport(const DavPushSupport &other) = default;
+DavPushSupport::DavPushSupport(DavPushSupport &&) = default;
+DavPushSupport &DavPushSupport::operator=(const DavPushSupport &other) = default;
+DavPushSupport &DavPushSupport::operator=(DavPushSupport &&) = default;
+DavPushSupport::~DavPushSupport() = default;
+
+bool DavPushSupport::operator==(const DavPushSupport &other) const
+{
+ return (*d) == (*other.d);
+}
+
+bool DavPushSupport::isValid() const
+{
+ return !d->topic.isEmpty();
+}
+
+void DavPushSupport::setTopic(const QString &topic)
+{
+ d->topic = topic;
+}
+
+QString DavPushSupport::topic() const
+{
+ return d->topic;
+}
+
+void DavPushSupport::setVapidPublicKey(const QByteArray &vapidPublicKey)
+{
+ d->vapidPublicKey = vapidPublicKey;
+}
+
+QByteArray DavPushSupport::vapidPublicKey() const
+{
+ return d->vapidPublicKey;
+}
diff --git a/src/common/davpushsupport.h b/src/common/davpushsupport.h
new file mode 100644
index 0000000..54ba345
--- /dev/null
+++ b/src/common/davpushsupport.h
@@ -0,0 +1,82 @@
+/*
+ SPDX-FileCopyrightText: 2026 Dominique Michel <[email protected]>
+
+ SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KDAV_DAVPUSH_H
+#define KDAV_DAVPUSH_H
+
+#include "kdav_export.h"
+
+#include <QSharedDataPointer>
+
+class DavPushSupportPrivate;
+
+namespace KDAV
+{
+/*!
+ * \class KDAV::DavPushSupport
+ * \inheaderfile KDAV/DavPushSupport
+ * \inmodule KDAV
+ *
+ * \brief A helper class to store information about Support of DavPush.
+ *
+ * This class is used as a container to transfer DavPush support of
+ * DavCollections from the dav server.
+ * \sa https://bitfireat.github.io/webdav-push/draft-bitfire-webdav-push-00.html
+ *
+ * \since 6.29
+ */
+class KDAV_EXPORT DavPushSupport
+{
+public:
+ /*!
+ * Creates an empty DAV Push.
+ */
+ DavPushSupport();
+
+ DavPushSupport(const DavPushSupport &other);
+ DavPushSupport(DavPushSupport &&);
+ DavPushSupport &operator=(const DavPushSupport &other);
+ DavPushSupport &operator=(DavPushSupport &&);
+ ~DavPushSupport();
+
+ bool operator==(const DavPushSupport &) const;
+
+ /*!
+ * Returns true if this DavPushSupport is valid
+ */
+ [[nodiscard]] bool isValid() const;
+
+ /*!
+ * Sets this push's topic
+ */
+ void setTopic(const QString &topic);
+
+ /*!
+ * Returns this push's topic, empty if no value was found
+ */
+ [[nodiscard]] QString topic() const;
+
+ /*!
+ * Sets this push's vapid public key
+ * vapid must be in base64url (not base64)
+ */
+ void setVapidPublicKey(const QByteArray &vapidPublicKey);
+
+ /*!
+ * Returns this push's vapid public key, empty if no value was found
+ * vapid format is returned in base64url (not base64)
+ */
+ [[nodiscard]] QByteArray vapidPublicKey() const;
+
+private:
+ QSharedDataPointer<DavPushSupportPrivate> d;
+};
+
+}
+
+Q_DECLARE_TYPEINFO(KDAV::DavPushSupport, Q_RELOCATABLE_TYPE);
+
+#endif
diff --git a/src/common/utils.cpp b/src/common/utils.cpp
index ea76016..9960088 100644
--- a/src/common/utils.cpp
+++ b/src/common/utils.cpp
@@ -6,6 +6,7 @@
#include "utils_p.h"
+#include "davpushsupport.h"
#include "enums.h"
#include <QString>
@@ -101,3 +102,29 @@ Privileges Utils::parsePrivilege(const QDomElement &element)
return final;
}
+
+std::optional<DavPushSupport> Utils::extractDavPushSupport(const QDomElement &element)
+{
+ constexpr auto davPushNS = QLatin1StringView("https://bitfire.at/webdav-push");
+ const auto topicElt = firstChildElementNS(element, davPushNS, QStringLiteral("topic"));
+ const auto transportsElt = firstChildElementNS(element, davPushNS, QStringLiteral("transports"));
+ // TODO: supported-triggers is missing from the nextcloud reference implementation, let's ignore it for now
+
+ if (topicElt.isNull() || transportsElt.isNull()) {
+ return {};
+ }
+
+ const auto webPushElt = firstChildElementNS(transportsElt, davPushNS, QStringLiteral("web-push"));
+ if (webPushElt.isNull()) {
+ return {};
+ }
+ const auto vapidPubKeyElt = firstChildElementNS(webPushElt, davPushNS, QStringLiteral("vapid-public-key"));
+ if (vapidPubKeyElt.isNull()) {
+ return {};
+ }
+
+ auto res = DavPushSupport();
+ res.setTopic(topicElt.text());
+ res.setVapidPublicKey(vapidPubKeyElt.text().toUtf8());
+ return res;
+}
diff --git a/src/common/utils_p.h b/src/common/utils_p.h
index 533af1d..eade085 100644
--- a/src/common/utils_p.h
+++ b/src/common/utils_p.h
@@ -11,6 +11,11 @@
#include <QDomElement>
+namespace KDAV
+{
+class DavPushSupport;
+}
+
namespace KDAV
{
namespace Utils
@@ -39,6 +44,13 @@ Q_REQUIRED_RESULT Privileges extractPrivileges(const QDomElement &element);
*/
Q_REQUIRED_RESULT Privileges parsePrivilege(const QDomElement &element);
+/*!
+ * \internal
+ * Extracts DavPushSupport from @p element, element being a <prop> tag.
+ *
+ * \since 6.29
+ */
+[[nodiscard]] std::optional<DavPushSupport> extractDavPushSupport(const QDomElement &element);
}
}
diff --git a/src/protocols/caldavprotocol.cpp b/src/protocols/caldavprotocol.cpp
index 187e807..008b445 100644
--- a/src/protocols/caldavprotocol.cpp
+++ b/src/protocols/caldavprotocol.cpp
@@ -24,9 +24,12 @@ class CaldavCollectionQueryBuilder : public XMLQueryBuilder
public:
QDomDocument buildQuery() const override
{
+ constexpr auto davPushNs = QLatin1StringView("https://bitfire.at/webdav-push");
+
QDomDocument document;
QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind"));
+ propfindElement.setAttribute(QStringLiteral("xmlns:P"), davPushNs);
document.appendChild(propfindElement);
QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
@@ -39,6 +42,11 @@ public:
propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-privilege-set")));
propElement.appendChild(document.createElementNS(QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag")));
+ // Add discovery of push notifications
+ propElement.appendChild(document.createElementNS(davPushNs, QStringLiteral("P:transports")));
+ propElement.appendChild(document.createElementNS(davPushNs, QStringLiteral("P:topic")));
+ propElement.appendChild(document.createElementNS(davPushNs, QStringLiteral("P:supported-triggers")));
+
return document;
}
@@ -438,7 +446,7 @@ void CaldavProtocol::writeMkCol(QXmlStreamWriter &writer, KDAV::DavCollection &c
if (collection.color().isValid()) {
// If it's ARGB, we need to print it in RGBA format
- const auto color = [&] -> QString {
+ const auto color = [&]() -> QString {
if (collection.color().alpha() == 255) {
return collection.color().name(QColor::HexRgb);
}