#!/bin/rc # pim/rsvp -- answer an invitation. # # pim/rsvp accepted 'meet with ben' # pim/rsvp declined /mnt/pim/calendars/work/events/date/2026/08/24/1000-API-WG # # Takes an occurrence path, as pim/agenda -p prints and cal9 plumbs, or a # pattern to search for. The answer goes to the event's partstat, and # what happens next is the backend's business: a caldav server with # calendar-auto-schedule updates your copy and mails the organiser, and # a published .ics refuses outright, which is the honest answer there. rfork e mtpt=/mnt/pim days=90 only=() while(~ $1 -*){ switch($1){ case -m mtpt=$2; shift case -c only=($only $2); shift case -n days=$2; shift case * echo 'usage: rsvp [-m mtpt] [-c cal] [-n days] accepted|declined|tentative path|pattern' >[1=2] exit usage } shift } if(test $#* -lt 2){ echo 'usage: rsvp [-m mtpt] [-c cal] [-n days] accepted|declined|tentative path|pattern' >[1=2] exit usage } want=`{echo $1 | tr a-z A-Z} shift switch($want){ case ACCEPTED DECLINED TENTATIVE ; case * echo 'pim/rsvp: want accepted, declined or tentative' >[1=2] exit usage } pat=$"* # an occurrence path names one outright; anything else is a search occ=() if(test -f $"pat) occ=$"pat if(~ $#occ 0){ hits=`{pim/show -m $mtpt -n $days $only -a $"pat >[2]/dev/null | sed -n 's/^at *//p'} if(~ $#hits 0){ echo 'pim/rsvp: nothing matching '^$"pat >[1=2] exit notfound } # A recurring event matches once per occurrence, and the answer # applies to the series, so count distinct events rather than hits. evs=() for(h in $hits){ hd=`{basename -d $h} he=`{sed -n 's/^event: //p' $h} if(! ~ $#he 0) evs=($evs `{cleanname $hd/$"he}) } evs=`{echo $evs | tr ' ' '\n' | sort -u} if(! ~ $#evs 1){ echo 'pim/rsvp: '^$#evs^' events match; be more specific:' >[1=2] for(x in $evs) echo ' '^$x >[1=2] exit ambiguous } occ=$hits(1) } # the occurrence points at its event; 9P has no symlinks, so it is a path d=`{basename -d $"occ} ev=`{sed -n 's/^event: //p' $"occ} if(~ $#ev 0){ echo 'pim/rsvp: '^$"occ^' has no event: line' >[1=2] exit noevent } e=`{cleanname $d/$"ev} if(! test -f $e/partstat){ echo 'pim/rsvp: '^$"e^' has no partstat' >[1=2] exit nopartstat } # Say why before the write fails. A published .ics has nowhere to put a # reply and no invitation to reply to, and "permission denied" does not # explain that. c=`{echo $"e | sed 's|(/.*/calendars/[^/]+)/.*|\1|'} caps=`{sed -n 's/^caps //p' $"c/ctl >[2]/dev/null} # ~ takes its first argument as the subject, so `~ $caps rsvp` asks # whether "read" is "rsvp". Walk the list instead. can=() for(x in $caps) if(~ $x rsvp) can=1 if(! ~ $#caps 0) if(~ $#can 0){ echo 'pim/rsvp: '^`{basename $"c}^' is '^$"caps^', it cannot answer invitations' >[1=2] exit readonly } echo $want >$e/partstat sum=`{sed -n 's/^summary: //p' $"occ} echo $"sum^': '^$want exit 0