From 4647f615ac01ee82298f6f79e4efda30fb2fc326 Mon Sep 17 00:00:00 2001 From: SebastianKrupinski Date: Tue, 30 Dec 2025 13:48:29 -0500 Subject: [PATCH 1/3] fix: send participation reply on fresh event Signed-off-by: SebastianKrupinski --- 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 6f0b1ed2f..fc3db753c 100644 --- a/lib/ITip/Broker.php +++ b/lib/ITip/Broker.php @@ -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; } } diff --git a/tests/VObject/ITip/BrokerAttendeeReplyTest.php b/tests/VObject/ITip/BrokerAttendeeReplyTest.php index 284075adf..38b0f5100 100644 --- a/tests/VObject/ITip/BrokerAttendeeReplyTest.php +++ b/tests/VObject/ITip/BrokerAttendeeReplyTest.php @@ -1210,4 +1210,56 @@ public function testPartyCrasher() $this->parse($oldMessage, $newMessage, $expected); } + + public function testNewEventWithReply(): void + { + $oldMessage = null; + + $newMessage = << 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<parse($oldMessage, $newMessage, $expected); + } } From 5bdd38e8fcad60bbe41e987849500c3e313ff613 Mon Sep 17 00:00:00 2001 From: Phillip Davis Date: Mon, 12 Jan 2026 15:23:17 +0545 Subject: [PATCH 2/3] tests: remove whitespace from VCALENDAR end --- tests/VObject/ITip/BrokerAttendeeReplyTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/VObject/ITip/BrokerAttendeeReplyTest.php b/tests/VObject/ITip/BrokerAttendeeReplyTest.php index 38b0f5100..b8e7eb056 100644 --- a/tests/VObject/ITip/BrokerAttendeeReplyTest.php +++ b/tests/VObject/ITip/BrokerAttendeeReplyTest.php @@ -1203,7 +1203,6 @@ public function testPartyCrasher() ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org END:VEVENT END:VCALENDAR - ICS ], ]; From c990e14a3f8d09955deda56dad14ce76ec091602 Mon Sep 17 00:00:00 2001 From: Phillip Davis Date: Mon, 12 Jan 2026 15:30:32 +0545 Subject: [PATCH 3/3] tests: remove comma for PHP 7.1 7.2 compatibility --- tests/VObject/ITip/BrokerAttendeeReplyTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/VObject/ITip/BrokerAttendeeReplyTest.php b/tests/VObject/ITip/BrokerAttendeeReplyTest.php index b8e7eb056..8497fab1e 100644 --- a/tests/VObject/ITip/BrokerAttendeeReplyTest.php +++ b/tests/VObject/ITip/BrokerAttendeeReplyTest.php @@ -1255,7 +1255,7 @@ public function testNewEventWithReply(): void ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org END:VEVENT END:VCALENDAR -ICS, +ICS ], ];