generated from Nodarx/template
3dd9c2f983
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
103 lines
3.1 KiB
PHP
103 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KTXM\ProviderImap\Client\Command;
|
|
|
|
use KTXM\ProviderImap\Client\ImapException;
|
|
use KTXM\ProviderImap\Client\Protocol\RequestFrame;
|
|
use KTXM\ProviderImap\Client\Protocol\Response\ContinuationResponse;
|
|
use KTXM\ProviderImap\Client\Protocol\Response\TaggedResponse;
|
|
use KTXM\ProviderImap\Client\Protocol\ResponseStream;
|
|
use KTXM\ProviderImap\Client\SessionContext;
|
|
use KTXM\ProviderImap\Client\SessionState;
|
|
|
|
/**
|
|
* APPEND a raw RFC822 message to a mailbox (RFC 3501 §6.3.11).
|
|
*
|
|
* Uses a synchronizing literal: the command line ends with `{<len>}`, the
|
|
* server replies with a continuation request ("+"), and only then is the
|
|
* message streamed back via {@see ResponseStream::respond()}. Returns the
|
|
* assigned UID when the server reports APPENDUID (RFC 4315 / UIDPLUS),
|
|
* otherwise null.
|
|
*
|
|
* @implements CommandInterface<int|null>
|
|
*/
|
|
final class AppendCommand implements CommandInterface
|
|
{
|
|
private readonly string $literal;
|
|
|
|
/**
|
|
* @param list<string> $flags optional initial flags, e.g. ['\\Seen']
|
|
*/
|
|
public function __construct(
|
|
private readonly string $mailbox,
|
|
string $message,
|
|
private readonly array $flags = [],
|
|
) {
|
|
// IMAP literals are octet-counted; normalise to CRLF line endings.
|
|
$this->literal = (string) preg_replace('/\r\n|\r|\n/', "\r\n", $message);
|
|
}
|
|
|
|
public function name(): string
|
|
{
|
|
return 'APPEND';
|
|
}
|
|
|
|
public function allowedStates(): array
|
|
{
|
|
return [SessionState::Authenticated, SessionState::Selected];
|
|
}
|
|
|
|
public function encode(string $tag, SessionContext $context): RequestFrame
|
|
{
|
|
unset($tag, $context);
|
|
|
|
$flagSegment = $this->flags === [] ? '' : '(' . implode(' ', $this->flags) . ') ';
|
|
|
|
return new RequestFrame(sprintf(
|
|
'APPEND %s %s{%d}',
|
|
$this->quote($this->mailbox),
|
|
$flagSegment,
|
|
strlen($this->literal),
|
|
));
|
|
}
|
|
|
|
public function handle(ResponseStream $responses, SessionContext $context): ?int
|
|
{
|
|
unset($context);
|
|
|
|
foreach ($responses as $response) {
|
|
if ($response instanceof ContinuationResponse) {
|
|
// Continuation granted: stream the literal, then CRLF to end the command.
|
|
$responses->respond($this->literal . "\r\n");
|
|
continue;
|
|
}
|
|
|
|
if ($response instanceof TaggedResponse) {
|
|
if (!$response->isOk()) {
|
|
throw new ImapException('APPEND failed: ' . $response->text());
|
|
}
|
|
|
|
return $this->parseAppendUid($response->text());
|
|
}
|
|
}
|
|
|
|
throw new ImapException('APPEND did not receive a tagged completion response.');
|
|
}
|
|
|
|
private function quote(string $mailbox): string
|
|
{
|
|
return '"' . addcslashes($mailbox, "\\\"") . '"';
|
|
}
|
|
|
|
private function parseAppendUid(string $text): ?int
|
|
{
|
|
if (preg_match('/\[APPENDUID\s+\d+\s+(\d+)\]/i', $text, $matches) === 1) {
|
|
return (int) $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|