Skip to content

fix(imap): handle mailbox names containing parentheses - #289

Open
hobleyd wants to merge 1 commit into
Enough-Software:mainfrom
hobleyd:fix/imap-mailbox-names-with-parens
Open

hobleyd wants to merge 1 commit into
Enough-Software:mainfrom
hobleyd:fix/imap-mailbox-names-with-parens

Conversation

@hobleyd

@hobleyd hobleyd commented Sep 22, 2026

Copy link
Copy Markdown

Problem

Two independent failures for a mailbox such as INBOX.Financial.Audit(s) (seen against Dovecot):

  1. ListParser, for an extended LIST response (LIST-STATUS / LIST-EXTENDED return options, isExtended == true), located the extended-data block with listDetails.indexOf('('). That matched the ( inside the quoted mailbox name, so s)" was treated as extended data and the name was truncated, taking the closing quote with it. The later quote-strip then ate the final real character and the mailbox surfaced as Aud at a path that did not exist on the server.

  2. _encodeMailboxPath only quoted a path when it contained a space. RFC 3501 section 9 lists ( ) { among the atom-specials, so an unquoted COPY 1:3 INBOX.Financial.Audit(s) (or SELECT, MOVE, CREATE, ...) is rejected by servers with BAD Invalid characters in atom. LIST was unaffected because it passes alwaysQuote: true.

Fix

  • ListParser looks for the first ( that is outside a double-quoted string.
  • _encodeMailboxPath forces quoting when the encoded path contains (, ) or {, as it already does for a space.
  • MockImapServer records every chunk the client sends in requests, so tests can assert on the command text actually written to the socket.

Tests

Two new tests in imap_client_test.dart: a LIST-STATUS response with "INBOX.Financial.Audit(s)" parses to the right name and path, and copy(..., targetMailboxPath: 'INBOX.Financial.Audit(s)') sends COPY 1:3 "INBOX.Financial.Audit(s)". Both fail against main.

Two independent failures for a mailbox such as INBOX.Financial.Audit(s):

ListParser, for an extended LIST response (LIST-STATUS / LIST-EXTENDED
return options), found the extended-data block with indexOf('(') which
matched the '(' inside the quoted mailbox name. The name was truncated
(taking the closing quote with it), so the later quote-strip ate the
final character and the mailbox surfaced as 'Aud' at a path that did not
exist on the server. It now looks for the first '(' outside a
double-quoted string.

_encodeMailboxPath only quoted a path containing a space. RFC 3501
section 9 lists '(' ')' '{' among the atom-specials, so an unquoted
`COPY 1:3 INBOX.Audit(s)` (or SELECT, MOVE, CREATE, ...) is rejected by
servers with "BAD Invalid characters in atom". Those characters now
force quoting as a space does.

MockImapServer records what the client sends so tests can assert on the
command text actually written.
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.

2 participants