.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.