From 1e90ff3d6c3d1e208a59a27bdda8af31b165b67b Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 23 Aug 2025 19:42:58 +0200 Subject: [PATCH] carddav: Remove enforcement of UID matching filename (Apple Contacts doesn't play well) --- crates/carddav/src/address_object/methods.rs | 3 +-- crates/ical/src/address_object.rs | 26 ++++++++++---------- crates/store_sqlite/src/addressbook_store.rs | 12 +-------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/crates/carddav/src/address_object/methods.rs b/crates/carddav/src/address_object/methods.rs index 896f1ab..a28aeb6 100644 --- a/crates/carddav/src/address_object/methods.rs +++ b/crates/carddav/src/address_object/methods.rs @@ -86,8 +86,7 @@ pub async fn put_object( true }; - let object = AddressObject::from_vcf(body)?; - assert_eq!(object.get_id(), object_id); + let object = AddressObject::from_vcf(object_id, body)?; addr_store .put_object(principal, addressbook_id, object, overwrite) .await?; diff --git a/crates/ical/src/address_object.rs b/crates/ical/src/address_object.rs index c4c389c..5e3e987 100644 --- a/crates/ical/src/address_object.rs +++ b/crates/ical/src/address_object.rs @@ -11,6 +11,7 @@ use std::{collections::HashMap, io::BufReader}; #[derive(Debug, Clone)] pub struct AddressObject { + id: String, vcf: String, vcard: VcardContact, } @@ -19,16 +20,21 @@ impl TryFrom for AddressObject { type Error = Error; fn try_from(vcard: VcardContact) -> Result { - if vcard.get_uid().is_none() { - return Err(Error::InvalidData("missing UID".to_owned())); - } + let uid = vcard + .get_uid() + .ok_or(Error::InvalidData("missing UID".to_owned()))? + .to_owned(); let vcf = vcard.generate(); - Ok(Self { vcf, vcard }) + Ok(Self { + vcf, + vcard, + id: uid, + }) } } impl AddressObject { - pub fn from_vcf(vcf: String) -> Result { + pub fn from_vcf(id: String, vcf: String) -> Result { let mut parser = vcard::VcardParser::new(BufReader::new(vcf.as_bytes())); let vcard = parser.next().ok_or(Error::MissingContact)??; if parser.next().is_some() { @@ -36,17 +42,11 @@ impl AddressObject { "multiple vcards, only one allowed".to_owned(), )); } - - if vcard.get_uid().is_none() { - return Err(Error::InvalidData("missing UID".to_owned())); - } - Ok(Self { vcf, vcard }) + Ok(Self { id, vcf, vcard }) } pub fn get_id(&self) -> &str { - self.vcard - .get_uid() - .expect("We've validated before that UID exists") + &self.id } pub fn get_etag(&self) -> String { diff --git a/crates/store_sqlite/src/addressbook_store.rs b/crates/store_sqlite/src/addressbook_store.rs index a74140f..ddcc4f6 100644 --- a/crates/store_sqlite/src/addressbook_store.rs +++ b/crates/store_sqlite/src/addressbook_store.rs @@ -20,17 +20,7 @@ impl TryFrom for AddressObject { type Error = rustical_store::Error; fn try_from(value: AddressObjectRow) -> Result { - let object = Self::from_vcf(value.vcf)?; - if object.get_id() != value.id { - return Err(rustical_store::Error::IcalError( - rustical_ical::Error::InvalidData(format!( - "object_id={} and UID={} don't match", - object.get_id(), - value.id - )), - )); - } - Ok(object) + Ok(Self::from_vcf(value.id, value.vcf)?) } }