use alloc::{
collections::BTreeSet,
string::{String, ToString},
vec::Vec,
};
use log::trace;
use url::Url;
use crate::{
coroutine::*,
rfc4791::calendar::{CALENDAR_DATA, calendar_query_body},
rfc4918::{
GETETAG, WebdavAuth,
report::Report,
send::SendError,
trace_unrecognized, {Property, ResponseEntry},
},
webdav_try,
};
const ITEM_PROPS: &[Property] = &[GETETAG, CALENDAR_DATA];
#[derive(Debug)]
pub struct ListItems {
state: State,
}
impl ListItems {
pub fn new(
base_url: &Url,
auth: &WebdavAuth,
user_agent: &str,
calendar_path: &str,
comp_filter: &str,
) -> Self {
let body = calendar_query_body(ITEM_PROPS, comp_filter);
let report = Report::new(base_url, auth, user_agent, calendar_path, 1, body);
Self {
state: State::Report(report),
}
}
}
impl WebdavCoroutine for ListItems {
type Yield = WebdavYield;
type Return = Result<BTreeSet<ItemEntry>, 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 items = multistatus
.responses
.iter()
.filter_map(from_entry)
.collect();
WebdavCoroutineState::Complete(Ok(items))
}
}
}
}
fn from_entry(entry: &ResponseEntry) -> Option<ItemEntry> {
let id = entry.id().trim_end_matches(".ics");
if id.is_empty() {
return None;
}
let data = entry.text(CALENDAR_DATA)?;
trace_unrecognized(entry, ITEM_PROPS);
let etag = entry
.text(GETETAG)
.map(|raw| raw.trim_matches('"').to_string());
Some(ItemEntry {
id: id.to_string(),
etag,
data: data.as_bytes().to_vec(),
})
}
#[derive(Debug)]
enum State {
Report(Report),
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ItemEntry {
pub id: String,
pub etag: Option<String>,
pub data: Vec<u8>,
}