Skip to content

Commit

Permalink
Merge pull request #10359 from nextcloud/backport/10328/stable3.7
Browse files Browse the repository at this point in the history
[stable3.7] fix: Junk/NotJunk flags
  • Loading branch information
kesselb authored Nov 17, 2024
2 parents 8c777f3 + d07a1c9 commit fb04c03
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 16 deletions.
33 changes: 22 additions & 11 deletions lib/Service/MailManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 [];
}

Expand Down
39 changes: 34 additions & 5 deletions tests/Unit/Service/MailManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -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);

Expand Down

0 comments on commit fb04c03

Please sign in to comment.