diff options
Diffstat (limited to 'pim/lib/cal/tree.go')
| -rw-r--r-- | pim/lib/cal/tree.go | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/pim/lib/cal/tree.go b/pim/lib/cal/tree.go index cd9e9d2..f78f2eb 100644 --- a/pim/lib/cal/tree.go +++ b/pim/lib/cal/tree.go @@ -112,6 +112,7 @@ func (s *Server) buildEvents(root *fs.StaticDir, evs []*Event) { s.file(ed, "attendees", attendeeText(e.Attendees)) } s.file(ed, "uid", e.UID+"\n") + s.addPartstat(ed, e) s.file(ed, "raw", e.Raw) } } @@ -215,3 +216,60 @@ func attendeeText(as []Attendee) string { } return b.String() } + +// addPartstat publishes your own reply status for an event. +// +// Reading it says where you stand. Writing it answers the invitation -- +// but only if the backend can actually do both halves of that: update +// the calendar and tell the organiser. A published .ics can do neither, +// so there the file is read-only and says why. +func (s *Server) addPartstat(dir *fs.StaticDir, e *Event) { + var me []string + if id, ok := s.be.(Identity); ok { + me = id.Me() + } + cur := "" // no identity, or not an attendee + for _, a := range e.Attendees { + for _, m := range me { + if strings.EqualFold(a.Email, m) || strings.EqualFold(a.Name, m) { + cur = a.Partstat + } + } + } + if cur == "" && len(me) == 0 { + cur = "unknown" + } else if cur == "" { + cur = "not-an-attendee" + } + + rsvp, canWrite := s.be.(RSVPer) + mode := uint32(0444) + if canWrite { + mode = 0666 + } + st := s.fsys.NewStat("partstat", s.user, s.user, mode) + base := fs.NewStaticFile(st, []byte(cur+"\n")) + if !canWrite { + dir.AddChild(base) + return + } + uid := e.UID + dir.AddChild(&fs.WrappedFile{ + File: base, + WriteF: func(fid uint64, off uint64, data []byte) (uint32, error) { + want := strings.ToUpper(strings.TrimSpace(string(data))) + switch want { + case "ACCEPTED", "DECLINED", "TENTATIVE": + default: + return 0, fmt.Errorf("partstat: want ACCEPTED, DECLINED or TENTATIVE") + } + if len(me) == 0 { + return 0, fmt.Errorf("partstat: no me= for this calendar") + } + if err := rsvp.RSVP(uid, time.Time{}, want); err != nil { + return 0, err + } + return uint32(len(data)), nil + }, + }) +} |
