2024-03-08 17:23:23 +00:00
|
|
|
use chrono::NaiveDateTime;
|
2024-05-16 15:38:34 +00:00
|
|
|
use quick_xml::events::Event;
|
2024-03-08 17:23:23 +00:00
|
|
|
|
2024-03-05 17:15:03 +00:00
|
|
|
use super::caltypes::*;
|
2024-03-08 17:23:23 +00:00
|
|
|
use super::error::ParsingError;
|
2024-05-16 15:38:34 +00:00
|
|
|
use super::types as dav;
|
|
|
|
use super::xml::{IRead, QRead, Reader, CAL_URN, DAV_URN};
|
2024-03-05 17:15:03 +00:00
|
|
|
|
|
|
|
// ---- ROOT ELEMENTS ---
|
2024-03-08 17:23:23 +00:00
|
|
|
impl<E: dav::Extension> QRead<MkCalendar<E>> for MkCalendar<E> {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "mkcalendar").await?;
|
|
|
|
let set = xml.find().await?;
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(MkCalendar(set))
|
2024-03-08 10:34:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-18 19:45:30 +00:00
|
|
|
impl<E: dav::Extension> QRead<MkCalendarResponse<E>> for MkCalendarResponse<E> {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "mkcalendar-response").await?;
|
|
|
|
let propstats = xml.collect().await?;
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(MkCalendarResponse(propstats))
|
2024-03-08 10:34:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-27 16:16:53 +00:00
|
|
|
impl<E: dav::Extension> QRead<ReportType<E>> for ReportType<E> {
|
2024-03-20 12:15:56 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
match CalendarQuery::<E>::qread(xml).await {
|
|
|
|
Err(ParsingError::Recoverable) => (),
|
2024-05-16 15:38:34 +00:00
|
|
|
otherwise => return otherwise.map(Self::Query),
|
2024-03-20 12:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
match CalendarMultiget::<E>::qread(xml).await {
|
|
|
|
Err(ParsingError::Recoverable) => (),
|
|
|
|
otherwise => return otherwise.map(Self::Multiget),
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeBusyQuery::qread(xml).await.map(Self::FreeBusy)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
impl<E: dav::Extension> QRead<CalendarQuery<E>> for CalendarQuery<E> {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "calendar-query").await?;
|
|
|
|
let (mut selector, mut filter, mut timezone) = (None, None, None);
|
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
|
|
|
xml.maybe_read(&mut selector, &mut dirty).await?;
|
|
|
|
xml.maybe_read(&mut filter, &mut dirty).await?;
|
|
|
|
xml.maybe_read(&mut timezone, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
|
|
|
match xml.peek() {
|
|
|
|
Event::End(_) => break,
|
|
|
|
_ => xml.skip().await?,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xml.close().await?;
|
|
|
|
|
|
|
|
match filter {
|
2024-05-16 15:38:34 +00:00
|
|
|
Some(filter) => Ok(CalendarQuery {
|
|
|
|
selector,
|
|
|
|
filter,
|
|
|
|
timezone,
|
|
|
|
}),
|
2024-03-08 20:39:12 +00:00
|
|
|
_ => Err(ParsingError::MissingChild),
|
|
|
|
}
|
2024-03-08 10:34:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
impl<E: dav::Extension> QRead<CalendarMultiget<E>> for CalendarMultiget<E> {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-03-20 13:46:07 +00:00
|
|
|
xml.open(CAL_URN, "calendar-multiget").await?;
|
2024-03-08 20:39:12 +00:00
|
|
|
let mut selector = None;
|
|
|
|
let mut href = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
|
|
|
xml.maybe_read(&mut selector, &mut dirty).await?;
|
|
|
|
xml.maybe_push(&mut href, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
|
|
|
match xml.peek() {
|
|
|
|
Event::End(_) => break,
|
|
|
|
_ => xml.skip().await?,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(CalendarMultiget { selector, href })
|
2024-03-08 10:34:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
impl QRead<FreeBusyQuery> for FreeBusyQuery {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-03-20 13:46:07 +00:00
|
|
|
xml.open(CAL_URN, "free-busy-query").await?;
|
2024-03-08 20:39:12 +00:00
|
|
|
let range = xml.find().await?;
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(FreeBusyQuery(range))
|
2024-03-08 10:34:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-28 10:38:22 +00:00
|
|
|
impl QRead<ReportTypeName> for ReportTypeName {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
if xml.maybe_open(DAV_URN, "calendar-query").await?.is_some() {
|
|
|
|
xml.close().await?;
|
|
|
|
return Ok(Self::Query);
|
|
|
|
}
|
|
|
|
if xml
|
|
|
|
.maybe_open(DAV_URN, "calendar-multiget")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
xml.close().await?;
|
|
|
|
return Ok(Self::Multiget);
|
|
|
|
}
|
|
|
|
if xml.maybe_open(DAV_URN, "free-busy-query").await?.is_some() {
|
|
|
|
xml.close().await?;
|
|
|
|
return Ok(Self::FreeBusy);
|
|
|
|
}
|
|
|
|
Err(ParsingError::Recoverable)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-05 17:15:03 +00:00
|
|
|
// ---- EXTENSIONS ---
|
2024-03-08 17:23:23 +00:00
|
|
|
impl QRead<Violation> for Violation {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open(DAV_URN, "resource-must-be-null")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::ResourceMustBeNull)
|
|
|
|
} else if xml.maybe_open(DAV_URN, "need-privileges").await?.is_some() {
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::NeedPrivileges)
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "calendar-collection-location-ok")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::CalendarCollectionLocationOk)
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "valid-calendar-data")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::ValidCalendarData)
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "initialize-calendar-collection")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::InitializeCalendarCollection)
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "supported-calendar-data")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::SupportedCalendarData)
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "valid-calendar-object-resource")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::ValidCalendarObjectResource)
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "supported-calendar-component")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::SupportedCalendarComponent)
|
|
|
|
} else if xml.maybe_open(CAL_URN, "no-uid-conflict").await?.is_some() {
|
|
|
|
let href = xml.find().await?;
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::NoUidConflict(href))
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "max-resource-size")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::MaxResourceSize)
|
|
|
|
} else if xml.maybe_open(CAL_URN, "min-date-time").await?.is_some() {
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::MinDateTime)
|
|
|
|
} else if xml.maybe_open(CAL_URN, "max-date-time").await?.is_some() {
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::MaxDateTime)
|
|
|
|
} else if xml.maybe_open(CAL_URN, "max-instances").await?.is_some() {
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::MaxInstances)
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "max-attendees-per-instance")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::MaxAttendeesPerInstance)
|
|
|
|
} else if xml.maybe_open(CAL_URN, "valid-filter").await?.is_some() {
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::ValidFilter)
|
|
|
|
} else if xml.maybe_open(CAL_URN, "supported-filter").await?.is_some() {
|
|
|
|
let (mut comp, mut prop, mut param) = (Vec::new(), Vec::new(), Vec::new());
|
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
|
|
|
xml.maybe_push(&mut comp, &mut dirty).await?;
|
|
|
|
xml.maybe_push(&mut prop, &mut dirty).await?;
|
|
|
|
xml.maybe_push(&mut param, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
|
|
|
match xml.peek() {
|
|
|
|
Event::End(_) => break,
|
|
|
|
_ => xml.skip().await?,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::SupportedFilter { comp, prop, param })
|
2024-05-16 15:38:34 +00:00
|
|
|
} else if xml
|
|
|
|
.maybe_open(CAL_URN, "number-of-matches-within-limits")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self::NumberOfMatchesWithinLimits)
|
|
|
|
} else {
|
|
|
|
Err(ParsingError::Recoverable)
|
|
|
|
}
|
2024-03-05 17:15:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
impl QRead<Property> for Property {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "calendar-home-set")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-18 21:56:49 +00:00
|
|
|
let href = xml.find().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::CalendarHomeSet(href));
|
2024-03-18 21:56:49 +00:00
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "calendar-description")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let lang = xml.prev_attr("xml:lang");
|
|
|
|
let text = xml.tag_string().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::CalendarDescription { lang, text });
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "calendar-timezone")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let tz = xml.tag_string().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::CalendarTimezone(tz));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "supported-calendar-component-set")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let comp = xml.collect().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::SupportedCalendarComponentSet(comp));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "supported-calendar-data")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let mime = xml.collect().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::SupportedCalendarData(mime));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "max-resource-size")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let sz = xml.tag_string().await?.parse::<u64>()?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::MaxResourceSize(sz));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "max-date-time")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let dtstr = xml.tag_string().await?;
|
2024-05-23 08:01:43 +00:00
|
|
|
let dt = NaiveDateTime::parse_from_str(dtstr.as_str(), UTC_DATETIME_FMT)?.and_utc();
|
2024-03-08 17:23:23 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::MaxDateTime(dt));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "max-instances")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let sz = xml.tag_string().await?.parse::<u64>()?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::MaxInstances(sz));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "max-attendees-per-instance")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let sz = xml.tag_string().await?.parse::<u64>()?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::MaxAttendeesPerInstance(sz));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open_start(CAL_URN, "supported-collation-set")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 17:23:23 +00:00
|
|
|
let cols = xml.collect().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::SupportedCollationSet(cols));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut dirty = false;
|
|
|
|
let mut caldata: Option<CalendarDataPayload> = None;
|
|
|
|
xml.maybe_read(&mut caldata, &mut dirty).await?;
|
|
|
|
if let Some(cal) = caldata {
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Property::CalendarData(cal));
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Err(ParsingError::Recoverable)
|
2024-03-05 17:15:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
impl QRead<PropertyRequest> for PropertyRequest {
|
2024-03-08 20:51:34 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "calendar-home-set")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-18 21:56:49 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::CalendarHomeSet);
|
|
|
|
}
|
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "calendar-description")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:51:34 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::CalendarDescription);
|
|
|
|
}
|
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "calendar-timezone")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:51:34 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::CalendarTimezone);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "supported-calendar-component-set")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:51:34 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::SupportedCalendarComponentSet);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "supported-calendar-data")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:51:34 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::SupportedCalendarData);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "max-resource-size")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:51:34 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::MaxResourceSize);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
|
|
|
if xml.maybe_open(CAL_URN, "min-date-time").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::MinDateTime);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
|
|
|
if xml.maybe_open(CAL_URN, "max-date-time").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::MaxDateTime);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
|
|
|
if xml.maybe_open(CAL_URN, "max-instances").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::MaxInstances);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "max-attendees-per-instance")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:51:34 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::MaxAttendeesPerInstance);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
if xml
|
|
|
|
.maybe_open(CAL_URN, "supported-collation-set")
|
|
|
|
.await?
|
|
|
|
.is_some()
|
|
|
|
{
|
2024-03-08 20:51:34 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::SupportedCollationSet);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
|
|
|
let mut dirty = false;
|
|
|
|
let mut m_cdr = None;
|
|
|
|
xml.maybe_read(&mut m_cdr, &mut dirty).await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
m_cdr
|
|
|
|
.ok_or(ParsingError::Recoverable)
|
|
|
|
.map(Self::CalendarData)
|
2024-03-05 17:15:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
impl QRead<ResourceType> for ResourceType {
|
2024-03-08 20:51:34 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
if xml.maybe_open(CAL_URN, "calendar").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::Calendar);
|
2024-03-08 20:51:34 +00:00
|
|
|
}
|
|
|
|
Err(ParsingError::Recoverable)
|
2024-03-05 17:15:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---- INNER XML ----
|
2024-03-08 17:23:23 +00:00
|
|
|
impl QRead<SupportedCollation> for SupportedCollation {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "supported-collation").await?;
|
|
|
|
let col = Collation::new(xml.tag_string().await?);
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(SupportedCollation(col))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CalendarDataPayload> for CalendarDataPayload {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "calendar-data").await?;
|
|
|
|
let mime = CalendarDataSupport::qread(xml).await.ok();
|
|
|
|
let payload = xml.tag_string().await?;
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(CalendarDataPayload { mime, payload })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CalendarDataSupport> for CalendarDataSupport {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
let ct = xml.prev_attr("content-type");
|
|
|
|
let vs = xml.prev_attr("version");
|
|
|
|
match (ct, vs) {
|
2024-05-16 15:38:34 +00:00
|
|
|
(Some(content_type), Some(version)) => Ok(Self {
|
|
|
|
content_type,
|
|
|
|
version,
|
|
|
|
}),
|
2024-03-08 17:23:23 +00:00
|
|
|
_ => Err(ParsingError::Recoverable),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CalendarDataRequest> for CalendarDataRequest {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "calendar-data").await?;
|
|
|
|
let mime = CalendarDataSupport::qread(xml).await.ok();
|
|
|
|
let (mut comp, mut recurrence, mut limit_freebusy_set) = (None, None, None);
|
|
|
|
|
2024-03-13 08:11:52 +00:00
|
|
|
if !xml.parent_has_child() {
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self {
|
|
|
|
mime,
|
|
|
|
comp,
|
|
|
|
recurrence,
|
|
|
|
limit_freebusy_set,
|
|
|
|
});
|
2024-03-13 08:11:52 +00:00
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
|
|
|
xml.maybe_read(&mut comp, &mut dirty).await?;
|
|
|
|
xml.maybe_read(&mut recurrence, &mut dirty).await?;
|
|
|
|
xml.maybe_read(&mut limit_freebusy_set, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
|
|
|
match xml.peek() {
|
|
|
|
Event::End(_) => break,
|
|
|
|
_ => xml.skip().await?,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
Ok(Self {
|
|
|
|
mime,
|
|
|
|
comp,
|
|
|
|
recurrence,
|
|
|
|
limit_freebusy_set,
|
|
|
|
})
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CalendarDataEmpty> for CalendarDataEmpty {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "calendar-data").await?;
|
|
|
|
let mime = CalendarDataSupport::qread(xml).await.ok();
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self(mime))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<Comp> for Comp {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-03-12 09:18:13 +00:00
|
|
|
let (mut prop_kind, mut comp_kind) = (None, None);
|
|
|
|
|
|
|
|
let bs = xml.open(CAL_URN, "comp").await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
let name = Component::new(
|
|
|
|
xml.prev_attr("name")
|
|
|
|
.ok_or(ParsingError::MissingAttribute)?,
|
|
|
|
);
|
2024-03-08 17:23:23 +00:00
|
|
|
|
2024-03-12 09:18:13 +00:00
|
|
|
// Return early if it's an empty tag
|
|
|
|
if matches!(bs, Event::Empty(_)) {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self {
|
|
|
|
name,
|
|
|
|
prop_kind,
|
|
|
|
comp_kind,
|
|
|
|
});
|
2024-03-12 09:18:13 +00:00
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
|
|
|
|
loop {
|
2024-05-16 15:38:34 +00:00
|
|
|
let mut dirty = false;
|
|
|
|
let (mut tmp_prop_kind, mut tmp_comp_kind): (Option<PropKind>, Option<CompKind>) =
|
|
|
|
(None, None);
|
2024-03-12 09:18:13 +00:00
|
|
|
|
|
|
|
xml.maybe_read(&mut tmp_prop_kind, &mut dirty).await?;
|
|
|
|
Box::pin(xml.maybe_read(&mut tmp_comp_kind, &mut dirty)).await?;
|
|
|
|
|
|
|
|
//@FIXME hack
|
|
|
|
// Merge
|
|
|
|
match (tmp_prop_kind, &mut prop_kind) {
|
|
|
|
(Some(PropKind::Prop(mut a)), Some(PropKind::Prop(ref mut b))) => b.append(&mut a),
|
2024-05-16 15:38:34 +00:00
|
|
|
(Some(PropKind::AllProp), v) => *v = Some(PropKind::AllProp),
|
2024-03-12 09:18:13 +00:00
|
|
|
(Some(x), b) => *b = Some(x),
|
|
|
|
(None, _) => (),
|
|
|
|
};
|
|
|
|
match (tmp_comp_kind, &mut comp_kind) {
|
|
|
|
(Some(CompKind::Comp(mut a)), Some(CompKind::Comp(ref mut b))) => b.append(&mut a),
|
2024-05-16 15:38:34 +00:00
|
|
|
(Some(CompKind::AllComp), v) => *v = Some(CompKind::AllComp),
|
2024-03-12 09:18:13 +00:00
|
|
|
(Some(a), b) => *b = Some(a),
|
|
|
|
(None, _) => (),
|
|
|
|
};
|
|
|
|
|
|
|
|
if !dirty {
|
2024-03-08 17:23:23 +00:00
|
|
|
match xml.peek() {
|
|
|
|
Event::End(_) => break,
|
|
|
|
_ => xml.skip().await?,
|
|
|
|
};
|
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
|
2024-03-12 09:18:13 +00:00
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
Ok(Self {
|
|
|
|
name,
|
|
|
|
prop_kind,
|
|
|
|
comp_kind,
|
|
|
|
})
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CompSupport> for CompSupport {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "comp").await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
let inner = Component::new(
|
|
|
|
xml.prev_attr("name")
|
|
|
|
.ok_or(ParsingError::MissingAttribute)?,
|
|
|
|
);
|
2024-03-08 17:23:23 +00:00
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self(inner))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CompKind> for CompKind {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
let mut comp = Vec::new();
|
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
|
|
|
|
|
|
|
if xml.maybe_open(CAL_URN, "allcomp").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(CompKind::AllComp);
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xml.maybe_push(&mut comp, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
2024-05-16 15:38:34 +00:00
|
|
|
break;
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-12 09:18:13 +00:00
|
|
|
match &comp[..] {
|
2024-05-16 15:38:34 +00:00
|
|
|
[] => Err(ParsingError::Recoverable),
|
|
|
|
_ => Ok(CompKind::Comp(comp)),
|
2024-03-12 09:18:13 +00:00
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<PropKind> for PropKind {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
let mut prop = Vec::new();
|
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
|
|
|
|
|
|
|
if xml.maybe_open(CAL_URN, "allprop").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(PropKind::AllProp);
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xml.maybe_push(&mut prop, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
2024-05-16 15:38:34 +00:00
|
|
|
break;
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-12 09:18:13 +00:00
|
|
|
|
|
|
|
match &prop[..] {
|
|
|
|
[] => Err(ParsingError::Recoverable),
|
|
|
|
_ => Ok(PropKind::Prop(prop)),
|
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<RecurrenceModifier> for RecurrenceModifier {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
match Expand::qread(xml).await {
|
|
|
|
Err(ParsingError::Recoverable) => (),
|
|
|
|
otherwise => return otherwise.map(RecurrenceModifier::Expand),
|
|
|
|
}
|
2024-05-16 15:38:34 +00:00
|
|
|
LimitRecurrenceSet::qread(xml)
|
|
|
|
.await
|
|
|
|
.map(RecurrenceModifier::LimitRecurrenceSet)
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<Expand> for Expand {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "expand").await?;
|
|
|
|
let (rstart, rend) = match (xml.prev_attr("start"), xml.prev_attr("end")) {
|
|
|
|
(Some(start), Some(end)) => (start, end),
|
|
|
|
_ => return Err(ParsingError::MissingAttribute),
|
|
|
|
};
|
2024-05-16 15:38:34 +00:00
|
|
|
|
2024-05-23 08:01:43 +00:00
|
|
|
let start = NaiveDateTime::parse_from_str(rstart.as_str(), UTC_DATETIME_FMT)?.and_utc();
|
|
|
|
let end = NaiveDateTime::parse_from_str(rend.as_str(), UTC_DATETIME_FMT)?.and_utc();
|
2024-03-08 20:39:12 +00:00
|
|
|
if start > end {
|
2024-05-16 15:38:34 +00:00
|
|
|
return Err(ParsingError::InvalidValue);
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Expand(start, end))
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<LimitRecurrenceSet> for LimitRecurrenceSet {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "limit-recurrence-set").await?;
|
|
|
|
let (rstart, rend) = match (xml.prev_attr("start"), xml.prev_attr("end")) {
|
|
|
|
(Some(start), Some(end)) => (start, end),
|
|
|
|
_ => return Err(ParsingError::MissingAttribute),
|
|
|
|
};
|
2024-05-16 15:38:34 +00:00
|
|
|
|
2024-05-23 08:01:43 +00:00
|
|
|
let start = NaiveDateTime::parse_from_str(rstart.as_str(), UTC_DATETIME_FMT)?.and_utc();
|
|
|
|
let end = NaiveDateTime::parse_from_str(rend.as_str(), UTC_DATETIME_FMT)?.and_utc();
|
2024-03-08 20:39:12 +00:00
|
|
|
if start > end {
|
2024-05-16 15:38:34 +00:00
|
|
|
return Err(ParsingError::InvalidValue);
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(LimitRecurrenceSet(start, end))
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<LimitFreebusySet> for LimitFreebusySet {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "limit-freebusy-set").await?;
|
|
|
|
let (rstart, rend) = match (xml.prev_attr("start"), xml.prev_attr("end")) {
|
|
|
|
(Some(start), Some(end)) => (start, end),
|
|
|
|
_ => return Err(ParsingError::MissingAttribute),
|
|
|
|
};
|
2024-05-16 15:38:34 +00:00
|
|
|
|
2024-05-23 08:01:43 +00:00
|
|
|
let start = NaiveDateTime::parse_from_str(rstart.as_str(), UTC_DATETIME_FMT)?.and_utc();
|
|
|
|
let end = NaiveDateTime::parse_from_str(rend.as_str(), UTC_DATETIME_FMT)?.and_utc();
|
2024-03-08 20:39:12 +00:00
|
|
|
if start > end {
|
2024-05-16 15:38:34 +00:00
|
|
|
return Err(ParsingError::InvalidValue);
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(LimitFreebusySet(start, end))
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<E: dav::Extension> QRead<CalendarSelector<E>> for CalendarSelector<E> {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
// allprop
|
|
|
|
if let Some(_) = xml.maybe_open(DAV_URN, "allprop").await? {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::AllProp);
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// propname
|
|
|
|
if let Some(_) = xml.maybe_open(DAV_URN, "propname").await? {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::PropName);
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// prop
|
|
|
|
let (mut maybe_prop, mut dirty) = (None, false);
|
2024-05-16 15:38:34 +00:00
|
|
|
xml.maybe_read::<dav::PropName<E>>(&mut maybe_prop, &mut dirty)
|
|
|
|
.await?;
|
2024-03-08 20:39:12 +00:00
|
|
|
if let Some(prop) = maybe_prop {
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::Prop(prop));
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Err(ParsingError::Recoverable)
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CompFilter> for CompFilter {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "comp-filter").await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
let name = Component::new(
|
|
|
|
xml.prev_attr("name")
|
|
|
|
.ok_or(ParsingError::MissingAttribute)?,
|
|
|
|
);
|
2024-03-08 20:39:12 +00:00
|
|
|
let additional_rules = Box::pin(xml.maybe_find()).await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
Ok(Self {
|
|
|
|
name,
|
|
|
|
additional_rules,
|
|
|
|
})
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CompFilterRules> for CompFilterRules {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
let mut time_range = None;
|
|
|
|
let mut prop_filter = Vec::new();
|
|
|
|
let mut comp_filter = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
2024-03-13 08:11:52 +00:00
|
|
|
|
|
|
|
if xml.maybe_open(CAL_URN, "is-not-defined").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::IsNotDefined);
|
2024-03-13 08:11:52 +00:00
|
|
|
}
|
|
|
|
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.maybe_read(&mut time_range, &mut dirty).await?;
|
|
|
|
xml.maybe_push(&mut prop_filter, &mut dirty).await?;
|
|
|
|
xml.maybe_push(&mut comp_filter, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
|
|
|
match xml.peek() {
|
|
|
|
Event::End(_) => break,
|
|
|
|
_ => xml.skip().await?,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match (&time_range, &prop_filter[..], &comp_filter[..]) {
|
|
|
|
(None, [], []) => Err(ParsingError::Recoverable),
|
2024-05-16 15:38:34 +00:00
|
|
|
_ => Ok(Self::Matches(CompFilterMatch {
|
|
|
|
time_range,
|
|
|
|
prop_filter,
|
|
|
|
comp_filter,
|
|
|
|
})),
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-13 08:11:52 +00:00
|
|
|
impl QRead<CompFilterMatch> for CompFilterMatch {
|
|
|
|
async fn qread(_xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
impl QRead<PropFilter> for PropFilter {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "prop-filter").await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
let name = ComponentProperty(
|
|
|
|
xml.prev_attr("name")
|
|
|
|
.ok_or(ParsingError::MissingAttribute)?,
|
|
|
|
);
|
2024-03-08 20:39:12 +00:00
|
|
|
let additional_rules = xml.maybe_find().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
Ok(Self {
|
|
|
|
name,
|
|
|
|
additional_rules,
|
|
|
|
})
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<PropFilterRules> for PropFilterRules {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
let mut time_or_text = None;
|
|
|
|
let mut param_filter = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let mut dirty = false;
|
2024-03-13 08:11:52 +00:00
|
|
|
|
|
|
|
if xml.maybe_open(CAL_URN, "is-not-defined").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::IsNotDefined);
|
2024-03-13 08:11:52 +00:00
|
|
|
}
|
|
|
|
|
2024-03-08 20:39:12 +00:00
|
|
|
xml.maybe_read(&mut time_or_text, &mut dirty).await?;
|
|
|
|
xml.maybe_push(&mut param_filter, &mut dirty).await?;
|
|
|
|
|
|
|
|
if !dirty {
|
|
|
|
match xml.peek() {
|
|
|
|
Event::End(_) => break,
|
|
|
|
_ => xml.skip().await?,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-21 16:09:21 +00:00
|
|
|
match (&time_or_text, ¶m_filter[..]) {
|
|
|
|
(None, []) => Err(ParsingError::Recoverable),
|
2024-05-16 15:38:34 +00:00
|
|
|
_ => Ok(PropFilterRules::Match(PropFilterMatch {
|
|
|
|
time_or_text,
|
|
|
|
param_filter,
|
|
|
|
})),
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-13 08:11:52 +00:00
|
|
|
impl QRead<PropFilterMatch> for PropFilterMatch {
|
|
|
|
async fn qread(_xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 20:39:12 +00:00
|
|
|
impl QRead<ParamFilter> for ParamFilter {
|
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "param-filter").await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
let name = PropertyParameter(
|
|
|
|
xml.prev_attr("name")
|
|
|
|
.ok_or(ParsingError::MissingAttribute)?,
|
|
|
|
);
|
2024-03-08 20:39:12 +00:00
|
|
|
let additional_rules = xml.maybe_find().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
Ok(Self {
|
|
|
|
name,
|
|
|
|
additional_rules,
|
|
|
|
})
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<TimeOrText> for TimeOrText {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
match TimeRange::qread(xml).await {
|
|
|
|
Err(ParsingError::Recoverable) => (),
|
|
|
|
otherwise => return otherwise.map(Self::Time),
|
|
|
|
}
|
|
|
|
TextMatch::qread(xml).await.map(Self::Text)
|
2024-03-08 10:34:24 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
|
|
|
|
impl QRead<TextMatch> for TextMatch {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "text-match").await?;
|
|
|
|
let collation = xml.prev_attr("collation").map(Collation::new);
|
|
|
|
let negate_condition = xml.prev_attr("negate-condition").map(|v| v == "yes");
|
|
|
|
let text = xml.tag_string().await?;
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
Ok(Self {
|
|
|
|
collation,
|
|
|
|
negate_condition,
|
|
|
|
text,
|
|
|
|
})
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<ParamFilterMatch> for ParamFilterMatch {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
if xml.maybe_open(CAL_URN, "is-not-defined").await?.is_some() {
|
|
|
|
xml.close().await?;
|
2024-05-16 15:38:34 +00:00
|
|
|
return Ok(Self::IsNotDefined);
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
TextMatch::qread(xml).await.map(Self::Match)
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<TimeZone> for TimeZone {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "timezone").await?;
|
|
|
|
let inner = xml.tag_string().await?;
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self(inner))
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<Filter> for Filter {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-03-12 09:18:13 +00:00
|
|
|
xml.open(CAL_URN, "filter").await?;
|
2024-03-08 20:39:12 +00:00
|
|
|
let comp_filter = xml.find().await?;
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self(comp_filter))
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<TimeRange> for TimeRange {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
|
|
|
xml.open(CAL_URN, "time-range").await?;
|
|
|
|
|
|
|
|
let start = match xml.prev_attr("start") {
|
2024-05-26 08:33:04 +00:00
|
|
|
Some(r) => Some(NaiveDateTime::parse_from_str(r.as_str(), UTC_DATETIME_FMT)?.and_utc()),
|
2024-03-08 20:39:12 +00:00
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
let end = match xml.prev_attr("end") {
|
2024-05-26 08:33:04 +00:00
|
|
|
Some(r) => Some(NaiveDateTime::parse_from_str(r.as_str(), UTC_DATETIME_FMT)?.and_utc()),
|
2024-03-08 20:39:12 +00:00
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
xml.close().await?;
|
|
|
|
|
|
|
|
match (start, end) {
|
|
|
|
(Some(start), Some(end)) => {
|
|
|
|
if start > end {
|
2024-05-16 15:38:34 +00:00
|
|
|
return Err(ParsingError::InvalidValue);
|
2024-03-08 20:39:12 +00:00
|
|
|
}
|
|
|
|
Ok(TimeRange::FullRange(start, end))
|
2024-05-16 15:38:34 +00:00
|
|
|
}
|
2024-03-08 20:39:12 +00:00
|
|
|
(Some(start), None) => Ok(TimeRange::OnlyStart(start)),
|
|
|
|
(None, Some(end)) => Ok(TimeRange::OnlyEnd(end)),
|
|
|
|
(None, None) => Err(ParsingError::MissingAttribute),
|
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QRead<CalProp> for CalProp {
|
2024-03-08 20:39:12 +00:00
|
|
|
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
|
2024-05-16 15:38:34 +00:00
|
|
|
xml.open(CAL_URN, "prop").await?;
|
|
|
|
let name = ComponentProperty(
|
|
|
|
xml.prev_attr("name")
|
|
|
|
.ok_or(ParsingError::MissingAttribute)?,
|
|
|
|
);
|
2024-03-08 20:39:12 +00:00
|
|
|
let novalue = xml.prev_attr("novalue").map(|v| v == "yes");
|
|
|
|
xml.close().await?;
|
|
|
|
Ok(Self { name, novalue })
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use crate::realization::Calendar;
|
2024-03-18 19:45:30 +00:00
|
|
|
use crate::xml::Node;
|
2024-05-16 15:38:34 +00:00
|
|
|
use chrono::{TimeZone, Utc};
|
2024-03-08 17:23:23 +00:00
|
|
|
//use quick_reader::NsReader;
|
|
|
|
|
|
|
|
async fn deserialize<T: Node<T>>(src: &str) -> T {
|
2024-05-16 15:38:34 +00:00
|
|
|
let mut rdr = Reader::new(quick_xml::NsReader::from_reader(src.as_bytes()))
|
|
|
|
.await
|
|
|
|
.unwrap();
|
2024-03-08 17:23:23 +00:00
|
|
|
rdr.find().await.unwrap()
|
|
|
|
}
|
|
|
|
|
2024-05-23 06:55:53 +00:00
|
|
|
#[tokio::test]
|
|
|
|
async fn simple_comp_filter() {
|
|
|
|
let expected = CompFilter {
|
|
|
|
name: Component::VEvent,
|
|
|
|
additional_rules: None,
|
|
|
|
};
|
|
|
|
let src = r#"<C:comp-filter name="VEVENT" xmlns:C="urn:ietf:params:xml:ns:caldav" />"#;
|
|
|
|
let got = deserialize::<CompFilter>(src).await;
|
|
|
|
assert_eq!(got, expected);
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:23:23 +00:00
|
|
|
#[tokio::test]
|
|
|
|
async fn basic_mkcalendar() {
|
2024-05-16 15:38:34 +00:00
|
|
|
let expected = MkCalendar(dav::Set(dav::PropValue(vec![dav::Property::DisplayName(
|
|
|
|
"Lisa's Events".into(),
|
|
|
|
)])));
|
2024-03-08 17:23:23 +00:00
|
|
|
|
|
|
|
let src = r#"
|
|
|
|
<?xml version="1.0" encoding="utf-8" ?>
|
|
|
|
<C:mkcalendar xmlns:D="DAV:"
|
|
|
|
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
|
|
|
<D:set>
|
|
|
|
<D:prop>
|
|
|
|
<D:displayname>Lisa's Events</D:displayname>
|
|
|
|
</D:prop>
|
|
|
|
</D:set>
|
|
|
|
</C:mkcalendar>
|
|
|
|
"#;
|
|
|
|
let got = deserialize::<MkCalendar<Calendar>>(src).await;
|
|
|
|
assert_eq!(got, expected)
|
|
|
|
}
|
2024-03-08 21:03:46 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn rfc_mkcalendar() {
|
|
|
|
let expected = MkCalendar(dav::Set(dav::PropValue(vec![
|
|
|
|
dav::Property::DisplayName("Lisa's Events".into()),
|
|
|
|
dav::Property::Extension(Property::CalendarDescription {
|
|
|
|
lang: Some("en".into()),
|
|
|
|
text: "Calendar restricted to events.".into(),
|
|
|
|
}),
|
|
|
|
dav::Property::Extension(Property::SupportedCalendarComponentSet(vec![
|
|
|
|
CompSupport(Component::VEvent)
|
|
|
|
])),
|
|
|
|
dav::Property::Extension(Property::CalendarTimezone("BEGIN:VCALENDAR\nPRODID:-//Example Corp.//CalDAV Client//EN\nVERSION:2.0\nEND:VCALENDAR".into())),
|
|
|
|
])));
|
|
|
|
|
|
|
|
let src = r#"
|
|
|
|
<?xml version="1.0" encoding="utf-8" ?>
|
|
|
|
<C:mkcalendar xmlns:D="DAV:"
|
|
|
|
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
|
|
|
<D:set>
|
|
|
|
<D:prop>
|
|
|
|
<D:displayname>Lisa's Events</D:displayname>
|
|
|
|
<C:calendar-description xml:lang="en"
|
|
|
|
>Calendar restricted to events.</C:calendar-description>
|
|
|
|
<C:supported-calendar-component-set>
|
|
|
|
<C:comp name="VEVENT"/>
|
|
|
|
</C:supported-calendar-component-set>
|
|
|
|
<C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
|
|
|
|
PRODID:-//Example Corp.//CalDAV Client//EN
|
|
|
|
VERSION:2.0
|
|
|
|
END:VCALENDAR]]></C:calendar-timezone>
|
|
|
|
</D:prop>
|
|
|
|
</D:set>
|
|
|
|
</C:mkcalendar>"#;
|
|
|
|
|
|
|
|
let got = deserialize::<MkCalendar<Calendar>>(src).await;
|
|
|
|
assert_eq!(got, expected)
|
|
|
|
}
|
2024-03-12 09:18:13 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn rfc_calendar_query() {
|
|
|
|
let expected = CalendarQuery {
|
|
|
|
selector: Some(CalendarSelector::Prop(dav::PropName(vec![
|
|
|
|
dav::PropertyRequest::GetEtag,
|
2024-05-16 15:38:34 +00:00
|
|
|
dav::PropertyRequest::Extension(PropertyRequest::CalendarData(
|
|
|
|
CalendarDataRequest {
|
|
|
|
mime: None,
|
|
|
|
comp: Some(Comp {
|
|
|
|
name: Component::VCalendar,
|
|
|
|
prop_kind: Some(PropKind::Prop(vec![CalProp {
|
2024-03-12 09:18:13 +00:00
|
|
|
name: ComponentProperty("VERSION".into()),
|
|
|
|
novalue: None,
|
2024-05-16 15:38:34 +00:00
|
|
|
}])),
|
|
|
|
comp_kind: Some(CompKind::Comp(vec![
|
|
|
|
Comp {
|
|
|
|
name: Component::VEvent,
|
|
|
|
prop_kind: Some(PropKind::Prop(vec![
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("SUMMARY".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("UID".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("DTSTART".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("DTEND".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("DURATION".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("RRULE".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("RDATE".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("EXRULE".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("EXDATE".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
CalProp {
|
|
|
|
name: ComponentProperty("RECURRENCE-ID".into()),
|
|
|
|
novalue: None,
|
|
|
|
},
|
|
|
|
])),
|
|
|
|
comp_kind: None,
|
|
|
|
},
|
|
|
|
Comp {
|
|
|
|
name: Component::VTimeZone,
|
|
|
|
prop_kind: None,
|
|
|
|
comp_kind: None,
|
|
|
|
},
|
|
|
|
])),
|
|
|
|
}),
|
|
|
|
recurrence: None,
|
|
|
|
limit_freebusy_set: None,
|
|
|
|
},
|
|
|
|
)),
|
2024-03-12 09:18:13 +00:00
|
|
|
]))),
|
|
|
|
filter: Filter(CompFilter {
|
|
|
|
name: Component::VCalendar,
|
|
|
|
additional_rules: Some(CompFilterRules::Matches(CompFilterMatch {
|
|
|
|
prop_filter: vec![],
|
2024-05-16 15:38:34 +00:00
|
|
|
comp_filter: vec![CompFilter {
|
|
|
|
name: Component::VEvent,
|
|
|
|
additional_rules: Some(CompFilterRules::Matches(CompFilterMatch {
|
|
|
|
prop_filter: vec![],
|
|
|
|
comp_filter: vec![],
|
|
|
|
time_range: Some(TimeRange::FullRange(
|
|
|
|
Utc.with_ymd_and_hms(2006, 1, 4, 0, 0, 0).unwrap(),
|
|
|
|
Utc.with_ymd_and_hms(2006, 1, 5, 0, 0, 0).unwrap(),
|
|
|
|
)),
|
|
|
|
})),
|
|
|
|
}],
|
2024-03-12 09:18:13 +00:00
|
|
|
time_range: None,
|
|
|
|
})),
|
|
|
|
}),
|
|
|
|
timezone: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let src = r#"
|
|
|
|
<?xml version="1.0" encoding="utf-8" ?>
|
|
|
|
<C:calendar-query xmlns:D="DAV:"
|
|
|
|
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
|
|
|
<D:prop>
|
|
|
|
<D:getetag/>
|
|
|
|
<C:calendar-data>
|
|
|
|
<C:comp name="VCALENDAR">
|
|
|
|
<C:prop name="VERSION"/>
|
|
|
|
<C:comp name="VEVENT">
|
|
|
|
<C:prop name="SUMMARY"/>
|
|
|
|
<C:prop name="UID"/>
|
|
|
|
<C:prop name="DTSTART"/>
|
|
|
|
<C:prop name="DTEND"/>
|
|
|
|
<C:prop name="DURATION"/>
|
|
|
|
<C:prop name="RRULE"/>
|
|
|
|
<C:prop name="RDATE"/>
|
|
|
|
<C:prop name="EXRULE"/>
|
|
|
|
<C:prop name="EXDATE"/>
|
|
|
|
<C:prop name="RECURRENCE-ID"/>
|
|
|
|
</C:comp>
|
|
|
|
<C:comp name="VTIMEZONE"/>
|
|
|
|
</C:comp>
|
|
|
|
</C:calendar-data>
|
|
|
|
</D:prop>
|
|
|
|
<C:filter>
|
|
|
|
<C:comp-filter name="VCALENDAR">
|
|
|
|
<C:comp-filter name="VEVENT">
|
|
|
|
<C:time-range start="20060104T000000Z"
|
|
|
|
end="20060105T000000Z"/>
|
|
|
|
</C:comp-filter>
|
|
|
|
</C:comp-filter>
|
|
|
|
</C:filter>
|
|
|
|
</C:calendar-query>
|
|
|
|
"#;
|
|
|
|
|
|
|
|
let got = deserialize::<CalendarQuery<Calendar>>(src).await;
|
|
|
|
assert_eq!(got, expected)
|
|
|
|
}
|
2024-03-13 08:11:52 +00:00
|
|
|
|
|
|
|
#[tokio::test]
|
2024-05-16 15:38:34 +00:00
|
|
|
async fn rfc_calendar_query_res() {
|
2024-03-18 19:45:30 +00:00
|
|
|
let expected = dav::Multistatus::<Calendar> {
|
2024-03-13 08:11:52 +00:00
|
|
|
responses: vec![
|
|
|
|
dav::Response {
|
|
|
|
status_or_propstat: dav::StatusOrPropstat::PropStat(
|
|
|
|
dav::Href("http://cal.example.com/bernard/work/abcd2.ics".into()),
|
2024-05-16 15:38:34 +00:00
|
|
|
vec![dav::PropStat {
|
|
|
|
prop: dav::AnyProp(vec![
|
|
|
|
dav::AnyProperty::Value(dav::Property::GetEtag(
|
|
|
|
"\"fffff-abcd2\"".into(),
|
|
|
|
)),
|
|
|
|
dav::AnyProperty::Value(dav::Property::Extension(
|
|
|
|
Property::CalendarData(CalendarDataPayload {
|
2024-03-13 08:11:52 +00:00
|
|
|
mime: None,
|
|
|
|
payload: "BEGIN:VCALENDAR".into(),
|
2024-05-16 15:38:34 +00:00
|
|
|
}),
|
|
|
|
)),
|
|
|
|
]),
|
|
|
|
status: dav::Status(http::status::StatusCode::OK),
|
|
|
|
error: None,
|
|
|
|
responsedescription: None,
|
|
|
|
}],
|
2024-03-13 08:11:52 +00:00
|
|
|
),
|
|
|
|
error: None,
|
|
|
|
location: None,
|
|
|
|
responsedescription: None,
|
|
|
|
},
|
|
|
|
dav::Response {
|
|
|
|
status_or_propstat: dav::StatusOrPropstat::PropStat(
|
|
|
|
dav::Href("http://cal.example.com/bernard/work/abcd3.ics".into()),
|
2024-05-16 15:38:34 +00:00
|
|
|
vec![dav::PropStat {
|
|
|
|
prop: dav::AnyProp(vec![
|
|
|
|
dav::AnyProperty::Value(dav::Property::GetEtag(
|
|
|
|
"\"fffff-abcd3\"".into(),
|
|
|
|
)),
|
|
|
|
dav::AnyProperty::Value(dav::Property::Extension(
|
|
|
|
Property::CalendarData(CalendarDataPayload {
|
2024-03-13 08:11:52 +00:00
|
|
|
mime: None,
|
|
|
|
payload: "BEGIN:VCALENDAR".into(),
|
2024-05-16 15:38:34 +00:00
|
|
|
}),
|
|
|
|
)),
|
|
|
|
]),
|
|
|
|
status: dav::Status(http::status::StatusCode::OK),
|
|
|
|
error: None,
|
|
|
|
responsedescription: None,
|
|
|
|
}],
|
2024-03-13 08:11:52 +00:00
|
|
|
),
|
|
|
|
error: None,
|
|
|
|
location: None,
|
|
|
|
responsedescription: None,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
responsedescription: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let src = r#"<D:multistatus xmlns:D="DAV:"
|
|
|
|
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
|
|
|
<D:response>
|
|
|
|
<D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
|
|
|
|
<D:propstat>
|
|
|
|
<D:prop>
|
|
|
|
<D:getetag>"fffff-abcd2"</D:getetag>
|
|
|
|
<C:calendar-data>BEGIN:VCALENDAR</C:calendar-data>
|
|
|
|
</D:prop>
|
|
|
|
<D:status>HTTP/1.1 200 OK</D:status>
|
|
|
|
</D:propstat>
|
|
|
|
</D:response>
|
|
|
|
<D:response>
|
|
|
|
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
|
|
|
|
<D:propstat>
|
|
|
|
<D:prop>
|
|
|
|
<D:getetag>"fffff-abcd3"</D:getetag>
|
|
|
|
<C:calendar-data>BEGIN:VCALENDAR</C:calendar-data>
|
|
|
|
</D:prop>
|
|
|
|
<D:status>HTTP/1.1 200 OK</D:status>
|
|
|
|
</D:propstat>
|
|
|
|
</D:response>
|
|
|
|
</D:multistatus>
|
|
|
|
"#;
|
|
|
|
|
2024-03-18 19:45:30 +00:00
|
|
|
let got = deserialize::<dav::Multistatus<Calendar>>(src).await;
|
2024-03-13 08:11:52 +00:00
|
|
|
assert_eq!(got, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
2024-05-16 15:38:34 +00:00
|
|
|
async fn rfc_recurring_evt() {
|
2024-03-13 08:11:52 +00:00
|
|
|
let expected = CalendarQuery::<Calendar> {
|
|
|
|
selector: Some(CalendarSelector::Prop(dav::PropName(vec![
|
2024-05-16 15:38:34 +00:00
|
|
|
dav::PropertyRequest::Extension(PropertyRequest::CalendarData(
|
|
|
|
CalendarDataRequest {
|
|
|
|
mime: None,
|
|
|
|
comp: None,
|
|
|
|
recurrence: Some(RecurrenceModifier::LimitRecurrenceSet(
|
|
|
|
LimitRecurrenceSet(
|
|
|
|
Utc.with_ymd_and_hms(2006, 1, 3, 0, 0, 0).unwrap(),
|
|
|
|
Utc.with_ymd_and_hms(2006, 1, 5, 0, 0, 0).unwrap(),
|
|
|
|
),
|
|
|
|
)),
|
|
|
|
limit_freebusy_set: None,
|
|
|
|
},
|
|
|
|
)),
|
2024-03-13 08:11:52 +00:00
|
|
|
]))),
|
|
|
|
filter: Filter(CompFilter {
|
|
|
|
name: Component::VCalendar,
|
|
|
|
additional_rules: Some(CompFilterRules::Matches(CompFilterMatch {
|
|
|
|
prop_filter: vec![],
|
2024-05-16 15:38:34 +00:00
|
|
|
comp_filter: vec![CompFilter {
|
|
|
|
name: Component::VEvent,
|
|
|
|
additional_rules: Some(CompFilterRules::Matches(CompFilterMatch {
|
|
|
|
prop_filter: vec![],
|
|
|
|
comp_filter: vec![],
|
|
|
|
time_range: Some(TimeRange::FullRange(
|
|
|
|
Utc.with_ymd_and_hms(2006, 1, 3, 0, 0, 0).unwrap(),
|
|
|
|
Utc.with_ymd_and_hms(2006, 1, 5, 0, 0, 0).unwrap(),
|
|
|
|
)),
|
|
|
|
})),
|
|
|
|
}],
|
2024-03-13 08:11:52 +00:00
|
|
|
time_range: None,
|
|
|
|
})),
|
|
|
|
}),
|
|
|
|
timezone: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let src = r#"
|
|
|
|
<?xml version="1.0" encoding="utf-8" ?>
|
|
|
|
<C:calendar-query xmlns:D="DAV:"
|
|
|
|
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
|
|
|
<D:prop>
|
|
|
|
<C:calendar-data>
|
|
|
|
<C:limit-recurrence-set start="20060103T000000Z"
|
|
|
|
end="20060105T000000Z"/>
|
|
|
|
</C:calendar-data>
|
|
|
|
</D:prop>
|
|
|
|
<C:filter>
|
|
|
|
<C:comp-filter name="VCALENDAR">
|
|
|
|
<C:comp-filter name="VEVENT">
|
|
|
|
<C:time-range start="20060103T000000Z"
|
|
|
|
end="20060105T000000Z"/>
|
|
|
|
</C:comp-filter>
|
|
|
|
</C:comp-filter>
|
|
|
|
</C:filter>
|
|
|
|
</C:calendar-query>"#;
|
|
|
|
|
|
|
|
let got = deserialize::<CalendarQuery<Calendar>>(src).await;
|
|
|
|
assert_eq!(got, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn rfc_pending_todos() {
|
|
|
|
let expected = CalendarQuery::<Calendar> {
|
|
|
|
selector: Some(CalendarSelector::Prop(dav::PropName(vec![
|
|
|
|
dav::PropertyRequest::GetEtag,
|
2024-05-16 15:38:34 +00:00
|
|
|
dav::PropertyRequest::Extension(PropertyRequest::CalendarData(
|
|
|
|
CalendarDataRequest {
|
|
|
|
mime: None,
|
|
|
|
comp: None,
|
|
|
|
recurrence: None,
|
|
|
|
limit_freebusy_set: None,
|
|
|
|
},
|
|
|
|
)),
|
2024-03-13 08:11:52 +00:00
|
|
|
]))),
|
|
|
|
filter: Filter(CompFilter {
|
|
|
|
name: Component::VCalendar,
|
|
|
|
additional_rules: Some(CompFilterRules::Matches(CompFilterMatch {
|
|
|
|
time_range: None,
|
|
|
|
prop_filter: vec![],
|
2024-05-16 15:38:34 +00:00
|
|
|
comp_filter: vec![CompFilter {
|
|
|
|
name: Component::VTodo,
|
|
|
|
additional_rules: Some(CompFilterRules::Matches(CompFilterMatch {
|
|
|
|
time_range: None,
|
|
|
|
comp_filter: vec![],
|
|
|
|
prop_filter: vec![
|
|
|
|
PropFilter {
|
|
|
|
name: ComponentProperty("COMPLETED".into()),
|
|
|
|
additional_rules: Some(PropFilterRules::IsNotDefined),
|
|
|
|
},
|
|
|
|
PropFilter {
|
|
|
|
name: ComponentProperty("STATUS".into()),
|
|
|
|
additional_rules: Some(PropFilterRules::Match(
|
|
|
|
PropFilterMatch {
|
2024-03-13 08:11:52 +00:00
|
|
|
param_filter: vec![],
|
|
|
|
time_or_text: Some(TimeOrText::Text(TextMatch {
|
|
|
|
collation: None,
|
|
|
|
negate_condition: Some(true),
|
|
|
|
text: "CANCELLED".into(),
|
|
|
|
})),
|
2024-05-16 15:38:34 +00:00
|
|
|
},
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
})),
|
|
|
|
}],
|
2024-03-13 08:11:52 +00:00
|
|
|
})),
|
|
|
|
}),
|
|
|
|
timezone: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let src = r#"<?xml version="1.0" encoding="utf-8" ?>
|
|
|
|
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
|
|
|
|
<D:prop xmlns:D="DAV:">
|
|
|
|
<D:getetag/>
|
|
|
|
<C:calendar-data/>
|
|
|
|
</D:prop>
|
|
|
|
<C:filter>
|
|
|
|
<C:comp-filter name="VCALENDAR">
|
|
|
|
<C:comp-filter name="VTODO">
|
|
|
|
<C:prop-filter name="COMPLETED">
|
|
|
|
<C:is-not-defined/>
|
|
|
|
</C:prop-filter>
|
|
|
|
<C:prop-filter name="STATUS">
|
|
|
|
<C:text-match
|
|
|
|
negate-condition="yes">CANCELLED</C:text-match>
|
|
|
|
</C:prop-filter>
|
|
|
|
</C:comp-filter>
|
|
|
|
</C:comp-filter>
|
|
|
|
</C:filter>
|
|
|
|
</C:calendar-query>"#;
|
|
|
|
|
|
|
|
let got = deserialize::<CalendarQuery<Calendar>>(src).await;
|
|
|
|
assert_eq!(got, expected)
|
|
|
|
}
|
2024-03-08 17:23:23 +00:00
|
|
|
}
|