*/ final class SelectCommand implements CommandInterface { public function __construct( private readonly string $mailbox, private readonly bool $readOnly = true, ) {} public function name(): string { return $this->readOnly ? 'EXAMINE' : 'SELECT'; } public function allowedStates(): array { return [ SessionState::Authenticated, SessionState::Selected, ]; } public function encode(string $tag, SessionContext $context): RequestFrame { unset($tag, $context); return new RequestFrame(sprintf( '%s %s', $this->name(), $this->quote($this->mailbox), )); } public function handle(ResponseStream $responses, SessionContext $context): Mailbox { $exists = 0; $recent = 0; $flags = []; $readOnly = $this->readOnly; foreach ($responses as $response) { if ($response instanceof UntaggedResponse) { $raw = $response->raw(); if (preg_match('/^\*\s+(\d+)\s+EXISTS$/i', $raw, $matches)) { $exists = (int) $matches[1]; continue; } if (preg_match('/^\*\s+(\d+)\s+RECENT$/i', $raw, $matches)) { $recent = (int) $matches[1]; continue; } if ($response->label() === 'FLAGS' && preg_match('/\(([^)]*)\)/', $response->payload(), $matches)) { $flags = $this->parseFlags($matches[1]); continue; } } if ($response instanceof TaggedResponse) { if (!$response->isOk()) { throw new ImapException($this->name() . ' failed: ' . $response->text()); } if (str_contains(strtoupper($response->text()), 'READ-ONLY')) { $readOnly = true; } $context->setSelectedMailbox($this->mailbox); $context->setState(SessionState::Selected); return new Mailbox( $this->mailbox, null, [], $exists, 0, null, $recent, $flags, $readOnly, ); } } throw new ImapException($this->name() . ' did not receive a tagged completion response.'); } /** * @return list */ private function parseFlags(string $flags): array { $flags = trim($flags); if ($flags === '') { return []; } return preg_split('/\s+/', $flags) ?: []; } private function quote(string $value): string { return '"' . addcslashes($value, "\\\"") . '"'; } }