diff --git a/caldav/caldav.go b/caldav/caldav.go index 60d84f4..9d5ca11 100644 --- a/caldav/caldav.go +++ b/caldav/caldav.go @@ -4,6 +4,7 @@ package caldav import ( + "fmt" "time" "github.com/emersion/go-ical" @@ -15,6 +16,51 @@ func NewCalendarHomeSet(path string) webdav.BackendSuppliedHomeSet { return &calendarHomeSet{Href: internal.Href{Path: path}} } +// ValidateCalendarObject checks the validity of a calendar object according to +// the contraints layed out in RFC 4791 section 4.1 and returns the only event +// type and UID occuring in this calendar, or an error if the calendar could +// not be validated. +func ValidateCalendarObject(cal *ical.Calendar) (eventType string, uid string, err error) { + // Calendar object resources contained in calendar collections + // MUST NOT specify the iCalendar METHOD property. + if prop := cal.Props.Get(ical.PropMethod); prop != nil { + return "", "", fmt.Errorf("calendar resource must not specify METHOD property") + } + + for _, comp := range cal.Children { + // Calendar object resources contained in calendar collections + // MUST NOT contain more than one type of calendar component + // (e.g., VEVENT, VTODO, VJOURNAL, VFREEBUSY, etc.) with the + // exception of VTIMEZONE components, which MUST be specified + // for each unique TZID parameter value specified in the + // iCalendar object. + if comp.Name != ical.CompTimezone { + if eventType == "" { + eventType = comp.Name + } + if eventType != comp.Name { + return "", "", fmt.Errorf("conflicting event types in calendar: %s, %s", eventType, comp.Name) + } + // TODO check VTIMEZONE for each TZID? + } + + // Calendar components in a calendar collection that have + // different UID property values MUST be stored in separate + // calendar object resources. + compUID, err := comp.Props.Text(ical.PropUID) + if err != nil { + return "", "", fmt.Errorf("error checking component UID: %v", err) + } + if uid == "" { + uid = compUID + } + if uid != compUID { + return "", "", fmt.Errorf("conflicting UID values in calendar: %s, %s", uid, compUID) + } + } + return eventType, uid, nil +} + type Calendar struct { Path string Name string