@@ -274,7 +274,8 @@ func (mbox *Mailbox) NewView() *MailboxView {
274274// selected state.
275275type MailboxView struct {
276276 * Mailbox
277- tracker * imapserver.SessionTracker
277+ tracker * imapserver.SessionTracker
278+ searchRes imap.UIDSet
278279}
279280
280281// Close releases the resources allocated for the mailbox view.
@@ -327,6 +328,9 @@ func (mbox *MailboxView) Search(numKind imapserver.NumKind, criteria *imap.Searc
327328 continue
328329 }
329330
331+ // Always populate the UID set, since it may be saved later for SEARCHRES
332+ uidSet .AddNum (msg .uid )
333+
330334 var num uint32
331335 switch numKind {
332336 case imapserver .NumKindSeq :
@@ -336,7 +340,6 @@ func (mbox *MailboxView) Search(numKind imapserver.NumKind, criteria *imap.Searc
336340 seqSet .AddNum (seqNum )
337341 num = seqNum
338342 case imapserver .NumKindUID :
339- uidSet .AddNum (msg .uid )
340343 num = uint32 (msg .uid )
341344 }
342345 if data .Min == 0 || num < data .Min {
@@ -355,15 +358,28 @@ func (mbox *MailboxView) Search(numKind imapserver.NumKind, criteria *imap.Searc
355358 data .All = uidSet
356359 }
357360
361+ if options .ReturnSave {
362+ mbox .searchRes = uidSet
363+ }
364+
358365 return & data , nil
359366}
360367
361368func (mbox * MailboxView ) staticSearchCriteria (criteria * imap.SearchCriteria ) {
369+ seqNums := make ([]imap.SeqSet , 0 , len (criteria .SeqNum ))
362370 for _ , seqSet := range criteria .SeqNum {
363- mbox .staticNumSet (seqSet )
371+ numSet := mbox .staticNumSet (seqSet )
372+ switch numSet := numSet .(type ) {
373+ case imap.SeqSet :
374+ seqNums = append (seqNums , numSet )
375+ case imap.UIDSet : // can happen with SEARCHRES
376+ criteria .UID = append (criteria .UID , numSet )
377+ }
364378 }
365- for _ , uidSet := range criteria .UID {
366- mbox .staticNumSet (uidSet )
379+ criteria .SeqNum = seqNums
380+
381+ for i , uidSet := range criteria .UID {
382+ criteria .UID [i ] = mbox .staticNumSet (uidSet ).(imap.UIDSet )
367383 }
368384
369385 for i := range criteria .Not {
@@ -404,7 +420,7 @@ func (mbox *MailboxView) forEach(numSet imap.NumSet, f func(seqNum uint32, msg *
404420func (mbox * MailboxView ) forEachLocked (numSet imap.NumSet , f func (seqNum uint32 , msg * message )) {
405421 // TODO: optimize
406422
407- mbox .staticNumSet (numSet )
423+ numSet = mbox .staticNumSet (numSet )
408424
409425 for i , msg := range mbox .l {
410426 seqNum := uint32 (i ) + 1
@@ -429,7 +445,13 @@ func (mbox *MailboxView) forEachLocked(numSet imap.NumSet, f func(seqNum uint32,
429445//
430446// This is necessary to properly handle the special symbol "*", which
431447// represents the maximum sequence number or UID in the mailbox.
432- func (mbox * MailboxView ) staticNumSet (numSet imap.NumSet ) {
448+ //
449+ // This function also handles the special SEARCHRES marker "$".
450+ func (mbox * MailboxView ) staticNumSet (numSet imap.NumSet ) imap.NumSet {
451+ if imap .IsSearchRes (numSet ) {
452+ return mbox .searchRes
453+ }
454+
433455 switch numSet := numSet .(type ) {
434456 case imap.SeqSet :
435457 max := uint32 (len (mbox .l ))
@@ -444,6 +466,8 @@ func (mbox *MailboxView) staticNumSet(numSet imap.NumSet) {
444466 staticNumRange ((* uint32 )(& r .Start ), (* uint32 )(& r .Stop ), max )
445467 }
446468 }
469+
470+ return numSet
447471}
448472
449473func staticNumRange (start , stop * uint32 , max uint32 ) {
0 commit comments