/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use crate::{ parser::{DavParser, Token, tokenizer::Tokenizer}, schema::{ Element, NamedElement, Namespace, property::{DavValue, Privilege}, request::{ Acl, AclPrincipalPropSet, DavPropertyValue, PrincipalMatch, PrincipalMatchProperties, PrincipalPropertySearch, PropertySearch, }, response::{Ace, GrantDeny, Href, List, Principal}, }, }; impl DavParser for Acl { fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result { stream.expect_named_element(NamedElement::dav(Element::Acl))?; let mut acl = Acl { aces: vec![] }; loop { match stream.token()? { Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Ace, }, .. } => { acl.aces.push(Ace::parse(stream)?); } Token::ElementEnd => { break; } Token::UnknownElement(_) => { stream.seek_element_end()?; } other => { return Err(other.into_unexpected()); } } } Ok(acl) } } impl DavParser for Ace { fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result { let mut ace = Ace { principal: Principal::All, invert: false, grant_deny: GrantDeny::Grant(List(vec![])), protected: false, inherited: None, }; let mut depth = 1; loop { match stream.token()? { Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Principal, }, .. } => { ace.principal = Principal::parse(stream)?; } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Invert, }, .. } if depth == 1 => { ace.invert = true; depth += 1; } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Protected, }, .. } if depth == 1 => { ace.protected = true; stream.expect_element_end()?; } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Inherited, }, .. } if depth == 1 => { stream.expect_named_element(NamedElement::dav(Element::Href))?; ace.inherited = stream.collect_string_value()?.map(Href); stream.expect_element_end()?; } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Grant, }, .. } if depth == 1 => { ace.grant_deny = GrantDeny::Grant(List(stream.collect_privileges()?)); } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Deny, }, .. } if depth == 1 => { ace.grant_deny = GrantDeny::Deny(List(stream.collect_privileges()?)); } Token::ElementEnd => { depth -= 1; if depth == 0 { break; } } Token::UnknownElement(_) => { stream.seek_element_end()?; } other => { return Err(other.into_unexpected()); } } } Ok(ace) } } impl DavParser for Principal { fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result { let result = match stream.unwrap_named_element()? { NamedElement { ns: Namespace::Dav, element: Element::Href, } => Principal::Href(Href(stream.collect_string_value()?.unwrap_or_default())), NamedElement { ns: Namespace::Dav, element: Element::All, } => { stream.expect_element_end()?; Principal::All } NamedElement { ns: Namespace::Dav, element: Element::Authenticated, } => { stream.expect_element_end()?; Principal::Authenticated } NamedElement { ns: Namespace::Dav, element: Element::Unauthenticated, } => { stream.expect_element_end()?; Principal::Unauthenticated } NamedElement { ns: Namespace::Dav, element: Element::Property, } => { let property = stream.collect_properties(Vec::new())?; Principal::Property(List( property .into_iter() .map(|prop| DavPropertyValue::new(prop, DavValue::Null)) .collect(), )) } NamedElement { ns: Namespace::Dav, element: Element::Self_, } => { stream.expect_element_end()?; Principal::Self_ } other => return Err(other.into_unexpected()), }; stream.expect_element_end()?; Ok(result) } } impl Tokenizer<'_> { pub fn collect_privileges(&mut self) -> crate::parser::Result> { let mut privileges = Vec::new(); let mut depth = 1; loop { match self.token()? { Token::ElementStart { name, .. } => { if let Some(privilege) = Privilege::from_element(name) { privileges.push(privilege); self.expect_element_end()?; } else { depth += 1; } } Token::ElementEnd => { depth -= 1; if depth == 0 { break; } } Token::UnknownElement(_) => { self.seek_element_end()?; } other => { return Err(other.into_unexpected()); } } } Ok(privileges) } } impl Privilege { pub fn from_element(element: NamedElement) -> Option { match (element.ns, element.element) { (Namespace::Dav, Element::Read) => Some(Privilege::Read), (Namespace::Dav, Element::Write) => Some(Privilege::Write), (Namespace::Dav, Element::WriteProperties) => Some(Privilege::WriteProperties), (Namespace::Dav, Element::WriteContent) => Some(Privilege::WriteContent), (Namespace::Dav, Element::Unlock) => Some(Privilege::Unlock), (Namespace::Dav, Element::ReadAcl) => Some(Privilege::ReadAcl), (Namespace::Dav, Element::ReadCurrentUserPrivilegeSet) => { Some(Privilege::ReadCurrentUserPrivilegeSet) } (Namespace::Dav, Element::WriteAcl) => Some(Privilege::WriteAcl), (Namespace::Dav, Element::Bind) => Some(Privilege::Bind), (Namespace::Dav, Element::Unbind) => Some(Privilege::Unbind), (Namespace::Dav, Element::All) => Some(Privilege::All), (Namespace::CalDav, Element::ReadFreeBusy) => Some(Privilege::ReadFreeBusy), (Namespace::CalDav, Element::ScheduleDeliver) => Some(Privilege::ScheduleDeliver), (Namespace::CalDav, Element::ScheduleDeliverInvite) => { Some(Privilege::ScheduleDeliverInvite) } (Namespace::CalDav, Element::ScheduleDeliverReply) => { Some(Privilege::ScheduleDeliverReply) } (Namespace::CalDav, Element::ScheduleQueryFreebusy) => { Some(Privilege::ScheduleQueryFreeBusy) } (Namespace::CalDav, Element::ScheduleSend) => Some(Privilege::ScheduleSend), (Namespace::CalDav, Element::ScheduleSendInvite) => Some(Privilege::ScheduleSendInvite), (Namespace::CalDav, Element::ScheduleSendReply) => Some(Privilege::ScheduleSendReply), (Namespace::CalDav, Element::ScheduleSendFreebusy) => { Some(Privilege::ScheduleSendFreeBusy) } _ => None, } } } impl DavParser for AclPrincipalPropSet { fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result { let mut acps = AclPrincipalPropSet { properties: vec![] }; loop { match stream.token()? { Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Prop, }, .. } => { acps.properties = stream.collect_properties(acps.properties)?; } Token::ElementEnd => { break; } Token::UnknownElement(_) => { stream.seek_element_end()?; } other => { return Err(other.into_unexpected()); } } } Ok(acps) } } impl DavParser for PrincipalMatch { fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result { let mut pm = PrincipalMatch { principal_properties: PrincipalMatchProperties::Self_, properties: vec![], }; loop { match stream.token()? { Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::PrincipalProperty, }, .. } => { pm.principal_properties = PrincipalMatchProperties::Properties( stream.collect_properties(Vec::new())?, ); } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Self_, }, .. } => { pm.principal_properties = PrincipalMatchProperties::Self_; stream.expect_element_end()?; } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Prop, }, .. } => { pm.properties = stream.collect_properties(pm.properties)?; } Token::ElementEnd => { break; } Token::UnknownElement(_) => { stream.seek_element_end()?; } other => { return Err(other.into_unexpected()); } } } Ok(pm) } } impl DavParser for PrincipalPropertySearch { fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result { let mut pps = PrincipalPropertySearch { property_search: vec![], properties: vec![], apply_to_principal_collection_set: false, }; loop { match stream.token()? { Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::PropertySearch, }, .. } => { if let Some(prop) = PropertySearch::parse(stream)? { pps.property_search.push(prop); } } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Prop, }, .. } => { pps.properties = stream.collect_properties(pps.properties)?; } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::ApplyToPrincipalCollectionSet, }, .. } => { stream.expect_element_end()?; pps.apply_to_principal_collection_set = true; } Token::ElementEnd => { break; } Token::UnknownElement(_) => { stream.seek_element_end()?; } other => { return Err(other.into_unexpected()); } } } Ok(pps) } } impl PropertySearch { fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result> { let mut property = None; let mut match_ = None; loop { match stream.token()? { Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Prop, }, .. } => { property = stream.collect_properties(Vec::new())?.into_iter().next(); } Token::ElementStart { name: NamedElement { ns: Namespace::Dav, element: Element::Match, }, .. } => { match_ = stream.collect_string_value()?; } Token::ElementEnd => { break; } Token::UnknownElement(_) => { stream.seek_element_end()?; } other => { return Err(other.into_unexpected()); } } } Ok(property.map(|property| PropertySearch { property, match_: match_.unwrap_or_default(), })) } }