Skip to content

Commit 5132a7f

Browse files
andrinofffloatpanebot
authored andcommitted
fix: gate status request (#1427)
## What? Gate the `LIST ... RETURN (STATUS (UNSEEN))` request in `FetchFolders` on the server advertising the LIST-STATUS capability (RFC 5819). When the server doesn't support it, send a plain `LIST "" "*"` and populate unread counts with a per-mailbox `STATUS (UNSEEN)` fallback instead. ## Why? Fixes #1426 Signed-off-by: drew <me@andrinoff.com> (cherry picked from commit d14a4cb)
1 parent e539993 commit 5132a7f

1 file changed

Lines changed: 34 additions & 6 deletions

File tree

fetcher/fetcher.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,11 +1919,18 @@ func FetchFolders(account *config.Account) ([]Folder, error) {
19191919
}
19201920
defer c.Close() //nolint:errcheck
19211921

1922-
listCmd := c.List("", "*", &imap.ListOptions{
1923-
ReturnStatus: &imap.StatusOptions{
1924-
NumUnseen: true,
1925-
},
1926-
})
1922+
// Only request the unseen count inline via LIST ... RETURN (STATUS (UNSEEN))
1923+
// when the server advertises LIST-STATUS (RFC 5819). Servers without it
1924+
// (e.g. Proton Mail Bridge, Exchange Online) either reject the RETURN
1925+
// argument outright or send a reply go-imap can't parse (#1408). For those
1926+
// we fall back to a per-mailbox STATUS below.
1927+
hasListStatus := c.Caps().Has(imap.CapListStatus)
1928+
listOpts := &imap.ListOptions{}
1929+
if hasListStatus {
1930+
listOpts.ReturnStatus = &imap.StatusOptions{NumUnseen: true}
1931+
}
1932+
1933+
listCmd := c.List("", "*", listOpts)
19271934
defer listCmd.Close() //nolint:errcheck
19281935

19291936
var folders []Folder
@@ -1938,7 +1945,7 @@ func FetchFolders(account *config.Account) ([]Folder, error) {
19381945
}
19391946

19401947
var unread uint32
1941-
if data.Status != nil {
1948+
if data.Status != nil && data.Status.NumUnseen != nil {
19421949
unread = *data.Status.NumUnseen
19431950
}
19441951

@@ -1958,6 +1965,27 @@ func FetchFolders(account *config.Account) ([]Folder, error) {
19581965
return nil, err
19591966
}
19601967

1968+
// Without LIST-STATUS the LIST reply carries no unseen counts, so issue a
1969+
// STATUS per mailbox to populate them. Skip \Noselect folders, which can't
1970+
// be queried with STATUS.
1971+
if !hasListStatus {
1972+
for i := range folders {
1973+
if slices.Contains(folders[i].Attributes, string(imap.MailboxAttrNoSelect)) {
1974+
continue
1975+
}
1976+
status, err := c.Status(folders[i].Name, &imap.StatusOptions{NumUnseen: true}).Wait()
1977+
if err != nil {
1978+
// A single failing mailbox shouldn't abort the whole listing;
1979+
// leave its unread count at zero.
1980+
loglevel.Debugf("STATUS UNSEEN failed for %q: %v", folders[i].Name, err)
1981+
continue
1982+
}
1983+
if status.NumUnseen != nil {
1984+
folders[i].Unread = *status.NumUnseen
1985+
}
1986+
}
1987+
}
1988+
19611989
return folders, nil
19621990
}
19631991

0 commit comments

Comments
 (0)