Skip to content

angee.parties_integrate_carddav.backend

CardDAV directory backend: discover address books and sync their contacts.

Real RFC 6764 + RFC 6352 discovery — .well-known/carddav (or the configured base) → current-user-principaladdressbook-home-set → enumerate the address-book collections — then per collection a list-then-multiget fetch: PROPFIND Depth:1 for the vCard hrefs + etags, then a batched addressbook-multiget REPORT for the cards. Everything goes over the shared SSRF-pinned client (allow_private=True — self-hosted CardDAV servers are common), authenticated by the directory's Basic-auth credential, following one level of redirect. vobject parses each card into a neutral ParsedContact; the idempotent (folder, source_uid) map onto parties is owned by Directory.sync + the parties managers, never here.

Auth is Basic only: HTTP Digest is not yet supported. A Digest server would need a DigestAuthCredentialHandler on the credential registry seam (the challenge / response round-trip), which is deferred until a Digest-only source needs it.

CardDavError

python
class CardDavError(Exception)

Raised when the CardDAV server returns an unexpected response.

CardDavDirectoryBackend

python
class CardDavDirectoryBackend(DirectoryBackend)

Discovers a CardDAV account's address books and fetches each one's vCards.

config["server_url"] is the account/server URL; discovery finds the collections, so the operator never pastes an exact collection URL. The directory's Basic-auth credential authenticates.

probe

python
def probe() -> None

Run discovery once to validate the URL + credentials before persisting.

Raises :class:CardDavError if the server URL is missing, unreachable, or rejects the credentials — so the connect mutation fails fast instead of saving a directory whose first sync would silently error. An empty (but reachable, authenticated) account is allowed.

discover

python
def discover() -> list[ParsedAddressbook]

Resolve the account's principal → home-set → address-book collections.

fetch_contacts

python
def fetch_contacts(addressbook: ParsedAddressbook) -> list[ParsedContact]

List the collection's vCard hrefs, multiget them, and resolve photo URIs.

Released under the AGPL-3.0 License.