From 54a24c9892838246cd5f0523ae0f8d8533cb09f8 Mon Sep 17 00:00:00 2001 From: Sebastian Krupinski Date: Sat, 26 Sep 2026 21:57:27 -0400 Subject: [PATCH] fix: entityExtant() Signed-off-by: Sebastian Krupinski --- lib/Providers/Service.php | 14 ++++++--- lib/Service/Remote/RemoteMailService.php | 19 ++++++++++++ tests/php/Unit/ServiceTest.php | 39 ++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 tests/php/Unit/ServiceTest.php diff --git a/lib/Providers/Service.php b/lib/Providers/Service.php index e9fa117..80104e1 100644 --- a/lib/Providers/Service.php +++ b/lib/Providers/Service.php @@ -596,11 +596,17 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC { $this->initialize(); - $allUids = $this->remoteService->entityList((string) $collection); - $uidSet = array_flip($allUids); // int[] → [uid => index] - $extant = []; + // only positive integers are valid UIDs; anything else cannot exist + $uids = array_values(array_filter( + array_map(static fn (string|int $id): int => (int) $id, $identifiers), + static fn (int $uid): bool => $uid > 0, + )); + + $existing = array_flip($this->remoteService->entityExtant((string) $collection, ...$uids)); + + $extant = []; foreach ($identifiers as $id) { - $extant[$id] = isset($uidSet[(int) $id]); + $extant[$id] = isset($existing[(int) $id]) && (string) (int) $id === (string) $id; } return $extant; } diff --git a/lib/Service/Remote/RemoteMailService.php b/lib/Service/Remote/RemoteMailService.php index 2b547df..a1a4001 100644 --- a/lib/Service/Remote/RemoteMailService.php +++ b/lib/Service/Remote/RemoteMailService.php @@ -298,6 +298,25 @@ class RemoteMailService return $this->entityApplyRange($uids, $range); } + /** + * Determine which of the given UIDs exist in a mailbox. + * + * @return int[] the subset of the given UIDs that exist + */ + public function entityExtant(string $collection, int ...$uids): array + { + if ($uids === []) { + return []; + } + + $this->imapClient()->perform(new SelectCommand($collection, true)); + + return $this->imapClient()->perform(new SearchCommand( + SearchCriteriaBuilder::create()->uid(SequenceSet::items(...$uids)), + IdentifierMode::Uid, + ))->matches(); + } + /** * Retrieve a list of messages in a mailbox matching the given filter, sorted and paginated as requested. * diff --git a/tests/php/Unit/ServiceTest.php b/tests/php/Unit/ServiceTest.php new file mode 100644 index 0000000..471702a --- /dev/null +++ b/tests/php/Unit/ServiceTest.php @@ -0,0 +1,39 @@ +createStub(Service::class)); + $remote->existing = [5]; + (new ReflectionProperty(Service::class, 'remoteService'))->setValue($service, $remote); + + $result = $service->entityExtant('INBOX', 5, '6', 'abc', 0); + + $this->assertSame([5 => true, 6 => false, 'abc' => false, 0 => false], $result); + $this->assertSame([['INBOX', [5, 6]]], $remote->extantCalls); + } +} + +final class ServiceTestRemoteStub extends RemoteMailService +{ + /** @var int[] */ + public array $existing = []; + public array $extantCalls = []; + + public function entityExtant(string $collection, int ...$uids): array + { + $this->extantCalls[] = [$collection, $uids]; + return array_values(array_intersect($uids, $this->existing)); + } +}