Skip to content

Commit 9dac7ac

Browse files
lubo92kesselb
authored andcommitted
fixup! fix(imap): detect iMIP when method= is missing or mime is application/ics
Address review feedback from kesselb: - drop application/ics handling in both detection sites (Thunderbird's stance — re-evaluate if a real-world provider that only ships application/ics shows up) - tighten METHOD regex to /^METHOD:([A-Z]+)/mi with === 1 check (matches the iCalendar grammar: METHOD value is bare token, no whitespace allowed between colon and value per RFC 5545) - remove the now-obsolete application/ics fixture + test row NOTE for squash: original commit body still mentions application/ics support. When squashing, please drop that section so the message only covers the Proton Bridge / METHOD-from-body fix. AI-assisted: Claude Code (Claude Opus 4.7) Signed-off-by: Wolfgang Lubowski <w.lub92@gmail.com>
1 parent 7d9442b commit 9dac7ac

4 files changed

Lines changed: 12 additions & 93 deletions

File tree

lib/IMAP/ImapMessageFetcher.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,11 @@ public function fetchMessage(?Horde_Imap_Client_Data_Fetch $fetch = null): IMAPM
287287
*/
288288
private function getPart(Horde_Mime_Part $p, string $partNo, bool $isFetched): void {
289289
// iMIP messages
290-
// Handle text/calendar and application/ics parts first because they
291-
// might be attachments at the same time. Otherwise, some of the
292-
// following if-conditions might break the handling and treat iMIP
290+
// Handle text/calendar parts first because they might be attachments at the same time.
291+
// Otherwise, some of the following if-conditions might break the handling and treat iMIP
293292
// data like regular attachments.
294293
$allContentTypeParameters = $p->getAllContentTypeParameters();
295-
if ($p->getType() === 'text/calendar'
296-
|| $p->getType() === 'application/ics') {
294+
if ($p->getType() === 'text/calendar') {
297295
// Handle event data like a regular attachment
298296
// Outlook doesn't set a content disposition
299297
// We work around this by checking for the name only
@@ -318,7 +316,7 @@ private function getPart(Horde_Mime_Part $p, string $partNo, bool $isFetched): v
318316
$contents = null;
319317
if ($method === null) {
320318
$contents = $this->loadBodyData($p, $partNo, $isFetched);
321-
if (preg_match('/^METHOD:\s*(\S+)/mi', $contents, $m)) {
319+
if (preg_match('/^METHOD:([A-Z]+)/mi', $contents, $m) === 1) {
322320
$method = $m[1];
323321
}
324322
}

lib/IMAP/MessageMapper.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -899,16 +899,15 @@ public function getBodyStructureData(Horde_Imap_Client_Socket $client,
899899
$hasAttachments = true;
900900
}
901901

902-
// Flag the message as iMIP when we see a text/calendar or
903-
// application/ics part. Proton Mail Bridge is known to strip the
904-
// `method=` parameter from the Content-Type header while
905-
// re-assembling a message after E2E-decryption, so requiring the
906-
// parameter here would drop every Bridge-delivered invitation.
907-
// The actual method (REQUEST/REPLY/CANCEL) is parsed out of the
908-
// ICS body downstream in ImapMessageFetcher::getPart() — see the
902+
// Flag the message as iMIP when we see a text/calendar part.
903+
// Proton Mail Bridge is known to strip the `method=` parameter
904+
// from the Content-Type header while re-assembling a message
905+
// after E2E-decryption, so requiring the parameter here would
906+
// drop every Bridge-delivered invitation. The actual method
907+
// (REQUEST/REPLY/CANCEL) is parsed out of the ICS body
908+
// downstream in ImapMessageFetcher::getPart() — see the
909909
// matching fallback there.
910-
if ($part->getType() === 'text/calendar'
911-
|| $part->getType() === 'application/ics') {
910+
if ($part->getType() === 'text/calendar') {
912911
$isImipMessage = true;
913912
}
914913
}

tests/Unit/IMAP/MessageMapperTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -755,10 +755,6 @@ public function isImipMessageProvider(): array {
755755
// body. Must still be flagged as iMIP so downstream processing
756756
// picks it up.
757757
'proton bridge request (method= stripped)' => ['request_proton_bridge', true],
758-
// Google occasionally attaches the same invitation twice: once as
759-
// text/calendar and once as application/ics. We used to ignore the
760-
// latter even though it is functionally equivalent.
761-
'application/ics request' => ['request_application_ics', true],
762758
];
763759
}
764760

tests/data/imip/request_application_ics.txt

Lines changed: 0 additions & 74 deletions
This file was deleted.

0 commit comments

Comments
 (0)