Import upstream v0.16.22, stripped

Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
2026-09-18 10:21:56 -07:00
commit 7dae9b29fd
1650 changed files with 485521 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+441
View File
@@ -0,0 +1,441 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use super::{
Collation, Namespace,
request::DavPropertyValue,
response::{Ace, AclRestrictions, Href, List, Response, SupportedPrivilege},
};
use crate::{Depth, Timeout};
use calcard::{
icalendar::{ICalendar, ICalendarComponentType, ICalendarProperty},
vcard::{VCard, VCardProperty, VCardVersion},
};
use types::{
TimeRange,
dead_property::{DeadElementTag, DeadProperty},
};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(test, serde(tag = "type", content = "data"))]
pub enum DavProperty {
WebDav(WebDavProperty),
CardDav(CardDavProperty),
CalDav(CalDavProperty),
Principal(PrincipalProperty),
DeadProperty(DeadElementTag),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(test, serde(tag = "type", content = "data"))]
pub enum WebDavProperty {
CreationDate,
DisplayName,
GetContentLanguage,
GetContentLength,
GetContentType,
GetETag,
GetLastModified,
ResourceType,
LockDiscovery,
SupportedLock,
SupportedReportSet,
CurrentUserPrincipal,
// Quota properties
QuotaAvailableBytes,
QuotaUsedBytes,
// Sync properties
SyncToken,
// ACL properties (all protected)
Owner,
Group,
SupportedPrivilegeSet,
CurrentUserPrivilegeSet,
Acl,
AclRestrictions,
InheritedAclSet,
PrincipalCollectionSet,
// Apple proprietary properties
GetCTag,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(test, serde(tag = "type", content = "data"))]
pub enum CardDavProperty {
AddressbookDescription,
SupportedAddressData,
SupportedCollationSet,
MaxResourceSize,
AddressData {
properties: Vec<CardDavPropertyName>,
#[cfg_attr(test, serde(skip))]
version: Option<VCardVersion>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct CardDavPropertyName {
pub group: Option<String>,
pub name: VCardProperty,
pub no_value: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(test, serde(tag = "type", content = "data"))]
pub enum CalDavProperty {
CalendarDescription,
CalendarTimezone,
SupportedCalendarComponentSet,
SupportedCalendarData,
SupportedCollationSet,
MaxResourceSize,
MinDateTime,
MaxDateTime,
MaxInstances,
MaxAttendeesPerInstance,
CalendarData(CalendarData),
TimezoneServiceSet,
TimezoneId,
ScheduleDefaultCalendarURL,
ScheduleTag,
ScheduleCalendarTransp,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(test, serde(tag = "type", content = "data"))]
pub enum PrincipalProperty {
AlternateURISet,
PrincipalURL,
GroupMemberSet,
GroupMembership,
CalendarHomeSet,
AddressbookHomeSet,
PrincipalAddress,
CalendarUserAddressSet,
CalendarUserType,
ScheduleInboxURL,
ScheduleOutboxURL,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct CalendarData {
pub properties: Vec<CalDavPropertyName>,
pub expand: Option<TimeRange>,
pub limit_recurrence: Option<TimeRange>,
pub limit_freebusy: Option<TimeRange>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct CalDavPropertyName {
pub component: Option<ICalendarComponentType>,
pub name: Option<ICalendarProperty>,
pub no_value: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Rfc1123DateTime(pub(crate) i64);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum DavValue {
Timestamp(i64),
Rfc1123Date(Rfc1123DateTime),
Uint64(u64),
String(String),
CData(String),
ResourceTypes(List<ResourceType>),
ActiveLocks(List<ActiveLock>),
LockEntries(List<LockEntry>),
ReportSets(List<ReportSet>),
ICalendar(ICalendar),
VCard(VCard),
Components(List<Comp>),
Collations(List<SupportedCollation>),
PrivilegeSet(List<SupportedPrivilege>),
Privileges(List<Privilege>),
Href(List<Href>),
Acl(List<Ace>),
AclRestrictions(AclRestrictions),
Response(Box<Response>),
DeadProperty(DeadProperty),
SupportedAddressData,
SupportedCalendarData,
Null,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum ReportSet {
SyncCollection,
ExpandProperty,
AddressbookQuery,
AddressbookMultiGet,
CalendarQuery,
CalendarMultiGet,
FreeBusyQuery,
AclPrincipalPropSet,
PrincipalMatch,
PrincipalPropertySearch,
PrincipalSearchPropertySet,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct Comp(pub ICalendarComponentType);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct SupportedCollation {
pub collation: Collation,
pub namespace: Namespace,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum ResourceType {
Collection,
Principal,
AddressBook,
Calendar,
ScheduleInbox,
ScheduleOutbox,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct LockDiscovery(pub List<ActiveLock>);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct ActiveLock {
pub lock_scope: LockScope,
pub lock_type: LockType,
pub depth: Depth,
pub owner: Option<DeadProperty>,
pub timeout: Timeout,
pub lock_token: Option<Href>,
pub lock_root: Href,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct SupportedLock(pub List<LockEntry>);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct LockEntry {
pub lock_scope: LockScope,
pub lock_type: LockType,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum LockType {
Write,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum LockScope {
Exclusive,
Shared,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum Privilege {
Read,
Write,
WriteProperties,
WriteContent,
Unlock,
ReadAcl,
ReadCurrentUserPrivilegeSet,
WriteAcl,
Bind,
Unbind,
All,
ReadFreeBusy,
ScheduleDeliver,
ScheduleDeliverInvite,
ScheduleDeliverReply,
ScheduleQueryFreeBusy,
ScheduleSend,
ScheduleSendInvite,
ScheduleSendReply,
ScheduleSendFreeBusy,
}
impl Privilege {
pub fn all(is_calendar: bool) -> Vec<Privilege> {
if is_calendar {
vec![
Privilege::All,
Privilege::Read,
Privilege::Write,
Privilege::WriteProperties,
Privilege::WriteContent,
Privilege::Unlock,
Privilege::ReadAcl,
Privilege::ReadCurrentUserPrivilegeSet,
Privilege::WriteAcl,
Privilege::Bind,
Privilege::Unbind,
Privilege::ReadFreeBusy,
]
} else {
vec![
Privilege::All,
Privilege::Read,
Privilege::Write,
Privilege::WriteProperties,
Privilege::WriteContent,
Privilege::Unlock,
Privilege::ReadAcl,
Privilege::ReadCurrentUserPrivilegeSet,
Privilege::WriteAcl,
Privilege::Bind,
Privilege::Unbind,
]
}
}
pub fn scheduling(is_inbox: bool, is_owner: bool) -> Vec<Privilege> {
let mut privileges = if is_inbox {
vec![
Privilege::Read,
Privilege::ReadCurrentUserPrivilegeSet,
Privilege::ScheduleDeliver,
Privilege::ScheduleDeliverInvite,
Privilege::ScheduleDeliverReply,
Privilege::ScheduleQueryFreeBusy,
]
} else {
vec![
Privilege::Read,
Privilege::ReadCurrentUserPrivilegeSet,
Privilege::ScheduleSend,
Privilege::ScheduleSendInvite,
Privilege::ScheduleSendReply,
Privilege::ScheduleSendFreeBusy,
]
};
if is_owner {
privileges.extend([
Privilege::All,
Privilege::Write,
Privilege::WriteProperties,
Privilege::WriteContent,
Privilege::ReadAcl,
Privilege::WriteAcl,
]);
}
privileges
}
}
impl From<DavProperty> for DavPropertyValue {
fn from(value: DavProperty) -> Self {
DavPropertyValue {
property: value,
value: DavValue::Null,
}
}
}
impl Rfc1123DateTime {
pub fn new(timestamp: i64) -> Self {
Self(timestamp)
}
}
impl DavProperty {
pub const ALL_PROPS: [DavProperty; 11] = [
DavProperty::WebDav(WebDavProperty::CreationDate),
DavProperty::WebDav(WebDavProperty::DisplayName),
DavProperty::WebDav(WebDavProperty::GetETag),
DavProperty::WebDav(WebDavProperty::GetLastModified),
DavProperty::WebDav(WebDavProperty::ResourceType),
DavProperty::WebDav(WebDavProperty::LockDiscovery),
DavProperty::WebDav(WebDavProperty::SupportedLock),
DavProperty::WebDav(WebDavProperty::CurrentUserPrincipal),
DavProperty::WebDav(WebDavProperty::GetContentLanguage),
DavProperty::WebDav(WebDavProperty::GetContentLength),
DavProperty::WebDav(WebDavProperty::GetContentType),
];
pub fn is_all_prop(&self) -> bool {
matches!(
self,
DavProperty::WebDav(WebDavProperty::CreationDate)
| DavProperty::WebDav(WebDavProperty::DisplayName)
| DavProperty::WebDav(WebDavProperty::GetETag)
| DavProperty::WebDav(WebDavProperty::GetLastModified)
| DavProperty::WebDav(WebDavProperty::ResourceType)
| DavProperty::WebDav(WebDavProperty::LockDiscovery)
| DavProperty::WebDav(WebDavProperty::SupportedLock)
| DavProperty::WebDav(WebDavProperty::CurrentUserPrincipal)
| DavProperty::WebDav(WebDavProperty::GetContentLanguage)
| DavProperty::WebDav(WebDavProperty::GetContentLength)
| DavProperty::WebDav(WebDavProperty::GetContentType)
| DavProperty::DeadProperty(_)
)
}
}
impl ReportSet {
pub fn calendar() -> Vec<ReportSet> {
vec![
ReportSet::SyncCollection,
ReportSet::AclPrincipalPropSet,
ReportSet::PrincipalMatch,
ReportSet::ExpandProperty,
ReportSet::CalendarQuery,
ReportSet::CalendarMultiGet,
ReportSet::FreeBusyQuery,
]
}
pub fn addressbook() -> Vec<ReportSet> {
vec![
ReportSet::SyncCollection,
ReportSet::AclPrincipalPropSet,
ReportSet::PrincipalMatch,
ReportSet::ExpandProperty,
ReportSet::AddressbookQuery,
ReportSet::AddressbookMultiGet,
]
}
pub fn file() -> Vec<ReportSet> {
vec![
ReportSet::SyncCollection,
ReportSet::AclPrincipalPropSet,
ReportSet::PrincipalMatch,
]
}
pub fn principal() -> Vec<ReportSet> {
vec![
ReportSet::PrincipalPropertySearch,
ReportSet::PrincipalSearchPropertySet,
ReportSet::PrincipalMatch,
]
}
}
+295
View File
@@ -0,0 +1,295 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* 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<DavProperty>),
Prop(Vec<DavProperty>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct PropertyUpdate {
pub set: Vec<DavPropertyValue>,
pub remove: Vec<DavProperty>,
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<DavPropertyValue>,
}
#[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<DeadProperty>,
}
#[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<ExpandPropertyItem>,
}
#[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<Filter<(), VCardPropertyWithGroup, VCardParameterName>>,
pub limit: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct VCardPropertyWithGroup {
pub name: VCardProperty,
pub group: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct CalendarQuery {
pub properties: PropFind,
pub filters:
Vec<Filter<Vec<ICalendarComponentType>, 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<TimeRange>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct MultiGet {
pub properties: PropFind,
pub hrefs: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct SyncCollection {
pub sync_token: Option<String>,
pub properties: PropFind,
pub depth: Depth,
pub limit: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(test, serde(tag = "type"))]
pub enum Filter<A, B, C> {
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<Ace>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct AclPrincipalPropSet {
pub properties: Vec<DavProperty>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct PrincipalMatch {
pub principal_properties: PrincipalMatchProperties,
pub properties: Vec<DavProperty>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum PrincipalMatchProperties {
Properties(Vec<DavProperty>),
Self_,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct PrincipalPropertySearch {
pub property_search: Vec<PropertySearch>,
pub properties: Vec<DavProperty>,
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<DavPropertyValue>);
}
impl DavDeadProperty for ArchivedDeadProperty {
fn to_dav_values(&self, output: &mut Vec<DavPropertyValue>) {
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,
}
}
}
+430
View File
@@ -0,0 +1,430 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use super::{
Namespaces,
property::{DavProperty, Privilege},
request::{DavPropertyValue, Filter},
};
use calcard::{
icalendar::{ICalendarComponentType, ICalendarParameterName, ICalendarProperty},
vcard::{VCardParameterName, VCardProperty},
};
use hyper::StatusCode;
use std::{borrow::Cow, fmt::Display};
pub struct MultiStatus {
pub namespaces: Namespaces,
pub response: List<Response>,
pub response_description: Option<ResponseDescription>,
pub sync_token: Option<SyncToken>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct Response {
pub href: Href,
pub typ: ResponseType,
pub error: Option<Condition>,
pub response_description: Option<ResponseDescription>,
pub location: Option<Location>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum ResponseType {
PropStat(List<PropStat>),
Status { href: List<Href>, status: Status },
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Status(pub StatusCode);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Location(pub Href);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct ResponseDescription(pub String);
#[repr(transparent)]
pub struct SyncToken(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Href(pub String);
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct List<T: Display>(pub Vec<T>);
pub struct MkColResponse {
pub namespaces: Namespaces,
pub propstat: List<PropStat>,
pub mkcalendar: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct PropStat {
pub prop: Prop,
pub status: Status,
pub error: Option<Condition>,
pub response_description: Option<ResponseDescription>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Prop(pub List<DavPropertyValue>);
pub struct PropResponse {
pub namespaces: Namespaces,
pub properties: List<DavPropertyValue>,
}
#[derive(Default)]
pub struct ScheduleResponse {
pub items: List<ScheduleResponseItem>,
}
#[derive(Default)]
pub struct ScheduleResponseItem {
pub recipient: Href,
pub request_status: Cow<'static, str>,
pub calendar_data: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct SupportedPrivilege {
pub privilege: Privilege,
pub abstract_: bool,
pub description: String,
pub supported_privilege: List<SupportedPrivilege>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct Ace {
pub principal: Principal,
pub invert: bool,
pub grant_deny: GrantDeny,
pub protected: bool,
pub inherited: Option<Href>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum GrantDeny {
Grant(List<Privilege>),
Deny(List<Privilege>),
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum Principal {
Href(Href),
Response(Response),
All,
#[default]
Authenticated,
Unauthenticated,
Property(List<DavPropertyValue>),
Self_,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct AclRestrictions {
pub grant_only: bool,
pub no_invert: bool,
pub deny_before_grant: bool,
pub required_principal: Option<RequiredPrincipal>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum RequiredPrincipal {
All,
Authenticated,
Unauthenticated,
Self_,
Href(List<Href>),
Property(Vec<DavPropertyValue>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct PrincipalSearchPropertySet {
pub namespaces: Namespaces,
pub properties: List<PrincipalSearchProperty>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct PrincipalSearchProperty {
pub name: DavProperty,
pub description: String,
}
pub struct ErrorResponse {
pub namespaces: Namespaces,
pub error: Condition,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum Condition {
Base(BaseCondition),
Cal(CalCondition),
Card(CardCondition),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum BaseCondition {
NoConflictingLock(List<Href>),
LockTokenSubmitted(List<Href>),
LockTokenMatchesRequestUri,
CannotModifyProtectedProperty,
NoExternalEntities,
PreservedLiveProperties,
PropFindFiniteDepth,
ResourceMustBeNull,
NeedPrivileges(List<Resource>),
NoAceConflict,
NoProtectedAceConflict,
NoInheritedAceConflict,
LimitedNumberOfAces,
DenyBeforeGrant,
GrantOnly,
NoInvert,
NoAbstract,
NotSupportedPrivilege,
MissingRequiredPrincipal,
RecognizedPrincipal,
AllowedPrincipal,
NumberOfMatchesWithinLimit,
QuotaNotExceeded,
ValidResourceType,
ValidSyncToken,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub struct Resource {
pub href: Href,
pub privilege: Privilege,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum CalCondition {
CalendarCollectionLocationOk,
ValidCalendarData,
ValidFilter,
ValidCalendarObjectResource,
ValidTimezone,
NoUidConflict(Href),
InitializeCalendarCollection,
SupportedCalendarData,
SupportedFilter(
Vec<Filter<Vec<ICalendarComponentType>, ICalendarProperty, ICalendarParameterName>>,
),
SupportedCollation(String),
SupportedCalendarComponent,
MinDateTime,
MaxDateTime,
MaxResourceSize(u32),
MaxInstances,
MaxAttendeesPerInstance,
UniqueSchedulingObjectResource(Href),
SameOrganizerInAllComponents,
AllowedOrganizerObjectChange,
AllowedAttendeeObjectChange,
DefaultCalendarNeeded,
ValidScheduleDefaultCalendarUrl,
ValidSchedulingMessage,
ValidOrganizer,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
pub enum CardCondition {
SupportedAddressData,
SupportedAddressDataConversion,
SupportedFilter(Vec<Filter<(), VCardProperty, VCardParameterName>>),
SupportedCollation(String),
ValidAddressData,
NoUidConflict(Href),
MaxResourceSize(u32),
AddressBookCollectionLocationOk,
}
impl BaseCondition {
pub fn status(&self) -> StatusCode {
match self {
BaseCondition::NoConflictingLock(_) => StatusCode::LOCKED,
BaseCondition::CannotModifyProtectedProperty => StatusCode::FORBIDDEN,
BaseCondition::LockTokenSubmitted(_) => StatusCode::LOCKED,
BaseCondition::LockTokenMatchesRequestUri => StatusCode::CONFLICT,
BaseCondition::NoExternalEntities => StatusCode::FORBIDDEN,
BaseCondition::PreservedLiveProperties => StatusCode::CONFLICT,
BaseCondition::PropFindFiniteDepth => StatusCode::FORBIDDEN,
BaseCondition::ResourceMustBeNull => StatusCode::CONFLICT,
BaseCondition::NeedPrivileges(_) => StatusCode::FORBIDDEN,
BaseCondition::NumberOfMatchesWithinLimit => StatusCode::FORBIDDEN,
_ => StatusCode::FORBIDDEN,
}
}
}
impl From<String> for Href {
fn from(value: String) -> Self {
Self(value)
}
}
impl From<&str> for Href {
fn from(value: &str) -> Self {
Self(value.to_string())
}
}
impl MultiStatus {
pub fn is_empty(&self) -> bool {
self.response.0.is_empty()
}
}
impl BaseCondition {
pub fn display_name(&self) -> &'static str {
match self {
BaseCondition::NoConflictingLock(_) => "NoConflictingLock",
BaseCondition::CannotModifyProtectedProperty => "CannotModifyProtectedProperty",
BaseCondition::LockTokenSubmitted(_) => "LockTokenSubmitted",
BaseCondition::LockTokenMatchesRequestUri => "LockTokenMatchesRequestUri",
BaseCondition::NoExternalEntities => "NoExternalEntities",
BaseCondition::PreservedLiveProperties => "PreservedLiveProperties",
BaseCondition::PropFindFiniteDepth => "PropFindFiniteDepth",
BaseCondition::ResourceMustBeNull => "ResourceMustBeNull",
BaseCondition::NeedPrivileges(_) => "NeedPrivileges",
BaseCondition::NoAceConflict => "NoAceConflict",
BaseCondition::NoProtectedAceConflict => "NoProtectedAceConflict",
BaseCondition::NoInheritedAceConflict => "NoInheritedAceConflict",
BaseCondition::LimitedNumberOfAces => "LimitedNumberOfAces",
BaseCondition::DenyBeforeGrant => "DenyBeforeGrant",
BaseCondition::GrantOnly => "GrantOnly",
BaseCondition::NoInvert => "NoInvert",
BaseCondition::NoAbstract => "NoAbstract",
BaseCondition::NotSupportedPrivilege => "NotSupportedPrivilege",
BaseCondition::MissingRequiredPrincipal => "MissingRequiredPrincipal",
BaseCondition::RecognizedPrincipal => "RecognizedPrincipal",
BaseCondition::AllowedPrincipal => "AllowedPrincipal",
BaseCondition::NumberOfMatchesWithinLimit => "NumberOfMatchesWithinLimit",
BaseCondition::QuotaNotExceeded => "QuotaNotExceeded",
BaseCondition::ValidResourceType => "ValidResourceType",
BaseCondition::ValidSyncToken => "ValidSyncToken",
}
}
}
impl CalCondition {
pub fn display_name(&self) -> &'static str {
match self {
CalCondition::CalendarCollectionLocationOk => "CalendarCollectionLocationOk",
CalCondition::ValidCalendarData => "ValidCalendarData",
CalCondition::ValidFilter => "ValidFilter",
CalCondition::ValidCalendarObjectResource => "ValidCalendarObjectResource",
CalCondition::ValidTimezone => "ValidTimezone",
CalCondition::NoUidConflict(_) => "NoUidConflict",
CalCondition::InitializeCalendarCollection => "InitializeCalendarCollection",
CalCondition::SupportedCalendarData => "SupportedCalendarData",
CalCondition::SupportedFilter(_) => "SupportedFilter",
CalCondition::SupportedCollation(_) => "SupportedCollation",
CalCondition::MinDateTime => "MinDateTime",
CalCondition::MaxDateTime => "MaxDateTime",
CalCondition::MaxResourceSize(_) => "MaxResourceSize",
CalCondition::MaxInstances => "MaxInstances",
CalCondition::MaxAttendeesPerInstance => "MaxAttendeesPerInstance",
CalCondition::UniqueSchedulingObjectResource(_) => "UniqueSchedulingObjectResource",
CalCondition::SameOrganizerInAllComponents => "SameOrganizerInAllComponents",
CalCondition::AllowedOrganizerObjectChange => "AllowedOrganizerObjectChange",
CalCondition::AllowedAttendeeObjectChange => "AllowedAttendeeObjectChange",
CalCondition::DefaultCalendarNeeded => "DefaultCalendarNeeded",
CalCondition::ValidScheduleDefaultCalendarUrl => "ValidScheduleDefaultCalendarUrl",
CalCondition::ValidSchedulingMessage => "ValidSchedulingMessage",
CalCondition::ValidOrganizer => "ValidOrganizer",
CalCondition::SupportedCalendarComponent => "SupportedCalendarComponent",
}
}
}
impl CardCondition {
pub fn display_name(&self) -> &'static str {
match self {
CardCondition::SupportedAddressData => "SupportedAddressData",
CardCondition::SupportedAddressDataConversion => "SupportedAddressDataConversion",
CardCondition::SupportedFilter(_) => "SupportedFilter",
CardCondition::SupportedCollation(_) => "SupportedCollation",
CardCondition::ValidAddressData => "ValidAddressData",
CardCondition::NoUidConflict(_) => "NoUidConflict",
CardCondition::MaxResourceSize(_) => "MaxResourceSize",
CardCondition::AddressBookCollectionLocationOk => "AddressBookCollectionLocationOk",
}
}
}
impl Condition {
pub fn display_name(&self) -> &'static str {
match self {
Condition::Base(base) => base.display_name(),
Condition::Cal(cal) => cal.display_name(),
Condition::Card(card) => card.display_name(),
}
}
}
#[cfg(test)]
mod serde_impl {
use super::Status;
use hyper::StatusCode;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
impl Serialize for Status {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// Serialize the status code as a u16
serializer.serialize_u16(self.0.as_u16())
}
}
impl<'de> Deserialize<'de> for Status {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Deserialize as u16
let status_value = u16::deserialize(deserializer)?;
// Convert u16 to StatusCode
let status_code = StatusCode::try_from(status_value).map_err(|_| {
serde::de::Error::custom(format!("Invalid status code: {}", status_value))
})?;
Ok(Status(status_code))
}
}
}