Support of UID EXPUNGE

This commit is contained in:
Michal Horejsek
2021-01-20 13:16:27 +01:00
parent 07c100bd66
commit 1909ceed67
6 changed files with 101 additions and 23 deletions

View File

@ -191,7 +191,20 @@ func (im *imapMailbox) Expunge() error {
im.user.backend.setUpdatesBeBlocking(im.user.currentAddressLowercase, im.name, operationDeleteMessage)
defer im.user.backend.unsetUpdatesBeBlocking(im.user.currentAddressLowercase, im.name, operationDeleteMessage)
return im.storeMailbox.RemoveDeleted()
return im.storeMailbox.RemoveDeleted(nil)
}
// UIDExpunge permanently removes messages that have the \Deleted flag set
// and UID passed from SeqSet from the currently selected mailbox.
func (im *imapMailbox) UIDExpunge(seqSet *imap.SeqSet) error {
im.user.backend.setUpdatesBeBlocking(im.user.currentAddressLowercase, im.name, operationDeleteMessage)
defer im.user.backend.unsetUpdatesBeBlocking(im.user.currentAddressLowercase, im.name, operationDeleteMessage)
messageIDs, err := im.apiIDsFromSeqSet(true, seqSet)
if err != nil || len(messageIDs) == 0 {
return err
}
return im.storeMailbox.RemoveDeleted(messageIDs)
}
func (im *imapMailbox) ListQuotas() ([]string, error) {

View File

@ -89,7 +89,7 @@ type storeMailboxProvider interface {
MarkMessagesDeleted(apiID []string) error
MarkMessagesUndeleted(apiID []string) error
ImportMessage(msg *pmapi.Message, body []byte, labelIDs []string) error
RemoveDeleted() error
RemoveDeleted(apiIDs []string) error
}
type storeMessageProvider interface {

View File

@ -116,40 +116,70 @@ func (os *OrderedSeq) String() string {
// UIDExpunge implements server.Handler but Bridge is not supporting
// UID EXPUNGE with specific UIDs.
type UIDExpungeMailbox interface {
Expunge() error
UIDExpunge(*imap.SeqSet) error
}
type UIDExpunge struct {
expunge *server.Expunge
SeqSet *imap.SeqSet
}
func newUIDExpunge() *UIDExpunge {
return &UIDExpunge{expunge: &server.Expunge{}}
return &UIDExpunge{}
}
func (e *UIDExpunge) Parse(fields []interface{}) error {
if len(fields) < 1 {
return e.expunge.Parse(fields)
if len(fields) == 0 {
return nil // It could be regular EXPUNGE without arguments.
}
if len(fields) > 1 {
return errors.New("too many arguments")
}
// RFC4315#section-2.1
// The UID EXPUNGE command permanently removes all messages that both
// have the \Deleted flag set and have a UID that is included in the
// specified sequence set from the currently selected mailbox. If a
// message either does not have the \Deleted flag set or has a UID
// that is not included in the specified sequence set, it is not
// affected.
//
// Current implementation supports only deletion of all messages
// marked as deleted. It will probably need mailbox interface change:
// ExpungeUIDs(seqSet). Not sure how to combine with original
// e.expunge.Handle().
return errors.New("UID EXPUNGE with UIDs is not supported")
seqset, ok := fields[0].(string)
if !ok {
return errors.New("sequence set must be an atom")
}
var err error
e.SeqSet, err = imap.ParseSeqSet(seqset)
return err
}
func (e *UIDExpunge) Handle(conn server.Conn) error {
return e.expunge.Handle(conn)
mailbox, err := e.getMailbox(conn)
if err != nil {
return err
}
return mailbox.Expunge()
}
func (e *UIDExpunge) UidHandle(conn server.Conn) error { //nolint[golint]
return e.expunge.Handle(conn)
if e.SeqSet == nil {
return errors.New("missing sequence set")
}
mailbox, err := e.getMailbox(conn)
if err != nil {
return err
}
return mailbox.UIDExpunge(e.SeqSet)
}
func (e *UIDExpunge) getMailbox(conn server.Conn) (UIDExpungeMailbox, error) {
ctx := conn.Context()
if ctx.Mailbox == nil {
return nil, server.ErrNoMailboxSelected
}
if ctx.MailboxReadOnly {
return nil, server.ErrMailboxReadOnly
}
mailbox, ok := ctx.Mailbox.(UIDExpungeMailbox)
if !ok {
return nil, errors.New("UID EXPUNGE is not implemented")
}
return mailbox, nil
}
type extension struct{}

View File

@ -208,14 +208,35 @@ func (storeMailbox *Mailbox) MarkMessagesUndeleted(apiIDs []string) error {
// If the mailbox is All Mail or All Sent, it does nothing.
// If the mailbox is Trash or Spam and message is not in any other mailbox, messages is deleted.
// In all other cases the message is only removed from the mailbox.
func (storeMailbox *Mailbox) RemoveDeleted() error {
// If nil is passed, all messages with \Deleted flag are removed.
// In other cases only messages with \Deleted flag and included in the passed list.
func (storeMailbox *Mailbox) RemoveDeleted(apiIDs []string) error {
storeMailbox.log.Trace("Deleting messages")
apiIDs, err := storeMailbox.GetDeletedAPIIDs()
deletedAPIIDs, err := storeMailbox.GetDeletedAPIIDs()
if err != nil {
return err
}
if apiIDs == nil {
apiIDs = deletedAPIIDs
} else {
filteredAPIIDs := []string{}
for _, apiID := range apiIDs {
found := false
for _, deletedAPIID := range deletedAPIIDs {
if apiID == deletedAPIID {
found = true
break
}
}
if found {
filteredAPIIDs = append(filteredAPIIDs, apiID)
}
}
apiIDs = filteredAPIIDs
}
if len(apiIDs) == 0 {
storeMailbox.log.Debug("List to expunge is empty")
return nil

View File

@ -99,3 +99,16 @@ Feature: IMAP remove messages from mailbox
And there is IMAP client selected in "All Mail"
When IMAP client marks message seq "1" as deleted
Then IMAP response is "IMAP error: NO operation not allowed for 'All Mail' folder"
Scenario: Expunge specific message only
Given there are 5 messages in mailbox "INBOX" for "user"
And there is IMAP client logged in as "user"
And there is IMAP client selected in "INBOX"
When IMAP client marks message seq "1" as deleted
Then IMAP response is "OK"
When IMAP client marks message seq "2" as deleted
Then IMAP response is "OK"
When IMAP client sends command "UID EXPUNGE 1"
Then IMAP response is "OK"
And mailbox "INBOX" for "user" has 4 messages
And message "2" in "INBOX" for "user" is marked as deleted

View File

@ -13,6 +13,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/)
* GODT-804 Added GUI notification on silent update installed (promt to restart).
* GODT-275 Added option to disable autoupdates in settings (default autoupdate is enabled).
* GODT-874 Added manual triggers to Updater module.
* GODT-851 Added support of UID EXPUNGE.
### Changed
* GODT-97 Don't log errors caused by SELECT "".