Assisted CalDAV/CardDAV shared resource discovery (closes #1691)

This commit is contained in:
mdecimus
2025-06-24 13:28:29 +02:00
parent 020bcaef8b
commit 01f7c8f56d
10 changed files with 772 additions and 528 deletions

View File

@@ -75,6 +75,10 @@ pub(crate) enum DavQueryResource<'x> {
parent_collection: Collection,
items: Vec<PropFindItem>,
},
Discovery {
parent_collection: Collection,
account_ids: Vec<u32>,
},
#[default]
None,
}
@@ -299,6 +303,29 @@ impl<'x> DavQuery<'x> {
}
}
pub fn discovery(
propfind: PropFind,
account_ids: Vec<u32>,
collection: Collection,
headers: &RequestHeaders<'x>,
) -> Self {
Self {
resource: DavQueryResource::Discovery {
parent_collection: collection,
account_ids,
},
propfind,
depth: 0,
ret: headers.ret,
depth_no_root: headers.depth_no_root,
uri: headers.uri,
sync_type: Default::default(),
limit: Default::default(),
max_vcard_version: headers.max_vcard_version,
expand: false,
}
}
pub fn is_minimal(&self) -> bool {
self.ret == Return::Minimal
}

File diff suppressed because it is too large Load Diff

View File

@@ -178,11 +178,11 @@ impl OwnedUri<'_> {
}
}
impl<A, R> UriResource<A, R> {
/*impl<A, R> UriResource<A, R> {
pub fn collection_path(&self) -> &'static str {
DavResourceName::from(self.collection).collection_path()
}
}
}*/
impl Urn {
pub fn try_extract_sync_id(token: &str) -> Option<&str> {

View File

@@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
#![warn(clippy::large_futures)]
pub mod calendar;
pub mod card;

View File

@@ -270,28 +270,54 @@ impl PrincipalPropFind for Server {
))],
));
}
PrincipalProperty::CalendarHomeSet => {
fields.push(DavPropertyValue::new(
property.clone(),
vec![Href(format!(
"{}/{}/",
DavResourceName::Cal.base_path(),
percent_encoding::utf8_percent_encode(&name, RFC_3986),
))],
));
response.set_namespace(Namespace::CalDav);
}
PrincipalProperty::AddressbookHomeSet => {
fields.push(DavPropertyValue::new(
property.clone(),
vec![Href(format!(
"{}/{}/",
DavResourceName::Card.base_path(),
percent_encoding::utf8_percent_encode(&name, RFC_3986),
))],
));
response.set_namespace(Namespace::CardDav);
PrincipalProperty::CalendarHomeSet
| PrincipalProperty::AddressbookHomeSet => {
let mut hrefs = Vec::new();
let (collection, resource_name, namespace) =
if principal_property == &PrincipalProperty::CalendarHomeSet {
(
Collection::Calendar,
DavResourceName::Cal,
Namespace::CalDav,
)
} else {
(
Collection::AddressBook,
DavResourceName::Card,
Namespace::CardDav,
)
};
for account_id in access_token.all_ids_by_collection(collection) {
let href = if account_id == access_token.primary_id() {
format!(
"{}/{}/",
resource_name.base_path(),
percent_encoding::utf8_percent_encode(
&access_token.name,
RFC_3986
),
)
} else {
let name = self
.store()
.get_principal_name(account_id)
.await
.caused_by(trc::location!())?
.unwrap_or_else(|| format!("_{account_id}"));
format!(
"{}/{}/",
resource_name.base_path(),
percent_encoding::utf8_percent_encode(&name, RFC_3986),
)
};
hrefs.push(Href(href));
}
fields.push(DavPropertyValue::new(property.clone(), hrefs));
response.set_namespace(namespace);
}
PrincipalProperty::PrincipalAddress => {
fields_not_found.push(DavPropertyValue::empty(property.clone()));
response.set_namespace(Namespace::CardDav);