Implement deleted flag GODT-461

This commit is contained in:
Jakub
2020-08-25 07:16:13 +02:00
committed by Michal Horejsek
parent 803353e300
commit 66e04dd5ed
25 changed files with 396 additions and 135 deletions

View File

@ -173,9 +173,8 @@ func (im *imapMailbox) Check() error {
// Expunge permanently removes all messages that have the \Deleted flag set
// from the currently selected mailbox.
// Our messages do not have \Deleted flag, nothing to do here.
func (im *imapMailbox) Expunge() error {
return nil
return im.storeMailbox.RemoveDeleted()
}
func (im *imapMailbox) ListQuotas() ([]string, error) {

View File

@ -220,6 +220,9 @@ func (im *imapMailbox) getMessage(storeMessage storeMessageProvider, items []ima
}
case imap.FetchFlags:
msg.Flags = message.GetFlags(m)
if storeMessage.IsMarkedDeleted() {
msg.Flags = append(msg.Flags, imap.DeletedFlag)
}
case imap.FetchInternalDate:
msg.InternalDate = time.Unix(m.Time, 0)
case imap.FetchRFC822Size:
@ -237,26 +240,30 @@ func (im *imapMailbox) getMessage(storeMessage storeMessageProvider, items []ima
return nil, err
}
default:
s := item
var section *imap.BodySectionName
if section, err = imap.ParseBodySectionName(s); err != nil {
err = nil // Ignore error
break
}
var literal imap.Literal
if literal, err = im.getMessageBodySection(storeMessage, section); err != nil {
if err = im.getLiteralForSection(item, msg, storeMessage); err != nil {
return
}
msg.Body[section] = literal
}
}
return msg, err
}
func (im *imapMailbox) getLiteralForSection(itemSection imap.FetchItem, msg *imap.Message, storeMessage storeMessageProvider) error {
section, err := imap.ParseBodySectionName(itemSection)
if err != nil { // Ignore error
return nil
}
var literal imap.Literal
if literal, err = im.getMessageBodySection(storeMessage, section); err != nil {
return err
}
msg.Body[section] = literal
return nil
}
func (im *imapMailbox) getBodyStructure(storeMessage storeMessageProvider) (
structure *message.BodyStructure,
bodyReader *bytes.Reader, err error,

View File

@ -97,7 +97,11 @@ func (im *imapMailbox) setFlags(messageIDs, flags []string) error {
}
if deleted {
if err := im.storeMailbox.DeleteMessages(messageIDs); err != nil {
if err := im.storeMailbox.MarkMessagesDeleted(messageIDs); err != nil {
return err
}
} else {
if err := im.storeMailbox.MarkMessagesUndeleted(messageIDs); err != nil {
return err
}
}
@ -145,11 +149,15 @@ func (im *imapMailbox) addOrRemoveFlags(operation imap.FlagsOp, messageIDs, flag
}
}
case imap.DeletedFlag:
if operation == imap.RemoveFlags {
break // Nothing to do, no message has the \Deleted flag.
}
if err := im.storeMailbox.DeleteMessages(messageIDs); err != nil {
return err
switch operation {
case imap.AddFlags:
if err := im.storeMailbox.MarkMessagesDeleted(messageIDs); err != nil {
return err
}
case imap.RemoveFlags:
if err := im.storeMailbox.MarkMessagesUndeleted(messageIDs); err != nil {
return err
}
}
case imap.AnsweredFlag, imap.DraftFlag, imap.RecentFlag:
// Not supported.
@ -349,6 +357,9 @@ func (im *imapMailbox) SearchMessages(isUID bool, criteria *imap.SearchCriteria)
if !m.Has(pmapi.FlagOpened) {
messageFlagsMap[imap.RecentFlag] = true
}
if storeMessage.IsMarkedDeleted() {
messageFlagsMap[imap.DeletedFlag] = true
}
flagMatch := true
for _, flag := range criteria.WithFlags {

View File

@ -83,8 +83,10 @@ type storeMailboxProvider interface {
MarkMessagesUnread(apiID []string) error
MarkMessagesStarred(apiID []string) error
MarkMessagesUnstarred(apiID []string) error
MarkMessagesDeleted(apiID []string) error
MarkMessagesUndeleted(apiID []string) error
ImportMessage(msg *pmapi.Message, body []byte, labelIDs []string) error
DeleteMessages(apiID []string) error
RemoveDeleted() error
}
type storeMessageProvider interface {
@ -92,6 +94,7 @@ type storeMessageProvider interface {
UID() (uint32, error)
SequenceNumber() (uint32, error)
Message() *pmapi.Message
IsMarkedDeleted() bool
SetSize(int64) error
SetContentTypeAndHeader(string, mail.Header) error

View File

@ -25,6 +25,7 @@
package uidplus
import (
"errors"
"fmt"
"github.com/emersion/go-imap"
@ -120,11 +121,51 @@ func (os *OrderedSeq) String() string {
// If not implemented it would cause harmless IMAP error.
//
// This overrides the standard EXPUNGE functionality.
type UIDExpunge struct{}
type UIDExpunge struct {
expunge *server.Expunge
seqset *imap.SeqSet
}
func (e *UIDExpunge) Parse(fields []interface{}) error { log.Traceln("parse", fields); return nil }
func (e *UIDExpunge) Handle(conn server.Conn) error { log.Traceln("handle"); return nil }
func (e *UIDExpunge) UidHandle(conn server.Conn) error { log.Traceln("uid handle"); return nil } //nolint[golint]
func newUIDExpunge() *UIDExpunge {
return &UIDExpunge{expunge: &server.Expunge{}}
}
func (e *UIDExpunge) Parse(fields []interface{}) error {
if len(fields) < 1 { // asuming no UID
return e.expunge.Parse(fields)
}
var err error
if seqset, ok := fields[0].(string); !ok {
return errors.New("sequence set must be an atom")
} else if e.seqset, err = imap.ParseSeqSet(seqset); err != nil {
return err
}
return nil
}
func (e *UIDExpunge) Handle(conn server.Conn) error {
log.Traceln("handle")
return e.expunge.Handle(conn)
}
func (e *UIDExpunge) UidHandle(conn server.Conn) error { //nolint[golint]
log.Traceln("uid handle")
// 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.
//
// NOTE missing implementation: It will probably need mailbox interface
// change: ExpungeUIDs(seqSet) not sure how to combine with original
// e.expunge.Handle().
//
// Current implementation deletes all marked as deleted.
return e.expunge.Handle(conn)
}
type extension struct{}
@ -143,7 +184,7 @@ func (ext *extension) Capabilities(c server.Conn) []string {
func (ext *extension) Command(name string) server.HandlerFactory {
if name == "EXPUNGE" {
return func() server.Handler {
return &UIDExpunge{}
return newUIDExpunge()
}
}