imapserver: check for UIDNEXT overflow when adding a message to a mailbox

Return an error, with instructions so a user may be able to work around the
issue.
This commit is contained in:
Mechiel Lukkien 2025-04-11 18:22:29 +02:00
parent 507ca73b96
commit 1a6d268e1d
No known key found for this signature in database
3 changed files with 21 additions and 6 deletions

View File

@ -4733,7 +4733,8 @@ func (c *conn) cmdxCopy(isUID bool, tag, cmd string, p *parser) {
// Reserve the uids in the destination mailbox.
uidFirst := mbDst.UIDNext
mbDst.UIDNext += store.UID(len(uids))
err = mbDst.UIDNextAdd(len(uids))
xcheckf(err, "adding uid")
// Fetch messages from database.
q := bstore.QueryTx[store.Message](tx)
@ -5043,7 +5044,8 @@ func (c *conn) xmoveMessages(tx *bstore.Tx, q *bstore.Query[store.Message], expe
nm := om
nm.MailboxID = mbDst.ID
nm.UID = mbDst.UIDNext
mbDst.UIDNext++
err := mbDst.UIDNextAdd(1)
xcheckf(err, "adding uid")
nm.ModSeq = modseq
nm.CreateSeq = modseq
nm.SaveDate = &now
@ -5057,7 +5059,7 @@ func (c *conn) xmoveMessages(tx *bstore.Tx, q *bstore.Query[store.Message], expe
nm.JunkFlagsForMailbox(*mbDst, accConf)
err := tx.Update(&nm)
err = tx.Update(&nm)
xcheckf(err, "updating message with new mailbox")
mbDst.Add(nm.MailboxCounts())

View File

@ -298,6 +298,16 @@ type SpecialUse struct {
Trash bool
}
// UIDNextAdd increases the UIDNext value by n, returning an error on overflow.
func (mb *Mailbox) UIDNextAdd(n int) error {
uidnext := mb.UIDNext + UID(n)
if uidnext < mb.UIDNext {
return fmt.Errorf("uid overflow on mailbox %q (id %d): uidnext %d, adding %d; consider recreating the mailbox and copying its messages to compact", mb.Name, mb.ID, mb.UIDNext, n)
}
mb.UIDNext = uidnext
return nil
}
// CalculateCounts calculates the full current counts for messages in the mailbox.
func (mb *Mailbox) CalculateCounts(tx *bstore.Tx) (mc MailboxCounts, err error) {
q := bstore.QueryTx[Message](tx)
@ -2218,7 +2228,9 @@ func (a *Account) MessageAdd(log mlog.Log, tx *bstore.Tx, mb *Mailbox, m *Messag
}
if m.UID == 0 {
m.UID = mb.UIDNext
mb.UIDNext++
if err := mb.UIDNextAdd(1); err != nil {
return fmt.Errorf("adding uid: %v", err)
}
}
if m.ModSeq == 0 {
modseq, err := a.NextModSeq(tx)

View File

@ -473,7 +473,8 @@ func (x XOps) MessageMoveTx(ctx context.Context, log mlog.Log, acc *store.Accoun
nm := om
nm.MailboxID = mbDst.ID
nm.UID = mbDst.UIDNext
mbDst.UIDNext++
err := mbDst.UIDNextAdd(1)
x.Checkf(ctx, err, "adding uid")
nm.ModSeq = *modseq
nm.CreateSeq = *modseq
nm.SaveDate = &now
@ -490,7 +491,7 @@ func (x XOps) MessageMoveTx(ctx context.Context, log mlog.Log, acc *store.Accoun
nm.JunkFlagsForMailbox(mbDst, accConf)
err := tx.Update(&nm)
err = tx.Update(&nm)
x.Checkf(ctx, err, "updating message with new mailbox")
mbDst.Add(nm.MailboxCounts())