diff options
| author | Calvin Morrison <calvin@pobox.com> | 2026-08-22 13:16:49 -0400 |
|---|---|---|
| committer | Calvin Morrison <calvin@pobox.com> | 2026-08-22 13:16:49 -0400 |
| commit | 8a3d2c99bff60cb775ebc42516c0c3912d54ba3d (patch) | |
| tree | fd136a3b7927146763cdc11e6be07c71f92bb92c /pim/man/ical.4 | |
| parent | 9aacce8b3b54060d0037eca897856d7273e6e5e8 (diff) | |
pim: personal information management, starting with a calendar
A calendar as a file tree, and tools that only know the tree:
events/date/yyyy/mm/dd/hhmm-summary as lived
events/uuid/<uid>/ as stored
ctl query alarm changed
lib/cal owns all of that. A backend supplies events and, where its
protocol allows, takes changes back -- six methods. cmd/icalfs is the
first: it reads .ics files from a directory and nothing else, because
fetching is rc/fetch's job and hget already exists. That keeps
net/http out of the binary and makes a subscribed calendar and a local
one the same thing.
The tools are rc on purpose. If the tree needs a compiled program to be
useful, the tree is the wrong shape. Three things were added to the
tree because the rc port needed them: a path from an occurrence to its
event, epoch seconds beside RFC3339, and a numeric slot for all-day
events so test(1) can compare it.
ctl reports caps, so a tool can say "read only" instead of trying and
failing. A published .ics is read only: nowhere to PUT, and no
METHOD:REQUEST to reply to. CalDAV would be read write rsvp schedule,
and that is the next backend.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'pim/man/ical.4')
| -rw-r--r-- | pim/man/ical.4 | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/pim/man/ical.4 b/pim/man/ical.4 new file mode 100644 index 0000000..022749f --- /dev/null +++ b/pim/man/ical.4 @@ -0,0 +1,269 @@ +.TH ICAL 4 +.SH NAME +ical \- calendar file system +.SH SYNOPSIS +.B ical/fs +[ +.B -n +] [ +.B -c +.I config +] [ +.B -d +.I dir +] [ +.B -s +.I service +] [ +.B -M +.I mtpt +] [ +.B -w +.I days +] [ +.B -u +.I url +] [ +.B -U +.I file +] [ +.B -a +.I addr +] +.SH DESCRIPTION +.I Ical/fs +presents a calendar as a file tree. +It reads iCalendar +.RB ( .ics ) +files from +.I dir +(default +.BR . ), +expands recurring events, and posts a service file descriptor in +.BR /srv/\fIservice . +.PP +The default service name is +.BI ical. user . pid\fR, +as +.IR rio (1) +and +.IR plumb (1) +name theirs, so that several may run at once. +A name given with +.B -s +is used unchanged, for a singleton something else expects to find by +name. +The name posted is written to standard error. +.I Ical/fs +does not mount itself; a start script would say +.IP +.EX +ical/fs & +mount /srv/ical.$user.$apid /mnt/pim +.EE +.PP +Calendars named in +.I config +(default +.BR $home/lib/pim ) +are fetched over HTTP and kept current without being asked. +Each line is a tuple of attribute-value pairs in the syntax of +.IR ndb (6): +.IP +.EX +cal=work url=https://... refresh=15m +.EE +.PP +.B Refresh +defaults to 15 minutes. +A fetch whose content is unchanged rebuilds nothing. +The +.B -u +and +.B -U +flags name a single url directly, the latter reading it from +.IR file ; +the url of a private calendar is a secret and belongs in a file +rather than in the arguments, where +.IR ps (1) +would show it. +.PP +The +.B -w +flag sets how many days either side of now recurrences are expanded +into, default 400. +.B -M +is the mount point reported in query answers, default +.BR /mnt/pim . +.B -a +also serves 9P on a TCP address. +.B -n +loads the calendars, reports what was found, and exits. +.PP +The top level contains the files +.BR ctl , +.BR query , +.BR alarm , +.BR changed , +and the directory +.BR events . +.SS Events +.B Events/date +holds one file per occurrence, at +.BI events/date/ yyyy/mm/dd/hhmm-summary\fR. +Times are local, zero filled, and four digits wide, so that a day +sorts by name. +All day events are named +.BI 0000-allday- summary\fR. +Each file holds a header of +.BI attribute :\ value +lines, a blank line, and the description: +.IP +.EX +summary: API WG +start: 2026-08-19T10:00:00-04:00 +end: 2026-08-19T11:05:00-04:00 +epoch: 1787148000 +epochend: 1787151900 +uid: 1avg0u8b0k5v4bqokqfvgr157v@google.com +event: ../../../../uuid/1avg0u8b0k5v4bqokqfvgr157v_google.com +.EE +.PP +.B Epoch +and +.B epochend +are seconds, for +.IR date (1). +.B Event +is the path of the event this occurrence belongs to; 9P has no +symbolic links. +.PP +.B Events/uuid +holds one directory per event, named for its +.BR uid , +containing the files +.BR summary , +.BR start , +.BR end , +.BR location , +.BR description , +.BR rrule , +.BR organizer , +.BR attendees , +.BR uid , +and +.BR raw . +Absent values have no file. +.B Attendees +holds one line per attendee: participation status, name, and address, +separated by tabs. +.B Raw +is the event as it arrived. +.SS Ctl +Reading +.B ctl +reports the source directory, the expansion window, the number of +events, and one line per calendar giving its refresh interval and the +time of its last fetch. +Writing to it accepts: +.TF "\fLwindow\fI n\fL" +.TP +.B refresh +Reload from +.IR dir . +.TP +.BI window \ n +Expand recurrences +.I n +days either side of now, and reload. +.SS Query +.B Query +answers questions the tree does not index. +Write a query, then read the answer, as with +.IR cs (8); +one path is returned per line. +A query is a list of +.IB attribute = value +terms, all of which must match: +.BR summary , +.BR attendee , +.BR organizer , +.BR location , +and +.B uid +match a substring, without regard to case; +.B from +and +.B to +bound the occurrence time and are written +.BR yyyy-mm-dd . +.IP +.EX +% echo 'attendee=michael from=2026-08-19' >/mnt/pim/query +% cat /mnt/pim/query +.EE +.PP +Holding one file descriptor across the write and the read is correct +usage. +The last answer is also returned to a descriptor that has none of its +own, so that +.B echo +and +.B cat +work. +.SS Alarm and changed +A read of +.B alarm +blocks until an alarm is due and returns the alarm time, the start of +the event, and its summary, separated by tabs. +Only +.B VALARM +triggers relative to the start are honoured. +.PP +A read of +.B changed +blocks until the tree has been rebuilt. +A program displaying a calendar should walk the tree again when it +returns rather than poll. +The whole tree is rebuilt, so open file descriptors should not be +assumed to remain valid. +.SH EXAMPLE +Serve the calendars named in the config and mount them: +.IP +.EX +% ical/fs -s pim +% mount /srv/pim /mnt/pim +% pim/agenda +.EE +.SH SOURCE +.B /sys/src/pim +.SH "SEE ALSO" +.IR agenda (1), +.IR date (1), +.IR ndb (6), +.IR cs (8) +.PP +Desruisseaux, +``Internet Calendaring and Scheduling Core Object Specification'', +RFC 5545. +.SH BUGS +Embedded +.B VTIMEZONE +definitions are ignored; +.B TZID +is resolved by IANA name. +.PP +.B RECURRENCE-ID +overrides are applied, but +.B METHOD:CANCEL +is not. +.PP +Absolute alarm triggers, +.BR RELATED=END , +and repeating alarms are ignored. +.PP +Nothing can be written but +.B ctl +and +.BR query . +Replying to an invitation is not yet possible. |
