*/ final class StoreCommand implements CommandInterface { private readonly SequenceSet $sequenceSet; private readonly IdentifierMode $identifierMode; /** * @param list $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' : '', ); } }