use alloc::{collections::BTreeSet, string::ToString};
use log::trace;
use url::Url;
use crate::{
coroutine::*,
rfc4918::{GETETAG, Property, ResponseEntry, WebdavAuth, report::Report, send::SendError},
rfc6352::{addressbook::addressbook_query_body, card::CardRef},
webdav_try,
};
const ENUM_PROPS: &[Property] = &[GETETAG];
#[derive(Debug)]
pub struct EnumCards {
state: State,
}
impl EnumCards {
pub fn new(
base_url: &Url,
auth: &WebdavAuth,
user_agent: &str,
addressbook_path: &str,
) -> Self {
let body = addressbook_query_body(ENUM_PROPS);
let report = Report::new(base_url, auth, user_agent, addressbook_path, 1, body);
Self {
state: State::Report(report),
}
}
}
impl WebdavCoroutine for EnumCards {
type Yield = WebdavYield;
type Return = Result<BTreeSet<CardRef>, SendError>;
fn resume(&mut self, arg: Option<&[u8]>) -> WebdavCoroutineState<Self::Yield, Self::Return> {
trace!("sending request");
match &mut self.state {
State::Report(report) => {
let multistatus = webdav_try!(report, arg);
let refs = multistatus
.responses
.iter()
.filter_map(from_entry)
.collect();
WebdavCoroutineState::Complete(Ok(refs))
}
}
}
}
fn from_entry(entry: &ResponseEntry) -> Option<CardRef> {
if entry.href.ends_with('/') {
return None;
}
let uri = entry.id();
let id = uri.trim_end_matches(".vcf");
if id.is_empty() {
return None;
}
Some(CardRef {
id: id.to_string(),
uri: uri.to_string(),
etag: entry
.text(GETETAG)
.map(|raw| raw.trim_matches('"').to_string()),
})
}
#[derive(Debug)]
enum State {
Report(Report),
}