feat: harmonize mailbox messages

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-10-05 20:34:02 -04:00
parent b02ca63208
commit 65fdb23fa4
12 changed files with 879 additions and 43 deletions
+14
View File
@@ -22,6 +22,8 @@ final class Mailbox
private readonly int $recent = 0,
private readonly array $flags = [],
private readonly bool $readOnly = true,
private readonly ?int $uidNext = null,
private readonly ?int $highestModSeq = null,
) {}
public function fromStatus(MailboxStatusResult $status): self
@@ -38,6 +40,8 @@ final class Mailbox
$this->recent,
$this->flags,
$this->readOnly,
$items['UIDNEXT'] ?? $this->uidNext,
$items['HIGHESTMODSEQ'] ?? $this->highestModSeq,
);
}
@@ -64,6 +68,16 @@ final class Mailbox
return $this->uidValidity;
}
public function uidNext(): ?int
{
return $this->uidNext;
}
public function highestModSeq(): ?int
{
return $this->highestModSeq;
}
public function messages(): int
{
return $this->messages;
+2 -11
View File
@@ -13,6 +13,7 @@ use KTXM\ProviderImap\Client\ImapException;
use KTXM\ProviderImap\Client\Protocol\Command\Argument\ListReturnOptions;
use KTXM\ProviderImap\Client\Protocol\Command\Argument\ListSelectionOptions;
use KTXM\ProviderImap\Client\Mailbox;
use KTXM\ProviderImap\Client\Result\MailboxStatusResult;
use KTXM\ProviderImap\Client\Protocol\RequestFrame;
use KTXM\ProviderImap\Client\Protocol\Response\TaggedResponse;
use KTXM\ProviderImap\Client\Protocol\Response\UntaggedResponse;
@@ -144,16 +145,6 @@ final class ListCommand implements CommandInterface
*/
private function applyStatus(Mailbox $mailbox, array $status): Mailbox
{
return new Mailbox(
$mailbox->name(),
$mailbox->delimiter(),
$mailbox->attributes(),
$status['MESSAGES'] ?? $mailbox->messages(),
$status['UNSEEN'] ?? $mailbox->unread(),
$mailbox->uidValidity(),
$mailbox->recent(),
$mailbox->flags(),
$mailbox->readOnly(),
);
return $mailbox->fromStatus(new MailboxStatusResult($mailbox->name(), $status));
}
}
+20 -1
View File
@@ -53,6 +53,9 @@ final class SelectCommand implements CommandInterface
{
$exists = 0;
$recent = 0;
$uidValidity = null;
$uidNext = null;
$highestModSeq = null;
$flags = [];
$readOnly = $this->readOnly;
@@ -70,6 +73,16 @@ final class SelectCommand implements CommandInterface
continue;
}
// response codes, e.g. "* OK [UIDVALIDITY 3857529045] UIDs valid"
if (preg_match('/^\*\s+OK\s+\[(UIDVALIDITY|UIDNEXT|HIGHESTMODSEQ)\s+(\d+)\]/i', $raw, $matches)) {
match (strtoupper($matches[1])) {
'UIDVALIDITY' => $uidValidity = (int) $matches[2],
'UIDNEXT' => $uidNext = (int) $matches[2],
'HIGHESTMODSEQ' => $highestModSeq = (int) $matches[2],
};
continue;
}
if ($response->label() === 'FLAGS' && preg_match('/\(([^)]*)\)/', $response->payload(), $matches)) {
$flags = $this->parseFlags($matches[1]);
continue;
@@ -77,6 +90,10 @@ final class SelectCommand implements CommandInterface
}
if ($response instanceof TaggedResponse) {
// a failed SELECT leaves no mailbox selected (RFC 3501 6.3.1)
if ($response->status() !== 'OK') {
$context->setSelectedMailbox(null);
}
CompletionChecker::assertSuccess($this->name(), $response);
if (str_contains(strtoupper($response->text()), 'READ-ONLY')) {
@@ -92,10 +109,12 @@ final class SelectCommand implements CommandInterface
[],
$exists,
0,
null,
$uidValidity,
$recent,
$flags,
$readOnly,
$uidNext,
$highestModSeq,
);
}
}