diff options
Diffstat (limited to 'aero-dav/src/caldecoder.rs')
-rw-r--r-- | aero-dav/src/caldecoder.rs | 181 |
1 files changed, 150 insertions, 31 deletions
diff --git a/aero-dav/src/caldecoder.rs b/aero-dav/src/caldecoder.rs index 239b005..2e833a1 100644 --- a/aero-dav/src/caldecoder.rs +++ b/aero-dav/src/caldecoder.rs @@ -357,25 +357,41 @@ impl QRead<CalendarDataEmpty> for CalendarDataEmpty { impl QRead<Comp> for Comp { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> { - xml.open(CAL_URN, "comp").await?; + let (mut prop_kind, mut comp_kind) = (None, None); + + let bs = xml.open(CAL_URN, "comp").await?; let name = Component::new(xml.prev_attr("name").ok_or(ParsingError::MissingAttribute)?); - let additional_rules = Box::pin(xml.maybe_find()).await?; - xml.close().await?; - Ok(Self { name, additional_rules }) - } -} -impl QRead<CompInner> for CompInner { - async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> { - let (mut prop_kind, mut comp_kind) = (None, None); + // Return early if it's an empty tag + if matches!(bs, Event::Empty(_)) { + xml.close().await?; + return Ok(Self { name, prop_kind, comp_kind }) + } loop { let mut dirty = false; - - xml.maybe_read(&mut prop_kind, &mut dirty).await?; - xml.maybe_read(&mut comp_kind, &mut dirty).await?; + let (mut tmp_prop_kind, mut tmp_comp_kind): (Option<PropKind>, Option<CompKind>) = (None, None); + + 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), + (Some(PropKind::AllProp), v) => *v = Some(PropKind::AllProp), + (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), + (Some(CompKind::AllComp), v) => *v = Some(CompKind::AllComp), + (Some(a), b) => *b = Some(a), + (None, _) => (), + }; + - if !dirty { + if !dirty { match xml.peek() { Event::End(_) => break, _ => xml.skip().await?, @@ -383,19 +399,15 @@ impl QRead<CompInner> for CompInner { } }; - match (prop_kind, comp_kind) { - (Some(prop_kind), Some(comp_kind)) => Ok(Self { prop_kind, comp_kind }), - _ => Err(ParsingError::MissingChild), - } + xml.close().await?; + Ok(Self { name, prop_kind, comp_kind }) } } impl QRead<CompSupport> for CompSupport { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> { xml.open(CAL_URN, "comp").await?; - println!("before"); let inner = Component::new(xml.prev_attr("name").ok_or(ParsingError::MissingAttribute)?); - println!("after"); xml.close().await?; Ok(Self(inner)) } @@ -415,13 +427,13 @@ impl QRead<CompKind> for CompKind { xml.maybe_push(&mut comp, &mut dirty).await?; if !dirty { - match xml.peek() { - Event::End(_) => break, - _ => xml.skip().await?, - }; + break } } - Ok(CompKind::Comp(comp)) + match &comp[..] { + [] => Err(ParsingError::Recoverable), + _ => Ok(CompKind::Comp(comp)), + } } } @@ -439,13 +451,14 @@ impl QRead<PropKind> for PropKind { xml.maybe_push(&mut prop, &mut dirty).await?; if !dirty { - match xml.peek() { - Event::End(_) => break, - _ => xml.skip().await?, - }; + break } } - Ok(PropKind::Prop(prop)) + + match &prop[..] { + [] => Err(ParsingError::Recoverable), + _ => Ok(PropKind::Prop(prop)), + } } } @@ -687,7 +700,7 @@ impl QRead<TimeZone> for TimeZone { impl QRead<Filter> for Filter { async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> { - xml.open(CAL_URN, "timezone").await?; + xml.open(CAL_URN, "filter").await?; let comp_filter = xml.find().await?; xml.close().await?; Ok(Self(comp_filter)) @@ -736,7 +749,7 @@ impl QRead<CalProp> for CalProp { #[cfg(test)] mod tests { use super::*; - //use chrono::{FixedOffset, TimeZone}; + use chrono::{Utc, TimeZone}; use crate::realization::Calendar; //use quick_reader::NsReader; @@ -803,4 +816,110 @@ END:VCALENDAR]]></C:calendar-timezone> let got = deserialize::<MkCalendar<Calendar>>(src).await; assert_eq!(got, expected) } + + #[tokio::test] + async fn rfc_calendar_query() { + let expected = CalendarQuery { + selector: Some(CalendarSelector::Prop(dav::PropName(vec![ + dav::PropertyRequest::GetEtag, + dav::PropertyRequest::Extension(PropertyRequest::CalendarData(CalendarDataRequest { + mime: None, + comp: Some(Comp { + name: Component::VCalendar, + prop_kind: Some(PropKind::Prop(vec![ + CalProp { + name: ComponentProperty("VERSION".into()), + novalue: None, + } + ])), + 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, + })), + ]))), + filter: Filter(CompFilter { + name: Component::VCalendar, + additional_rules: Some(CompFilterRules::Matches(CompFilterMatch { + prop_filter: vec![], + 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(), + )), + })), + }, + ], + 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) + } } |