forked from Silverfish/proton-bridge
GODT-1984: Handle permanent message deletion
Only delete messages when unlabeled from trash/spam if they only exists in All Mail and (spam or trash). This patch also ports delete_from_trash.feature and use status rather than fetch to count messages in a mailboxes.
This commit is contained in:
committed by
James Houlahan
parent
df818bc2b8
commit
8f420d728c
@ -165,6 +165,7 @@ func TestFeatures(testingT *testing.T) {
|
||||
ctx.Step(`^IMAP client "([^"]*)" sees (\d+) messages in "([^"]*)"$`, s.imapClientSeesMessagesInMailbox)
|
||||
ctx.Step(`^IMAP client "([^"]*)" eventually sees (\d+) messages in "([^"]*)"$`, s.imapClientEventuallySeesMessagesInMailbox)
|
||||
ctx.Step(`^IMAP client "([^"]*)" marks message (\d+) as deleted$`, s.imapClientMarksMessageAsDeleted)
|
||||
ctx.Step(`^IMAP client "([^"]*)" marks the message with subject "([^"]*)" as deleted$`, s.imapClientMarksTheMessageWithSubjectAsDeleted)
|
||||
ctx.Step(`^IMAP client "([^"]*)" marks message (\d+) as not deleted$`, s.imapClientMarksMessageAsNotDeleted)
|
||||
ctx.Step(`^IMAP client "([^"]*)" marks all messages as deleted$`, s.imapClientMarksAllMessagesAsDeleted)
|
||||
ctx.Step(`^IMAP client "([^"]*)" sees that message (\d+) has the flag "([^"]*)"$`, s.imapClientSeesThatMessageHasTheFlag)
|
||||
|
||||
59
tests/features/imap/message/delete_from_trash.feature
Normal file
59
tests/features/imap/message/delete_from_trash.feature
Normal file
@ -0,0 +1,59 @@
|
||||
Feature: IMAP remove messages from Trash
|
||||
Background:
|
||||
Given there exists an account with username "user@pm.me" and password "password"
|
||||
And the account "user@pm.me" has the following custom mailboxes:
|
||||
| name | type |
|
||||
| mbox | folder |
|
||||
| label | label |
|
||||
|
||||
Scenario Outline: Message in Trash or Spam and some other label is not permanently deleted
|
||||
And the address "user@pm.me" of account "user@pm.me" has the following messages in "<mailbox>":
|
||||
| from | to | subject | body |
|
||||
| john.doe@mail.com | user@pm.me | foo | hello |
|
||||
| jane.doe@mail.com | name@pm.me | bar | world |
|
||||
And bridge starts
|
||||
And the user logs in with username "user@pm.me" and password "password"
|
||||
And user "user@pm.me" finishes syncing
|
||||
And user "user@pm.me" connects and authenticates IMAP client "1"
|
||||
And IMAP client "1" selects "<mailbox>"
|
||||
When IMAP client "1" copies the message with subject "foo" from "<mailbox>" to "Labels/label"
|
||||
Then it succeeds
|
||||
When IMAP client "1" marks the message with subject "foo" as deleted
|
||||
Then it succeeds
|
||||
And IMAP client "1" sees 2 messages in "<mailbox>"
|
||||
And IMAP client "1" sees 2 messages in "All Mail"
|
||||
And IMAP client "1" sees 1 messages in "Labels/label"
|
||||
When IMAP client "1" expunges
|
||||
Then it succeeds
|
||||
And IMAP client "1" sees 1 messages in "<mailbox>"
|
||||
And IMAP client "1" sees 2 messages in "All Mail"
|
||||
And IMAP client "1" sees 1 messages in "Labels/label"
|
||||
|
||||
Examples:
|
||||
| mailbox |
|
||||
| Spam |
|
||||
| Trash |
|
||||
|
||||
Scenario Outline: Message in Trash or Spam only is permanently deleted
|
||||
And the address "user@pm.me" of account "user@pm.me" has the following messages in "<mailbox>":
|
||||
| from | to | subject | body |
|
||||
| john.doe@mail.com | user@pm.me | foo | hello |
|
||||
| jane.doe@mail.com | name@pm.me | bar | world |
|
||||
And bridge starts
|
||||
And the user logs in with username "user@pm.me" and password "password"
|
||||
And user "user@pm.me" finishes syncing
|
||||
And user "user@pm.me" connects and authenticates IMAP client "1"
|
||||
And IMAP client "1" selects "<mailbox>"
|
||||
When IMAP client "1" marks the message with subject "foo" as deleted
|
||||
Then it succeeds
|
||||
And IMAP client "1" sees 2 messages in "<mailbox>"
|
||||
And IMAP client "1" sees 2 messages in "All Mail"
|
||||
When IMAP client "1" expunges
|
||||
Then it succeeds
|
||||
And IMAP client "1" sees 1 messages in "<mailbox>"
|
||||
And IMAP client "1" eventually sees 1 messages in "All Mail"
|
||||
|
||||
Examples:
|
||||
| mailbox |
|
||||
| Spam |
|
||||
| Trash |
|
||||
@ -284,13 +284,13 @@ func (s *scenario) imapClientEventuallySeesTheFollowingMessagesInMailbox(clientI
|
||||
func (s *scenario) imapClientSeesMessagesInMailbox(clientID string, count int, mailbox string) error {
|
||||
_, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
fetch, err := clientFetch(client, mailbox)
|
||||
status, err := client.Status(mailbox, []imap.StatusItem{imap.StatusMessages})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(fetch) != count {
|
||||
return fmt.Errorf("expected mailbox %v to be empty, got %v", mailbox, fetch)
|
||||
if int(status.Messages) != count {
|
||||
return fmt.Errorf("expected mailbox %v to have %v items, got %v", mailbox, count, status.Messages)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -305,18 +305,32 @@ func (s *scenario) imapClientEventuallySeesMessagesInMailbox(clientID string, co
|
||||
func (s *scenario) imapClientMarksMessageAsDeleted(clientID string, seq int) error {
|
||||
_, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
_, err := clientStore(client, seq, seq, imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag)
|
||||
if _, err := clientStore(client, seq, seq, false, imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientMarksTheMessageWithSubjectAsDeleted(clientID, subject string) error {
|
||||
_, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
uid, err := clientGetUIDBySubject(client, client.Mailbox().Name, subject)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := clientStore(client, int(uid), int(uid), true, imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientMarksMessageAsNotDeleted(clientID string, seq int) error {
|
||||
_, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
_, err := clientStore(client, seq, seq, imap.FormatFlagsOp(imap.RemoveFlags, true), imap.DeletedFlag)
|
||||
_, err := clientStore(client, seq, seq, false, imap.FormatFlagsOp(imap.RemoveFlags, true), imap.DeletedFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -327,7 +341,7 @@ func (s *scenario) imapClientMarksMessageAsNotDeleted(clientID string, seq int)
|
||||
func (s *scenario) imapClientMarksAllMessagesAsDeleted(clientID string) error {
|
||||
_, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
_, err := clientStore(client, 1, int(client.Mailbox().Messages), imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag)
|
||||
_, err := clientStore(client, 1, int(client.Mailbox().Messages), false, imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -488,11 +502,19 @@ func clientCopy(client *client.Client, from, to string, uid ...uint32) error {
|
||||
return client.UidCopy(seqset, to)
|
||||
}
|
||||
|
||||
func clientStore(client *client.Client, from, to int, item imap.StoreItem, flags ...string) ([]*imap.Message, error) { //nolint:unparam
|
||||
func clientStore(client *client.Client, from, to int, isUID bool, item imap.StoreItem, flags ...string) ([]*imap.Message, error) { //nolint:unparam
|
||||
resCh := make(chan *imap.Message)
|
||||
|
||||
go func() {
|
||||
if err := client.Store(
|
||||
var storeFunc func(seqset *imap.SeqSet, item imap.StoreItem, value interface{}, ch chan *imap.Message) error
|
||||
|
||||
if isUID {
|
||||
storeFunc = client.UidStore
|
||||
} else {
|
||||
storeFunc = client.Store
|
||||
}
|
||||
|
||||
if err := storeFunc(
|
||||
&imap.SeqSet{Set: []imap.Seq{{Start: uint32(from), Stop: uint32(to)}}},
|
||||
item,
|
||||
xslices.Map(flags, func(flag string) interface{} { return flag }),
|
||||
|
||||
Reference in New Issue
Block a user