summaryrefslogtreecommitdiff
path: root/pim/lib/cal/ical.go
diff options
context:
space:
mode:
authorCalvin Morrison <calvin@pobox.com>2026-08-22 14:04:17 -0400
committerCalvin Morrison <calvin@pobox.com>2026-08-22 14:04:17 -0400
commit08155ead7bf80308b4cb67063cc91e3e3679ce16 (patch)
treeb0c0673b3e7f20d318695ec1992ef1cdf47e284d /pim/lib/cal/ical.go
parent8a3d2c99bff60cb775ebc42516c0c3912d54ba3d (diff)
pim: a caldav backend, and a partstat that refuses to lie
caldav/fs is the second backend, and it cost ~330 lines: discovery, a report for the window, ETags to decide whether anything moved. The event model, recurrence expansion, the tree, ctl, query, alarm and changed all came from lib/cal untouched, which is what the split was for. go-webdav hands back *ical.Calendar from the same library lib/cal parses with, so FromCalendars takes it straight in. Two interfaces, both optional. Identity says whose calendar this is, because in iTIP your identity is the mailto: in your own ATTENDEE line and nothing else can tell which attendee is you. RSVPer says the backend can answer an invitation -- meaning both halves of it, updating your copy and telling the organiser. A backend that can only do one should not implement it, so partstat is 0444 on a published .ics and writing to it fails rather than half-working. Two bugs worth naming. go-webdav resolves paths with path.Join, which drops a trailing slash: pointed at /dav/ it asks about /dav, and Cyrus answers 405 for that spelling and 207 for the other, so the first PROPFIND is done by hand. And an absolute DAV href replaces the endpoint's path rather than extending it; appending gave /dav/dav/calendars/..., a 404, and a probe reading 404 as "no" hid calendar-auto-schedule, which fastmail does in fact offer. pimup brings mail and the calendars up and mounts them; riostart runs it before opening any window, since a mount only exists in the namespace that made it. rio does not run riostart by itself: it is the argument to -i. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'pim/lib/cal/ical.go')
-rw-r--r--pim/lib/cal/ical.go26
1 files changed, 20 insertions, 6 deletions
diff --git a/pim/lib/cal/ical.go b/pim/lib/cal/ical.go
index f52b333..5477030 100644
--- a/pim/lib/cal/ical.go
+++ b/pim/lib/cal/ical.go
@@ -95,29 +95,43 @@ func LoadDir(dir string) ([]*Event, error) {
return nil, err
}
sort.Strings(names)
- var evs []*Event
+ var cals []*ical.Calendar
for _, name := range names {
f, err := os.Open(name)
if err != nil {
Warnf("%s: %v", name, err)
continue
}
- cal, err := ical.NewDecoder(f).Decode()
+ c, err := ical.NewDecoder(f).Decode()
f.Close()
if err != nil {
Warnf("%s: %v", name, err)
continue
}
- for _, c := range cal.Events() {
- ev, err := newEvent(&c)
+ cals = append(cals, c)
+ }
+ return FromCalendars(cals), nil
+}
+
+// FromCalendars turns decoded iCalendar objects into events, with
+// RECURRENCE-ID overrides attached to the series they belong to.
+//
+// A backend that already holds parsed calendars -- CalDAV hands them
+// straight back from a REPORT -- comes through here rather than writing
+// them to disk first.
+func FromCalendars(cals []*ical.Calendar) []*Event {
+ var evs []*Event
+ for _, c := range cals {
+ for _, e := range c.Events() {
+ ev, err := newEvent(&e)
if err != nil {
- Warnf("%s: %v", name, err)
+ Warnf("%v", err)
continue
}
evs = append(evs, ev)
}
}
- return link(evs), nil
+ return link(evs)
}
// link attaches RECURRENCE-ID events to the series they override.