Skip to content

[BUG] FETCH response merges literals for multi-item requests, breaks strict IMAP clients (Nextcloud/Horde) #298

Description

@maneesha-xyz

Bug Report

Steps to Reproduce

Connect directly to raven's IMAPS port, authenticate, select INBOX, and issue a FETCH requesting two literal-bearing items in one command — the exact request Nextcloud's Mail app (Horde IMAP client) sends when opening a message body:

1 AUTHENTICATE PLAIN <creds>
2 SELECT INBOX
3 UID FETCH 6 (BODY.PEEK[1] BODY.PEEK[1.MIME])

Expected Behavior

Per RFC 3501 §4.3, each literal must immediately follow the item name it belongs to:

* 6 FETCH (UID 6 BODY[1] {197}
<197 bytes of body text>
 BODY[1.MIME] {43}
Content-Type: text/plain; charset=UTF-8

)
3 OK UID FETCH completed

Actual Behavior

All item names are emitted first, then all literals concatenated together afterward — captured byte-for-byte from a live raven:dev instance:

* 6 FETCH (UID 6 BODY[1] BODY[1.MIME] {197}
<197 bytes of body text>  {43}
Content-Type: text/plain; charset=UTF-8

)
3 OK UID FETCH completed

This is not valid IMAP. A client parsing positionally has no way to associate the trailing literals with BODY[1] and BODY[1.MIME]. Confirmed against Nextcloud 34.0.2.1's Mail app, which throws Cannot access offset of type Horde_Stream_Temp in isset or empty in Horde_Imap_Client_Socket::_parseFetch and fails to open the message. Any FETCH requesting a single literal item works fine — this only breaks once two or more literal-bearing items are requested together.

Root cause: internal/server/message/fetch.go:212 declares one shared literalData string for the whole FETCH response. Every literal-bearing block appends its item name to responseParts, but appends its literal bytes to that separate shared string instead:

  • numeric body sections, BODY[n] / BODY[n.MIME] (~line 404-416)
  • BODY[HEADER.FIELDS (...)] (~line 500)
  • BODY[TEXT] (~line 537)
  • BODY[HEADER] (~line 553)
  • RFC822.HEADER (~line 568)
  • RFC822.TEXT (~line 583)
  • full BODY[] (~line 596)

The final response (~line 600) joins all names first, then appends the concatenated literals. Correct only when exactly one literal item is requested per FETCH.

Suggested fix: remove the shared literalData accumulator. At each append site, build the item's {size}\r\n<data> inline as part of the same responseParts entry, in call order, then join responseParts alone at the end.

Relevant Logs / Screenshots

  • raven image: ghcr.io/opengovmail/raven:dev
  • raven source: github.com/OpenGovMail/raven, repro'd against 0df808b on main
  • Client: Nextcloud 34.0.2.1, Mail app (Horde_Imap_Client)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions