@@ -25,6 +25,7 @@ type Mailbox struct {
2525 subscribed bool
2626 l []* message
2727 uidNext uint32
28+ flags map [imap.Flag ]struct {}
2829}
2930
3031// NewMailbox creates a new mailbox.
@@ -33,6 +34,7 @@ func NewMailbox(name string) *Mailbox {
3334 tracker : imapserver .NewMailboxTracker (0 ),
3435 name : name ,
3536 uidNext : 1 ,
37+ flags : make (map [imap.Flag ]struct {}),
3638 }
3739}
3840
@@ -149,6 +151,8 @@ func (mbox *Mailbox) appendBytes(buf []byte, options *imap.AppendOptions) *imap.
149151 mbox .l = append (mbox .l , msg )
150152 mbox .tracker .QueueNumMessages (uint32 (len (mbox .l )))
151153
154+ mbox .addFlagsLocked (options .Flags )
155+
152156 return & imap.AppendData {
153157 UIDValidity : uidValidity ,
154158 UID : msg .uid ,
@@ -169,7 +173,7 @@ func (mbox *Mailbox) SetSubscribed(subscribed bool) {
169173}
170174
171175func (mbox * Mailbox ) selectDataLocked () * imap.SelectData {
172- flags := mbox .flagsLocked ( )
176+ flags := flagMapToList ( mbox .flags )
173177
174178 permanentFlags := make ([]imap.Flag , len (flags ))
175179 copy (permanentFlags , flags )
@@ -184,24 +188,17 @@ func (mbox *Mailbox) selectDataLocked() *imap.SelectData {
184188 }
185189}
186190
187- func (mbox * Mailbox ) flagsLocked () []imap.Flag {
188- m := make ( map [imap. Flag ] struct {})
189- for _ , msg := range mbox . l {
190- for flag := range msg .flags {
191- m [ flag ] = struct {}{}
191+ func (mbox * Mailbox ) addFlagsLocked ( flags []imap.Flag ) {
192+ changed := false
193+ for _ , flag := range flags {
194+ if _ , ok := mbox .flags [ canonicalFlag ( flag )]; ! ok {
195+ changed = true
192196 }
197+ mbox .flags [canonicalFlag (flag )] = struct {}{}
193198 }
194-
195- var l []imap.Flag
196- for flag := range m {
197- l = append (l , flag )
199+ if changed {
200+ mbox .tracker .QueueMailboxFlags (flagMapToList (mbox .flags ))
198201 }
199-
200- sort .Slice (l , func (i , j int ) bool {
201- return l [i ] < l [j ]
202- })
203-
204- return l
205202}
206203
207204func (mbox * Mailbox ) Expunge (w * imapserver.ExpungeWriter , uids * imap.SeqSet ) error {
@@ -351,16 +348,30 @@ func (mbox *MailboxView) Search(numKind imapserver.NumKind, criteria *imap.Searc
351348}
352349
353350func (mbox * MailboxView ) Store (w * imapserver.FetchWriter , numKind imapserver.NumKind , seqSet imap.SeqSet , flags * imap.StoreFlags ) error {
354- mbox .forEach (numKind , seqSet , func (seqNum uint32 , msg * message ) {
355- msg .store (flags )
356- mbox .Mailbox .tracker .QueueMessageFlags (seqNum , msg .uid , msg .flagList (), mbox .tracker )
357- })
351+ mbox .store (numKind , seqSet , flags )
358352 if ! flags .Silent {
359353 return mbox .Fetch (w , numKind , seqSet , []imap.FetchItem {imap .FetchItemFlags })
360354 }
361355 return nil
362356}
363357
358+ func (mbox * MailboxView ) store (numKind imapserver.NumKind , seqSet imap.SeqSet , flags * imap.StoreFlags ) {
359+ mbox .mutex .Lock ()
360+ defer mbox .mutex .Unlock ()
361+
362+ // We need to announce the new flags via a FLAGS response before sending
363+ // FETCH FLAGS responses
364+ switch flags .Op {
365+ case imap .StoreFlagsSet , imap .StoreFlagsAdd :
366+ mbox .addFlagsLocked (flags .Flags )
367+ }
368+
369+ mbox .forEachLocked (numKind , seqSet , func (seqNum uint32 , msg * message ) {
370+ msg .store (flags )
371+ mbox .Mailbox .tracker .QueueMessageFlags (seqNum , msg .uid , msg .flagList (), mbox .tracker )
372+ })
373+ }
374+
364375func (mbox * MailboxView ) Poll (w * imapserver.UpdateWriter , allowExpunge bool ) error {
365376 return mbox .tracker .Poll (w , allowExpunge )
366377}
@@ -427,3 +438,16 @@ func (mbox *MailboxView) staticSeqSet(seqSet imap.SeqSet, numKind imapserver.Num
427438 }
428439 }
429440}
441+
442+ func flagMapToList (m map [imap.Flag ]struct {}) []imap.Flag {
443+ var l []imap.Flag
444+ for flag := range m {
445+ l = append (l , flag )
446+ }
447+
448+ sort .Slice (l , func (i , j int ) bool {
449+ return l [i ] < l [j ]
450+ })
451+
452+ return l
453+ }
0 commit comments