A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
at lambda-fork/main 911 lines 25 kB view raw
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}