@@ -288,9 +288,10 @@ func (mbox *Mailbox) expungeLocked(expunged map[*message]struct{}) (seqNums []ui
288288// Callers must call MailboxView.Close once they are done with the mailbox view.
289289func (mbox * Mailbox ) NewView (options * imap.SelectOptions ) * MailboxView {
290290 return & MailboxView {
291- Mailbox : mbox ,
292- tracker : mbox .tracker .NewSession (),
293- options : * options ,
291+ Mailbox : mbox ,
292+ tracker : mbox .tracker .NewSession (),
293+ readOnly : options .ReadOnly ,
294+ recent : make (map [imap.UID ]struct {}),
294295 }
295296}
296297
@@ -304,9 +305,11 @@ func (mbox *Mailbox) NewView(options *imap.SelectOptions) *MailboxView {
304305// selected state.
305306type MailboxView struct {
306307 * Mailbox
307- options imap.SelectOptions // immutable
308- tracker * imapserver.SessionTracker
309- searchRes imap.UIDSet
308+ readOnly bool // immutable
309+ tracker * imapserver.SessionTracker
310+ searchRes imap.UIDSet
311+ recent map [imap.UID ]struct {}
312+ prevNumRecent uint32
310313}
311314
312315// Close releases the resources allocated for the mailbox view.
@@ -335,11 +338,8 @@ func (mbox *MailboxView) Fetch(w *imapserver.FetchWriter, numSet imap.NumSet, op
335338 }
336339
337340 respWriter := w .CreateMessage (mbox .tracker .EncodeSeqNum (seqNum ))
338- err = msg .fetch (respWriter , options )
339-
340- if ! mbox .options .ReadOnly {
341- delete (msg .flags , canonicalFlag ("\\ Recent" ))
342- }
341+ _ , isRecent := mbox .recent [msg .uid ]
342+ err = msg .fetch (respWriter , options , isRecent )
343343 })
344344 return err
345345}
@@ -358,7 +358,8 @@ func (mbox *MailboxView) Search(numKind imapserver.NumKind, criteria *imap.Searc
358358 for i , msg := range mbox .l {
359359 seqNum := mbox .tracker .EncodeSeqNum (uint32 (i ) + 1 )
360360
361- if ! msg .search (seqNum , criteria ) {
361+ _ , isRecent := mbox .recent [msg .uid ]
362+ if ! msg .search (seqNum , criteria , isRecent ) {
362363 continue
363364 }
364365
@@ -438,7 +439,19 @@ func (mbox *MailboxView) Store(w *imapserver.FetchWriter, numSet imap.NumSet, fl
438439}
439440
440441func (mbox * MailboxView ) Poll (w * imapserver.UpdateWriter , allowExpunge bool ) error {
441- return mbox .tracker .Poll (w , allowExpunge )
442+ if err := mbox .tracker .Poll (w , allowExpunge ); err != nil {
443+ return err
444+ }
445+ mbox .mutex .Lock ()
446+ mbox .pollRecentLocked ()
447+ numRecent := uint32 (len (mbox .recent ))
448+ sendNumRecent := numRecent != mbox .prevNumRecent
449+ mbox .prevNumRecent = numRecent
450+ mbox .mutex .Unlock ()
451+ if sendNumRecent {
452+ w .WriteNumRecent (numRecent )
453+ }
454+ return nil
442455}
443456
444457func (mbox * MailboxView ) Idle (w * imapserver.UpdateWriter , stop <- chan struct {}) error {
@@ -518,3 +531,15 @@ func staticNumRange(start, stop *uint32, max uint32) {
518531 * start , * stop = * stop , * start
519532 }
520533}
534+
535+ func (mbox * MailboxView ) pollRecentLocked () {
536+ if mbox .readOnly {
537+ return
538+ }
539+ for _ , msg := range mbox .l {
540+ if _ , ok := msg .flags [canonicalFlag ("\\ Recent" )]; ok {
541+ mbox .recent [msg .uid ] = struct {}{}
542+ delete (msg .flags , canonicalFlag ("\\ Recent" ))
543+ }
544+ }
545+ }
0 commit comments