generated from Nodarx/template
129 lines
3.7 KiB
PHP
129 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Gricob\IMAP\Protocol;
|
|
|
|
use Generator;
|
|
use Gricob\IMAP\Protocol\Command\Command;
|
|
use Gricob\IMAP\Protocol\Command\StartTlsCommand;
|
|
use Gricob\IMAP\Protocol\Response\Line\Line;
|
|
use Gricob\IMAP\Protocol\Response\Line\Status\Status;
|
|
use Gricob\IMAP\Protocol\Response\Line\Status\StatusType;
|
|
use Gricob\IMAP\Protocol\Response\Parser\Parser;
|
|
use Gricob\IMAP\Protocol\Response\Response;
|
|
use Gricob\IMAP\Transport\Connection;
|
|
use RuntimeException;
|
|
|
|
class Imap
|
|
{
|
|
protected Connection $connection;
|
|
private TagGenerator $tagGenerator;
|
|
private ResponseHandler $responseHandler;
|
|
|
|
public function __construct(Connection $connection)
|
|
{
|
|
$this->connection = $connection;
|
|
$this->tagGenerator = new TagGenerator();
|
|
$this->responseHandler = new ResponseHandler(new Parser());
|
|
}
|
|
|
|
public function __destruct()
|
|
{
|
|
$this->disconnect();
|
|
}
|
|
|
|
public function connect(): void
|
|
{
|
|
if ($this->connection->isOpen()) {
|
|
return;
|
|
}
|
|
|
|
$this->connection->open();
|
|
|
|
$responseStream = $this->connection->receive();
|
|
|
|
$greeting = $this->responseHandler->handle('*', $responseStream, new UnexpectedContinuationHandler());
|
|
|
|
match ($greeting->status->type) {
|
|
StatusType::OK => null, // Do nothing
|
|
StatusType::PREAUTH => throw new RuntimeException('pre-auth is not supported'),
|
|
StatusType::BAD,
|
|
StatusType::NO,
|
|
StatusType::BYE => throw new ConnectionRejected($greeting->status->message),
|
|
};
|
|
}
|
|
|
|
public function disconnect(): void
|
|
{
|
|
$this->connection->close();
|
|
}
|
|
|
|
/**
|
|
* Perform STARTTLS negotiation (patch).
|
|
*
|
|
* Sends the STARTTLS command and upgrades the underlying socket to TLS.
|
|
* The connection must be a SocketConnection (or any Connection that
|
|
* implements upgradeTls()). Call this after connect() but before logIn().
|
|
*
|
|
* @throws \RuntimeException if the server rejects STARTTLS
|
|
* @throws \BadMethodCallException if the connection does not support TLS upgrade
|
|
*/
|
|
public function startTls(): void
|
|
{
|
|
if (!method_exists($this->connection, 'upgradeTls')) {
|
|
throw new \BadMethodCallException(
|
|
'The current Connection implementation does not support STARTTLS upgrade'
|
|
);
|
|
}
|
|
|
|
$response = $this->send(new StartTlsCommand());
|
|
|
|
if ($response->status->type !== StatusType::OK) {
|
|
throw new \RuntimeException(
|
|
'Server rejected STARTTLS: ' . $response->status->message
|
|
);
|
|
}
|
|
|
|
$this->connection->upgradeTls();
|
|
}
|
|
|
|
public function send(Command $command): Response
|
|
{
|
|
$interaction = new CommandInteraction(
|
|
$this->connection,
|
|
$this->responseHandler,
|
|
$this->tagGenerator->next(),
|
|
$command,
|
|
);
|
|
|
|
$response = $interaction->interact();
|
|
|
|
if ($response->status->type != StatusType::OK) {
|
|
throw CommandFailed::withStatus($response->status);
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Sends $command and returns a Generator that yields each untagged Line as
|
|
* it arrives from the socket. CommandFailed is thrown (inside the generator)
|
|
* if the server responds with NO or BAD.
|
|
*
|
|
* @return Generator<int, Line, mixed, Status>
|
|
*/
|
|
public function sendStreaming(Command $command): Generator
|
|
{
|
|
$this->connect();
|
|
|
|
$interaction = new CommandInteraction(
|
|
$this->connection,
|
|
$this->responseHandler,
|
|
$this->tagGenerator->next(),
|
|
$command,
|
|
);
|
|
|
|
yield from $interaction->streamInteract();
|
|
}
|
|
} |