Include DTSTART/DTEND properties in iMIP CANCEL messages (fixes #1775)

This commit is contained in:
mdecimus
2025-07-14 16:44:34 +02:00
parent fccc25fb71
commit 20bab962d4
6 changed files with 81 additions and 59 deletions

View File

@@ -5,7 +5,7 @@
*/
use crate::scheduling::{
InstanceId, ItipError, ItipMessage, ItipSnapshots, ItipSummary,
InstanceId, ItipError, ItipMessage, ItipSummary,
attendee::attendee_decline,
itip::{itip_add_tz, itip_build_envelope},
snapshot::itip_snapshot,
@@ -18,7 +18,6 @@ use calcard::{
ICalendarParticipationStatus, ICalendarProperty, ICalendarStatus, ICalendarValue,
},
};
use std::fmt::Display;
pub fn itip_cancel(
ical: &ICalendar,
@@ -58,19 +57,20 @@ pub fn itip_cancel(
}
if !recipients.is_empty() && component_type != &ICalendarComponentType::VFreebusy {
let instance = itip.main_instance_or_default();
message.components.push(build_cancel_component(
component_type.clone(),
&itip,
instance.comp,
sequence,
dt_stamp,
cancel_guests.iter(),
&[],
));
// Add timezones
itip_add_tz(&mut message, ical);
Ok(ItipMessage {
to: recipients.into_iter().collect(),
summary: ItipSummary::Cancel(
itip.main_instance_or_default().build_summary(None, &[]),
),
summary: ItipSummary::Cancel(instance.build_summary(None, &[])),
from: itip.organizer.email.email,
from_organizer: true,
message,
@@ -121,19 +121,14 @@ pub fn itip_cancel(
}
}
pub(crate) fn build_cancel_component<T, I>(
component_type: ICalendarComponentType,
itip: &ItipSnapshots<'_>,
pub(crate) fn build_cancel_component(
component: &ICalendarComponent,
sequence: i64,
dt_stamp: PartialDateTime,
cancel_guests: T,
) -> ICalendarComponent
where
T: Iterator<Item = I>,
I: Display,
{
attendees: &[&str],
) -> ICalendarComponent {
let mut cancel_comp = ICalendarComponent {
component_type,
component_type: component.component_type.clone(),
entries: Vec::with_capacity(7),
component_ids: vec![],
};
@@ -143,17 +138,39 @@ where
);
cancel_comp.add_dtstamp(dt_stamp);
cancel_comp.add_sequence(sequence);
cancel_comp.add_uid(itip.uid);
cancel_comp.add_property(
ICalendarProperty::Organizer,
ICalendarValue::Text(itip.organizer.email.to_string()),
cancel_comp.entries.extend(
component
.entries
.iter()
.filter(|e| match e.name {
ICalendarProperty::Organizer
| ICalendarProperty::Uid
| ICalendarProperty::Summary
| ICalendarProperty::Dtstart
| ICalendarProperty::Dtend
| ICalendarProperty::Due
| ICalendarProperty::RecurrenceId
| ICalendarProperty::Created
| ICalendarProperty::LastModified
| ICalendarProperty::Description
| ICalendarProperty::Location => true,
ICalendarProperty::Attendee => {
attendees.is_empty()
|| e.values
.first()
.and_then(|v| v.as_text())
.is_some_and(|email| {
attendees.iter().any(|attendee| {
email
.strip_suffix(attendee)
.is_some_and(|v| v.ends_with(':') || v.is_empty())
})
})
}
_ => false,
})
.cloned(),
);
for email in cancel_guests {
cancel_comp.add_property(
ICalendarProperty::Attendee,
ICalendarValue::Text(email.to_string()),
);
}
cancel_comp
}

View File

@@ -264,20 +264,7 @@ pub(crate) fn organizer_handle_update(
ItipExportAs::Organizer(&ICalendarParticipationStatus::NeedsAction),
)
} else {
let mut cancel_comp = build_cancel_component(
orig_component.component_type.clone(),
itip,
sequence,
dt_stamp.clone(),
emails.iter().map(|e| format!("mailto:{}", e)),
);
if let InstanceId::Recurrence(recurrence_id) = instance_id {
cancel_comp
.entries
.push(orig_component.entries[recurrence_id.entry_id as usize].clone());
}
cancel_comp
build_cancel_component(orig_component, sequence, dt_stamp.clone(), &emails)
};
// Add component to message