mirror of
https://github.com/1f349/go-webdav.git
synced 2024-12-22 16:24:14 +00:00
carddav: add Client.FindAddressBooks
This commit is contained in:
parent
3d05533a31
commit
9dfabd89c8
@ -1,3 +1,18 @@
|
|||||||
package carddav
|
package carddav
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
)
|
||||||
|
|
||||||
const namespace = "urn:ietf:params:xml:ns:carddav"
|
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
|
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"}
|
name := xml.Name{namespace, "addressbook-home-set"}
|
||||||
propfind := internal.NewPropPropfind(name)
|
propfind := internal.NewPropPropfind(name)
|
||||||
|
|
||||||
@ -42,3 +42,50 @@ func (c *Client) FindAddressbookHomeSet(principal string) (string, error) {
|
|||||||
|
|
||||||
return prop.Href, nil
|
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 {
|
type addressbookHomeSet struct {
|
||||||
Name xml.Name `xml:"urn:ietf:params:xml:ns:carddav addressbook-home-set"`
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:carddav addressbook-home-set"`
|
||||||
Href string `xml:"href"`
|
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 {
|
type currentUserPrincipal struct {
|
||||||
Name xml.Name `xml:"DAV: current-user-principal"`
|
XMLName xml.Name `xml:"DAV: current-user-principal"`
|
||||||
Href string `xml:"href"`
|
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) {
|
func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
||||||
// TODO: remove this quirk
|
// TODO: remove this quirk
|
||||||
req.SetBasicAuth("simon", "")
|
req.SetBasicAuth("emersion", "")
|
||||||
return c.http.Do(req)
|
return c.http.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ type Multistatus struct {
|
|||||||
func (ms *Multistatus) Get(href string) (*Response, error) {
|
func (ms *Multistatus) Get(href string) (*Response, error) {
|
||||||
for i := range ms.Responses {
|
for i := range ms.Responses {
|
||||||
resp := &ms.Responses[i]
|
resp := &ms.Responses[i]
|
||||||
for _, h := range resp.Href {
|
for _, h := range resp.Hrefs {
|
||||||
if h == href {
|
if h == href {
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ func (ms *Multistatus) Get(href string) (*Response, error) {
|
|||||||
// https://tools.ietf.org/html/rfc4918#section-14.24
|
// https://tools.ietf.org/html/rfc4918#section-14.24
|
||||||
type Response struct {
|
type Response struct {
|
||||||
XMLName xml.Name `xml:"DAV: response"`
|
XMLName xml.Name `xml:"DAV: response"`
|
||||||
Href []string `xml:"href"`
|
Hrefs []string `xml:"href"`
|
||||||
Propstats []Propstat `xml:"propstat,omitempty"`
|
Propstats []Propstat `xml:"propstat,omitempty"`
|
||||||
ResponseDescription string `xml:"responsedescription,omitempty"`
|
ResponseDescription string `xml:"responsedescription,omitempty"`
|
||||||
Status Status `xml:"status,omitempty"`
|
Status Status `xml:"status,omitempty"`
|
||||||
@ -63,6 +63,16 @@ type Response struct {
|
|||||||
Location *Location `xml:"location,omitempty"`
|
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 {
|
func (resp *Response) DecodeProp(name xml.Name, v interface{}) error {
|
||||||
if err := resp.Status.Err(); err != nil {
|
if err := resp.Status.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -71,13 +81,11 @@ func (resp *Response) DecodeProp(name xml.Name, v interface{}) error {
|
|||||||
propstat := &resp.Propstats[i]
|
propstat := &resp.Propstats[i]
|
||||||
for j := range propstat.Prop.Raw {
|
for j := range propstat.Prop.Raw {
|
||||||
raw := &propstat.Prop.Raw[j]
|
raw := &propstat.Prop.Raw[j]
|
||||||
if start, ok := raw.tok.(xml.StartElement); ok {
|
if start, ok := raw.tok.(xml.StartElement); ok && name == start.Name {
|
||||||
if name == start.Name {
|
if err := propstat.Status.Err(); err != nil {
|
||||||
if err := propstat.Status.Err(); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return raw.Decode(v)
|
|
||||||
}
|
}
|
||||||
|
return raw.Decode(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,3 +128,20 @@ func NewPropPropfind(names ...xml.Name) *Propfind {
|
|||||||
}
|
}
|
||||||
return &Propfind{Prop: &Prop{Raw: children}}
|
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