Files
provider_imap/lib/Client/Command/ExpungeCommand.php
2026-05-08 00:16:43 -04:00

106 lines
3.2 KiB
PHP

<?php
declare(strict_types=1);
namespace KTXM\ProviderImap\Client\Command;
use KTXM\ProviderImap\Client\FetchTarget;
use KTXM\ProviderImap\Client\IdentifierMode;
use KTXM\ProviderImap\Client\ImapException;
use KTXM\ProviderImap\Client\Protocol\RequestFrame;
use KTXM\ProviderImap\Client\Protocol\Response\TaggedResponse;
use KTXM\ProviderImap\Client\Protocol\Response\UntaggedResponse;
use KTXM\ProviderImap\Client\Protocol\ResponseStream;
use KTXM\ProviderImap\Client\SequenceSet;
use KTXM\ProviderImap\Client\SessionContext;
use KTXM\ProviderImap\Client\SessionState;
/**
* @implements CommandInterface<list<int>>
*/
final class ExpungeCommand implements CommandInterface
{
private readonly ?SequenceSet $sequenceSet;
public function __construct(FetchTarget|string|SequenceSet|null $target = null)
{
if ($target === null) {
$this->sequenceSet = null;
return;
}
$resolvedTarget = match (true) {
$target instanceof FetchTarget => $target,
$target instanceof SequenceSet => FetchTarget::sequence($target),
is_string($target) => FetchTarget::sequence($target),
default => null,
};
if ($resolvedTarget === null || $resolvedTarget->identifierMode() !== IdentifierMode::Uid) {
throw new ImapException('Targeted EXPUNGE requires a UID target.');
}
$this->sequenceSet = $resolvedTarget->sequenceSet();
}
public function name(): string
{
return 'EXPUNGE';
}
public function allowedStates(): array
{
return [SessionState::Selected];
}
public function encode(string $tag, SessionContext $context): RequestFrame
{
unset($tag);
if ($this->sequenceSet === null) {
unset($context);
return new RequestFrame('EXPUNGE');
}
if (!$context->hasCapability('UIDPLUS')) {
throw new ImapException('UID EXPUNGE requires the IMAP UIDPLUS capability.');
}
return new RequestFrame(sprintf(
'UID EXPUNGE %s',
$this->sequenceSet->toCommand(),
));
}
public function handle(ResponseStream $responses, SessionContext $context): array
{
if ($context->selectedMailbox() === null) {
throw new ImapException('EXPUNGE requires a selected mailbox.');
}
$expunged = [];
foreach ($responses as $response) {
if ($response instanceof UntaggedResponse && preg_match('/^\*\s+(\d+)\s+EXPUNGE$/i', $response->raw(), $matches) === 1) {
$expunged[] = (int) $matches[1];
continue;
}
if ($response instanceof TaggedResponse) {
if (!$response->isOk()) {
throw new ImapException($this->sequenceSet === null
? 'EXPUNGE failed: ' . $response->text()
: 'UID EXPUNGE failed: ' . $response->text());
}
return $expunged;
}
}
throw new ImapException($this->sequenceSet === null
? 'EXPUNGE did not receive a tagged completion response.'
: 'UID EXPUNGE did not receive a tagged completion response.');
}
}