diff --git a/carddav/client.go b/carddav/client.go index 9d03987..bb905cc 100644 --- a/carddav/client.go +++ b/carddav/client.go @@ -38,7 +38,7 @@ func (c *Client) FindAddressBookHomeSet(principal string) (string, error) { } var prop addressbookHomeSet - if err := resp.DecodeProp(name, &prop); err != nil { + if err := resp.DecodeProp(&prop); err != nil { return "", err } @@ -70,7 +70,7 @@ func (c *Client) FindAddressBooks(addressBookHomeSet string) ([]AddressBook, err } var resTypeProp internal.ResourceType - if err := resp.DecodeProp(resTypeName, &resTypeProp); err != nil { + if err := resp.DecodeProp(&resTypeProp); err != nil { return nil, err } if !resTypeProp.Is(addressBookName) { @@ -78,7 +78,7 @@ func (c *Client) FindAddressBooks(addressBookHomeSet string) ([]AddressBook, err } var descProp addressbookDescription - if err := resp.DecodeProp(descName, &descProp); err != nil { + if err := resp.DecodeProp(&descProp); err != nil { return nil, err } @@ -92,8 +92,6 @@ func (c *Client) FindAddressBooks(addressBookHomeSet string) ([]AddressBook, err } func (c *Client) QueryAddressBook(addressBook string, query *AddressBookQuery) ([]Address, error) { - addrDataName := xml.Name{namespace, "address-data"} - var addrDataReq addressDataReq for _, name := range query.Props { addrDataReq.Props = append(addrDataReq.Props, prop{Name: name}) @@ -126,7 +124,7 @@ func (c *Client) QueryAddressBook(addressBook string, query *AddressBookQuery) ( } var addrData addressDataResp - if err := resp.DecodeProp(addrDataName, &addrData); err != nil { + if err := resp.DecodeProp(&addrData); err != nil { return nil, err } diff --git a/client.go b/client.go index 9aab567..488f41f 100644 --- a/client.go +++ b/client.go @@ -29,7 +29,7 @@ func (c *Client) FindCurrentUserPrincipal() (string, error) { } var prop currentUserPrincipal - if err := resp.DecodeProp(name, &prop); err != nil { + if err := resp.DecodeProp(&prop); err != nil { return "", err } diff --git a/internal/elements.go b/internal/elements.go index 9f441e2..43f8ad1 100644 --- a/internal/elements.go +++ b/internal/elements.go @@ -73,7 +73,11 @@ func (resp *Response) Href() (string, error) { return resp.Hrefs[0], nil } -func (resp *Response) DecodeProp(name xml.Name, v interface{}) error { +func (resp *Response) DecodeProp(v interface{}) error { + name, err := valueXMLName(v) + if err != nil { + return err + } if err := resp.Status.Err(); err != nil { return err } diff --git a/internal/xml.go b/internal/xml.go index 398d09c..69d5ffc 100644 --- a/internal/xml.go +++ b/internal/xml.go @@ -2,7 +2,10 @@ package internal import ( "encoding/xml" + "fmt" "io" + "reflect" + "strings" ) // RawXMLValue is a raw XML value. It implements xml.Unmarshaler and @@ -88,6 +91,9 @@ func (val *RawXMLValue) Decode(v interface{}) error { // TokenReader returns a stream of tokens for the XML value. func (val *RawXMLValue) TokenReader() xml.TokenReader { + if val.out != nil { + panic("webdav: called RawXMLValue.TokenReader on a marshal-only XML value") + } return &rawXMLValueReader{val: val} } @@ -133,3 +139,30 @@ func (tr *rawXMLValueReader) Token() (xml.Token, error) { } var _ xml.TokenReader = (*rawXMLValueReader)(nil) + +func valueXMLName(v interface{}) (xml.Name, error) { + t := reflect.TypeOf(v) + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return xml.Name{}, fmt.Errorf("webdav: %T is not a struct", v) + } + nameField, ok := t.FieldByName("XMLName") + if !ok { + return xml.Name{}, fmt.Errorf("webdav: %T is missing an XMLName struct field", v) + } + if nameField.Type != reflect.TypeOf(xml.Name{}) { + return xml.Name{}, fmt.Errorf("webdav: %T.XMLName isn't an xml.Name", v) + } + tag := nameField.Tag.Get("xml") + if tag == "" { + return xml.Name{}, fmt.Errorf(`webdav: %T.XMLName is missing an "xml" tag`, v) + } + name := strings.Split(tag, ",")[0] + nameParts := strings.Split(name, " ") + if len(nameParts) != 2 { + return xml.Name{}, fmt.Errorf("webdav: expected a namespace and local name in %T.XMLName's xml tag", v) + } + return xml.Name{nameParts[0], nameParts[1]}, nil +}