Files
provider_imap/lib/Client/Client.php
2026-05-08 00:16:43 -04:00

98 lines
3.3 KiB
PHP

<?php
declare(strict_types=1);
namespace KTXM\ProviderImap\Client;
use KTXM\ProviderImap\Client\Command\CapabilityCommand;
use KTXM\ProviderImap\Client\Command\CommandInterface;
use KTXM\ProviderImap\Client\Command\LoginCommand;
use KTXM\ProviderImap\Client\Command\StatusCommand;
use KTXM\ProviderImap\Client\Command\StartTlsCommand;
use KTXM\ProviderImap\Client\Protocol\CommandExecutor;
use KTXM\ProviderImap\Client\Protocol\ProtocolReader;
use KTXM\ProviderImap\Client\Protocol\ProtocolWriter;
use KTXM\ProviderImap\Client\Protocol\TagGenerator;
use KTXM\ProviderImap\Client\Transport\ConnectionFactoryInterface;
use KTXM\ProviderImap\Client\Transport\SocketConnectionFactory;
use Psr\Log\LoggerInterface;
final class Client implements ClientInterface
{
private ?SessionContext $session = null;
private ?CommandExecutor $executor = null;
public function __construct(
private readonly ConnectionFactoryInterface $connectionFactory = new SocketConnectionFactory(),
private readonly ?LoggerInterface $logger = null,
) {}
public function connect(ConnectionConfig $config): void
{
$connection = $this->connectionFactory->create($config, $this->logger);
$connection->connect($config);
$reader = new ProtocolReader($connection, $this->logger);
$writer = new ProtocolWriter($connection, $this->logger);
$session = new SessionContext($config, $connection);
$greeting = $reader->readGreeting();
$session->setGreeting($greeting);
$session->setState(match ($greeting->status()) {
'OK' => SessionState::NotAuthenticated,
'PREAUTH' => SessionState::Authenticated,
'BYE' => SessionState::Logout,
default => throw new ImapException('Unexpected IMAP greeting status: ' . $greeting->status()),
});
if ($session->state() === SessionState::Logout) {
throw new ImapException('IMAP server rejected the connection: ' . $greeting->text());
}
$this->session = $session;
$this->executor = new CommandExecutor($reader, $writer, new TagGenerator(), $this->logger);
$this->perform(new CapabilityCommand());
if ($config->security() === ConnectionSecurity::StartTls) {
$this->perform(new StartTlsCommand());
$this->perform(new CapabilityCommand());
}
if ($config->hasCredentials()) {
$this->perform(new LoginCommand(
$config->username() ?? '',
$config->password() ?? '',
));
$this->perform(new CapabilityCommand());
}
}
public function capabilities(): array
{
return $this->session()->capabilities();
}
public function hasCapability(string $capability): bool
{
return $this->session()->hasCapability($capability);
}
public function perform(CommandInterface $command): mixed
{
if ($this->session === null || $this->executor === null) {
throw new ImapException('IMAP client is not connected.');
}
return $this->executor->perform($command, $this->session);
}
public function session(): SessionContext
{
if ($this->session === null) {
throw new ImapException('IMAP client is not connected.');
}
return $this->session;
}
}