trimTrailingLineEnding($this->connection->readLine()); if (!str_starts_with($raw, '* ')) { throw new ImapException(sprintf('Expected IMAP greeting, got: %s', $raw)); } $parts = preg_split('/\s+/', substr($raw, 2), 2) ?: []; $status = strtoupper($parts[0] ?? ''); $text = $parts[1] ?? ''; $this->logger?->debug('IMAP greeting received: {raw}', [ 'status' => $status, 'raw' => $raw, ]); return new GreetingResponse($status, $text, $raw); } public function readResponse(): ResponseInterface { $raw = $this->readRawResponse(); if ($raw === '') { throw new ImapException('Received empty IMAP response line.'); } if (str_starts_with($raw, '* ')) { $parts = preg_split('/\s+/', substr($raw, 2), 2) ?: []; $label = strtoupper($parts[0] ?? ''); $this->logger?->debug('IMAP untagged response received: {raw}', [ 'label' => $label, 'raw' => $raw, ]); return new UntaggedResponse( $label, $parts[1] ?? '', $raw, ); } if (str_starts_with($raw, '+')) { $this->logger?->debug('IMAP continuation response received: {raw}', [ 'raw' => $raw, ]); return new ContinuationResponse(ltrim(substr($raw, 1)), $raw); } $parts = preg_split('/\s+/', $raw, 3) ?: []; if (count($parts) < 2) { throw new ImapException(sprintf('Malformed tagged IMAP response: %s', $raw)); } $status = strtoupper($parts[1]); $this->logger?->debug('IMAP tagged response received: {raw}', [ 'tag' => $parts[0], 'status' => $status, 'raw' => $raw, ]); return new TaggedResponse($parts[0], $status, $parts[2] ?? '', $raw); } private function readRawResponse(): string { $raw = $this->connection->readLine(); while (($literalLength = $this->trailingLiteralLength($raw)) !== null) { $raw .= $this->connection->readBytes($literalLength); $raw .= $this->connection->readLine(); } return $this->trimTrailingLineEnding($raw); } private function trailingLiteralLength(string $raw): ?int { if (preg_match('/\{(\d+)\}\r?\n$/', $raw, $matches) !== 1) { return null; } return (int) $matches[1]; } private function trimTrailingLineEnding(string $raw): string { if (str_ends_with($raw, "\r\n")) { return substr($raw, 0, -2); } if (str_ends_with($raw, "\n")) { return substr($raw, 0, -1); } return $raw; } }