From 0ed7542d17fe5ef659a3466e3b1823493041efda Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 9 Sep 2017 16:37:14 +0200 Subject: [PATCH] carddav: implement AddressObject.Stat --- carddav/carddav.go | 72 ++++++++++++++++++++++++++++++++++++------ protonmail/contacts.go | 21 ++++++++---- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/carddav/carddav.go b/carddav/carddav.go index 7d4b511..b6094e1 100644 --- a/carddav/carddav.go +++ b/carddav/carddav.go @@ -4,6 +4,7 @@ import ( "net/http" "os" "strings" + "time" "github.com/emersion/hydroxide/protonmail" "github.com/emersion/go-vcard" @@ -14,9 +15,37 @@ type contextKey string const ClientContextKey = contextKey("client") +type addressFileInfo struct { + contact *protonmail.Contact +} + +func (fi *addressFileInfo) Name() string { + return fi.contact.ID + ".vcf" +} + +func (fi *addressFileInfo) Size() int64 { + return int64(fi.contact.Size) +} + +func (fi *addressFileInfo) Mode() os.FileMode { + return os.ModePerm +} + +func (fi *addressFileInfo) ModTime() time.Time { + return time.Unix(fi.contact.ModifyTime, 0) +} + +func (fi *addressFileInfo) IsDir() bool { + return false +} + +func (fi *addressFileInfo) Sys() interface{} { + return nil +} + type addressObject struct { c *protonmail.Client - contact *protonmail.ContactExport + contact *protonmail.Contact } func (ao *addressObject) ID() string { @@ -51,12 +80,12 @@ func (ao *addressObject) Card() (vcard.Card, error) { } func (ao *addressObject) Stat() (os.FileInfo, error) { - return nil, nil + return &addressFileInfo{ao.contact}, nil } type addressBook struct { c *protonmail.Client - cache map[string]carddav.AddressObject + cache map[string]*addressObject total int } @@ -73,6 +102,24 @@ func (ab *addressBook) ListAddressObjects() ([]carddav.AddressObject, error) { return aos, nil } + // Get a list of all contacts + // TODO: paging support + total, contacts, err := ab.c.ListContacts(0, 0) + if err != nil { + return nil, err + } + ab.total = total + + for _, contact := range contacts { + if _, ok := ab.cache[contact.ID]; !ok { + ab.cache[contact.ID] = &addressObject{ + c: ab.c, + contact: contact, + } + } + } + + // Get all contacts cards var aos []carddav.AddressObject page := 0 for { @@ -87,8 +134,16 @@ func (ab *addressBook) ListAddressObjects() ([]carddav.AddressObject, error) { } for _, contact := range contacts { - ao := &addressObject{c: ab.c, contact: contact} - ab.cache[contact.ID] = ao + ao, ok := ab.cache[contact.ID] + if !ok { + ao = &addressObject{ + c: ab.c, + contact: &protonmail.Contact{ID: contact.ID}, + } + ab.cache[contact.ID] = ao + } + + ao.contact.Cards = contact.Cards aos = append(aos, ao) } @@ -115,10 +170,7 @@ func (ab *addressBook) GetAddressObject(id string) (carddav.AddressObject, error ao := &addressObject{ c: ab.c, - contact: &protonmail.ContactExport{ - ID: contact.ID, - Cards: contact.Cards, - }, + contact: contact, } ab.cache[id] = ao return ao, nil @@ -127,7 +179,7 @@ func (ab *addressBook) GetAddressObject(id string) (carddav.AddressObject, error func NewHandler(c *protonmail.Client) http.Handler { return carddav.NewHandler(&addressBook{ c: c, - cache: make(map[string]carddav.AddressObject), + cache: make(map[string]*addressObject), total: -1, }) } diff --git a/protonmail/contacts.go b/protonmail/contacts.go index 4187430..c6e2ea1 100644 --- a/protonmail/contacts.go +++ b/protonmail/contacts.go @@ -11,8 +11,8 @@ type Contact struct { Name string UID string Size int - CreateTime int - ModifyTime int + CreateTime int64 + ModifyTime int64 LabelIDs []string // Not when using ListContacts @@ -73,21 +73,28 @@ type ContactExport struct { Cards []*ContactCard } -func (c *Client) ListContacts() ([]*Contact, error) { - req, err := c.newRequest(http.MethodGet, "/contacts", nil) +func (c *Client) ListContacts(page, pageSize int) (total int, contacts []*Contact, err error) { + v := url.Values{} + v.Set("Page", strconv.Itoa(page)) + if pageSize > 0 { + v.Set("PageSize", strconv.Itoa(pageSize)) + } + + req, err := c.newRequest(http.MethodGet, "/contacts?"+v.Encode(), nil) if err != nil { - return nil, err + return 0, nil, err } var respData struct { resp Contacts []*Contact + Total int } if err := c.doJSON(req, &respData); err != nil { - return nil, err + return 0, nil, err } - return respData.Contacts, nil + return respData.Total, respData.Contacts, nil } func (c *Client) ListContactsEmails(page, pageSize int) (total int, emails []*ContactEmail, err error) {