Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .patches/sabre-vobject-iTipBroker-replies.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
From 49d53f187089ec9a67917e564a87c6dea89ea839 Mon Sep 17 00:00:00 2001
From: SebastianKrupinski <krupinskis05@gmail.com>
Date: Tue, 30 Dec 2025 13:48:29 -0500
Subject: [PATCH] fix: send participation reply on fresh event

Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
---
lib/ITip/Broker.php | 25 ++++++---
.../VObject/ITip/BrokerAttendeeReplyTest.php | 52 +++++++++++++++++++
2 files changed, 71 insertions(+), 6 deletions(-)

diff --git a/lib/ITip/Broker.php b/lib/ITip/Broker.php
index 76ee0c71..e621c6e2 100644
--- a/lib/ITip/Broker.php
+++ b/lib/ITip/Broker.php
@@ -246,16 +246,29 @@ public function parseEvent($calendar, $userHref, $oldCalendar = null): array
$baseCalendar = $oldCalendar;
}

+ // Check if the user is the organizer
if (in_array($eventInfo['organizer'], $userHref)) {
return $this->parseEventForOrganizer($baseCalendar, $eventInfo, $oldEventInfo);
- } elseif ($oldCalendar) {
- // We need to figure out if the user is an attendee, but we're only
- // doing so if there's an oldCalendar, because we only want to
- // process updates, not creation of new events.
- foreach ($eventInfo['attendees'] as $attendee) {
- if (in_array($attendee['href'], $userHref)) {
+ }
+
+ // Check if the user is an attendee
+ foreach ($eventInfo['attendees'] as $attendee) {
+ if (in_array($attendee['href'], $userHref)) {
+ // If this is a event update, we always generate a reply
+ if ($oldCalendar) {
return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
}
+
+ // If this is a new event, we only generate a reply if the participation status is set
+ foreach ($attendee['instances'] as $instance) {
+ if (isset($instance['partstat']) && 'NEEDS-ACTION' !== $instance['partstat']) {
+ // Attendee has responded (ACCEPTED/DECLINED/TENTATIVE) - generate REPLY
+ return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
+ }
+ }
+
+ // User is attendee but no response to process
+ break;
}
}

3 changes: 2 additions & 1 deletion composer.patches.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"Check for instanceof INode instead of Node": ".patches/check-for-instanceof-INode-instead-of-Node-1595.patch"
},
"sabre/vobject": {
"fix use RDATE in time range check and use all instances": ".patches/sabre-vobject-rdate.patch"
"fix use RDATE in time range check and use all instances": ".patches/sabre-vobject-rdate.patch",
"fix send participation reply on fresh event": ".patches/sabre-vobject-iTipBroker-replies.patch"
}
}
}
4 changes: 4 additions & 0 deletions sabre/vobject/PATCHES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ fix use RDATE in time range check and use all instances
Source: .patches/sabre-vobject-rdate.patch


fix send participation reply on fresh event
Source: .patches/sabre-vobject-iTipBroker-replies.patch


25 changes: 19 additions & 6 deletions sabre/vobject/lib/ITip/Broker.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,16 +240,29 @@ public function parseEvent($calendar, $userHref, $oldCalendar = null)
$baseCalendar = $oldCalendar;
}

// Check if the user is the organizer
if (in_array($eventInfo['organizer'], $userHref)) {
return $this->parseEventForOrganizer($baseCalendar, $eventInfo, $oldEventInfo);
} elseif ($oldCalendar) {
// We need to figure out if the user is an attendee, but we're only
// doing so if there's an oldCalendar, because we only want to
// process updates, not creation of new events.
foreach ($eventInfo['attendees'] as $attendee) {
if (in_array($attendee['href'], $userHref)) {
}

// Check if the user is an attendee
foreach ($eventInfo['attendees'] as $attendee) {
if (in_array($attendee['href'], $userHref)) {
// If this is a event update, we always generate a reply
if ($oldCalendar) {
return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
}

// If this is a new event, we only generate a reply if the participation status is set
foreach ($attendee['instances'] as $instance) {
if (isset($instance['partstat']) && 'NEEDS-ACTION' !== $instance['partstat']) {
// Attendee has responded (ACCEPTED/DECLINED/TENTATIVE) - generate REPLY
return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
}
}

// User is attendee but no response to process
break;
}
}

Expand Down