Skip to content

Commit c13c0d5

Browse files
committed
wip
1 parent dda7e0f commit c13c0d5

File tree

3 files changed

+79
-21
lines changed

3 files changed

+79
-21
lines changed

imapserver/imapmemserver/mailbox.go

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
289289
func (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.
305306
type 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

440441
func (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

444457
func (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+
}

imapserver/imapmemserver/message.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ type message struct {
2525
flags map[imap.Flag]struct{}
2626
}
2727

28-
func (msg *message) fetch(w *imapserver.FetchResponseWriter, options *imap.FetchOptions) error {
28+
func (msg *message) fetch(w *imapserver.FetchResponseWriter, options *imap.FetchOptions, isRecent bool) error {
2929
w.WriteUID(msg.uid)
3030

3131
if options.Flags {
32-
w.WriteFlags(msg.flagList())
32+
flags := msg.flagList()
33+
if isRecent {
34+
flags = append(flags, "\\Recent")
35+
}
36+
w.WriteFlags(flags)
3337
}
3438
if options.InternalDate {
3539
w.WriteInternalDate(msg.t)
@@ -121,7 +125,7 @@ func (msg *message) reader() *gomessage.Entity {
121125
return r
122126
}
123127

124-
func (msg *message) search(seqNum uint32, criteria *imap.SearchCriteria) bool {
128+
func (msg *message) search(seqNum uint32, criteria *imap.SearchCriteria, isRecent bool) bool {
125129
for _, seqSet := range criteria.SeqNum {
126130
if seqNum == 0 || !seqSet.Contains(seqNum) {
127131
return false
@@ -136,13 +140,20 @@ func (msg *message) search(seqNum uint32, criteria *imap.SearchCriteria) bool {
136140
return false
137141
}
138142

143+
hasFlag := func(flag imap.Flag) bool {
144+
if isRecent && canonicalFlag(flag) == canonicalFlag("\\Recent") {
145+
return true
146+
}
147+
_, ok := msg.flags[canonicalFlag(flag)]
148+
return ok
149+
}
139150
for _, flag := range criteria.Flag {
140-
if _, ok := msg.flags[canonicalFlag(flag)]; !ok {
151+
if !hasFlag(flag) {
141152
return false
142153
}
143154
}
144155
for _, flag := range criteria.NotFlag {
145-
if _, ok := msg.flags[canonicalFlag(flag)]; ok {
156+
if hasFlag(flag) {
146157
return false
147158
}
148159
}
@@ -183,12 +194,12 @@ func (msg *message) search(seqNum uint32, criteria *imap.SearchCriteria) bool {
183194
}
184195

185196
for _, not := range criteria.Not {
186-
if msg.search(seqNum, &not) {
197+
if msg.search(seqNum, &not, isRecent) {
187198
return false
188199
}
189200
}
190201
for _, or := range criteria.Or {
191-
if !msg.search(seqNum, &or[0]) && !msg.search(seqNum, &or[1]) {
202+
if !msg.search(seqNum, &or[0], isRecent) && !msg.search(seqNum, &or[1], isRecent) {
192203
return false
193204
}
194205
}

imapserver/imapmemserver/session.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,12 @@ func (sess *UserSession) Select(name string, options *imap.SelectOptions) (*imap
4141
mbox.mutex.Lock()
4242
defer mbox.mutex.Unlock()
4343
sess.mailbox = mbox.NewView(options)
44-
return mbox.selectDataLocked(), nil
44+
data := mbox.selectDataLocked()
45+
if !options.ReadOnly && data.NumRecent > 0 {
46+
sess.mailbox.pollRecentLocked()
47+
sess.mailbox.prevNumRecent = data.NumRecent
48+
}
49+
return data, nil
4550
}
4651

4752
func (sess *UserSession) Unselect() error {
@@ -138,3 +143,20 @@ func (sess *UserSession) Idle(w *imapserver.UpdateWriter, stop <-chan struct{})
138143
}
139144
return sess.mailbox.Idle(w, stop)
140145
}
146+
147+
func (sess *UserSession) Status(name string, options *imap.StatusOptions) (*imap.StatusData, error) {
148+
data, err := sess.user.Status(name, options)
149+
if err != nil {
150+
return nil, err
151+
}
152+
153+
if mbox := sess.mailbox; mbox != nil && data.NumRecent != nil {
154+
mbox.mutex.Lock()
155+
if mbox.name == name {
156+
*data.NumRecent += uint32(len(mbox.recent))
157+
}
158+
mbox.mutex.Unlock()
159+
}
160+
161+
return data, nil
162+
}

0 commit comments

Comments
 (0)