generated from Nodarx/template
112 lines
3.5 KiB
PHP
112 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXM\ProviderImap\Client\Command;
|
|
|
|
use KTXM\ProviderImap\Client\Command\Result\CommandStatusResult;
|
|
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\ResponseStream;
|
|
use KTXM\ProviderImap\Client\SequenceSet;
|
|
use KTXM\ProviderImap\Client\SessionContext;
|
|
use KTXM\ProviderImap\Client\SessionState;
|
|
|
|
/**
|
|
* @implements CommandInterface<CommandStatusResult>
|
|
*/
|
|
final class StoreCommand implements CommandInterface
|
|
{
|
|
private readonly SequenceSet $sequenceSet;
|
|
private readonly IdentifierMode $identifierMode;
|
|
|
|
/**
|
|
* @param list<string> $flags
|
|
*/
|
|
public function __construct(
|
|
FetchTarget|string|SequenceSet|null $target = null,
|
|
private array $flags = [],
|
|
private string $action = '',
|
|
private bool $silent = true,
|
|
) {
|
|
$resolvedTarget = match (true) {
|
|
$target instanceof FetchTarget => $target,
|
|
$target instanceof SequenceSet => FetchTarget::sequence($target),
|
|
is_string($target) => FetchTarget::sequence($target),
|
|
default => FetchTarget::all(),
|
|
};
|
|
|
|
$normalizedAction = trim($this->action);
|
|
if (!in_array($normalizedAction, ['', '+', '-'], true)) {
|
|
throw new ImapException('STORE action must be one of "", "+", or "-".');
|
|
}
|
|
|
|
$normalizedFlags = array_values(array_filter(array_map(
|
|
static fn (string $flag): string => trim($flag),
|
|
$this->flags,
|
|
), static fn (string $flag): bool => $flag !== ''));
|
|
|
|
if ($normalizedFlags === []) {
|
|
throw new ImapException('STORE requires at least one flag.');
|
|
}
|
|
|
|
$this->flags = $normalizedFlags;
|
|
$this->action = $normalizedAction;
|
|
$this->sequenceSet = $resolvedTarget->sequenceSet();
|
|
$this->identifierMode = $resolvedTarget->identifierMode();
|
|
}
|
|
|
|
public function name(): string
|
|
{
|
|
return 'STORE';
|
|
}
|
|
|
|
public function allowedStates(): array
|
|
{
|
|
return [SessionState::Selected];
|
|
}
|
|
|
|
public function encode(string $tag, SessionContext $context): RequestFrame
|
|
{
|
|
unset($tag, $context);
|
|
|
|
return new RequestFrame(sprintf(
|
|
'%sSTORE %s %s (%s)',
|
|
$this->identifierMode === IdentifierMode::Uid ? 'UID ' : '',
|
|
$this->sequenceSet->toCommand(),
|
|
$this->itemName(),
|
|
implode(' ', $this->flags),
|
|
));
|
|
}
|
|
|
|
public function handle(ResponseStream $responses, SessionContext $context): CommandStatusResult
|
|
{
|
|
if ($context->selectedMailbox() === null) {
|
|
throw new ImapException('STORE requires a selected mailbox.');
|
|
}
|
|
|
|
foreach ($responses as $response) {
|
|
if ($response instanceof TaggedResponse) {
|
|
if (!$response->isOk()) {
|
|
throw new ImapException('STORE failed: ' . $response->text());
|
|
}
|
|
|
|
return new CommandStatusResult($response->status(), $response->text());
|
|
}
|
|
}
|
|
|
|
throw new ImapException('STORE did not receive a tagged completion response.');
|
|
}
|
|
|
|
private function itemName(): string
|
|
{
|
|
return sprintf(
|
|
'%sFLAGS%s',
|
|
$this->action,
|
|
$this->silent ? '.SILENT' : '',
|
|
);
|
|
}
|
|
} |