Expand description
Contacts and calendars on a server: CardDAV (RFC 6352) and CalDAV (RFC
4791), both WebDAV (RFC 4918), synced both ways with the folders on disk
(sioul_core::vdir).
- Finding them: the address you give, else
/.well-known/caldavand/.well-known/carddavon the domain (RFC 6764), else the known places of some providers; then your principal (RFC 5397) and its home sets, and the address books and calendars in them. - What you changed here goes first: a changed file is sent with
If-Matchand its ETag, so nobody’s change is overwritten silently; a new one withIf-None-Match: *; a deleted one is deleted there. - Then what changed there: with the sync token when the server keeps
one (RFC 6578), else by comparing ETags; changed items come in batches
(
calendar-multiget,addressbook-multiget) of 50 at most, half as many after a slow or cut answer, twice as many again after quick ones (pace). - A new item whose UID the server holds already (an invitation
answered on two devices): the item there takes its place here, said
when its answer differs (
same_uid_there,adopt). - When both changed the same item, the server’s version wins and yours
is kept among this device’s earlier versions (
history::ACCOUNTS), which the window lists and puts back, said in the report. - Cut short (the network lost, the app killed), a sync resumes where it stopped: what was sent or brought is known at once, never sent twice.
Only HTTPS, with the password in the system keyring and sent as Basic
authentication over TLS; for Google, its OAuth access token instead
(google.rs). A small client on ureq, written for this: the protocol
needed is a handful of requests.
Structs§
- Answer 🔒
- What a server answered.
- Budget 🔒
- How long a request may wait: to connect; for each read or write, so a big answer trickling in on a weak signal goes on as long as it moves, and one that stops is given up soon; and for the whole of it, a bound for the worst.
- Client
- A connection to one server, with its login.
- Homes
- Where the account’s contacts or calendars live, as found.
- Listed
- An address book or calendar the server lists.
- Prop 🔒
- One property, found (200) or not.
- Report
- What a sync of one account did.
- Response 🔒
- One
responseof a multistatus: an address and what was found there.
Enums§
- Sent 🔒
- What became of an item known to the server, at a push.
Constants§
- APPLE 🔒
- BATCH 🔒
- Items asked for in one multiget, at most: the batch after quick answers.
- BUDGET 🔒
- CALDAV 🔒
- CALSERVER 🔒
- CARDDAV 🔒
- DAV 🔒
- PRINCIPAL 🔒
- QUICK 🔒
- A multiget answered within this is quick: the next batch is twice as
large, up to
BATCH. - SETTLED 🔒
- A file’s time is trusted to tell it unchanged once this old: a change made within the same tick of the file system’s clock (two seconds on FAT) would keep it.
- SLOW 🔒
- A multiget answered in this long or more is slow: the next batch of that
collection is half as large (one item at least). A batch of 50 events with
their attachments, or of 50 cards with their photos, on a weak signal, can
take longer than a request may (
BUDGET): asked again whole, it would fail again at every sync.
Statics§
- PACE 🔒
- Each collection’s batch now, by its address, in this process: halved after
a slow answer or a cut one, doubled after a quick one (
pace). Not kept on disk: a new start begins atBATCH, and a slow line slows it again at the first batch.
Functions§
- absolute
hrefmade absolute againstbase(“https://host/a/b/” + “/c/” → “https://host/c/”). An absolutehrefis kept as it is, whatever its server: the login goes only to the account’s own (Client::keep_to).- adopt 🔒
- A new item here (
file, holdingmine) whose UID the server holds already under another address,theirs: that item takes its place, under its file, never sent again. An invitation answered on two devices: the same answers (agenda::answers), taken as it is; others, the server’s kept, and said (Report::answered): the organizer may have had both. An item without guests (a contact, a task) that differs: yours set aside first, as any item changed on both sides. - agent 🔒
- allowed 🔒
- Plain HTTP only to this computer, and only in a test build.
- as_
noted 🔒 - Whether a file is as noted for its item: the same size and the same settled time.
- batch_
of 🔒 - The batch of the collection at
urlnow. - both_
ways 🔒 - What changed here, sent; then, unless nothing changed on either side, what changed there, brought. The ctag is kept once both went through; what the server refused of an item is said once the rest is done.
- candidates 🔒
- Where to look for the server of
domain: the address given, the well-known places, then the providers that put it elsewhere. - changed_
here 🔒 - An item’s file, when it changed here since the server last agreed on it (or never did).
- changes_
since 🔒 - RFC 6578: what changed since
token: (changed with their ETags, gone, the new token). None when the server has forgotten the token or does not keep them. - client_
for - An account’s client: Google’s access token, or its login and the password in the keyring.
- collections
- The collections in a home.
- component_
of 🔒 - The component a calendar item holds (“VEVENT”, “VTODO”…), for a query.
- config 🔒
- create_
on_ 🔒google - A new item on Google: no If-None-Match (it takes If-Match only), cards in vCard 3.0, and a new contact by POST when its address book refuses the PUT (RFC 5995). Where Google filed it (its Location) is where it is known; what Google kept of it comes back at the pull.
- create_
pending 🔒 - Creates on the server the collections made here: a calendar or task list
with MKCALENDAR (RFC 4791 §5.3.1), an address book with an extended MKCOL
(RFC 5689), at
<home><id>/, with its name, colour and, for a calendar, what it holds. Already there (405) counts as made. One refused, the others are still made; the first refusal is returned. - crlf 🔒
- Lines ended with CRLF, as items are written here (RFC 5545 §3.1, RFC 6350 §3.2).
- discover
- Finds an account’s calendar home and address book home: where the
calendars and address books are.
givenis a server address you typed, if any. - domain 🔒
- The domain an address belongs to (“caldav.example.org” → “example.org”).
- everything 🔒
- Every item’s ETag, compared with what is known: (changed, gone, no token).
- fetch 🔒
- Items by their addresses, with their ETags: a multiget, else one GET each.
- file_
name 🔒 - A file name for an item, from its address: safe on every system, unique in its folder.
- forget_
gone 🔒 - Collections deleted on the server go here too: they were copies. One made here and not created there yet stays, and so does one holding items never sent, new or changed since (as Google Tasks’ lists do).
- go_on 🔒
- Goes on after an error of one collection: the first is kept, to say at the end. A lasting one (a refused password, a certificate) stops there: the others would meet it too, and retries can lock an account.
- has_
local_ 🔒changes - hash_of 🔒
- holding_
uid 🔒 - The items of a collection holding
uid, by a query (RFC 4791 §7.8, RFC 6352 §8.6); none from a server that answers no query. - home 🔒
- From a starting address: follows redirects, finds the principal, then its home for
kind. - homes_
path 🔒 - local_
files 🔒 - multistatus 🔒
- The responses of a 207 Multi-Status, and the sync token when one came.
- named_
in_ 🔒refusal - The item a
no-uid-conflictrefusal names, when it names one. - origin 🔒
- An address’s origin, what a login is kept to: its scheme, host and port,
in lowercase, the port written even when it is the scheme’s own
(
https://dav.example.org:443). None without a scheme or a host. - pace 🔒
- A multiget of that collection answered (
Some: in that long) or cut by the network (None): its next batch follows. - path_
key 🔒 - The path of an address, percent-decoded: what to compare hrefs by, however a server writes them.
- pull 🔒
- Brings what changed there: by sync token, else by comparing ETags. The state is kept after each batch, so a pull cut short loses one batch at most; the sync token moves once everything came.
- push 🔒
- Sends what changed here: edits with If-Match, new items with If-None-Match, deletions. The state follows each answer, so a push cut short keeps what it did. What the server refuses of one item, or what cannot be read of it, is returned, the others sent all the same; a lost connection stops it.
- read_
item 🔒 - An item’s file, read whole.
- read_
text 🔒 - An item’s file as text; what cannot be read is said with its path.
- same_
text 🔒 - Whether two versions of an item say the same, however their lines end.
- same_
uid_ 🔒there - The item the server holds under the UID of
text, a new item it refused athrefbecause another holds that UID (RFC 4791 §5.3.2.1 and RFC 6352 §6.3.2.1,no-uid-conflict, said with 403 or 409; Nextcloud says 400, and a server may say 412): where the refusal names it, else found by a query on the UID (calendar-query,addressbook-query). Its address, ETag and text; None when no other item there holds that UID (a server that answers no query included), and the refusal is what it was. - send_
changes 🔒 - Tells the server the collections renamed here (PROPPATCH, RFC 4918 §9.2), and deletes those deleted here (RFC 4918 §9.6), only when the server holds nothing in them either: one filled elsewhere meanwhile comes back. One refused, the others are still told; the first refusal is returned.
- send_
known 🔒 - One item known to the server, sent if it changed here, deleted there if deleted here. A file whose size and time are as noted is not read.
- set_
aside 🔒 - Your version of an item changed on both sides, kept where you can find it,
on a phone too: among this device’s earlier versions (
history, the parthistory::ACCOUNTS, named by the item’s place in the data folder), which the window lists and puts back (Settings ▸ Your folder and sharing ▸ Show earlier versions), sharing on or off. Until 10 October 2026 it went to$XDG_STATE_HOME/sioul/dav/conflicts, out of reach on a phone. Not kept (a full disk), the sync stops there: the server’s version does not take its place, and yours is never lost. - shared_
agent 🔒 - The sharing’s server’s one agent in this process (
remote::Server): its connections and TLS sessions kept between the requests of a pull, of the sends after it and of the next pull, so that a phone’s step opens one connection, not one per pull, per send and per file sent (on mobile data, each new one wakes the radio for a TLS handshake). Each request says its own budget (its whole and its connection’s time,configure_request; its stall,stalls::ask); ureq keeps an idle connection fifteen seconds. - stamp 🔒
- A file’s size and modification time (nanoseconds since 1970), noted to tell it unchanged later without reading it; the time 0 (unknown) while too recent, or ahead of now.
- status_
code 🔒 - store 🔒
- Writes an item brought from the server (href, ETag, text). Your version, changed here since the server last agreed on it (or never agreed), is set aside first, unless it is the same.
- summary_
of 🔒 - An event’s title, as its first
SUMMARYline says. - sync
- Syncs every address book and calendar of a contacts-and-calendars account. An error in one collection (refused, cut, timed out) is said at the end, the first one, the others synced all the same; a lasting one (a refused password, a certificate) stops the sync at once.
- sync_
collection 🔒 - One collection: what changed here goes first, then what changed there. Its state follows every answer and is kept whatever happens: what was sent or brought before an error is known at the next sync, never sent twice.
- sync_
with 🔒 - test
- Tests the login and finds where the account’s contacts and calendars are.
- test_
google - Finds a Google account’s calendars and contacts, once signed in.
- uid_of 🔒
- An item’s UID, as its first
UIDline says. - unchanged 🔒
- Whether an item’s file is as last synced: by its size and time when noted, else by its hash.
- url_
segment 🔒 - A file name as a URL path segment.
- watch
- Syncs an account now, then every
everyuntil stopped (seeControl::pause: counted on the wall clock; while quiet, only when nudged), each sync reported. After a lasting error (a refused password…) it waits for a nudge instead of ending, then tries again (seefetch::Parked: a refused password, unchanged, not before an hour unlessControl::retry). - watch_
with 🔒 watch, syncing withsync;passwordreads the one kept now.- xml_
escape 🔒 - Text made safe in XML, between tags and between quotes (a component’s
name="…").