go-webdav/caldav/elements.go

227 lines
7.1 KiB
Go
Raw Normal View History

2020-01-30 12:18:05 +00:00
package caldav
import (
"encoding/xml"
"fmt"
2020-02-05 16:07:35 +00:00
"time"
2020-01-30 12:18:05 +00:00
"github.com/emersion/go-webdav/internal"
)
const namespace = "urn:ietf:params:xml:ns:caldav"
2020-01-30 12:28:32 +00:00
var (
calendarHomeSetName = xml.Name{namespace, "calendar-home-set"}
calendarDescriptionName = xml.Name{namespace, "calendar-description"}
supportedCalendarDataName = xml.Name{namespace, "supported-calendar-data"}
supportedCalendarComponentSetName = xml.Name{namespace, "supported-calendar-component-set"}
maxResourceSizeName = xml.Name{namespace, "max-resource-size"}
calendarQueryName = xml.Name{namespace, "calendar-query"}
calendarMultigetName = xml.Name{namespace, "calendar-multiget"}
2020-01-30 12:51:02 +00:00
calendarName = xml.Name{namespace, "calendar"}
calendarDataName = xml.Name{namespace, "calendar-data"}
2020-01-30 12:28:32 +00:00
)
2020-01-30 12:18:05 +00:00
// https://tools.ietf.org/html/rfc4791#section-6.2.1
type calendarHomeSet struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-home-set"`
Href internal.Href `xml:"DAV: href"`
}
2020-01-30 12:28:32 +00:00
// https://tools.ietf.org/html/rfc4791#section-5.2.1
type calendarDescription struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-description"`
Description string `xml:",chardata"`
}
// https://tools.ietf.org/html/rfc4791#section-5.2.4
type supportedCalendarData struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav supported-calendar-data"`
Types []calendarDataType `xml:"calendar-data"`
}
// https://tools.ietf.org/html/rfc4791#section-5.2.3
type supportedCalendarComponentSet struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav supported-calendar-component-set"`
Comp []comp `xml:"comp"`
}
2020-01-30 12:28:32 +00:00
// https://tools.ietf.org/html/rfc4791#section-9.6
type calendarDataType struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-data"`
ContentType string `xml:"content-type,attr"`
Version string `xml:"version,attr"`
}
// https://tools.ietf.org/html/rfc4791#section-5.2.5
type maxResourceSize struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav max-resource-size"`
Size int64 `xml:",chardata"`
}
// https://tools.ietf.org/html/rfc4791#section-9.5
type calendarQuery struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-query"`
Prop *internal.Prop `xml:"DAV: prop,omitempty"`
AllProp *struct{} `xml:"DAV: allprop,omitempty"`
PropName *struct{} `xml:"DAV: propname,omitempty"`
2020-02-05 16:07:35 +00:00
Filter filter `xml:"filter"`
// TODO: timezone
}
2020-05-13 15:45:10 +01:00
// https://tools.ietf.org/html/rfc4791#section-9.10
type calendarMultiget struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-multiget"`
Hrefs []internal.Href `xml:"DAV: href"`
Prop *internal.Prop `xml:"DAV: prop,omitempty"`
AllProp *struct{} `xml:"DAV: allprop,omitempty"`
PropName *struct{} `xml:"DAV: propname,omitempty"`
}
2020-02-05 16:07:35 +00:00
// https://tools.ietf.org/html/rfc4791#section-9.7
type filter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav filter"`
CompFilter compFilter `xml:"comp-filter"`
2020-02-05 16:07:35 +00:00
}
// https://tools.ietf.org/html/rfc4791#section-9.7.1
type compFilter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav comp-filter"`
Name string `xml:"name,attr"`
IsNotDefined *struct{} `xml:"is-not-defined,omitempty"`
TimeRange *timeRange `xml:"time-range,omitempty"`
PropFilters []propFilter `xml:"prop-filter,omitempty"`
CompFilters []compFilter `xml:"comp-filter,omitempty"`
}
// https://tools.ietf.org/html/rfc4791#section-9.7.2
type propFilter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav prop-filter"`
Name string `xml:"name,attr"`
IsNotDefined *struct{} `xml:"is-not-defined,omitempty"`
TimeRange *timeRange `xml:"time-range,omitempty"`
TextMatch *textMatch `xml:"text-match,omitempty"`
ParamFilter []paramFilter `xml:"param-filter,omitempty"`
}
// https://tools.ietf.org/html/rfc4791#section-9.7.3
type paramFilter struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav param-filter"`
Name string `xml:"name,attr"`
IsNotDefined *struct{} `xml:"is-not-defined,omitempty"`
TextMatch *textMatch `xml:"text-match,omitempty"`
}
// https://tools.ietf.org/html/rfc4791#section-9.7.5
type textMatch struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav text-match"`
Text string `xml:",chardata"`
Collation string `xml:"collation,attr,omitempty"`
NegateCondition negateCondition `xml:"negate-condition,attr,omitempty"`
}
type negateCondition bool
func (nc *negateCondition) UnmarshalText(b []byte) error {
switch s := string(b); s {
case "yes":
*nc = true
case "no":
*nc = false
default:
return fmt.Errorf("caldav: invalid negate-condition value: %q", s)
}
return nil
}
func (nc negateCondition) MarshalText() ([]byte, error) {
if nc {
return []byte("yes"), nil
}
return nil, nil
2020-02-05 16:07:35 +00:00
}
// https://tools.ietf.org/html/rfc4791#section-9.9
type timeRange struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav time-range"`
Start dateWithUTCTime `xml:"start,attr,omitempty"`
End dateWithUTCTime `xml:"end,attr,omitempty"`
2020-02-05 16:07:35 +00:00
}
const dateWithUTCTimeLayout = "20060102T150405Z"
// dateWithUTCTime is the "date with UTC time" format defined in RFC 5545 page
// 34.
type dateWithUTCTime time.Time
func (t *dateWithUTCTime) UnmarshalText(b []byte) error {
tt, err := time.Parse(dateWithUTCTimeLayout, string(b))
if err != nil {
return err
}
*t = dateWithUTCTime(tt)
return nil
}
func (t *dateWithUTCTime) MarshalText() ([]byte, error) {
s := time.Time(*t).Format(dateWithUTCTimeLayout)
return []byte(s), nil
}
// Request variant of https://tools.ietf.org/html/rfc4791#section-9.6
type calendarDataReq struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-data"`
Comp *comp `xml:"comp,omitempty"`
// TODO: expand, limit-recurrence-set, limit-freebusy-set
}
// https://tools.ietf.org/html/rfc4791#section-9.6.1
type comp struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav comp"`
Name string `xml:"name,attr"`
Allprop *struct{} `xml:"allprop,omitempty"`
Prop []prop `xml:"prop,omitempty"`
Allcomp *struct{} `xml:"allcomp,omitempty"`
Comp []comp `xml:"comp,omitempty"`
}
// https://tools.ietf.org/html/rfc4791#section-9.6.4
type prop struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav prop"`
Name string `xml:"name,attr"`
// TODO: novalue
}
// Response variant of https://tools.ietf.org/html/rfc4791#section-9.6
2020-02-03 16:26:55 +00:00
type calendarDataResp struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar-data"`
Data []byte `xml:",chardata"`
}
type reportReq struct {
Query *calendarQuery
Multiget *calendarMultiget
// TODO: CALDAV:free-busy-query
}
func (r *reportReq) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var v interface{}
switch start.Name {
case calendarQueryName:
r.Query = &calendarQuery{}
v = r.Query
case calendarMultigetName:
r.Multiget = &calendarMultiget{}
v = r.Multiget
default:
return fmt.Errorf("caldav: unsupported REPORT root %q %q", start.Name.Space, start.Name.Local)
}
return d.DecodeElement(v, &start)
}