Files
provider_imap/lib/Smtp/Protocol/ReplyReader.php
T
Sebastian ad6b7c5eba feat: smtp sending
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
2026-06-23 16:29:16 -04:00

69 lines
1.9 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXM\ProviderImap\Smtp\Protocol;
use KTXM\ProviderImap\Smtp\SmtpException;
use KTXM\ProviderImap\Smtp\Transport\ConnectionInterface;
use Psr\Log\LoggerInterface;
/**
* Reads SMTP replies, assembling multi-line responses.
*
* A multi-line reply repeats the status code on every line, using a hyphen
* ("250-text") to indicate continuation and a space ("250 text") on the final
* line. See RFC 5321 §4.2.
*/
final class ReplyReader
{
public function __construct(
private readonly ConnectionInterface $connection,
private readonly ?LoggerInterface $logger = null,
) {}
public function read(): Reply
{
$lines = [];
$raw = '';
$code = null;
while (true) {
$rawLine = $this->connection->readLine();
$raw .= $rawLine;
$trimmed = rtrim($rawLine, "\r\n");
if (!preg_match('/^(\d{3})([ -]?)(.*)$/', $trimmed, $matches)) {
throw new SmtpException(sprintf('Malformed SMTP reply line: %s', $trimmed));
}
$lineCode = (int) $matches[1];
$separator = $matches[2];
$lines[] = $matches[3];
if ($code === null) {
$code = $lineCode;
} elseif ($lineCode !== $code) {
throw new SmtpException(sprintf('Inconsistent SMTP reply code: %s', $trimmed));
}
// A space separator (or no separator) marks the final line.
if ($separator !== '-') {
break;
}
}
$this->logger?->debug('SMTP reply received: {raw}', [
'code' => $code,
'raw' => rtrim($raw, "\r\n"),
]);
return new Reply($code ?? 0, $lines, rtrim($raw, "\r\n"));
}
}