Fix bug gathering "changes" to broadcast during a mailbox rename in certain situations

We weren't appending the individual changes to the slice, but the entire slice.
Since "Change" is an "any", this isn't a type error. So make a Change a
non-empty interface (I had seen an issue like this coming, should have made it
an interface then, at least now we have a reasonable method, to get the modseq
of a change).

Found while working on an imap webpush prototype.
This commit is contained in:
Mechiel Lukkien
2025-03-15 10:45:35 +01:00
parent 0cf0bfb8a6
commit eadbda027c
2 changed files with 28 additions and 2 deletions

View File

@ -37,7 +37,9 @@ type UID uint32 // IMAP UID.
// Change to mailboxes/subscriptions/messages in an account. One of the Change*
// types in this package.
type Change any
type Change interface {
ChangeModSeq() ModSeq // returns -1 for "modseq not applicable"
}
// ChangeAddUID is sent for a new message in a mailbox.
type ChangeAddUID struct {
@ -48,6 +50,8 @@ type ChangeAddUID struct {
Keywords []string // Other flags.
}
func (c ChangeAddUID) ChangeModSeq() ModSeq { return c.ModSeq }
// ChangeRemoveUIDs is sent for removal of one or more messages from a mailbox.
type ChangeRemoveUIDs struct {
MailboxID int64
@ -56,6 +60,8 @@ type ChangeRemoveUIDs struct {
MsgIDs []int64 // Message.ID, for erasing, order does not necessarily correspond with UIDs!
}
func (c ChangeRemoveUIDs) ChangeModSeq() ModSeq { return c.ModSeq }
// ChangeFlags is sent for an update to flags for a message, e.g. "Seen".
type ChangeFlags struct {
MailboxID int64
@ -66,6 +72,8 @@ type ChangeFlags struct {
Keywords []string // Non-system/well-known flags/keywords/labels.
}
func (c ChangeFlags) ChangeModSeq() ModSeq { return c.ModSeq }
// ChangeThread is sent when muted/collapsed changes.
type ChangeThread struct {
MessageIDs []int64
@ -73,6 +81,8 @@ type ChangeThread struct {
Collapsed bool
}
func (c ChangeThread) ChangeModSeq() ModSeq { return -1 }
// ChangeRemoveMailbox is sent for a removed mailbox.
type ChangeRemoveMailbox struct {
MailboxID int64
@ -80,6 +90,8 @@ type ChangeRemoveMailbox struct {
ModSeq ModSeq
}
func (c ChangeRemoveMailbox) ChangeModSeq() ModSeq { return c.ModSeq }
// ChangeAddMailbox is sent for a newly created mailbox.
type ChangeAddMailbox struct {
Mailbox Mailbox
@ -87,6 +99,8 @@ type ChangeAddMailbox struct {
ModSeq ModSeq
}
func (c ChangeAddMailbox) ChangeModSeq() ModSeq { return c.ModSeq }
// ChangeRenameMailbox is sent for a rename mailbox.
type ChangeRenameMailbox struct {
MailboxID int64
@ -96,12 +110,16 @@ type ChangeRenameMailbox struct {
ModSeq ModSeq
}
func (c ChangeRenameMailbox) ChangeModSeq() ModSeq { return c.ModSeq }
// ChangeAddSubscription is sent for an added subscription to a mailbox.
type ChangeAddSubscription struct {
Name string
Flags []string // For additional IMAP flags like \NonExistent.
}
func (c ChangeAddSubscription) ChangeModSeq() ModSeq { return -1 }
// ChangeMailboxCounts is sent when the number of total/deleted/unseen/unread messages changes.
type ChangeMailboxCounts struct {
MailboxID int64
@ -109,6 +127,8 @@ type ChangeMailboxCounts struct {
MailboxCounts
}
func (c ChangeMailboxCounts) ChangeModSeq() ModSeq { return -1 }
// ChangeMailboxSpecialUse is sent when a special-use flag changes.
type ChangeMailboxSpecialUse struct {
MailboxID int64
@ -117,6 +137,8 @@ type ChangeMailboxSpecialUse struct {
ModSeq ModSeq
}
func (c ChangeMailboxSpecialUse) ChangeModSeq() ModSeq { return c.ModSeq }
// ChangeMailboxKeywords is sent when keywords are changed for a mailbox. For
// example, when a message is added with a previously unseen keyword.
type ChangeMailboxKeywords struct {
@ -125,6 +147,8 @@ type ChangeMailboxKeywords struct {
Keywords []string
}
func (c ChangeMailboxKeywords) ChangeModSeq() ModSeq { return -1 }
// ChangeAnnotation is sent when an annotation is added/updated/removed, either for
// a mailbox or a global per-account annotation. The value is not included.
type ChangeAnnotation struct {
@ -134,6 +158,8 @@ type ChangeAnnotation struct {
ModSeq ModSeq
}
func (c ChangeAnnotation) ChangeModSeq() ModSeq { return c.ModSeq }
func messageEraser(donec chan struct{}, cleanc chan map[*Account][]int64) {
log := mlog.New("store", nil)