@@ -23,6 +23,7 @@ type Mailbox struct {
23
23
subscribed bool
24
24
l []* message
25
25
uidNext imap.UID
26
+ flags map [imap.Flag ]struct {}
26
27
}
27
28
28
29
// NewMailbox creates a new mailbox.
@@ -32,6 +33,7 @@ func NewMailbox(name string, uidValidity uint32) *Mailbox {
32
33
uidValidity : uidValidity ,
33
34
name : name ,
34
35
uidNext : 1 ,
36
+ flags : make (map [imap.Flag ]struct {}),
35
37
}
36
38
}
37
39
@@ -148,6 +150,8 @@ func (mbox *Mailbox) appendBytes(buf []byte, options *imap.AppendOptions) *imap.
148
150
mbox .l = append (mbox .l , msg )
149
151
mbox .tracker .QueueNumMessages (uint32 (len (mbox .l )))
150
152
153
+ mbox .addFlagsLocked (options .Flags )
154
+
151
155
return & imap.AppendData {
152
156
UIDValidity : mbox .uidValidity ,
153
157
UID : msg .uid ,
@@ -168,7 +172,7 @@ func (mbox *Mailbox) SetSubscribed(subscribed bool) {
168
172
}
169
173
170
174
func (mbox * Mailbox ) selectDataLocked () * imap.SelectData {
171
- flags := mbox .flagsLocked ( )
175
+ flags := flagMapToList ( mbox .flags )
172
176
173
177
permanentFlags := make ([]imap.Flag , len (flags ))
174
178
copy (permanentFlags , flags )
@@ -183,24 +187,17 @@ func (mbox *Mailbox) selectDataLocked() *imap.SelectData {
183
187
}
184
188
}
185
189
186
- func (mbox * Mailbox ) flagsLocked () []imap.Flag {
187
- m := make ( map [imap. Flag ] struct {})
188
- for _ , msg := range mbox . l {
189
- for flag := range msg .flags {
190
- m [ flag ] = struct {}{}
190
+ func (mbox * Mailbox ) addFlagsLocked ( flags []imap.Flag ) {
191
+ changed := false
192
+ for _ , flag := range flags {
193
+ if _ , ok := mbox .flags [ canonicalFlag ( flag )]; ! ok {
194
+ changed = true
191
195
}
196
+ mbox .flags [canonicalFlag (flag )] = struct {}{}
192
197
}
193
-
194
- var l []imap.Flag
195
- for flag := range m {
196
- l = append (l , flag )
198
+ if changed {
199
+ mbox .tracker .QueueMailboxFlags (flagMapToList (mbox .flags ))
197
200
}
198
-
199
- sort .Slice (l , func (i , j int ) bool {
200
- return l [i ] < l [j ]
201
- })
202
-
203
- return l
204
201
}
205
202
206
203
func (mbox * Mailbox ) Expunge (w * imapserver.ExpungeWriter , uids * imap.UIDSet ) error {
@@ -393,16 +390,31 @@ func (mbox *MailboxView) staticSearchCriteria(criteria *imap.SearchCriteria) {
393
390
}
394
391
395
392
func (mbox * MailboxView ) Store (w * imapserver.FetchWriter , numSet imap.NumSet , flags * imap.StoreFlags , options * imap.StoreOptions ) error {
396
- mbox .forEach (numSet , func (seqNum uint32 , msg * message ) {
397
- msg .store (flags )
398
- mbox .Mailbox .tracker .QueueMessageFlags (seqNum , msg .uid , msg .flagList (), mbox .tracker )
399
- })
393
+ mbox .store (numSet , flags )
400
394
if ! flags .Silent {
395
+ // TODO: this sends message flags updates before mailbox flags update
401
396
return mbox .Fetch (w , numSet , & imap.FetchOptions {Flags : true })
402
397
}
403
398
return nil
404
399
}
405
400
401
+ func (mbox * MailboxView ) store (numSet imap.NumSet , flags * imap.StoreFlags ) {
402
+ mbox .mutex .Lock ()
403
+ defer mbox .mutex .Unlock ()
404
+
405
+ // We need to announce the new flags via a FLAGS response before sending
406
+ // FETCH FLAGS responses
407
+ switch flags .Op {
408
+ case imap .StoreFlagsSet , imap .StoreFlagsAdd :
409
+ mbox .addFlagsLocked (flags .Flags )
410
+ }
411
+
412
+ mbox .forEachLocked (numSet , func (seqNum uint32 , msg * message ) {
413
+ msg .store (flags )
414
+ mbox .Mailbox .tracker .QueueMessageFlags (seqNum , msg .uid , msg .flagList (), mbox .tracker )
415
+ })
416
+ }
417
+
406
418
func (mbox * MailboxView ) Poll (w * imapserver.UpdateWriter , allowExpunge bool ) error {
407
419
return mbox .tracker .Poll (w , allowExpunge )
408
420
}
@@ -484,3 +496,16 @@ func staticNumRange(start, stop *uint32, max uint32) {
484
496
* start , * stop = * stop , * start
485
497
}
486
498
}
499
+
500
+ func flagMapToList (m map [imap.Flag ]struct {}) []imap.Flag {
501
+ var l []imap.Flag
502
+ for flag := range m {
503
+ l = append (l , flag )
504
+ }
505
+
506
+ sort .Slice (l , func (i , j int ) bool {
507
+ return l [i ] < l [j ]
508
+ })
509
+
510
+ return l
511
+ }
0 commit comments