io_webdav/rfc6352/addressbook/
list.rs1use alloc::{collections::BTreeSet, string::ToString};
48
49use log::trace;
50use url::Url;
51
52use crate::{
53 coroutine::*,
54 rfc4918::{
55 DISPLAYNAME, GETCTAG, RESOURCETYPE, ResponseEntry, SYNC_TOKEN, WebdavAuth,
56 propfind::Propfind, send::SendError, trace_unrecognized,
57 },
58 rfc6352::addressbook::{
59 ADDRESSBOOK, ADDRESSBOOK_COLOR, ADDRESSBOOK_DESCRIPTION, Addressbook, LIST_PROPS,
60 },
61 webdav_try,
62};
63
64#[derive(Debug)]
66pub struct ListAddressbooks {
67 state: State,
68}
69
70impl ListAddressbooks {
71 pub fn new(base_url: &Url, auth: &WebdavAuth, user_agent: &str, home_set_path: &str) -> Self {
73 let propfind = Propfind::new(base_url, auth, user_agent, home_set_path, 1, LIST_PROPS);
74 Self {
75 state: State::Propfind(propfind),
76 }
77 }
78}
79
80impl WebdavCoroutine for ListAddressbooks {
81 type Yield = WebdavYield;
82 type Return = Result<BTreeSet<Addressbook>, SendError>;
83
84 fn resume(&mut self, arg: Option<&[u8]>) -> WebdavCoroutineState<Self::Yield, Self::Return> {
85 trace!("sending request");
86 match &mut self.state {
87 State::Propfind(propfind) => {
88 let multistatus = webdav_try!(propfind, arg);
89 let addressbooks = multistatus
90 .responses
91 .iter()
92 .filter_map(from_entry)
93 .collect();
94 WebdavCoroutineState::Complete(Ok(addressbooks))
95 }
96 }
97 }
98}
99
100fn from_entry(entry: &ResponseEntry) -> Option<Addressbook> {
101 if !entry.has_resource_type(RESOURCETYPE, ADDRESSBOOK) {
102 trace!("skip non-addressbook response {}", entry.href);
103 return None;
104 }
105
106 let id = entry.id();
107 if id.is_empty() {
108 return None;
109 }
110
111 trace_unrecognized(entry, LIST_PROPS);
112
113 Some(Addressbook {
114 id: id.to_string(),
115 display_name: entry.text(DISPLAYNAME).map(ToString::to_string),
116 description: entry.text(ADDRESSBOOK_DESCRIPTION).map(ToString::to_string),
117 color: entry.text(ADDRESSBOOK_COLOR).map(ToString::to_string),
118 ctag: entry.text(GETCTAG).map(ToString::to_string),
119 sync_token: entry.text(SYNC_TOKEN).map(ToString::to_string),
120 })
121}
122
123#[derive(Debug)]
124enum State {
125 Propfind(Propfind),
126}