diff --git a/internal/imap/mailbox_messages.go b/internal/imap/mailbox_messages.go index 122cde6f..be6d15a2 100644 --- a/internal/imap/mailbox_messages.go +++ b/internal/imap/mailbox_messages.go @@ -215,7 +215,7 @@ func (im *imapMailbox) MoveMessages(uid bool, seqSet *imap.SeqSet, targetLabel s return im.labelMessages(uid, seqSet, targetLabel, true) } -func (im *imapMailbox) labelMessages(uid bool, seqSet *imap.SeqSet, targetLabel string, move bool) error { +func (im *imapMailbox) labelMessages(uid bool, seqSet *imap.SeqSet, targetLabel string, move bool) error { //nolint[funlen] messageIDs, err := im.apiIDsFromSeqSet(uid, seqSet) if err != nil || len(messageIDs) == 0 { return err @@ -230,6 +230,25 @@ func (im *imapMailbox) labelMessages(uid bool, seqSet *imap.SeqSet, targetLabel return err } + // Moving or copying from Inbox to Sent or from Sent to Inbox is no-op. + // Inbox and Sent is the same mailbox and message is showen in one or + // the other based on message flags. + // COPY operation has to be forbidden otherwise move by COPY+EXPUNGE + // would lead to message found only in All Mail, because COPY is no-op + // and EXPUNGE is translated as unlabel from the source. + // MOVE operation could be allowed, just it will do no change. It's better + // to refuse it as well so client is kept in proper state and no sync + // is needed. + isInboxOrSent := func(labelID string) bool { + return labelID == pmapi.InboxLabel || labelID == pmapi.SentLabel + } + if isInboxOrSent(im.storeMailbox.LabelID()) && isInboxOrSent(targetStoreMailbox.LabelID()) { + if im.storeMailbox.LabelID() == pmapi.InboxLabel { + return errors.New("move from Inbox to Sent is not allowed") + } + return errors.New("move from Sent to Inbox is not allowed") + } + deletedIDs := []string{} allDeletedIDs, err := im.storeMailbox.GetDeletedAPIIDs() if err != nil { diff --git a/test/features/bridge/imap/message/copy.feature b/test/features/bridge/imap/message/copy.feature index e4751823..625190b5 100644 --- a/test/features/bridge/imap/message/copy.feature +++ b/test/features/bridge/imap/message/copy.feature @@ -7,10 +7,13 @@ Feature: IMAP copy messages | from | to | subject | body | read | deleted | | john.doe@mail.com | user@pm.me | foo | hello | true | false | | jane.doe@mail.com | name@pm.me | bar | world | false | true | + And there are messages in mailbox "Sent" for "user" + | from | to | subject | body | + | john.doe@mail.com | user@pm.me | response | hello | And there is IMAP client logged in as "user" - And there is IMAP client selected in "INBOX" Scenario: Copy message to label + Given there is IMAP client selected in "INBOX" When IMAP client copies message seq "1" to "Labels/label" Then IMAP response is "OK" And mailbox "INBOX" for "user" has messages @@ -22,6 +25,7 @@ Feature: IMAP copy messages | john.doe@mail.com | user@pm.me | foo | hello | true | false | Scenario: Copy all messages to label + Given there is IMAP client selected in "INBOX" When IMAP client copies message seq "1:*" to "Labels/label" Then IMAP response is "OK" And mailbox "INBOX" for "user" has messages @@ -34,6 +38,7 @@ Feature: IMAP copy messages | jane.doe@mail.com | name@pm.me | bar | world | false | true | Scenario: Copy message to folder does move + Given there is IMAP client selected in "INBOX" When IMAP client copies message seq "1" to "Folders/mbox" Then IMAP response is "OK" And mailbox "INBOX" for "user" has messages @@ -44,6 +49,7 @@ Feature: IMAP copy messages | john.doe@mail.com | user@pm.me | foo | hello | true | false | Scenario: Copy all messages to folder does move + Given there is IMAP client selected in "INBOX" When IMAP client copies message seq "1:*" to "Folders/mbox" Then IMAP response is "OK" And mailbox "INBOX" for "user" has 0 messages @@ -51,3 +57,13 @@ Feature: IMAP copy messages | from | to | subject | body | read | deleted | | john.doe@mail.com | user@pm.me | foo | hello | true | false | | jane.doe@mail.com | name@pm.me | bar | world | false | true | + + Scenario: Copy message from Inbox to Sent is not possible + Given there is IMAP client selected in "INBOX" + When IMAP client copies message seq "1" to "Sent" + Then IMAP response is "move from Inbox to Sent is not allowed" + + Scenario: Copy message from Sent to Inbox is not possible + Given there is IMAP client selected in "Sent" + When IMAP client copies message seq "1" to "INBOX" + Then IMAP response is "move from Sent to Inbox is not allowed" diff --git a/test/features/bridge/imap/message/move.feature b/test/features/bridge/imap/message/move.feature index f3560868..2b4d1c01 100644 --- a/test/features/bridge/imap/message/move.feature +++ b/test/features/bridge/imap/message/move.feature @@ -8,6 +8,9 @@ Feature: IMAP move messages | from | to | subject | body | | john.doe@mail.com | user@pm.me | foo | hello | | jane.doe@mail.com | name@pm.me | bar | world | + And there are messages in mailbox "Sent" for "user" + | from | to | subject | body | + | john.doe@mail.com | user@pm.me | response | hello | And there are messages in mailbox "Labels/label2" for "user" | from | to | subject | body | | john.doe@mail.com | user@pm.me | baz | hello | @@ -87,3 +90,13 @@ Feature: IMAP move messages | john.doe@mail.com | user@pm.me | baz | And API endpoint "PUT /mail/v4/messages/label" is called And API endpoint "PUT /mail/v4/messages/unlabel" is not called + + Scenario: Move message from Inbox to Sent is not possible + Given there is IMAP client selected in "INBOX" + When IMAP client moves message seq "1" to "Sent" + Then IMAP response is "move from Inbox to Sent is not allowed" + + Scenario: Move message from Sent to Inbox is not possible + Given there is IMAP client selected in "Sent" + When IMAP client moves message seq "1" to "INBOX" + Then IMAP response is "move from Sent to Inbox is not allowed"