mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
GODT-1989: Handle Move with Append and Expunge
Resurrect Bridge feature test for move with append. Only for drafts, as it has been established that moving/appending to All Mail is no longer valid.
This commit is contained in:
@ -178,6 +178,7 @@ func TestFeatures(testingT *testing.T) {
|
||||
ctx.Step(`^IMAP client "([^"]*)" appends the following message to "([^"]*)":$`, s.imapClientAppendsTheFollowingMessageToMailbox)
|
||||
ctx.Step(`^IMAP client "([^"]*)" appends the following messages to "([^"]*)":$`, s.imapClientAppendsTheFollowingMessagesToMailbox)
|
||||
ctx.Step(`^IMAP client "([^"]*)" appends "([^"]*)" to "([^"]*)"$`, s.imapClientAppendsToMailbox)
|
||||
ctx.Step(`^IMAP clients "([^"]*)" and "([^"]*)" move message seq "([^"]*)" of "([^"]*)" to "([^"]*)" by ([^"]*) ([^"]*) ([^"]*)`, s.imapClientsMoveMessageSeqOfUserFromToByOrderedOperations)
|
||||
|
||||
// ==== SMTP ====
|
||||
ctx.Step(`^user "([^"]*)" connects SMTP client "([^"]*)"$`, s.userConnectsSMTPClient)
|
||||
|
||||
64
tests/features/imap/message/move_without_support.feature
Normal file
64
tests/features/imap/message/move_without_support.feature
Normal file
@ -0,0 +1,64 @@
|
||||
Feature: IMAP move messages by append and delete (without MOVE support, e.g., Outlook)
|
||||
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 |
|
||||
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 "source"
|
||||
And user "user@pm.me" connects and authenticates IMAP client "target"
|
||||
|
||||
Scenario Outline: Move message from <srcMailbox> to <dstMailbox> by <order>
|
||||
When IMAP client "source" appends the following message to "<srcMailbox>":
|
||||
"""
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
From: sndr1@pm.me
|
||||
To: rcvr1@pm.me
|
||||
Subject: subj1
|
||||
|
||||
body1
|
||||
"""
|
||||
Then it succeeds
|
||||
When IMAP client "source" appends the following message to "<srcMailbox>":
|
||||
"""
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
From: sndr2@pm.me
|
||||
To: rcvr2@pm.me
|
||||
Subject: subj2
|
||||
|
||||
body2
|
||||
"""
|
||||
Then it succeeds
|
||||
And IMAP client "source" selects "<srcMailbox>"
|
||||
And IMAP client "target" selects "<dstMailbox>"
|
||||
When IMAP clients "source" and "target" move message seq "2" of "user" to "<dstMailbox>" by <order>
|
||||
And IMAP client "source" sees 1 messages in "<srcMailbox>"
|
||||
And IMAP client "source" sees the following messages in "<srcMailbox>":
|
||||
| from | to | subject |
|
||||
| sndr1@pm.me | rcvr1@pm.me | subj1 |
|
||||
And IMAP client "target" sees 1 messages in "<dstMailbox>"
|
||||
And IMAP client "target" sees the following messages in "<dstMailbox>":
|
||||
| from | to | subject |
|
||||
| sndr2@pm.me | rcvr2@pm.me | subj2 |
|
||||
Examples:
|
||||
| srcMailbox | dstMailbox | order |
|
||||
| Trash | INBOX | APPEND DELETE EXPUNGE |
|
||||
| Spam | INBOX | APPEND DELETE EXPUNGE |
|
||||
| INBOX | Archive | APPEND DELETE EXPUNGE |
|
||||
| INBOX | Folders/mbox | APPEND DELETE EXPUNGE |
|
||||
| INBOX | Spam | APPEND DELETE EXPUNGE |
|
||||
| INBOX | Trash | APPEND DELETE EXPUNGE |
|
||||
| Trash | INBOX | DELETE APPEND EXPUNGE |
|
||||
| Spam | INBOX | DELETE APPEND EXPUNGE |
|
||||
| INBOX | Archive | DELETE APPEND EXPUNGE |
|
||||
| INBOX | Folders/mbox | DELETE APPEND EXPUNGE |
|
||||
| INBOX | Spam | DELETE APPEND EXPUNGE |
|
||||
| INBOX | Trash | DELETE APPEND EXPUNGE |
|
||||
| Trash | INBOX | DELETE EXPUNGE APPEND |
|
||||
| Spam | INBOX | DELETE EXPUNGE APPEND |
|
||||
| INBOX | Archive | DELETE EXPUNGE APPEND |
|
||||
| INBOX | Folders/mbox | DELETE EXPUNGE APPEND |
|
||||
| INBOX | Spam | DELETE EXPUNGE APPEND |
|
||||
| INBOX | Trash | DELETE EXPUNGE APPEND |
|
||||
@ -18,9 +18,12 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -408,6 +411,77 @@ func (s *scenario) imapClientAppendsToMailbox(clientID string, file, mailbox str
|
||||
return clientAppend(client, mailbox, string(b))
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientsMoveMessageSeqOfUserFromToByOrderedOperations(sourceIMAPClient, targetIMAPClient, messageSeq, bddUserID, targetMailboxName, op1, op2, op3 string) error {
|
||||
// call NOOP to prevent unilateral updates in following FETCH
|
||||
_, sourceClient := s.t.getIMAPClient(sourceIMAPClient)
|
||||
_, targetClient := s.t.getIMAPClient(targetIMAPClient)
|
||||
|
||||
sequenceID, err := strconv.Atoi(messageSeq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sourceClient.Noop(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := targetClient.Noop(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get the original message
|
||||
messages, err := clientFetchSequence(sourceClient, messageSeq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(messages) != 1 {
|
||||
return fmt.Errorf("more than one message in sequence set")
|
||||
}
|
||||
|
||||
bodySection, err := imap.ParseBodySectionName("BODY[]")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
literal, err := io.ReadAll(messages[0].GetBody(bodySection))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var targetErr error
|
||||
var storeErr error
|
||||
var expungeErr error
|
||||
|
||||
for _, op := range []string{op1, op2, op3} {
|
||||
switch op {
|
||||
case "APPEND":
|
||||
|
||||
flags := messages[0].Flags
|
||||
if index := xslices.Index(flags, imap.RecentFlag); index >= 0 {
|
||||
flags = xslices.Remove(flags, index, 1)
|
||||
}
|
||||
|
||||
targetErr = targetClient.Append(targetMailboxName, flags, time.Now(), bytes.NewReader(literal))
|
||||
case "DELETE":
|
||||
if _, err := clientStore(sourceClient, sequenceID, sequenceID, false, imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag); err != nil {
|
||||
storeErr = err
|
||||
}
|
||||
case "EXPUNGE":
|
||||
expungeErr = sourceClient.Expunge(nil)
|
||||
default:
|
||||
return fmt.Errorf("unknown IMAP operation " + op)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
if targetErr != nil || storeErr != nil || expungeErr != nil {
|
||||
return fmt.Errorf("one or more operations failed: append=%v store=%v expunge=%v", targetErr, storeErr, expungeErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func clientList(client *client.Client) []*imap.MailboxInfo {
|
||||
resCh := make(chan *imap.MailboxInfo)
|
||||
|
||||
@ -477,6 +551,27 @@ func clientFetch(client *client.Client, mailbox string) ([]*imap.Message, error)
|
||||
return iterator.Collect(iterator.Chan(resCh)), nil
|
||||
}
|
||||
|
||||
func clientFetchSequence(client *client.Client, sequenceSet string) ([]*imap.Message, error) {
|
||||
seqSet, err := imap.ParseSeqSet(sequenceSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resCh := make(chan *imap.Message)
|
||||
|
||||
go func() {
|
||||
if err := client.Fetch(
|
||||
seqSet,
|
||||
[]imap.FetchItem{imap.FetchFlags, imap.FetchEnvelope, imap.FetchUid, "BODY.PEEK[]"},
|
||||
resCh,
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
return iterator.Collect(iterator.Chan(resCh)), nil
|
||||
}
|
||||
|
||||
func clientCopy(client *client.Client, from, to string, uid ...uint32) error {
|
||||
status, err := client.Select(from, false)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user