From fb6a379f43ff579dbc224fb52180ba3a6d6cde5c Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 19 Mar 2024 17:36:32 +0100 Subject: Working thunderbird autodetect --- aero-dav/src/acldecoder.rs | 68 ++++++++++++++++++++++++++++++++ aero-dav/src/aclencoder.rs | 71 ++++++++++++++++++++++++++++++++++ aero-dav/src/acltypes.rs | 38 +++++++++++++++++- aero-dav/src/caltypes.rs | 1 - aero-dav/src/lib.rs | 8 +++- aero-dav/src/realization.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++- aero-dav/src/xml.rs | 2 +- 7 files changed, 275 insertions(+), 7 deletions(-) create mode 100644 aero-dav/src/acldecoder.rs create mode 100644 aero-dav/src/aclencoder.rs (limited to 'aero-dav') diff --git a/aero-dav/src/acldecoder.rs b/aero-dav/src/acldecoder.rs new file mode 100644 index 0000000..67dfb0b --- /dev/null +++ b/aero-dav/src/acldecoder.rs @@ -0,0 +1,68 @@ +use super::acltypes::*; +use super::types as dav; +use super::xml::{QRead, Reader, IRead, DAV_URN}; +use super::error::ParsingError; + +impl QRead for Property { + async fn qread(xml: &mut Reader) -> Result { + if xml.maybe_open_start(DAV_URN, "owner").await?.is_some() { + let href = xml.find().await?; + xml.close().await?; + return Ok(Self::Owner(href)) + } + if xml.maybe_open_start(DAV_URN, "current-user-principal").await?.is_some() { + let user = xml.find().await?; + xml.close().await?; + return Ok(Self::CurrentUserPrincipal(user)) + } + if xml.maybe_open_start(DAV_URN, "current-user-privilege-set").await?.is_some() { + xml.close().await?; + return Ok(Self::CurrentUserPrivilegeSet(vec![])) + } + + Err(ParsingError::Recoverable) + } +} + +impl QRead for PropertyRequest { + async fn qread(xml: &mut Reader) -> Result { + if xml.maybe_open(DAV_URN, "owner").await?.is_some() { + xml.close().await?; + return Ok(Self::Owner) + } + + if xml.maybe_open(DAV_URN, "current-user-principal").await?.is_some() { + xml.close().await?; + return Ok(Self::CurrentUserPrincipal) + } + + if xml.maybe_open(DAV_URN, "current-user-privilege-set").await?.is_some() { + xml.close().await?; + return Ok(Self::CurrentUserPrivilegeSet) + } + + Err(ParsingError::Recoverable) + } +} + +impl QRead for ResourceType { + async fn qread(xml: &mut Reader) -> Result { + if xml.maybe_open(DAV_URN, "principal").await?.is_some() { + xml.close().await?; + return Ok(Self::Principal) + } + Err(ParsingError::Recoverable) + } +} + +// ----- +impl QRead for User { + async fn qread(xml: &mut Reader) -> Result { + if xml.maybe_open(DAV_URN, "unauthenticated").await?.is_some() { + xml.close().await?; + return Ok(Self::Unauthenticated) + } + + dav::Href::qread(xml).await.map(Self::Authenticated) + } +} diff --git a/aero-dav/src/aclencoder.rs b/aero-dav/src/aclencoder.rs new file mode 100644 index 0000000..2fa4707 --- /dev/null +++ b/aero-dav/src/aclencoder.rs @@ -0,0 +1,71 @@ +use quick_xml::Error as QError; +use quick_xml::events::Event; + +use super::acltypes::*; +use super::xml::{QWrite, Writer, IWrite}; +use super::error::ParsingError; + +impl QWrite for Property { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + match self { + Self::Owner(href) => { + let start = xml.create_dav_element("owner"); + let end = start.to_end(); + xml.q.write_event_async(Event::Start(start.clone())).await?; + href.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await + }, + Self::CurrentUserPrincipal(user) => { + let start = xml.create_dav_element("current-user-principal"); + let end = start.to_end(); + xml.q.write_event_async(Event::Start(start.clone())).await?; + user.qwrite(xml).await?; + xml.q.write_event_async(Event::End(end)).await + }, + Self::CurrentUserPrivilegeSet(_) => { + let empty_tag = xml.create_dav_element("current-user-privilege-set"); + xml.q.write_event_async(Event::Empty(empty_tag)).await + }, + } + } +} + +impl QWrite for PropertyRequest { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + let mut atom = async |c| { + let empty_tag = xml.create_dav_element(c); + xml.q.write_event_async(Event::Empty(empty_tag)).await + }; + + match self { + Self::Owner => atom("owner").await, + Self::CurrentUserPrincipal => atom("current-user-principal").await, + Self::CurrentUserPrivilegeSet => atom("current-user-privilege-set").await, + } + } +} + +impl QWrite for ResourceType { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + match self { + Self::Principal => { + let empty_tag = xml.create_dav_element("principal"); + xml.q.write_event_async(Event::Empty(empty_tag)).await + } + } + } +} + +// ----- + +impl QWrite for User { + async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { + match self { + Self::Unauthenticated => { + let tag = xml.create_dav_element("unauthenticated"); + xml.q.write_event_async(Event::Empty(tag)).await + }, + Self::Authenticated(href) => href.qwrite(xml).await, + } + } +} diff --git a/aero-dav/src/acltypes.rs b/aero-dav/src/acltypes.rs index f356813..d5be413 100644 --- a/aero-dav/src/acltypes.rs +++ b/aero-dav/src/acltypes.rs @@ -1,4 +1,40 @@ -//@FIXME required for a full DAV implementation +use super::types as dav; + +//RFC covered: RFC3744 (ACL core) + RFC5397 (ACL Current Principal Extension) + + +//@FIXME required for a full CalDAV implementation // See section 6. of the CalDAV RFC // It seems mainly required for free-busy that I will not implement now. // It can also be used for discovering main calendar, not sure it is used. +// Note: it is used by Thunderbird + + +#[derive(Debug, PartialEq, Clone)] +pub enum PropertyRequest { + Owner, + CurrentUserPrincipal, + CurrentUserPrivilegeSet, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Property { + Owner(dav::Href), + CurrentUserPrincipal(User), + CurrentUserPrivilegeSet(Vec), +} + +#[derive(Debug, PartialEq, Clone)] +pub enum ResourceType { + Principal, +} + +/// Not implemented, it's a placeholder +#[derive(Debug, PartialEq, Clone)] +pub struct Privilege(()); + +#[derive(Debug, PartialEq, Clone)] +pub enum User { + Unauthenticated, + Authenticated(dav::Href), +} diff --git a/aero-dav/src/caltypes.rs b/aero-dav/src/caltypes.rs index aa056d4..602498c 100644 --- a/aero-dav/src/caltypes.rs +++ b/aero-dav/src/caltypes.rs @@ -2,7 +2,6 @@ use chrono::{DateTime,Utc}; use super::types as dav; -use super::xml; pub const ICAL_DATETIME_FMT: &str = "%Y%m%dT%H%M%SZ"; diff --git a/aero-dav/src/lib.rs b/aero-dav/src/lib.rs index 0ca8243..009951a 100644 --- a/aero-dav/src/lib.rs +++ b/aero-dav/src/lib.rs @@ -16,8 +16,12 @@ pub mod caltypes; pub mod calencoder; pub mod caldecoder; -// wip -mod acltypes; +// acl (wip) +pub mod acltypes; +pub mod aclencoder; +pub mod acldecoder; + +// versioning (wip) mod versioningtypes; // final type diff --git a/aero-dav/src/realization.rs b/aero-dav/src/realization.rs index 7bec729..bfed4d7 100644 --- a/aero-dav/src/realization.rs +++ b/aero-dav/src/realization.rs @@ -1,5 +1,6 @@ use super::types as dav; use super::caltypes as cal; +use super::acltypes as acl; use super::xml; use super::error; @@ -11,8 +12,8 @@ impl xml::QRead for Disabled { } } impl xml::QWrite for Disabled { - fn qwrite(&self, _xml: &mut xml::Writer) -> impl futures::Future> + Send { - async { unreachable!(); } + async fn qwrite(&self, _xml: &mut xml::Writer) -> Result<(), quick_xml::Error> { + unreachable!() } } @@ -40,3 +41,92 @@ impl dav::Extension for Calendar type ResourceType = cal::ResourceType; } +// ACL +#[derive(Debug, PartialEq, Clone)] +pub struct Acl {} +impl dav::Extension for Acl +{ + type Error = Disabled; + type Property = acl::Property; + type PropertyRequest = acl::PropertyRequest; + type ResourceType = acl::ResourceType; +} + +// All merged +#[derive(Debug, PartialEq, Clone)] +pub struct All {} +impl dav::Extension for All { + type Error = cal::Violation; + type Property = Property; + type PropertyRequest = PropertyRequest; + type ResourceType = ResourceType; +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Property { + Cal(cal::Property), + Acl(acl::Property), +} +impl xml::QRead for Property { + async fn qread(xml: &mut xml::Reader) -> Result { + match cal::Property::qread(xml).await { + Err(error::ParsingError::Recoverable) => (), + otherwise => return otherwise.map(Property::Cal), + } + acl::Property::qread(xml).await.map(Property::Acl) + } +} +impl xml::QWrite for Property { + async fn qwrite(&self, xml: &mut xml::Writer) -> Result<(), quick_xml::Error> { + match self { + Self::Cal(c) => c.qwrite(xml).await, + Self::Acl(a) => a.qwrite(xml).await, + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum PropertyRequest { + Cal(cal::PropertyRequest), + Acl(acl::PropertyRequest), +} +impl xml::QRead for PropertyRequest { + async fn qread(xml: &mut xml::Reader) -> Result { + match cal::PropertyRequest::qread(xml).await { + Err(error::ParsingError::Recoverable) => (), + otherwise => return otherwise.map(PropertyRequest::Cal), + } + acl::PropertyRequest::qread(xml).await.map(PropertyRequest::Acl) + } +} +impl xml::QWrite for PropertyRequest { + async fn qwrite(&self, xml: &mut xml::Writer) -> Result<(), quick_xml::Error> { + match self { + Self::Cal(c) => c.qwrite(xml).await, + Self::Acl(a) => a.qwrite(xml).await, + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum ResourceType { + Cal(cal::ResourceType), + Acl(acl::ResourceType), +} +impl xml::QRead for ResourceType { + async fn qread(xml: &mut xml::Reader) -> Result { + match cal::ResourceType::qread(xml).await { + Err(error::ParsingError::Recoverable) => (), + otherwise => return otherwise.map(ResourceType::Cal), + } + acl::ResourceType::qread(xml).await.map(ResourceType::Acl) + } +} +impl xml::QWrite for ResourceType { + async fn qwrite(&self, xml: &mut xml::Writer) -> Result<(), quick_xml::Error> { + match self { + Self::Cal(c) => c.qwrite(xml).await, + Self::Acl(a) => a.qwrite(xml).await, + } + } +} diff --git a/aero-dav/src/xml.rs b/aero-dav/src/xml.rs index 26f54cc..020ee6c 100644 --- a/aero-dav/src/xml.rs +++ b/aero-dav/src/xml.rs @@ -264,7 +264,7 @@ impl Reader { _ => return Err(ParsingError::Recoverable), }; - //println!("open tag {:?}", evt); + //println!("open start tag {:?}", evt); self.parents.push(evt.clone()); Ok(evt) } -- cgit v1.2.3