refactor: use custom imap client

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-05-08 00:16:43 -04:00
parent a728aeb11c
commit a8764747fd
179 changed files with 6782 additions and 5907 deletions

View File

@@ -0,0 +1,112 @@
<?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 readonly array $flags = [],
private readonly string $action = '',
private readonly 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' : '',
);
}
}