diff --git a/carddav/carddav.go b/carddav/carddav.go index fbc9e3b..32860a8 100644 --- a/carddav/carddav.go +++ b/carddav/carddav.go @@ -28,6 +28,7 @@ type AddressBookQuery struct { type PropFilter struct { Name string + Test FilterTest // defaults to FilterAnyOf // if IsNotDefined is set, TextMatches and Params need to be unset IsNotDefined bool @@ -37,7 +38,6 @@ type PropFilter struct { type ParamFilter struct { Name string - Test FilterTest // defaults to FilterAnyOf // if IsNotDefined is set, TextMatch needs to be unset IsNotDefined bool diff --git a/carddav/client.go b/carddav/client.go index 9088935..011eafe 100644 --- a/carddav/client.go +++ b/carddav/client.go @@ -157,6 +157,49 @@ func encodeAddressPropReq(props []string, allProp bool) (*internal.Prop, error) return internal.EncodeProp(&addrDataReq, getLastModReq, getETagReq) } +func encodePropFilter(pf *PropFilter) (*propFilter, error) { + el := &propFilter{Name: pf.Name, Test: filterTest(pf.Test)} + if pf.IsNotDefined { + if len(pf.TextMatches) > 0 || len(pf.Params) > 0 { + return nil, fmt.Errorf("carddav: failed to encode PropFilter: IsNotDefined cannot be set with TextMatches or Params") + } + el.IsNotDefined = &struct{}{} + } + for _, tm := range pf.TextMatches { + el.TextMatches = append(el.TextMatches, *encodeTextMatch(&tm)) + } + for _, param := range pf.Params { + paramEl, err := encodeParamFilter(¶m) + if err != nil { + return nil, err + } + el.Params = append(el.Params, *paramEl) + } + return el, nil +} + +func encodeParamFilter(pf *ParamFilter) (*paramFilter, error) { + el := ¶mFilter{Name: pf.Name} + if pf.IsNotDefined { + if pf.TextMatch != nil { + return nil, fmt.Errorf("carddav: failed to encode ParamFilter: only one of IsNotDefined or TextMatch can be set") + } + el.IsNotDefined = &struct{}{} + } + if pf.TextMatch != nil { + el.TextMatch = encodeTextMatch(pf.TextMatch) + } + return el, nil +} + +func encodeTextMatch(tm *TextMatch) *textMatch { + return &textMatch{ + Text: tm.Text, + NegateCondition: negateCondition(tm.NegateCondition), + MatchType: matchType(tm.MatchType), + } +} + func decodeAddressList(ms *internal.Multistatus) ([]AddressObject, error) { addrs := make([]AddressObject, 0, len(ms.Responses)) for _, resp := range ms.Responses { @@ -215,6 +258,14 @@ func (c *Client) QueryAddressBook(addressBook string, query *AddressBookQuery) ( } addressbookQuery := addressbookQuery{Prop: propReq} + addressbookQuery.Filter.Test = filterTest(query.FilterTest) + for _, pf := range query.PropFilters { + el, err := encodePropFilter(&pf) + if err != nil { + return nil, err + } + addressbookQuery.Filter.Props = append(addressbookQuery.Filter.Props, *el) + } if query.Limit > 0 { addressbookQuery.Limit = &limit{NResults: uint(query.Limit)} } diff --git a/carddav/elements.go b/carddav/elements.go index 49f3e3a..d224585 100644 --- a/carddav/elements.go +++ b/carddav/elements.go @@ -88,8 +88,8 @@ type propFilter struct { Test filterTest `xml:"test,attr,omitempty"` IsNotDefined *struct{} `xml:"is-not-defined,omitempty"` - TextMatch []textMatch `xml:"text-match,omitempty"` - ParamFilter []paramFilter `xml:"param-filter,omitempty"` + TextMatches []textMatch `xml:"text-match,omitempty"` + Params []paramFilter `xml:"param-filter,omitempty"` } // https://tools.ietf.org/html/rfc6352#section-10.5.4