mirror of
https://github.com/1f349/go-webdav.git
synced 2024-12-22 08:14:15 +00:00
carddav: add Client.FindAddressBooks
This commit is contained in:
parent
3d05533a31
commit
9dfabd89c8
@ -1,3 +1,18 @@
|
||||
package carddav
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
const namespace = "urn:ietf:params:xml:ns:carddav"
|
||||
|
||||
type AddressBook struct {
|
||||
Href string
|
||||
Description string
|
||||
}
|
||||
|
||||
var addressBookName = xml.Name{namespace, "addressbook"}
|
||||
|
||||
type AddressBookQuery struct {
|
||||
AddressDataProps []string
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ func NewClient(c *http.Client, endpoint string) (*Client, error) {
|
||||
return &Client{wc, ic}, nil
|
||||
}
|
||||
|
||||
func (c *Client) FindAddressbookHomeSet(principal string) (string, error) {
|
||||
func (c *Client) FindAddressBookHomeSet(principal string) (string, error) {
|
||||
name := xml.Name{namespace, "addressbook-home-set"}
|
||||
propfind := internal.NewPropPropfind(name)
|
||||
|
||||
@ -42,3 +42,50 @@ func (c *Client) FindAddressbookHomeSet(principal string) (string, error) {
|
||||
|
||||
return prop.Href, nil
|
||||
}
|
||||
|
||||
func (c *Client) FindAddressBooks(addressBookHomeSet string) ([]AddressBook, error) {
|
||||
resTypeName := xml.Name{"DAV:", "resourcetype"}
|
||||
descName := xml.Name{namespace, "addressbook-description"}
|
||||
propfind := internal.NewPropPropfind(resTypeName, descName)
|
||||
|
||||
req, err := c.ic.NewXMLRequest("PROPFIND", addressBookHomeSet, propfind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("Depth", "1")
|
||||
|
||||
ms, err := c.ic.DoMultiStatus(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := make([]AddressBook, 0, len(ms.Responses))
|
||||
for i := range ms.Responses {
|
||||
resp := &ms.Responses[i]
|
||||
href, err := resp.Href()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resTypeProp internal.ResourceType
|
||||
if err := resp.DecodeProp(resTypeName, &resTypeProp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !resTypeProp.Is(addressBookName) {
|
||||
continue
|
||||
}
|
||||
|
||||
var descProp addressbookDescription
|
||||
if err := resp.DecodeProp(descName, &descProp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l = append(l, AddressBook{
|
||||
Href: href,
|
||||
Description: descProp.Data,
|
||||
})
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
@ -5,6 +5,19 @@ import (
|
||||
)
|
||||
|
||||
type addressbookHomeSet struct {
|
||||
Name xml.Name `xml:"urn:ietf:params:xml:ns:carddav addressbook-home-set"`
|
||||
Href string `xml:"href"`
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:carddav addressbook-home-set"`
|
||||
Href string `xml:"href"`
|
||||
}
|
||||
|
||||
type addressbookDescription struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:carddav addressbook-description"`
|
||||
Data string `xml:",chardata"`
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc6352#section-10.3
|
||||
type addressbookQuery struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:carddav addressbook-query"`
|
||||
Prop *internal.Prop `xml:"DAV: prop,omitempty"`
|
||||
// TODO: DAV:allprop | DAV:propname
|
||||
// TODO: filter, limit?
|
||||
}
|
||||
|
@ -5,6 +5,6 @@ import (
|
||||
)
|
||||
|
||||
type currentUserPrincipal struct {
|
||||
Name xml.Name `xml:"DAV: current-user-principal"`
|
||||
Href string `xml:"href"`
|
||||
XMLName xml.Name `xml:"DAV: current-user-principal"`
|
||||
Href string `xml:"href"`
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func (c *Client) NewXMLRequest(method string, href string, v interface{}) (*http
|
||||
|
||||
func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
||||
// TODO: remove this quirk
|
||||
req.SetBasicAuth("simon", "")
|
||||
req.SetBasicAuth("emersion", "")
|
||||
return c.http.Do(req)
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ type Multistatus struct {
|
||||
func (ms *Multistatus) Get(href string) (*Response, error) {
|
||||
for i := range ms.Responses {
|
||||
resp := &ms.Responses[i]
|
||||
for _, h := range resp.Href {
|
||||
for _, h := range resp.Hrefs {
|
||||
if h == href {
|
||||
return resp, nil
|
||||
}
|
||||
@ -55,7 +55,7 @@ func (ms *Multistatus) Get(href string) (*Response, error) {
|
||||
// https://tools.ietf.org/html/rfc4918#section-14.24
|
||||
type Response struct {
|
||||
XMLName xml.Name `xml:"DAV: response"`
|
||||
Href []string `xml:"href"`
|
||||
Hrefs []string `xml:"href"`
|
||||
Propstats []Propstat `xml:"propstat,omitempty"`
|
||||
ResponseDescription string `xml:"responsedescription,omitempty"`
|
||||
Status Status `xml:"status,omitempty"`
|
||||
@ -63,6 +63,16 @@ type Response struct {
|
||||
Location *Location `xml:"location,omitempty"`
|
||||
}
|
||||
|
||||
func (resp *Response) Href() (string, error) {
|
||||
if err := resp.Status.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(resp.Hrefs) != 1 {
|
||||
return "", fmt.Errorf("webdav: malformed response: expected exactly one href element, got %v", len(resp.Hrefs))
|
||||
}
|
||||
return resp.Hrefs[0], nil
|
||||
}
|
||||
|
||||
func (resp *Response) DecodeProp(name xml.Name, v interface{}) error {
|
||||
if err := resp.Status.Err(); err != nil {
|
||||
return err
|
||||
@ -71,13 +81,11 @@ func (resp *Response) DecodeProp(name xml.Name, v interface{}) error {
|
||||
propstat := &resp.Propstats[i]
|
||||
for j := range propstat.Prop.Raw {
|
||||
raw := &propstat.Prop.Raw[j]
|
||||
if start, ok := raw.tok.(xml.StartElement); ok {
|
||||
if name == start.Name {
|
||||
if err := propstat.Status.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return raw.Decode(v)
|
||||
if start, ok := raw.tok.(xml.StartElement); ok && name == start.Name {
|
||||
if err := propstat.Status.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return raw.Decode(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,3 +128,20 @@ func NewPropPropfind(names ...xml.Name) *Propfind {
|
||||
}
|
||||
return &Propfind{Prop: &Prop{Raw: children}}
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc4918#section-15.9
|
||||
type ResourceType struct {
|
||||
XMLName xml.Name `xml:"DAV: resourcetype"`
|
||||
Raw []RawXMLValue `xml:",any"`
|
||||
}
|
||||
|
||||
func (t *ResourceType) Is(name xml.Name) bool {
|
||||
for _, raw := range t.Raw {
|
||||
if start, ok := raw.tok.(xml.StartElement); ok && name == start.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var CollectionName = xml.Name{"DAV:", "collection"}
|
||||
|
Loading…
Reference in New Issue
Block a user