Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/FetchedMessageData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace DirectoryTree\ImapEngine;

use DirectoryTree\ImapEngine\Connection\Responses\Data\ListData;
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
use DirectoryTree\ImapEngine\Exceptions\RuntimeException;

class FetchedMessageData
{
/**
* Constructor.
*/
public function __construct(
protected int $uid,
protected array $flags = [],
protected string $head = '',
protected string $body = '',
protected ?int $size = null,
protected ?ListData $bodyStructure = null,
) {}

/**
* Create message data from an IMAP FETCH response.
*/
public static function fromResponse(UntaggedResponse $response): static
{
$data = $response->tokenAt(3);

if (! $data instanceof ListData) {
throw new RuntimeException(sprintf(
'Expected instance of %s at index 3 in FETCH response, got %s',
ListData::class,
get_debug_type($data)
));
}

return new static(
uid: (int) $data->lookup('UID')->value,
flags: $data->lookup('FLAGS')?->values() ?? [],
head: $data->lookup('[HEADER]')->value ?? '',
body: $data->lookup('[TEXT]')->value ?? '',
size: ($size = $data->lookup('RFC822.SIZE')?->value) ? (int) $size : null,
bodyStructure: ($bodyStructure = $data->lookup('BODYSTRUCTURE')) instanceof ListData
? $bodyStructure
: null,
);
}

/**
* Get the message UID.
*/
public function uid(): int
{
return $this->uid;
}

/**
* Create a message for the given folder.
*/
public function toMessage(FolderInterface $folder): Message
{
return new Message(
$folder,
$this->uid,
$this->flags,
$this->head,
$this->body,
$this->size,
$this->bodyStructure,
);
}
}
57 changes: 57 additions & 0 deletions src/MessageData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace DirectoryTree\ImapEngine;

use DirectoryTree\ImapEngine\MessageData\Attribute;
use DirectoryTree\ImapEngine\MessageData\Body;

class MessageData
{
/**
* Create a FLAGS message data item.
*/
public static function flags(): Attribute
{
return Attribute::Flags;
}

/**
* Create an RFC822.SIZE message data item.
*/
public static function size(): Attribute
{
return Attribute::Size;
}

/**
* Create a BODYSTRUCTURE message data item.
*/
public static function bodyStructure(): Attribute
{
return Attribute::BodyStructure;
}

/**
* Create a message header data item.
*/
public static function headers(): Body
{
return Body::headers();
}

/**
* Create a message text data item.
*/
public static function text(): Body
{
return Body::text();
}

/**
* Create a message body section data item.
*/
public static function section(string $section): Body
{
return Body::section($section);
}
}
26 changes: 26 additions & 0 deletions src/MessageData/Attribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace DirectoryTree\ImapEngine\MessageData;

enum Attribute: string implements FetchItem
{
case Flags = 'FLAGS';
case Size = 'RFC822.SIZE';
case BodyStructure = 'BODYSTRUCTURE';

/**
* {@inheritDoc}
*/
public function key(): string
{
return $this->value;
}

/**
* {@inheritDoc}
*/
public function toImap(): string
{
return $this->value;
}
}
67 changes: 67 additions & 0 deletions src/MessageData/Body.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace DirectoryTree\ImapEngine\MessageData;

class Body implements FetchItem
{
/**
* Constructor.
*/
public function __construct(
protected string $section,
protected bool $peek = false,
) {}

/**
* Create a message header data item.
*/
public static function headers(): static
{
return new static('HEADER');
}

/**
* Create a message text data item.
*/
public static function text(): static
{
return new static('TEXT');
}

/**
* Create a message body section data item.
*/
public static function section(string $section): static
{
return new static($section);
}

/**
* Fetch the message body section without setting the seen flag.
*/
public function peek(): static
{
$item = clone $this;
$item->peek = true;

return $item;
}

/**
* {@inheritDoc}
*/
public function key(): string
{
return "BODY[{$this->section}]";
}

/**
* {@inheritDoc}
*/
public function toImap(): string
{
$item = $this->peek ? 'BODY.PEEK' : 'BODY';

return "{$item}[{$this->section}]";
}
}
16 changes: 16 additions & 0 deletions src/MessageData/FetchItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace DirectoryTree\ImapEngine\MessageData;

