Skip to content

Commit f438355

Browse files
authored
imapclient/search: handle UID SEARCH results without hits
When searching for unseen mails we can get the following error if there are none. > in response-data: imapwire: expected SP, got "\r" The reason is that the IMAP server is sending a response like this in case there are no search hits. T7 UID SEARCH RETURN (ALL) (UNSEEN) * ESEARCH (TAG "T7") UID T7 OK SEARCH completed (Success) The wire protocol parser is expecting a search option (like "ALL") to be present in any search result. As we can see above, this is not the case if there are no results, which results in the parser hitting a CRLF when it expected a space. To account for this we peek into the reply of the server to see whether there is a CRLF after the "UID" atom. If there is, we assume there were no results and return an empty result.
1 parent ea10af8 commit f438355

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

imapclient/search.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,9 @@ func flagSearchKey(flag imap.Flag) string {
277277

278278
func readESearchResponse(dec *imapwire.Decoder) (tag string, data *imap.SearchData, err error) {
279279
data = &imap.SearchData{}
280-
281280
if dec.Special('(') { // search-correlator
282281
var correlator string
283-
if !dec.ExpectAtom(&correlator) || !dec.ExpectSP() || !dec.ExpectAString(&tag) || !dec.ExpectSpecial(')') || !dec.ExpectSP() {
282+
if !dec.ExpectAtom(&correlator) || !dec.ExpectSP() || !dec.ExpectAString(&tag) || !dec.ExpectSpecial(')') {
284283
return "", nil, dec.Err()
285284
}
286285
if correlator != "TAG" {
@@ -289,16 +288,26 @@ func readESearchResponse(dec *imapwire.Decoder) (tag string, data *imap.SearchDa
289288
}
290289

291290
var name string
292-
if !dec.ExpectAtom(&name) || !dec.ExpectSP() {
291+
if !dec.SP() {
292+
return tag, data, nil
293+
} else if !dec.ExpectAtom(&name) {
293294
return "", nil, dec.Err()
294295
}
295296
data.UID = name == "UID"
297+
296298
if data.UID {
297-
if !dec.ExpectAtom(&name) || !dec.ExpectSP() {
299+
if !dec.SP() {
300+
return tag, data, nil
301+
} else if !dec.ExpectAtom(&name) {
298302
return "", nil, dec.Err()
299303
}
300304
}
305+
301306
for {
307+
if !dec.ExpectSP() {
308+
return "", nil, dec.Err()
309+
}
310+
302311
switch strings.ToUpper(name) {
303312
case "MIN":
304313
var num uint32
@@ -343,9 +352,7 @@ func readESearchResponse(dec *imapwire.Decoder) (tag string, data *imap.SearchDa
343352

344353
if !dec.SP() {
345354
break
346-
}
347-
348-
if !dec.ExpectAtom(&name) || !dec.ExpectSP() {
355+
} else if !dec.ExpectAtom(&name) {
349356
return "", nil, dec.Err()
350357
}
351358
}

0 commit comments

Comments
 (0)