A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1// SiYuan - Refactor your thinking
2// Copyright (c) 2020-present, b3log.org
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17package model
18
19import (
20 "bytes"
21 "context"
22 "errors"
23 "fmt"
24 "io"
25 "os"
26 "path"
27 "strings"
28 "sync"
29
30 "github.com/88250/gulu"
31 "github.com/88250/lute/ast"
32 "github.com/emersion/go-vcard"
33 "github.com/emersion/go-webdav/carddav"
34 "github.com/siyuan-note/logging"
35 "github.com/siyuan-note/siyuan/kernel/util"
36)
37
38const (
39 // REF: https://developers.google.com/people/carddav#resources
40 CardDavPrefixPath = "/carddav"
41 CardDavPrincipalsPath = CardDavPrefixPath + "/principals" // 0 resourceTypeRoot
42 CardDavUserPrincipalPath = CardDavPrincipalsPath + "/main" // 1 resourceTypeUserPrincipal
43 CardDavHomeSetPath = CardDavUserPrincipalPath + "/contacts" // 2 resourceTypeAddressBookHomeSet
44
45 CardDavDefaultAddressBookPath = CardDavHomeSetPath + "/default" // 3 resourceTypeAddressBook
46 CardDavDefaultAddressBookName = "default"
47
48 CardDavAddressBooksMetaDataFilePath = CardDavHomeSetPath + "/address-books.json"
49
50 VCardFileExt = "." + vcard.Extension // .vcf
51)
52
53type CardDavPathDepth int
54
55const (
56 cardDavPathDepth_Root CardDavPathDepth = 1 + iota // /carddav
57 cardDavPathDepth_Principals // /carddav/principals
58 cardDavPathDepth_UserPrincipal // /carddav/principals/main
59 cardDavPathDepth_HomeSet // /carddav/principals/main/contacts
60 cardDavPathDepth_AddressBook // /carddav/principals/main/contacts/default
61 cardDavPathDepth_Address // /carddav/principals/main/contacts/default/id.vcf
62)
63
64var (
65 addressBookMaxResourceSize int64 = 0
66 addressBookSupportedAddressData = []carddav.AddressDataType{
67 {
68 ContentType: vcard.MIMEType,
69 Version: "3.0",
70 },
71 {
72 ContentType: vcard.MIMEType,
73 Version: "4.0",
74 },
75 }
76
77 defaultAddressBook = carddav.AddressBook{
78 Path: CardDavDefaultAddressBookPath,
79 Name: CardDavDefaultAddressBookName,
80 Description: "Default address book",
81 MaxResourceSize: addressBookMaxResourceSize,
82 SupportedAddressData: addressBookSupportedAddressData,
83 }
84 contacts = Contacts{
85 loaded: false,
86 changed: false,
87 lock: sync.Mutex{},
88 books: sync.Map{},
89 booksMetaData: []*carddav.AddressBook{},
90 }
91
92 ErrorCardDavPathInvalid = errors.New("CardDAV: path is invalid")
93
94 ErrorCardDavBookNotFound = errors.New("CardDAV: address book not found")
95 ErrorCardDavBookPathInvalid = errors.New("CardDAV: address book path is invalid")
96
97 ErrorCardDavAddressNotFound = errors.New("CardDAV: address not found")
98 ErrorCardDavAddressFileExtensionNameInvalid = errors.New("CardDAV: address file extension name is invalid")
99)
100
101// ImportVCardFile imports a address book from a vCard file (*.vcf)
102func ImportAddressBook(addressBookPath, cardContent string) (addresses []*AddressObject, err error) {
103 // TODO: Check whether the path is valid (PathDepth: Address)
104 // TODO: Check whether the address book exists
105 // TODO: Decode the card content
106 // TODO: Save the cards to the file system
107 return
108}
109
110// ExportAddressBook exports a address book to a vCard file (*.vcf)
111func ExportAddressBook(addressBookPath string) (cardContent string, err error) {
112 // TODO: Check whether the path is valid (PathDepth: AddressBook)
113 // TODO: Check whether the address book exists
114 // TODO: Encode the card content
115 return
116}
117
118// AddressBooksMetaDataFilePath returns the absolute path of the address books meta data file
119func AddressBooksMetaDataFilePath() string {
120 return DavPath2DirectoryPath(CardDavAddressBooksMetaDataFilePath)
121}
122
123func GetCardDavPathDepth(urlPath string) CardDavPathDepth {
124 urlPath = PathCleanWithSlash(urlPath)
125 return CardDavPathDepth(len(strings.Split(urlPath, "/")) - 1)
126}
127
128// ParseAddressPath parses address path to address book path and address ID
129func ParseAddressPath(addressPath string) (addressBookPath string, addressID string, err error) {
130 addressBookPath, addressFileName := path.Split(addressPath)
131 addressID = path.Base(addressFileName)
132 addressFileExt := util.Ext(addressFileName)
133
134 if GetCardDavPathDepth(addressBookPath) != cardDavPathDepth_AddressBook {
135 err = ErrorCardDavBookPathInvalid
136 return
137 }
138
139 if addressFileExt != VCardFileExt {
140 err = ErrorCardDavAddressFileExtensionNameInvalid
141 return
142 }
143
144 return
145}
146
147// AddressPropsFilter filters address properties
148func AddressPropsFilter(address *carddav.AddressObject, req *carddav.AddressDataRequest) *carddav.AddressObject {
149 var card *vcard.Card
150 card = &address.Card
151
152 // if req.AllProp {
153 // card = &address.Card
154 // } else {
155 // card = &vcard.Card{}
156 // for _, prop := range req.Props {
157 // fields := address.Card[prop]
158 // if fields != nil {
159 // for _, field := range fields {
160 // card.Add(prop, field)
161 // }
162 // }
163 // }
164 // }
165
166 return &carddav.AddressObject{
167 Path: address.Path,
168 ModTime: address.ModTime,
169 ContentLength: address.ContentLength,
170 ETag: address.ETag,
171 Card: *card,
172 }
173}
174
175func LoadCards(filePath string) (cards []*vcard.Card, err error) {
176 data, err := os.ReadFile(filePath)
177 if err != nil {
178 logging.LogErrorf("read vCard file [%s] failed: %s", filePath, err)
179 return
180 }
181
182 decoder := vcard.NewDecoder(bytes.NewReader(data))
183 for {
184 card, err := decoder.Decode()
185 if err != nil {
186 if err == io.EOF {
187 break
188 }
189 logging.LogErrorf("decode vCard file [%s] failed: %s", filePath, err)
190 return nil, err
191 }
192 cards = append(cards, &card)
193 }
194
195 return
196}
197
198type Contacts struct {
199 loaded bool
200 changed bool
201 lock sync.Mutex // load & save
202 books sync.Map // Path -> *AddressBook
203 booksMetaData []*carddav.AddressBook
204}
205
206// load all contacts
207func (c *Contacts) load() error {
208 c.books.Clear()
209
210 // load address books meta data
211 addressBooksMetaDataFilePath := AddressBooksMetaDataFilePath()
212 metaData, err := os.ReadFile(addressBooksMetaDataFilePath)
213 if os.IsNotExist(err) {
214 // create & save default address book
215 c.booksMetaData = []*carddav.AddressBook{&defaultAddressBook}
216 if err := c.saveAddressBooksMetaData(); err != nil {
217 return err
218 }
219 } else {
220 // load meta data file
221 c.booksMetaData = []*carddav.AddressBook{}
222 if err = gulu.JSON.UnmarshalJSON(metaData, &c.booksMetaData); err != nil {
223 logging.LogErrorf("unmarshal address books meta data failed: %s", err)
224 return err
225 }
226 }
227
228 // load vCard files (*.vcf)
229 wg := &sync.WaitGroup{}
230 wg.Add(len(c.booksMetaData))
231 for _, addressBookMetaData := range c.booksMetaData {
232 addressBook := &AddressBook{
233 Changed: false,
234 DirectoryPath: DavPath2DirectoryPath(addressBookMetaData.Path),
235 MetaData: addressBookMetaData,
236 Addresses: sync.Map{},
237 }
238 c.books.Store(addressBookMetaData.Path, addressBook)
239 go func() {
240 defer wg.Done()
241 addressBook.load()
242 }()
243 }
244 wg.Wait()
245
246 c.loaded = true
247 c.changed = false
248 return nil
249}
250
251// save all contacts
252func (c *Contacts) save(force bool) error {
253 if force || c.changed {
254 // save address books meta data
255 if err := c.saveAddressBooksMetaData(); err != nil {
256 return err
257 }
258
259 // save all address to *.vbf files
260 wg := &sync.WaitGroup{}
261 c.books.Range(func(path any, book any) bool {
262 wg.Add(1)
263 go func() {
264 defer wg.Done()
265 // path_ := path.(string)
266 book_ := book.(*AddressBook)
267 book_.save(force)
268 }()
269 return true
270 })
271 wg.Wait()
272 c.changed = false
273 }
274 return nil
275}
276
277// save all contacts
278func (c *Contacts) saveAddressBooksMetaData() error {
279 return SaveMetaData(c.booksMetaData, AddressBooksMetaDataFilePath())
280}
281
282func (c *Contacts) Load() error {
283 c.lock.Lock()
284 defer c.lock.Unlock()
285
286 if !c.loaded {
287 return c.load()
288 }
289 return nil
290}
291
292func (c *Contacts) GetAddress(addressPath string) (addressBook *AddressBook, addressObject *AddressObject, err error) {
293 bookPath, addressID, err := ParseAddressPath(addressPath)
294 if err != nil {
295 logging.LogErrorf("parse address path [%s] failed: %s", addressPath, err)
296 return
297 }
298
299 if value, ok := c.books.Load(bookPath); ok {
300 addressBook = value.(*AddressBook)
301 } else {
302 err = ErrorCardDavBookNotFound
303 return
304 }
305
306 if value, ok := addressBook.Addresses.Load(addressID); ok {
307 addressObject = value.(*AddressObject)
308 } else {
309 err = ErrorCardDavAddressNotFound
310 return
311 }
312
313 return
314}
315
316func (c *Contacts) DeleteAddress(addressPath string) (addressBook *AddressBook, addressObject *AddressObject, err error) {
317 bookPath, addressID, err := ParseAddressPath(addressPath)
318 if err != nil {
319 logging.LogErrorf("parse address path [%s] failed: %s", addressPath, err)
320 return
321 }
322
323 if value, ok := c.books.Load(bookPath); ok {
324 addressBook = value.(*AddressBook)
325 } else {
326 err = ErrorCardDavBookNotFound
327 return
328 }
329
330 if value, loaded := addressBook.Addresses.LoadAndDelete(addressID); loaded {
331 addressObject = value.(*AddressObject)
332 } else {
333 err = ErrorCardDavAddressNotFound
334 return
335 }
336
337 if err = os.Remove(addressObject.FilePath); err != nil {
338 logging.LogErrorf("remove file [%s] failed: %s", addressObject.FilePath, err)
339 return
340 }
341
342 return
343}
344
345func (c *Contacts) ListAddressBooks() (addressBooks []carddav.AddressBook, err error) {
346 c.lock.Lock()
347 defer c.lock.Unlock()
348
349 for _, addressBook := range contacts.booksMetaData {
350 addressBooks = append(addressBooks, *addressBook)
351 }
352 return
353}
354
355func (c *Contacts) GetAddressBook(path string) (addressBook *carddav.AddressBook, err error) {
356 c.lock.Lock()
357 defer c.lock.Unlock()
358
359 if book, ok := contacts.books.Load(path); ok {
360 addressBook = book.(*AddressBook).MetaData
361 return
362 }
363
364 err = ErrorCardDavBookNotFound
365 return
366}
367
368func (c *Contacts) CreateAddressBook(addressBookMetaData *carddav.AddressBook) (err error) {
369 c.lock.Lock()
370 defer c.lock.Unlock()
371
372 var addressBook *AddressBook
373
374 // update map
375 if value, ok := c.books.Load(addressBookMetaData.Path); ok {
376 // update map item
377 addressBook = value.(*AddressBook)
378 addressBook.MetaData = addressBookMetaData
379 } else {
380 // insert map item
381 addressBook = &AddressBook{
382 Changed: false,
383 DirectoryPath: DavPath2DirectoryPath(addressBookMetaData.Path),
384 MetaData: addressBookMetaData,
385 Addresses: sync.Map{},
386 }
387 c.books.Store(addressBookMetaData.Path, addressBook)
388 }
389
390 var index = -1
391 for i, item := range c.booksMetaData {
392 if item.Path == addressBookMetaData.Path {
393 index = i
394 break
395 }
396 }
397
398 if index >= 0 {
399 // update list
400 c.booksMetaData[index] = addressBookMetaData
401 } else {
402 // insert list
403 c.booksMetaData = append(c.booksMetaData, addressBookMetaData)
404 }
405
406 // create address book directory
407 if err = os.MkdirAll(addressBook.DirectoryPath, 0755); err != nil {
408 logging.LogErrorf("create directory [%s] failed: %s", addressBook.DirectoryPath, err)
409 return
410 }
411
412 // save meta data
413 if err = c.saveAddressBooksMetaData(); err != nil {
414 return
415 }
416
417 return
418}
419
420func (c *Contacts) DeleteAddressBook(path string) (err error) {
421 c.lock.Lock()
422 defer c.lock.Unlock()
423
424 var addressBook *AddressBook
425
426 // delete map item
427 if value, loaded := c.books.LoadAndDelete(path); loaded {
428 addressBook = value.(*AddressBook)
429 }
430
431 // delete list item
432 for i, item := range c.booksMetaData {
433 if item.Path == path {
434 c.booksMetaData = append(c.booksMetaData[:i], c.booksMetaData[i+1:]...)
435 break
436 }
437 }
438
439 // remove address book directory
440 if err = os.RemoveAll(addressBook.DirectoryPath); err != nil {
441 logging.LogErrorf("remove directory [%s] failed: %s", addressBook.DirectoryPath, err)
442 return
443 }
444
445 // save meta data
446 if err = c.saveAddressBooksMetaData(); err != nil {
447 return
448 }
449
450 return nil
451}
452
453func (c *Contacts) GetAddressObject(addressPath string, req *carddav.AddressDataRequest) (addressObject *carddav.AddressObject, err error) {
454 c.lock.Lock()
455 defer c.lock.Unlock()
456
457 _, address, err := c.GetAddress(addressPath)
458 if err != nil {
459 return
460 }
461
462 addressObject = AddressPropsFilter(address.Data, req)
463 return
464}
465
466func (c *Contacts) ListAddressObjects(bookPath string, req *carddav.AddressDataRequest) (addressObjects []carddav.AddressObject, err error) {
467 c.lock.Lock()
468 defer c.lock.Unlock()
469
470 var addressBook *AddressBook
471 if value, ok := c.books.Load(bookPath); ok {
472 addressBook = value.(*AddressBook)
473 } else {
474 err = ErrorCardDavBookNotFound
475 return
476 }
477
478 addressBook.Addresses.Range(func(id any, address any) bool {
479 addressObjects = append(addressObjects, *AddressPropsFilter(address.(*AddressObject).Data, req))
480 return true
481 })
482
483 return
484}
485
486func (c *Contacts) QueryAddressObjects(urlPath string, query *carddav.AddressBookQuery) (addressObjects []carddav.AddressObject, err error) {
487 c.lock.Lock()
488 defer c.lock.Unlock()
489
490 switch GetCardDavPathDepth(urlPath) {
491 case cardDavPathDepth_Root, cardDavPathDepth_Principals, cardDavPathDepth_UserPrincipal, cardDavPathDepth_HomeSet:
492 c.books.Range(func(path any, book any) bool {
493 addressBook := book.(*AddressBook)
494 addressBook.Addresses.Range(func(id any, address any) bool {
495 addressObjects = append(addressObjects, *address.(*AddressObject).Data)
496 return true
497 })
498 return true
499 })
500 case cardDavPathDepth_AddressBook:
501 if value, ok := c.books.Load(urlPath); ok {
502 addressBook := value.(*AddressBook)
503 addressBook.Addresses.Range(func(id any, address any) bool {
504 addressObjects = append(addressObjects, *address.(*AddressObject).Data)
505 return true
506 })
507 }
508 case cardDavPathDepth_Address:
509 if _, address, _ := c.GetAddress(urlPath); address != nil {
510 addressObjects = append(addressObjects, *address.Data)
511 }
512 default:
513 err = ErrorCardDavPathInvalid
514 return
515 }
516
517 addressObjects, err = carddav.Filter(query, addressObjects)
518 return
519}
520
521func (c *Contacts) PutAddressObject(addressPath string, card vcard.Card, opts *carddav.PutAddressObjectOptions) (addressObject *carddav.AddressObject, err error) {
522 c.lock.Lock()
523 defer c.lock.Unlock()
524
525 bookPath, addressID, err := ParseAddressPath(addressPath)
526 if err != nil {
527 logging.LogErrorf("parse address path [%s] failed: %s", addressPath, err)
528 return
529 }
530
531 var addressBook *AddressBook
532 if value, ok := c.books.Load(bookPath); ok {
533 addressBook = value.(*AddressBook)
534 } else {
535 err = ErrorCardDavBookNotFound
536 return
537 }
538
539 // TODO: 处理 opts.IfNoneMatch (If-None-Match) 与 opts.IfMatch (If-Match)
540
541 var address *AddressObject
542 if value, ok := addressBook.Addresses.Load(addressID); ok {
543 address = value.(*AddressObject)
544 address.Data.Card = card
545 address.Changed = true
546 } else {
547 address = &AddressObject{
548 Changed: true,
549 FilePath: DavPath2DirectoryPath(addressPath),
550 BookPath: bookPath,
551 Data: &carddav.AddressObject{
552 Card: card,
553 },
554 }
555 }
556
557 err = address.save(true)
558 if err != nil {
559 return
560 }
561
562 err = address.update()
563 if err != nil {
564 return
565 }
566
567 addressBook.Addresses.Store(addressID, address)
568 addressObject = address.Data
569 return
570}
571
572func (c *Contacts) DeleteAddressObject(addressPath string) (err error) {
573 c.lock.Lock()
574 defer c.lock.Unlock()
575
576 _, _, err = c.DeleteAddress(addressPath)
577 if err != nil {
578 return
579 }
580
581 return
582}
583
584type AddressBook struct {
585 Changed bool
586 DirectoryPath string
587 MetaData *carddav.AddressBook
588 Addresses sync.Map // id -> *AddressObject
589}
590
591// load an address book from multiple *.vcf files
592func (b *AddressBook) load() error {
593 if err := os.MkdirAll(b.DirectoryPath, 0755); err != nil {
594 logging.LogErrorf("create directory [%s] failed: %s", b.DirectoryPath, err)
595 return err
596 }
597
598 entries, err := os.ReadDir(b.DirectoryPath)
599 if err != nil {
600 logging.LogErrorf("read dir [%s] failed: %s", b.DirectoryPath, err)
601 return err
602 }
603
604 wg := &sync.WaitGroup{}
605 for _, entry := range entries {
606 if !entry.IsDir() {
607 filename := entry.Name()
608 ext := util.Ext(filename)
609 if ext == VCardFileExt {
610 wg.Add(1)
611 go func() {
612 defer wg.Done()
613
614 // load cards
615 addressFilePath := path.Join(b.DirectoryPath, filename)
616 vCards, err := LoadCards(addressFilePath)
617 if err != nil {
618 return
619 }
620
621 switch len(vCards) {
622 case 0: // invalid file
623 case 1: // file contain 1 card
624 address := &AddressObject{
625 FilePath: addressFilePath,
626 BookPath: b.MetaData.Path,
627 Data: &carddav.AddressObject{
628 Card: *vCards[0],
629 },
630 }
631 if err := address.update(); err != nil {
632 return
633 }
634
635 id := path.Base(filename)
636 b.Addresses.Store(id, address)
637 default: // file contain multiple cards
638 // Create a file for each card
639 addressesWaitGroup := &sync.WaitGroup{}
640 for _, vCard := range vCards {
641 addressesWaitGroup.Add(1)
642 go func() {
643 defer addressesWaitGroup.Done()
644 filename_ := util.AssetName(filename, ast.NewNodeID())
645 address := &AddressObject{
646 FilePath: path.Join(b.DirectoryPath, filename_),
647 BookPath: b.MetaData.Path,
648 Data: &carddav.AddressObject{
649 Card: *vCard,
650 },
651 }
652 if err := address.save(true); err != nil {
653 return
654 }
655 if err := address.update(); err != nil {
656 return
657 }
658
659 id := path.Base(filename)
660 b.Addresses.Store(id, address)
661 }()
662 }
663
664 addressesWaitGroup.Wait()
665 // Delete original file with multiple cards
666 if err := os.Remove(addressFilePath); err != nil {
667 logging.LogErrorf("remove file [%s] failed: %s", addressFilePath, err)
668 return
669 }
670 }
671 }()
672 }
673 }
674 }
675 wg.Wait()
676 return nil
677}
678
679// save an address book to multiple *.vcf files
680func (b *AddressBook) save(force bool) error {
681 if force || b.Changed {
682 // create directory
683 if err := os.MkdirAll(b.DirectoryPath, 0755); err != nil {
684 logging.LogErrorf("create directory [%s] failed: %s", b.DirectoryPath, err)
685 return err
686 }
687
688 wg := &sync.WaitGroup{}
689 b.Addresses.Range(func(id any, address any) bool {
690 wg.Add(1)
691 go func() {
692 defer wg.Done()
693 // id_ := id.(string)
694 address_ := address.(*AddressObject)
695 address_.save(force)
696 address_.update()
697 }()
698 return true
699 })
700 wg.Wait()
701 b.Changed = false
702 }
703
704 return nil
705}
706
707type AddressObject struct {
708 Changed bool
709 FilePath string
710 BookPath string
711 Data *carddav.AddressObject
712}
713
714// load an address from *.vcf file
715func (o *AddressObject) load() error {
716 // load vCard file
717 cards, err := LoadCards(o.FilePath)
718 if err != nil {
719 return err
720 }
721 if len(cards) != 1 {
722 return fmt.Errorf("file [%s] contains multiple cards", o.FilePath)
723 }
724
725 // create address object
726 o.Data = &carddav.AddressObject{
727 Card: *cards[0],
728 }
729
730 // update file info
731 err = o.update()
732 if err != nil {
733 return err
734 }
735
736 o.Changed = false
737 return nil
738}
739
740// save an address to *.vcf file
741func (o *AddressObject) save(force bool) error {
742 if force || o.Changed {
743 var addressData bytes.Buffer
744
745 // encode data
746 encoder := vcard.NewEncoder(&addressData)
747 if err := encoder.Encode(o.Data.Card); err != nil {
748 logging.LogErrorf("encode card [%s] failed: %s", o.Data.Path, err)
749 return err
750 }
751
752 // create directory
753 dirPath := path.Dir(o.FilePath)
754 if err := os.MkdirAll(dirPath, 0755); err != nil {
755 logging.LogErrorf("create directory [%s] failed: %s", dirPath, err)
756 return err
757 }
758
759 // write file
760 if err := os.WriteFile(o.FilePath, addressData.Bytes(), 0755); err != nil {
761 logging.LogErrorf("write file [%s] failed: %s", o.FilePath, err)
762 return err
763 }
764
765 o.Changed = false
766 }
767 return nil
768}
769
770// update file info
771func (o *AddressObject) update() error {
772 addressFileInfo, err := os.Stat(o.FilePath)
773 if err != nil {
774 logging.LogErrorf("get file [%s] info failed: %s", o.FilePath, err)
775 return err
776 }
777
778 o.Data.Path = PathJoinWithSlash(o.BookPath, addressFileInfo.Name())
779 o.Data.ModTime = addressFileInfo.ModTime()
780 o.Data.ContentLength = addressFileInfo.Size()
781 o.Data.ETag = FileETag(addressFileInfo)
782
783 return nil
784}
785
786type CardDavBackend struct{}
787
788func (b *CardDavBackend) CurrentUserPrincipal(ctx context.Context) (string, error) {
789 // logging.LogDebugf("CardDAV CurrentUserPrincipal")
790 return CardDavUserPrincipalPath, nil
791}
792
793func (b *CardDavBackend) AddressBookHomeSetPath(ctx context.Context) (string, error) {
794 // logging.LogDebugf("CardDAV AddressBookHomeSetPath")
795 return CardDavHomeSetPath, nil
796}
797
798func (b *CardDavBackend) ListAddressBooks(ctx context.Context) (addressBooks []carddav.AddressBook, err error) {
799 // logging.LogDebugf("CardDAV ListAddressBooks")
800 if err = contacts.Load(); err != nil {
801 return
802 }
803
804 addressBooks, err = contacts.ListAddressBooks()
805 // logging.LogDebugf("CardDAV ListAddressBooks <- addressBooks: %#v, err: %s", addressBooks, err)
806 return
807}
808
809func (b *CardDavBackend) GetAddressBook(ctx context.Context, bookPath string) (addressBook *carddav.AddressBook, err error) {
810 // logging.LogDebugf("CardDAV GetAddressBook -> bookPath: %s", bookPath)
811 bookPath = PathCleanWithSlash(bookPath)
812
813 if err = contacts.Load(); err != nil {
814 return
815 }
816
817 addressBook, err = contacts.GetAddressBook(bookPath)
818 // logging.LogDebugf("CardDAV GetAddressBook <- addressBook: %#v, err: %s", addressBook, err)
819 return
820}
821
822func (b *CardDavBackend) CreateAddressBook(ctx context.Context, addressBook *carddav.AddressBook) (err error) {
823 // logging.LogDebugf("CardDAV CreateAddressBook -> addressBook: %#v", addressBook)
824 addressBook.Path = PathCleanWithSlash(addressBook.Path)
825
826 if err = contacts.Load(); err != nil {
827 return
828 }
829
830 err = contacts.CreateAddressBook(addressBook)
831 // logging.LogDebugf("CardDAV CreateAddressBook <- err: %s", err)
832 return
833}
834
835func (b *CardDavBackend) DeleteAddressBook(ctx context.Context, bookPath string) (err error) {
836 // logging.LogDebugf("CardDAV DeleteAddressBook -> bookPath: %s", bookPath)
837 bookPath = PathCleanWithSlash(bookPath)
838
839 if err = contacts.Load(); err != nil {
840 return
841 }
842
843 err = contacts.DeleteAddressBook(bookPath)
844 // logging.LogDebugf("CardDAV DeleteAddressBook <- err: %s", err)
845 return
846}
847
848func (b *CardDavBackend) GetAddressObject(ctx context.Context, addressPath string, req *carddav.AddressDataRequest) (addressObject *carddav.AddressObject, err error) {
849 // logging.LogDebugf("CardDAV GetAddressObject -> addressPath: %s, req: %#v", addressPath, req)
850 addressPath = PathCleanWithSlash(addressPath)
851
852 if err = contacts.Load(); err != nil {
853 return
854 }
855
856 addressObject, err = contacts.GetAddressObject(addressPath, req)
857 // logging.LogDebugf("CardDAV GetAddressObject <- addressObject: %#v, err: %s", addressObject, err)
858 return
859}
860
861func (b *CardDavBackend) ListAddressObjects(ctx context.Context, bookPath string, req *carddav.AddressDataRequest) (addressObjects []carddav.AddressObject, err error) {
862 // logging.LogDebugf("CardDAV ListAddressObjects -> bookPath: %s, req: %#v", bookPath, req)
863 bookPath = PathCleanWithSlash(bookPath)
864
865 if err = contacts.Load(); err != nil {
866 return
867 }
868
869 addressObjects, err = contacts.ListAddressObjects(bookPath, req)
870 // logging.LogDebugf("CardDAV ListAddressObjects <- addressObjects: %#v, err: %s", addressObjects, err)
871 return
872}
873
874func (b *CardDavBackend) QueryAddressObjects(ctx context.Context, urlPath string, query *carddav.AddressBookQuery) (addressObjects []carddav.AddressObject, err error) {
875 // logging.LogDebugf("CardDAV QueryAddressObjects -> urlPath: %s, query: %#v", urlPath, query)
876 urlPath = PathCleanWithSlash(urlPath)
877
878 if err = contacts.Load(); err != nil {
879 return
880 }
881
882 addressObjects, err = contacts.QueryAddressObjects(urlPath, query)
883 // logging.LogDebugf("CardDAV QueryAddressObjects <- addressObjects: %#v, err: %s", addressObjects, err)
884 return
885}
886
887func (b *CardDavBackend) PutAddressObject(ctx context.Context, addressPath string, card vcard.Card, opts *carddav.PutAddressObjectOptions) (addressObject *carddav.AddressObject, err error) {
888 // logging.LogDebugf("CardDAV PutAddressObject -> addressPath: %s, card: %#v, opts: %#v", addressPath, card, opts)
889 addressPath = PathCleanWithSlash(addressPath)
890
891 if err = contacts.Load(); err != nil {
892 return
893 }
894
895 addressObject, err = contacts.PutAddressObject(addressPath, card, opts)
896 // logging.LogDebugf("CardDAV PutAddressObject <- addressObject: %#v, err: %s", addressObject, err)
897 return
898}
899
900func (b *CardDavBackend) DeleteAddressObject(ctx context.Context, addressPath string) (err error) {
901 // logging.LogDebugf("CardDAV DeleteAddressObject -> addressPath: %s", addressPath)
902 addressPath = PathCleanWithSlash(addressPath)
903
904 if err = contacts.Load(); err != nil {
905 return
906 }
907
908 err = contacts.DeleteAddressObject(addressPath)
909 // logging.LogDebugf("CardDAV DeleteAddressObject <- err: %s", err)
910 return
911}