interface FetchItem
{
/**
* Get the unique message data item key.
*/
public function key(): string;

/**
* Get the IMAP representation of the message data item.
*/
public function toImap(): string;
}
85 changes: 10 additions & 75 deletions src/MessageQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
use DirectoryTree\ImapEngine\Collections\ResponseCollection;
use DirectoryTree\ImapEngine\Connection\ConnectionInterface;
use DirectoryTree\ImapEngine\Connection\ImapQueryBuilder;
use DirectoryTree\ImapEngine\Connection\Responses\Data\ListData;
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
use DirectoryTree\ImapEngine\Connection\Tokens\Token;
use DirectoryTree\ImapEngine\Enums\ImapFetchIdentifier;
use DirectoryTree\ImapEngine\Enums\ImapFlag;
use DirectoryTree\ImapEngine\Exceptions\ImapCapabilityException;
use DirectoryTree\ImapEngine\Exceptions\ImapCommandException;
use DirectoryTree\ImapEngine\Exceptions\RuntimeException;
use DirectoryTree\ImapEngine\MessageData\FetchItem;
use DirectoryTree\ImapEngine\Pagination\LengthAwarePaginator;
use DirectoryTree\ImapEngine\Support\Str;
use Illuminate\Support\Collection;
Expand Down Expand Up @@ -326,17 +325,8 @@ protected function populate(Collection $uids): MessageCollection

$messages->total($uids->count());

foreach ($this->fetch($uids) as $uid => $response) {
$messages->push(
$this->newMessage(
$uid,
$response['flags'] ?? [],
$response['head'] ?? '',
$response['body'] ?? '',
$response['size'] ?? null,
$response['bodystructure'] ?? null,
)
);
foreach ($this->fetch($uids) as $data) {
$messages->push($data->toMessage($this->folder));
}

return $messages;
Expand All @@ -359,68 +349,21 @@ protected function fetch(Collection $messages): array

$uids = $messages->forPage($this->page, $this->limit)->values();

$fetch = [];

if ($this->fetchFlags) {
$fetch[] = 'FLAGS';
}

if ($this->fetchSize) {
$fetch[] = 'RFC822.SIZE';
}

if ($this->fetchHeaders) {
$fetch[] = $this->fetchAsUnread
? 'BODY.PEEK[HEADER]'
: 'BODY[HEADER]';
}

if ($this->fetchBody) {
$fetch[] = $this->fetchAsUnread
? 'BODY.PEEK[TEXT]'
: 'BODY[TEXT]';
}

if ($this->fetchBodyStructure) {
$fetch[] = 'BODYSTRUCTURE';
}
$fetch = array_map(
fn (FetchItem $item) => $item->toImap(),
$this->fetchItems,
);

if (empty($fetch)) {
return $uids->mapWithKeys(fn (string|int $uid) => [
$uid => [
'size' => null,
'flags' => [],
'head' => '',
'body' => '',
'bodystructure' => null,
],
$uid => new FetchedMessageData((int) $uid),
])->all();
}

return $this->connection()->fetch($fetch, $uids->all())->mapWithKeys(function (UntaggedResponse $response) {
$data = $response->tokenAt(3);

if (! $data instanceof ListData) {
throw new RuntimeException(sprintf(
'Expected instance of %s at index 3 in FETCH response, got %s',
ListData::class,
get_debug_type($data)
));
}

$uid = $data->lookup('UID')->value;

$size = $data->lookup('RFC822.SIZE')?->value;
$data = FetchedMessageData::fromResponse($response);

return [
$uid => [
'size' => $size ? (int) $size : null,
'flags' => $data->lookup('FLAGS')?->values() ?? [],
'head' => $data->lookup('[HEADER]')->value ?? '',
'body' => $data->lookup('[TEXT]')->value ?? '',
'bodystructure' => $data->lookup('BODYSTRUCTURE'),
],
];
return [$data->uid() => $data];
})->all();
}

Expand Down Expand Up @@ -495,14 +438,6 @@ protected function id(int $id, ImapFetchIdentifier $identifier = ImapFetchIdenti
}
}

/**
* Make a new message from given raw components.
*/
protected function newMessage(int $uid, array $flags, string $head, string $body, ?int $size = null, ?ListData $bodystructure = null): Message
{
return new Message($this->folder, $uid, $flags, $head, $body, $size, $bodystructure);
}

/**
* Get the connection instance.
*/
Expand Down
Loading
Loading