Skip to content

fix: UID SEARCH on an empty mailbox must match nothing, not answer NO#478

Open
akeemjenkins wants to merge 1 commit into
ProtonMail:devfrom
akeemjenkins:fix/uid-search-empty-mailbox
Open

fix: UID SEARCH on an empty mailbox must match nothing, not answer NO#478
akeemjenkins wants to merge 1 commit into
ProtonMail:devfrom
akeemjenkins:fix/uid-search-empty-mailbox

Conversation

@akeemjenkins

Copy link
Copy Markdown

Problem

A SEARCH whose criteria reference UIDs answers NO no such message when the selected mailbox is empty:

A001 select inbox        (empty mailbox)
A001 OK [READ-WRITE]
A002 uid search uid 1
A002 NO no such message

RFC 3501 §6.4.8 requires the opposite:

A non-existent unique identifier is ignored without any error message generated.

In an empty mailbox every UID is non-existent, so a UID <sequence set> search key matches nothing — the correct answer is an empty untagged * SEARCH plus tagged OK. Gluon already behaves this way for non-existent UIDs in a non-empty mailbox (they resolve and simply match nothing), so the empty-mailbox NO is also internally inconsistent.

Root cause

buildSearchOpUID calls snap.resolveUIDInterval, whose resolveUID errors with ErrNoSuchMessage whenever the snapshot holds zero messages. The equivalent FETCH/STORE/COPY range path got an empty-mailbox guard back in b04fb94 (GODT-2218) — "If there are no messages in the mailbox, we still resolve without error" — but the SEARCH path calls resolveUIDInterval directly and was missed.

Impact

Any client that verifies its own mutations trips over this precisely when the mutation fully succeeds: after a MOVE that drains a mailbox, a verification UID SEARCH UID <moved set> against the now-empty source fails, reading as "move not applied" when the empty mailbox is exactly the expected outcome. Observed in practice through Proton Mail Bridge 3.25.0.

Fix

resolveUIDInterval returns no intervals for an empty snapshot (mirroring the GODT-2218 guard), so UID search keys match nothing instead of erroring. This also covers UID SEARCH UID 1:* on an empty mailbox. Sequence-number resolution is unchanged.

Added TestSearchUIDEmptyMailbox covering uid search uid 1, search uid 1,3:5, and uid search uid 1:* against an empty INBOX; it fails with NO no such message before the fix. go test ./tests ./internal/state passes.

RFC 3501 section 6.4.8: "A non-existent unique identifier is ignored
without any error message generated." In an empty mailbox every UID is
non-existent, so a UID search key matches nothing. resolveUIDInterval
instead reported ErrNoSuchMessage from resolveUID's empty-snapshot
guard, so e.g. 'UID SEARCH UID 1' against an empty mailbox answered
'NO no such message' rather than an empty untagged SEARCH plus OK.

Non-existent UIDs in a non-empty mailbox were already ignored without
error, and the FETCH/STORE/COPY range path got an equivalent
empty-mailbox guard in b04fb94 (GODT-2218); the SEARCH path calls
resolveUIDInterval directly and was missed. Clients that verify their
own mutations hit this whenever a MOVE drains a mailbox: the
verification search for the moved UIDs fails exactly when the move
fully succeeded.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant