Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ This project should adhere to [Semantic Versioning](https://semver.org/spec/v2.0
* A `features="icloud"` profile, from a caldav-server-tester run by a user - the documentation already referred to it, but it did not exist. https://github.com/python-caldav/caldav/issues/730
* Compatibility feature `sync-token.invalid-token`: whether a sync token the server never issued is refused with `DAV:valid-sync-token` as RFC 6578 section 3.2 says. Xandikos and CCS answer some such tokens with a 500, and Stalwart and Ox with a report and no error. https://github.com/jelmer/xandikos/issues/743
* Compatibility feature `propfind.principal-depth-1`: whether a Depth: 1 PROPFIND on the principal URL works. GMX answers it with a 400. https://github.com/python-caldav/caldav/pull/755
* Compatibility feature `save-load.event.no-dtend`: whether a VEVENT with neither DTEND nor DURATION is stored, as RFC 5545 section 3.6.1 allows. iCloud refuses one with a 404. https://github.com/python-caldav/caldav-server-tester/issues/24
* Negated searches: `add_property_filter()` passes the `!=` (alias `<>`), `!contains` and `def` operators of icalendar-searcher 1.1.0 on to the search. They are decided client-side (unless `post_filter=False`): the server query leaves them out, as no server has been probed for `negate-condition` support yet. `build_search_xml_query()` renders `!contains` as a negated `text-match`, and `!=` and `def` as a bare `prop-filter` - a negated `text-match` is a negated *substring* match, so it cannot express `!=`. https://github.com/python-caldav/caldav/issues/568
* Compatibility features `sync-token.limit` and `sync-token.limit.initial-sync`, for DAV:limit and the checkpoint tokens of a truncated sync-collection report (RFC 6578 sections 3.6 and 3.7). Hints for Stalwart, Xandikos, Radicale, Baïkal, Davis, Nextcloud, CCS and Infomaniak.

Expand Down
38 changes: 25 additions & 13 deletions caldav/compatibility_hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ class FeatureSet:
"default": { "support": "full" }
},
"save-load.event.no-summary": {"description": "The server stores a VEVENT without a SUMMARY property. RFC 5545 section 3.6.1 makes SUMMARY optional. 'ungraceful' when the PUT is refused with an error (Bedework 5 answers 500 missingeventproperty).", "default": {"support": "full"}},
"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"}},
## This was Claude's suggestion and it works as of today, the
Expand Down Expand Up @@ -1928,6 +1929,12 @@ def compare(self, observed):
## iCloud (https://caldav.icloud.com/). Not among the servers the maintainer
## tests against; probed 2026-10-09 by a user with caldav-server-tester 1.4.0
## (caldav 3.4.0), see https://github.com/python-caldav/caldav/issues/730 .
## Partly re-probed 2026-10-14 (caldav master and caldav-server-tester
## release-candidate, both with the no-dtend change), once the tester no
## longer stopped at the first event without an end, see
## https://github.com/python-caldav/caldav-server-tester/issues/24 . Only the
## entries marked 2026-10-14 come from that run; the search.recurrences and
## old-dates lines from 2026-10-09 were removed after it.
## Earlier, older observations are in https://github.com/python-caldav/caldav/issues/3
##
## The calendar-home-set lives on a per-account partition host
Expand All @@ -1950,6 +1957,10 @@ def compare(self, observed):
'freebusy-query': {'support': 'ungraceful', 'behaviour': '400 Bad Request'},
'principal-search': {'support': 'ungraceful'},
'propfind.allprop.resourcetype': {'support': 'unsupported'},
## 2026-10-14
'propfind.principal-depth-1': {'support': 'unsupported', 'behaviour': 'HTTP 400'},
## 2026-10-14
'save-load.event.no-dtend': {'support': 'ungraceful', 'behaviour': 'PUT refused with 404, or 403'},
'save-load.journal': {'support': 'unsupported'},
## A task needs a calendar of its own
'save-load.todo.mixed-calendar': {'support': 'unsupported'},
Expand All @@ -1959,26 +1970,27 @@ def compare(self, observed):
},
'save.duplicate-uid.cross-calendar': {'support': 'ungraceful', 'behaviour': 'PUT refused'},
'scheduling.schedule-tag': {'support': 'unsupported', 'behaviour': 'no Schedule-Tag returned on GET or via PROPFIND'},
## 2026-10-14: on another account, is-not-defined.category/class and
## search.text.case-* found nothing (an empty 207) in two tester runs, and
## SUMMARY and CATEGORIES filters by hand did not either, also 30 minutes
## after saving. Cause unknown; left as probed in #730.
'search.is-not-defined': {'support': 'fragile', 'behaviour': 'works for category, class but not all properties'},
'search.is-not-defined.category': {'support': 'full'},
'search.is-not-defined.class': {'support': 'full'},
'search.is-not-defined.dtend': {'support': 'unsupported'},
## 2026-10-14: recurring events are found and expanded, and so are events
## in year 2000. Recurring tasks cannot be measured while time-range
## searches for tasks do not work, so they are not left at the default.
'search.recurrences.includes-implicit.todo': {'support': 'unknown'},
'search.recurrences.expanded.todo': {'support': 'unknown'},
'search.text.category': {'support': 'unsupported'},
'search.time-range.alarm': {'support': 'unsupported'},
'search.time-range.todo': {'support': 'unsupported'},
## Like OX, the search window does not reach far into the past: objects in
## year 2000 are not found, neither by an open search nor by a time-range
## search. The checker reports search.unlimited-time-range as broken, but
## it is deliberately left at its default here: the workaround for it
## (sending a 1970-2126 time range with every open search) cannot help when
## old-dates time-range searches fail too, and with the recurrence search
## problems below it might drop recurring events an open search returns.
'search.time-range.event.old-dates': {'support': 'unsupported'},
## TODO: all recurrence searches came back unsupported. This may be an
## artifact of the search window above rather than missing recurrence
## support - the save-load.*.recurrences checks were inconclusive in the
## same run. Needs a closer look.
'search.recurrences': {'support': 'unsupported'},
## 2026-10-14
'sync-token.limit': {
'support': 'unsupported',
'behaviour': 'DAV:limit is ignored; lists the collection itself as a member',
},
}

## See the synology profile above: Synology Calendar ships a modified DAViCal,
Expand Down
Loading