/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use super::{ Collation, MatchType, property::{DavProperty, DavValue, LockScope, LockType}, response::Ace, }; use crate::{Condition, Depth}; use calcard::{ icalendar::{ICalendarComponentType, ICalendarParameterName, ICalendarProperty}, vcard::{VCardParameterName, VCardProperty}, }; use types::{ TimeRange, dead_property::{ArchivedDeadProperty, ArchivedDeadPropertyTag, DeadElementTag, DeadProperty}, }; #[derive(Debug, Clone, PartialEq, Eq, Default)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(test, serde(tag = "type", content = "data"))] pub enum PropFind { #[default] PropName, AllProp(Vec), Prop(Vec), } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct PropertyUpdate { pub set: Vec, pub remove: Vec, pub set_first: bool, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct DavPropertyValue { pub property: DavProperty, pub value: DavValue, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct MkCol { pub is_mkcalendar: bool, pub props: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct LockInfo { pub lock_scope: LockScope, pub lock_type: LockType, pub owner: Option, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(test, serde(tag = "type"))] pub enum Report { AddressbookQuery(AddressbookQuery), AddressbookMultiGet(MultiGet), CalendarQuery(CalendarQuery), CalendarMultiGet(MultiGet), FreeBusyQuery(FreeBusyQuery), SyncCollection(SyncCollection), ExpandProperty(ExpandProperty), AclPrincipalPropSet(AclPrincipalPropSet), PrincipalMatch(PrincipalMatch), PrincipalPropertySearch(PrincipalPropertySearch), PrincipalSearchPropertySet, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct ExpandProperty { pub properties: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct ExpandPropertyItem { pub property: DavProperty, pub depth: u32, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct AddressbookQuery { pub properties: PropFind, pub filters: Vec>, pub limit: Option, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct VCardPropertyWithGroup { pub name: VCardProperty, pub group: Option, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct CalendarQuery { pub properties: PropFind, pub filters: Vec, ICalendarProperty, ICalendarParameterName>>, pub timezone: Timezone, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(test, serde(tag = "type"))] pub enum Timezone { Name(String), Id(String), None, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct FreeBusyQuery { pub range: Option, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct MultiGet { pub properties: PropFind, pub hrefs: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct SyncCollection { pub sync_token: Option, pub properties: PropFind, pub depth: Depth, pub limit: Option, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(test, serde(tag = "type"))] pub enum Filter { AnyOf, AllOf, Component { comp: A, op: FilterOp, }, Property { comp: A, prop: B, op: FilterOp, }, Parameter { comp: A, prop: B, param: C, op: FilterOp, }, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(test, serde(tag = "type", content = "data"))] pub enum FilterOp { Exists, Undefined, TimeRange(TimeRange), TextMatch(TextMatch), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(test, serde(tag = "type"))] pub struct TextMatch { pub match_type: MatchType, pub value: String, pub collation: Collation, pub negate: bool, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct Acl { pub aces: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct AclPrincipalPropSet { pub properties: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct PrincipalMatch { pub principal_properties: PrincipalMatchProperties, pub properties: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub enum PrincipalMatchProperties { Properties(Vec), Self_, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct PrincipalPropertySearch { pub property_search: Vec, pub properties: Vec, pub apply_to_principal_collection_set: bool, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] pub struct PropertySearch { pub property: DavProperty, pub match_: String, } impl PropertyUpdate { pub fn has_changes(&self) -> bool { !self.set.is_empty() || !self.remove.is_empty() } } impl FreeBusyQuery { pub fn new(start: i64, end: i64) -> Self { FreeBusyQuery { range: Some(TimeRange { start, end }), } } } pub trait DavDeadProperty { fn to_dav_values(&self, output: &mut Vec); } impl DavDeadProperty for ArchivedDeadProperty { fn to_dav_values(&self, output: &mut Vec) { let mut depth: u32 = 0; let mut tags = Vec::new(); let mut tag_start = None; for tag in self.0.iter() { match tag { ArchivedDeadPropertyTag::ElementStart(start) => { if depth == 0 { tag_start = Some(DeadElementTag::from(start)); } else { tags.push(tag.into()); } depth += 1; } ArchivedDeadPropertyTag::ElementEnd => { depth = depth.saturating_sub(1); if depth > 0 { tags.push(tag.into()); } else if let Some(tag_start) = tag_start.take() { output.push(DavPropertyValue::new( DavProperty::DeadProperty(tag_start), DavValue::DeadProperty(DeadProperty(std::mem::take(&mut tags))), )); } } ArchivedDeadPropertyTag::Text(_) => { if tag_start.is_some() { tags.push(tag.into()); } } } } } } impl Condition<'_> { pub fn is_none_match(&self) -> bool { match self { Condition::ETag { is_not, .. } | Condition::Exists { is_not } => *is_not, Condition::StateToken { .. } => false, } } }