Unseen is first sequence number of unseen message not count of messages

This commit is contained in:
Michal Horejsek
2020-04-06 10:54:14 +02:00
parent ea0f3115a3
commit c939893131
11 changed files with 33 additions and 23 deletions

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated by ./release-notes.sh at Mon Apr 6 08:14:14 CEST 2020. DO NOT EDIT.
// Code generated by ./release-notes.sh at Mon Apr 6 10:56:36 CEST 2020. DO NOT EDIT.
package bridge

View File

@ -125,11 +125,12 @@ func (im *imapMailbox) Status(items []imap.StatusItem) (*imap.MailboxStatus, err
message.ThunderbirdNonJunkFlag,
}
dbTotal, dbUnread, err := im.storeMailbox.GetCounts()
l.Debugln("DB: total", dbTotal, "unread", dbUnread, "err", err)
dbTotal, dbUnread, dbUnreadSeqNum, err := im.storeMailbox.GetCounts()
l.Debugln("DB: total", dbTotal, "unread", dbUnread, "unreadSeqNum", dbUnreadSeqNum, "err", err)
if err == nil {
status.Messages = uint32(dbTotal)
status.Unseen = uint32(dbUnread)
status.UnseenSeqNum = uint32(dbUnreadSeqNum)
}
if status.UidNext, err = im.storeMailbox.GetNextUID(); err != nil {

View File

@ -68,7 +68,7 @@ type storeMailboxProvider interface {
GetAPIIDsFromSequenceRange(start, stop uint32) ([]string, error)
GetLatestAPIID() (string, error)
GetNextUID() (uint32, error)
GetCounts() (dbTotal, dbUnread uint, err error)
GetCounts() (dbTotal, dbUnread, dbUnreadSeqNum uint, err error)
GetUIDList(apiIDs []string) *uidplus.OrderedSeq
GetUIDByHeader(header *mail.Header) uint32
GetDelimiter() string

View File

@ -76,18 +76,20 @@ func (store *Store) imapDeleteMessage(address, mailboxName string, sequenceNumbe
store.imapSendUpdate(update)
}
func (store *Store) imapMailboxStatus(address, mailboxName string, total, unread uint) {
func (store *Store) imapMailboxStatus(address, mailboxName string, total, unread, unreadSeqNum uint) {
store.log.WithFields(logrus.Fields{
"address": address,
"mailbox": mailboxName,
"total": total,
"unread": unread,
"unreadSeqNum": unreadSeqNum,
}).Trace("IDLE status")
update := new(imapBackend.MailboxUpdate)
update.Update = imapBackend.NewUpdate(address, mailboxName)
update.MailboxStatus = imap.NewMailboxStatus(mailboxName, []imap.StatusItem{imap.StatusMessages, imap.StatusUnseen})
update.MailboxStatus.Messages = uint32(total)
update.MailboxStatus.Unseen = uint32(unread)
update.MailboxStatus.UnseenSeqNum = uint32(unreadSeqNum)
store.imapSendUpdate(update)
}

View File

@ -105,8 +105,8 @@ func checkMessageUpdate(username, mailbox string, seqNum, uid int) func(interfac
return func(update interface{}) bool {
switch u := update.(type) {
case *imapBackend.MessageUpdate:
return (u.Update.Username == username &&
u.Update.Mailbox == mailbox &&
return (u.Update.Username() == username &&
u.Update.Mailbox() == mailbox &&
u.Message.SeqNum == uint32(seqNum) &&
u.Message.Uid == uint32(uid))
default:
@ -119,8 +119,8 @@ func checkMessageDelete(username, mailbox string, seqNum int) func(interface{})
return func(update interface{}) bool {
switch u := update.(type) {
case *imapBackend.ExpungeUpdate:
return (u.Update.Username == username &&
u.Update.Mailbox == mailbox &&
return (u.Update.Username() == username &&
u.Update.Mailbox() == mailbox &&
u.SeqNum == uint32(seqNum))
default:
return false

View File

@ -81,7 +81,7 @@ func syncDraftsIfNecssary(tx *bolt.Tx, mb *Mailbox) { //nolint[funlen]
// If the drafts mailbox total is non-zero, it means it has already been used
// and there is no need to continue. Otherwise, we may need to do an initial sync.
total, _, err := mb.txGetCounts(tx)
total, _, _, err := mb.txGetCounts(tx)
if err != nil || total != 0 {
return
}

View File

@ -28,15 +28,15 @@ import (
)
// GetCounts returns numbers of total and unread messages in this mailbox bucket.
func (storeMailbox *Mailbox) GetCounts() (total, unread uint, err error) {
func (storeMailbox *Mailbox) GetCounts() (total, unread, unseenSeqNum uint, err error) {
err = storeMailbox.db().View(func(tx *bolt.Tx) error {
total, unread, err = storeMailbox.txGetCounts(tx)
total, unread, unseenSeqNum, err = storeMailbox.txGetCounts(tx)
return err
})
return
}
func (storeMailbox *Mailbox) txGetCounts(tx *bolt.Tx) (total, unread uint, err error) {
func (storeMailbox *Mailbox) txGetCounts(tx *bolt.Tx) (total, unread, unseenSeqNum uint, err error) {
// For total it would be enough to use `bolt.Bucket.Stats().KeyN` but
// we also need to retrieve the count of unread emails therefore we are
// looping all messages in this mailbox by `bolt.Cursor`
@ -48,16 +48,19 @@ func (storeMailbox *Mailbox) txGetCounts(tx *bolt.Tx) (total, unread uint, err e
total++
rawMsg := metaBucket.Get(apiID)
if rawMsg == nil {
return 0, 0, ErrNoSuchAPIID
return 0, 0, 0, ErrNoSuchAPIID
}
// Do not unmarshal whole JSON to speed up the looping.
// Instead, we assume it will contain JSON int field `Unread`
// where `1` means true (i.e. message is unread)
if bytes.Contains(rawMsg, []byte(`"Unread":1`)) {
if unseenSeqNum == 0 {
unseenSeqNum = total
}
unread++
}
}
return total, unread, err
return total, unread, unseenSeqNum, err
}
type mailboxCounts struct {

View File

@ -376,7 +376,7 @@ func (storeMailbox *Mailbox) txDeleteMessage(tx *bolt.Tx, apiID string) error {
}
func (storeMailbox *Mailbox) txMailboxStatusUpdate(tx *bolt.Tx) error {
total, unread, err := storeMailbox.txGetCounts(tx)
total, unread, unreadSeqNum, err := storeMailbox.txGetCounts(tx)
if err != nil {
return errors.Wrap(err, "cannot get counts for mailbox status update")
}
@ -385,6 +385,7 @@ func (storeMailbox *Mailbox) txMailboxStatusUpdate(tx *bolt.Tx) error {
storeMailbox.labelName,
total,
unread,
unreadSeqNum,
)
return nil
}

View File

@ -75,7 +75,7 @@ func (store *Store) isSynced(countsOnAPI []*pmapi.MessagesCount) (bool, error) {
)
}
mboxTot, mboxUnread, err := mbox.GetCounts()
mboxTot, mboxUnread, _, err := mbox.GetCounts()
if err != nil {
errW := errors.Wrap(err, "cannot count messages")
store.log.

View File

@ -10,6 +10,9 @@ Feature: IMAP get mailbox info
Scenario: Mailbox info contains mailbox name
When IMAP client gets info of "INBOX"
Then IMAP response contains "2 EXISTS"
And IMAP response contains "UNSEEN 1"
# Messages are inserted in opposite way to keep increasing UID.
# Sequence numbers are then opposite than listed above.
# Unseen should have first unseen message.
And IMAP response contains "UNSEEN 2"
And IMAP response contains "UIDNEXT 3"
And IMAP response contains "UIDVALIDITY"

View File

@ -93,7 +93,7 @@ func mailboxForAddressOfUserHasNumberOfMessages(mailboxName, bddAddressID, bddUs
start := time.Now()
for {
afterLimit := time.Since(start) > ctx.EventLoopTimeout()
total, _, _ := mailbox.GetCounts()
total, _, _, _ := mailbox.GetCounts()
if total == uint(countOfMessages) {
break
}