Legacy vCard 2.1 and 3.0 serialization support

This commit is contained in:
mdecimus
2025-05-27 12:42:03 +02:00
parent 30907f6a00
commit 48cc823432
13 changed files with 104 additions and 53 deletions

View File

@@ -14,7 +14,7 @@ directory = { path = "../directory" }
http_proto = { path = "../http-proto" }
jmap_proto = { path = "../jmap-proto" }
trc = { path = "../trc" }
calcard = { version = "0.1", features = ["rkyv"] }
calcard = { version = "0.1.1", features = ["rkyv"] }
hashify = { version = "0.2" }
hyper = { version = "1.0.1", features = ["server", "http1", "http2"] }
percent-encoding = "2.3.1"

View File

@@ -105,7 +105,14 @@ impl CardGetRequestHandler for Server {
.with_etag(etag)
.with_last_modified(Rfc1123DateTime::new(i64::from(card.modified)).to_string());
let vcard = card.card.to_string();
let mut vcard = String::with_capacity(128);
let _ = card.card.write_to(
&mut vcard,
headers
.max_vcard_version
.or_else(|| card.card.version())
.unwrap_or_default(),
);
if !is_head {
Ok(response.with_binary_body(vcard))

View File

@@ -13,7 +13,8 @@ use crate::{
},
};
use calcard::vcard::{
ArchivedVCard, ArchivedVCardEntry, ArchivedVCardParameter, VCardParameterName,
ArchivedVCard, ArchivedVCardEntry, ArchivedVCardParameter, VCardParameterName, VCardProperty,
VCardVersion,
};
use common::{Server, auth::AccessToken};
use dav_proto::{
@@ -200,22 +201,30 @@ fn find_parameter<'x>(
pub(crate) fn serialize_vcard_with_props(
card: &ArchivedVCard,
props: &[CardDavPropertyName],
version: Option<VCardVersion>,
) -> String {
let mut vcard = String::with_capacity(128);
let version = version.or_else(|| card.version()).unwrap_or_default();
if !props.is_empty() {
let mut vcard = String::with_capacity(128);
let _ = write!(&mut vcard, "BEGIN:VCARD\r\n");
let is_v4 = matches!(version, VCardVersion::V4_0);
for entry in card.entries.iter() {
for item in props {
if entry.name == item.name && entry.group == item.group {
let _ = entry.write_to(&mut vcard, !item.no_value);
if item.name != VCardProperty::Version {
let _ = entry.write_to(&mut vcard, !item.no_value, is_v4);
} else {
let _ = write!(&mut vcard, "VERSION:{version}\r\n");
}
break;
}
}
}
let _ = write!(&mut vcard, "END:VCARD\r\n");
vcard
} else {
card.to_string()
let _ = card.write_to(&mut vcard, version);
}
vcard
}

View File

@@ -6,7 +6,7 @@
use calcard::{
icalendar::{ICalendarComponentType, ICalendarParameterName, ICalendarProperty},
vcard::VCardParameterName,
vcard::{VCardParameterName, VCardVersion},
};
use dav_proto::{
Depth, RequestHeaders, Return,
@@ -35,7 +35,7 @@ pub mod lock;
pub mod propfind;
pub mod uri;
#[derive(Default, Debug)]
#[derive(Debug)]
pub(crate) struct DavQuery<'x> {
pub uri: &'x str,
pub resource: DavQueryResource<'x>,
@@ -43,6 +43,7 @@ pub(crate) struct DavQuery<'x> {
pub sync_type: SyncType,
pub depth: usize,
pub limit: Option<u32>,
pub max_vcard_version: Option<VCardVersion>,
pub ret: Return,
pub depth_no_root: bool,
pub expand: bool,
@@ -158,7 +159,10 @@ impl<'x> DavQuery<'x> {
ret: headers.ret,
depth_no_root: headers.depth_no_root,
uri: headers.uri,
..Default::default()
max_vcard_version: headers.max_vcard_version,
sync_type: Default::default(),
limit: Default::default(),
expand: Default::default(),
}
}
@@ -176,7 +180,11 @@ impl<'x> DavQuery<'x> {
ret: headers.ret,
depth_no_root: headers.depth_no_root,
uri: headers.uri,
..Default::default()
max_vcard_version: headers.max_vcard_version,
sync_type: Default::default(),
depth: Default::default(),
limit: Default::default(),
expand: Default::default(),
}
}
@@ -196,7 +204,10 @@ impl<'x> DavQuery<'x> {
ret: headers.ret,
depth_no_root: headers.depth_no_root,
uri: headers.uri,
..Default::default()
max_vcard_version: headers.max_vcard_version,
sync_type: Default::default(),
depth: Default::default(),
expand: Default::default(),
}
}
@@ -220,7 +231,11 @@ impl<'x> DavQuery<'x> {
ret: headers.ret,
depth_no_root: headers.depth_no_root,
uri: headers.uri,
..Default::default()
sync_type: Default::default(),
depth: Default::default(),
limit: Default::default(),
max_vcard_version: Default::default(),
expand: Default::default(),
}
}
@@ -249,6 +264,7 @@ impl<'x> DavQuery<'x> {
depth_no_root: headers.depth_no_root,
expand: false,
uri: headers.uri,
max_vcard_version: headers.max_vcard_version,
}
}
@@ -277,7 +293,9 @@ impl<'x> DavQuery<'x> {
depth_no_root: headers.depth_no_root,
expand: true,
uri: headers.uri,
..Default::default()
sync_type: Default::default(),
limit: Default::default(),
max_vcard_version: headers.max_vcard_version,
}
}

View File

@@ -1191,6 +1191,9 @@ impl PropFindRequestHandler for Server {
DavValue::CData(serialize_vcard_with_props(
&card.inner.card,
items,
query
.max_vcard_version
.or_else(|| card.inner.card.version()),
)),
));
}

View File

@@ -69,7 +69,10 @@ impl PrincipalMatching for Server {
ret: headers.ret,
depth_no_root: headers.depth_no_root,
uri: headers.uri,
..Default::default()
sync_type: Default::default(),
limit: Default::default(),
max_vcard_version: Default::default(),
expand: Default::default(),
},
)
.await;