From d07a1c988140da20d1fe04edcfb956e77b296b6e Mon Sep 17 00:00:00 2001 From: SebastianKrupinski Date: Tue, 5 Nov 2024 18:40:16 -0500 Subject: [PATCH] fix: Junk/NotJunk flags Signed-off-by: SebastianKrupinski --- lib/Service/MailManager.php | 33 ++++++++++++++-------- tests/Unit/Service/MailManagerTest.php | 39 ++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/lib/Service/MailManager.php b/lib/Service/MailManager.php index a2246174ca..35bba6848b 100644 --- a/lib/Service/MailManager.php +++ b/lib/Service/MailManager.php @@ -60,17 +60,15 @@ class MailManager implements IMailManager { /** - * https://tools.ietf.org/html/rfc3501#section-2.3.2 + * https://datatracker.ietf.org/doc/html/rfc9051#name-flags-message-attribute */ - private const ALLOWED_FLAGS = [ + private const SYSTEM_FLAGS = [ 'seen' => [Horde_Imap_Client::FLAG_SEEN], 'answered' => [Horde_Imap_Client::FLAG_ANSWERED], 'flagged' => [Horde_Imap_Client::FLAG_FLAGGED], 'deleted' => [Horde_Imap_Client::FLAG_DELETED], 'draft' => [Horde_Imap_Client::FLAG_DRAFT], 'recent' => [Horde_Imap_Client::FLAG_RECENT], - 'junk' => [Horde_Imap_Client::FLAG_JUNK, 'junk'], - 'mdnsent' => [Horde_Imap_Client::FLAG_MDNSENT], ]; /** @var IMAPClientFactory */ @@ -774,16 +772,29 @@ public function getTagByImapLabel(string $imapLabel, string $userId): Tag { * @return array */ public function filterFlags(Horde_Imap_Client_Socket $client, Account $account, string $flag, string $mailbox): array { - // check for RFC server flags - if (array_key_exists($flag, self::ALLOWED_FLAGS) === true) { - return self::ALLOWED_FLAGS[$flag]; + // check if flag is RFC defined system flag + if (array_key_exists($flag, self::SYSTEM_FLAGS) === true) { + return self::SYSTEM_FLAGS[$flag]; } - - // Only allow flag setting if IMAP supports Permaflags - // @TODO check if there are length & char limits on permflags - if ($this->isPermflagsEnabled($client, $account, $mailbox) === true) { + // check if server supports custom keywords / this specific keyword + try { + $capabilities = $client->status($mailbox, Horde_Imap_Client::STATUS_PERMFLAGS); + } catch (Horde_Imap_Client_Exception $e) { + throw new ServiceException( + 'Could not get message flag options from IMAP: ' . $e->getMessage(), + $e->getCode(), + $e + ); + } + // check if server returned supported flags + if (!isset($capabilities['permflags'])) { + return []; + } + // check if server supports custom flags or specific flag + if (in_array("\*", $capabilities['permflags']) || in_array($flag, $capabilities['permflags'])) { return [$flag]; } + return []; } diff --git a/tests/Unit/Service/MailManagerTest.php b/tests/Unit/Service/MailManagerTest.php index 691d85c55e..f60be32eb9 100644 --- a/tests/Unit/Service/MailManagerTest.php +++ b/tests/Unit/Service/MailManagerTest.php @@ -339,7 +339,7 @@ public function testUnsetCustomFlagWithIMAPCapabilities(): void { $this->manager->flagMessage($account, 'INBOX', 123, Tag::LABEL_IMPORTANT, false); } - public function testFilterFlagStandard(): void { + public function testFilterFlagsWithSystemFlags(): void { $account = $this->createMock(Account::class); $client = $this->createMock(Horde_Imap_Client_Socket::class); $flags = [ @@ -349,17 +349,46 @@ public function testFilterFlagStandard(): void { 'deleted' => [\Horde_Imap_Client::FLAG_DELETED], 'draft' => [\Horde_Imap_Client::FLAG_DRAFT], 'recent' => [\Horde_Imap_Client::FLAG_RECENT], - 'junk' => [\Horde_Imap_Client::FLAG_JUNK, 'junk'], - 'mdnsent' => [\Horde_Imap_Client::FLAG_MDNSENT], ]; - //standard flags + // test all system flags foreach ($flags as $k => $flag) { $this->assertEquals($this->manager->filterFlags($client, $account, $k, 'INBOX'), $flags[$k]); } } - public function testSetFilterFlagsNoCapabilities() { + public function testFilterFlagsWithDefinedKeyword() { + $account = $this->createMock(Account::class); + $client = $this->createMock(Horde_Imap_Client_Socket::class); + + $client->expects($this->exactly(2)) + ->method('status') + ->willReturn(['permflags' => ['\seen', '$junk', '$notjunk']]); + + // test keyword supported + $this->assertEquals(['$junk'], $this->manager->filterFlags($client, $account, '$junk', 'INBOX')); + // test keyword unsupported + $this->assertEquals([], $this->manager->filterFlags($client, $account, '$autojunk', 'INBOX')); + } + + public function testFilterFlagsWithCustomKeyword() { + $account = $this->createMock(Account::class); + $client = $this->createMock(Horde_Imap_Client_Socket::class); + + $client->expects($this->exactly(2)) + ->method('status') + ->willReturnOnConsecutiveCalls( + ['permflags' => ['\seen', '$junk', '$notjunk', '\*']], + ['permflags' => ['\seen', '$junk', '$notjunk']], + ); + + // test custom keyword supported + $this->assertEquals([Tag::LABEL_IMPORTANT], $this->manager->filterFlags($client, $account, Tag::LABEL_IMPORTANT, 'INBOX')); + // test custom keyword unsupported + $this->assertEquals([], $this->manager->filterFlags($client, $account, Tag::LABEL_IMPORTANT, 'INBOX')); + } + + public function testFilterFlagsNoCapabilities() { $account = $this->createMock(Account::class); $client = $this->createMock(Horde_Imap_Client_Socket::class);