generated from Nodarx/template
feat: append command
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user