summaryrefslogtreecommitdiff
path: root/pim/rc/rsvp
diff options
context:
space:
mode:
Diffstat (limited to 'pim/rc/rsvp')
-rwxr-xr-xpim/rc/rsvp111
1 files changed, 111 insertions, 0 deletions
diff --git a/pim/rc/rsvp b/pim/rc/rsvp
new file mode 100755
index 0000000..0e21f04
--- /dev/null
+++ b/pim/rc/rsvp
@@ -0,0 +1,111 @@
+#!/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