From 5bf82a54e0a65c1c5d1f2cbf27e621ec6bfc4541 Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Wed, 11 Nov 2026 21:23:52 +0100 Subject: [PATCH] feat: hint whether an event keeps its RDATE Zimbra drops every RDATE from an event, timed or all-day, while it keeps an RRULE beside it: seen on Zimbra 8.8 and 10.1 with caldav-server-tester's new probe and by hand. The new hint save-load.event.recurrences.rdate records it, unsupported in the zimbra_8_8 profile, which zimbra_10_1 inherits. Prompt: [about Zimbra 10.1 dropping RDATE only inside the suite's run:] Keep digging. Followup-Prompt: [make recurrence.rdate] as a new feature Assisted-By: Claude Opus 5.5 Reviewed-by: Tobias Brox --- caldav/compatibility_hints.py | 5 +++++ changes/+rdate.added.md | 1 + 2 files changed, 6 insertions(+) create mode 100644 changes/+rdate.added.md diff --git a/caldav/compatibility_hints.py b/caldav/compatibility_hints.py index b5b01ca4..b951e8e7 100644 --- a/caldav/compatibility_hints.py +++ b/caldav/compatibility_hints.py @@ -458,6 +458,7 @@ class FeatureSet: "save-load.event.no-dtend": {"description": "The server stores a VEVENT with neither DTEND nor DURATION. RFC 5545 section 3.6.1 allows one: an event on a date lasts that day, an event at a date-time ends when it starts. 'ungraceful' when the PUT is refused with an error (iCloud answers 404, or 403).", "default": {"support": "full"}}, "save-load.event.recurrences": {"description": "it's possible to save and load recurring events to the calendar - events with an RRULE property set, including recurrence sets", "default": {"support": "full"}}, "save-load.event.recurrences.count": {"description": "The server will receive and store a recurring event with a count set in the RRULE", "default": {"support": "full"}}, + "save-load.event.recurrences.rdate": {"description": "An event's RDATE (RFC 5545 section 3.8.5.2), occurrences given by date rather than by an RRULE, is stored. 'unsupported' when it is dropped (Zimbra drops every RDATE, and keeps an RRULE), 'broken' when it is stored with other dates.", "links": ["https://datatracker.ietf.org/doc/html/rfc5545#section-3.8.5.2"]}, ## This was Claude's suggestion and it works as of today, the ## "unsupported" description matches the behaviour of the Stalwart server. ## Stalwart apparently (in a breach with the RFC) stores the exception @@ -1978,6 +1979,10 @@ def compare(self, observed): "save.etag.matches-stored": {"support": "broken", "behaviour": "stored with STATUS, CLASS, TRANSP, LAST-MODIFIED and SEQUENCE added, yet the PUT answered with a strong ETag"}, ## Measured with caldav-server-tester, 2026-10-28. "save-load.event.floating": {"support": "unsupported", "behaviour": "a floating time is stored with TZID=\"UTC\""}, + ## Probed 2026-11-11 by caldav-server-tester (a timed RDATE), on 8.8 and + ## on 10.1; an all-day RDATE is dropped too, and an RRULE beside them is + ## kept (checked by hand). + "save-load.event.recurrences.rdate": {"support": "unsupported", "behaviour": "the RDATE is dropped"}, "save-load.icalendar.unknown-property": {"support": "unsupported", "behaviour": "ESTIMATED-DURATION is dropped"}, "save-load.icalendar.participant": {"support": "ungraceful", "behaviour": "an event with a PARTICIPANT is refused (500)"}, "scheduling.auto-schedule": {"support": "full"}, diff --git a/changes/+rdate.added.md b/changes/+rdate.added.md new file mode 100644 index 00000000..6d9712a5 --- /dev/null +++ b/changes/+rdate.added.md @@ -0,0 +1 @@ +New server hint `save-load.event.recurrences.rdate`: whether an event's RDATE is stored. Zimbra drops every RDATE, and keeps an RRULE.