[GODT-797] EXPUNGE waits for APPEND to prevent data loss when Outlook moves from Spam to Inbox

This commit is contained in:
Jakub
2021-01-14 16:39:34 +01:00
parent 2f149eb545
commit 44f8a49b47
6 changed files with 33 additions and 3 deletions

View File

@ -177,6 +177,17 @@ func (im *imapMailbox) Check() error {
// Expunge permanently removes all messages that have the \Deleted flag set
// from the currently selected mailbox.
func (im *imapMailbox) Expunge() error {
// Wait for any APPENDS to finish in order to avoid data loss when
// Outlook sends commands too quickly STORE \Deleted, APPEND, EXPUNGE,
// APPEND FINISHED:
//
// Based on Outlook APPEND request we will not create new message but
// move the original to desired mailbox. If the message is currently
// in Trash or Spam and EXPUNGE happens before APPEND processing is
// finished the message is deleted from Proton instead of moved to
// the desired mailbox.
im.user.waitForAppend()
im.user.backend.setUpdatesBeBlocking(im.user.currentAddressLowercase, im.name, operationDeleteMessage)
defer im.user.backend.unsetUpdatesBeBlocking(im.user.currentAddressLowercase, im.name, operationDeleteMessage)

View File

@ -70,6 +70,9 @@ func (im *imapMailbox) CreateMessage(flags []string, date time.Time, body imap.L
// Called from go-imap in goroutines - we need to handle panics for each function.
defer im.panicHandler.HandlePanic()
im.user.appendStarted()
defer im.user.appendFinished()
m, _, _, readers, err := message.Parse(body)
if err != nil {
return err

View File

@ -20,6 +20,7 @@ package imap
import (
"errors"
"strings"
"sync"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
imapquota "github.com/emersion/go-imap-quota"
@ -39,6 +40,8 @@ type imapUser struct {
storeAddress storeAddressProvider
currentAddressLowercase string
appendInProcess sync.WaitGroup
}
// This method should eventually no longer be necessary. Everything should go via store.
@ -238,3 +241,15 @@ func (iu *imapUser) CreateMessageLimit() *uint32 {
upload := uint32(maxUpload)
return &upload
}
func (iu *imapUser) appendStarted() {
iu.appendInProcess.Add(1)
}
func (iu *imapUser) appendFinished() {
iu.appendInProcess.Done()
}
func (iu *imapUser) waitForAppend() {
iu.appendInProcess.Wait()
}