mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
fix bug with cli import command in case the mbox/maildir had keywords, future delivery to the mailbox would fail with duplicate uid's.
accounts with a mailbox with this problem can be fixed by running the "mox fixuidmeta <account>" command. we were resetting the mailbox uidnext after delivering messages when we were setting new keywords on the mailbox at the end of the import. so in a future delivery attempt to that mailbox, a uid would be chosen that was already present. the fix is to fetch the updated mailbox from the database before setting the new keywords. http/import.go doesn't have this bug because it was already fetching the mailbox before updating keywords (because it can import into many mailboxes, so different code). the "mox verifydata" command (recommended with backups) also warns about this issue (but doesn't fix it) found while working on new functionality (webmail).
This commit is contained in:
parent
700118dbd2
commit
e3d0a3a001
3 changed files with 11 additions and 6 deletions
|
@ -386,6 +386,10 @@ func importctl(ctx context.Context, ctl *ctl, mbox bool) {
|
|||
process(m, msgf, origPath)
|
||||
}
|
||||
|
||||
// Load the mailbox again after delivering, its uidnext has been updated.
|
||||
err = tx.Get(&mb)
|
||||
ctl.xcheck(err, "fetching mailbox")
|
||||
|
||||
// If there are any new keywords, update the mailbox.
|
||||
var changed bool
|
||||
mb.Keywords, changed = store.MergeKeywords(mb.Keywords, maps.Keys(mailboxKeywords))
|
||||
|
|
3
main.go
3
main.go
|
@ -2240,9 +2240,10 @@ open, or is not running.
|
|||
} else if err != nil {
|
||||
return fmt.Errorf("finding message with max uid in mailbox: %w", err)
|
||||
}
|
||||
olduidnext := mb.UIDNext
|
||||
mb.UIDNext = m.UID + 1
|
||||
log.Printf("fixing uidnext to %d (max uid is %d, old uidnext was %d) for mailbox %q (id %d)", mb.UIDNext, m.UID, olduidnext, mb.Name, mb.ID)
|
||||
if err := tx.Update(&mb); err != nil {
|
||||
log.Printf("fixing uidnext to %d (max uid is %d) for mailbox id %d", mb.UIDNext, m.UID, mb.ID)
|
||||
return fmt.Errorf("updating mailbox uidnext: %v", err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -231,20 +231,20 @@ possibly making them potentially no longer readable by the previous version.
|
|||
checkf(err, dbpath, "missing nextuidvalidity")
|
||||
}
|
||||
|
||||
mailboxUIDNexts := map[int64]store.UID{}
|
||||
mailboxes := map[int64]store.Mailbox{}
|
||||
err := bstore.QueryDB[store.Mailbox](ctxbg, db).ForEach(func(mb store.Mailbox) error {
|
||||
mailboxUIDNexts[mb.ID] = mb.UIDNext
|
||||
mailboxes[mb.ID] = mb
|
||||
|
||||
if mb.UIDValidity >= uidvalidity.Next {
|
||||
checkf(errors.New(`inconsistent uidvalidity for mailbox/account, see "mox fixuidmeta"`), dbpath, "mailbox id %d has uidvalidity %d >= account nextuidvalidity %d", mb.ID, mb.UIDValidity, uidvalidity.Next)
|
||||
checkf(errors.New(`inconsistent uidvalidity for mailbox/account, see "mox fixuidmeta"`), dbpath, "mailbox %q (id %d) has uidvalidity %d >= account nextuidvalidity %d", mb.Name, mb.ID, mb.UIDValidity, uidvalidity.Next)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
checkf(err, dbpath, "reading mailboxes to check uidnext consistency")
|
||||
|
||||
err = bstore.QueryDB[store.Message](ctxbg, db).ForEach(func(m store.Message) error {
|
||||
if uidnext := mailboxUIDNexts[m.MailboxID]; m.UID >= uidnext {
|
||||
checkf(errors.New(`inconsistent uidnext for message/mailbox, see "mox fixuidmeta"`), dbpath, "message id %d in mailbox id %d has uid %d >= mailbox uidnext %d", m.ID, m.MailboxID, m.UID, uidnext)
|
||||
if mb := mailboxes[m.MailboxID]; m.UID >= mb.UIDNext {
|
||||
checkf(errors.New(`inconsistent uidnext for message/mailbox, see "mox fixuidmeta"`), dbpath, "message id %d in mailbox %q (id %d) has uid %d >= mailbox uidnext %d", m.ID, mb.Name, mb.ID, m.UID, mb.UIDNext)
|
||||
}
|
||||
|
||||
if m.Expunged {
|
||||
|
|
Loading…
Reference in a new issue