diff --git a/internal/smtp/send_recorder.go b/internal/smtp/send_recorder.go index 9e5eb677..360f4922 100644 --- a/internal/smtp/send_recorder.go +++ b/internal/smtp/send_recorder.go @@ -133,7 +133,7 @@ func (q *sendRecorder) isSendingOrSent(client messageGetter, hash string) (isSen if err != nil { return } - if message.Type == pmapi.MessageTypeDraft { + if message.IsDraft() { // If message is in draft for a long time, let's assume there is // some problem and message will not be sent anymore. if time.Since(time.Unix(message.Time, 0)).Minutes() > 10 { @@ -141,8 +141,8 @@ func (q *sendRecorder) isSendingOrSent(client messageGetter, hash string) (isSen } isSending = true } - // MessageTypeInboxAndSent can be when message was sent to myself. - if message.Type == pmapi.MessageTypeSent || message.Type == pmapi.MessageTypeInboxAndSent { + // Message can be in Inbox and Sent when message was sent to myself. + if message.Has(pmapi.FlagSent) { wasSent = true } diff --git a/internal/smtp/send_recorder_test.go b/internal/smtp/send_recorder_test.go index f98900fe..e3d39e4a 100644 --- a/internal/smtp/send_recorder_test.go +++ b/internal/smtp/send_recorder_test.go @@ -395,6 +395,9 @@ func TestSendRecorder_isSendingOrSent(t *testing.T) { q.addMessage("hash") q.setMessageID("hash", "messageID") + draftFlag := pmapi.FlagInternal | pmapi.FlagE2E + selfSent := pmapi.FlagSent | pmapi.FlagReceived + testCases := []struct { hash string message *pmapi.Message @@ -402,14 +405,14 @@ func TestSendRecorder_isSendingOrSent(t *testing.T) { wantIsSending bool wantWasSent bool }{ - {"badhash", &pmapi.Message{Type: pmapi.MessageTypeDraft}, nil, false, false}, + {"badhash", &pmapi.Message{Flags: draftFlag}, nil, false, false}, {"hash", nil, errors.New("message not found"), false, false}, - {"hash", &pmapi.Message{Type: pmapi.MessageTypeInbox}, nil, false, false}, - {"hash", &pmapi.Message{Type: pmapi.MessageTypeDraft, Time: time.Now().Add(-20 * time.Minute).Unix()}, nil, false, false}, - {"hash", &pmapi.Message{Type: pmapi.MessageTypeDraft, Time: time.Now().Unix()}, nil, true, false}, - {"hash", &pmapi.Message{Type: pmapi.MessageTypeSent}, nil, false, true}, - {"hash", &pmapi.Message{Type: pmapi.MessageTypeInboxAndSent}, nil, false, true}, - {"", &pmapi.Message{Type: pmapi.MessageTypeInboxAndSent}, nil, false, false}, + {"hash", &pmapi.Message{Flags: pmapi.FlagReceived}, nil, false, false}, + {"hash", &pmapi.Message{Flags: draftFlag, Time: time.Now().Add(-20 * time.Minute).Unix()}, nil, false, false}, + {"hash", &pmapi.Message{Flags: draftFlag, Time: time.Now().Unix()}, nil, true, false}, + {"hash", &pmapi.Message{Flags: pmapi.FlagSent}, nil, false, true}, + {"hash", &pmapi.Message{Flags: selfSent}, nil, false, true}, + {"", &pmapi.Message{Flags: selfSent}, nil, false, false}, } for i, tc := range testCases { tc := tc // bind diff --git a/internal/store/mailbox_message.go b/internal/store/mailbox_message.go index 2bfab0ae..1251c4c2 100644 --- a/internal/store/mailbox_message.go +++ b/internal/store/mailbox_message.go @@ -370,7 +370,7 @@ func (storeMailbox *Mailbox) txCreateOrUpdateMessages(tx *bolt.Tx, msgs []*pmapi // Draft bodies can change and bodies are not re-fetched by IMAP clients. // Every change has to be a new message; we need to delete the old one and always recreate it. - if msg.Type == pmapi.MessageTypeDraft || msg.IsDraft() { + if msg.IsDraft() { if err := storeMailbox.txDeleteMessage(tx, msg.ID); err != nil { return errors.Wrap(err, "cannot delete old draft") } diff --git a/internal/store/user_message_test.go b/internal/store/user_message_test.go index 3fcdfc53..01a4a79a 100644 --- a/internal/store/user_message_test.go +++ b/internal/store/user_message_test.go @@ -78,23 +78,23 @@ func TestCreateOrUpdateMessageMetadata(t *testing.T) { m.newStoreNoEvents(t, true) insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel}) - msg, err := m.store.getMessageFromDB("msg1") + metadata, err := m.store.getMessageFromDB("msg1") require.Nil(t, err) - message := &Message{msg: msg, store: m.store, storeMailbox: nil} + msg := &Message{msg: metadata, store: m.store, storeMailbox: nil} // Check non-meta and calculated data are cleared/empty. - a.Equal(t, "", message.msg.Body) - a.Equal(t, []*pmapi.Attachment(nil), message.msg.Attachments) - a.Equal(t, "", message.msg.MIMEType) - a.Equal(t, make(mail.Header), message.msg.Header) + a.Equal(t, "", metadata.Body) + a.Equal(t, []*pmapi.Attachment(nil), metadata.Attachments) + a.Equal(t, "", metadata.MIMEType) + a.Equal(t, make(mail.Header), metadata.Header) wantHeader, wantSize := putBodystructureAndSizeToDB(m, "msg1") // Check cached data. require.Nil(t, err) - a.Equal(t, wantHeader, message.GetMIMEHeader()) - haveSize, err := message.GetRFC822Size() + a.Equal(t, wantHeader, msg.GetMIMEHeader()) + haveSize, err := msg.GetRFC822Size() require.Nil(t, err) a.Equal(t, wantSize, haveSize) @@ -102,8 +102,8 @@ func TestCreateOrUpdateMessageMetadata(t *testing.T) { insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel}) require.Nil(t, err) - a.Equal(t, wantHeader, message.GetMIMEHeader()) - haveSize, err = message.GetRFC822Size() + a.Equal(t, wantHeader, msg.GetMIMEHeader()) + haveSize, err = msg.GetRFC822Size() require.Nil(t, err) a.Equal(t, wantSize, haveSize) } diff --git a/pkg/pmapi/messages.go b/pkg/pmapi/messages.go index 10c19c14..d5429efa 100644 --- a/pkg/pmapi/messages.go +++ b/pkg/pmapi/messages.go @@ -74,19 +74,19 @@ const ( // Message flag definitions. const ( - FlagReceived = 1 - FlagSent = 2 - FlagInternal = 4 - FlagE2E = 8 - FlagAuto = 16 - FlagReplied = 32 - FlagRepliedAll = 64 - FlagForwarded = 128 + FlagReceived = int64(1) + FlagSent = int64(2) + FlagInternal = int64(4) + FlagE2E = int64(8) + FlagAuto = int64(16) + FlagReplied = int64(32) + FlagRepliedAll = int64(64) + FlagForwarded = int64(128) - FlagAutoreplied = 256 - FlagImported = 512 - FlagOpened = 1024 - FlagReceiptSent = 2048 + FlagAutoreplied = int64(256) + FlagImported = int64(512) + FlagOpened = int64(1024) + FlagReceiptSent = int64(2048) ) // Draft flags. @@ -139,13 +139,6 @@ const ( RemoveLabels // Remove specified labels from current ones. ) -const ( - MessageTypeInbox int = iota - MessageTypeDraft - MessageTypeSent - MessageTypeInboxAndSent -) - // Due to API limitations, we shouldn't make requests with more than 100 message IDs at a time. const messageIDPageSize = 100 @@ -166,7 +159,6 @@ type Message struct { ConversationID string `json:",omitempty"` // only filter Subject string Unread Boolean - Type int Flags int64 Sender *mail.Address ReplyTo *mail.Address `json:",omitempty"` diff --git a/test/fakeapi/controller_control.go b/test/fakeapi/controller_control.go index d79bf8cc..cfec8a94 100644 --- a/test/fakeapi/controller_control.go +++ b/test/fakeapi/controller_control.go @@ -177,10 +177,8 @@ func (ctl *Controller) SetDraftBody(username string, messageID string, body stri message.Body = body // assuming this is draft we set following - // - Draft type (NOTE: Type is not part of pmapi.MessageEvent, but it's there on API) // - It must not have FlagReceived and FlagSent // - Standard labelsIDs NOTE:wrong behaviour once we will have edge case tests for drafts outside draft folder - message.Type = pmapi.MessageTypeDraft message.Flags = pmapi.FlagE2E | pmapi.FlagInternal message.LabelIDs = []string{pmapi.AllDraftsLabel, pmapi.AllMailLabel, pmapi.DraftLabel} diff --git a/test/fakeapi/messages.go b/test/fakeapi/messages.go index eba3f524..73f57f87 100644 --- a/test/fakeapi/messages.go +++ b/test/fakeapi/messages.go @@ -179,6 +179,7 @@ func (api *FakePMAPI) SendMessage(ctx context.Context, messageID string, sendMes } message.Time = time.Now().Unix() message.LabelIDs = append(message.LabelIDs, pmapi.SentLabel) + message.Flags |= pmapi.FlagSent api.addEventMessage(pmapi.EventUpdate, message) return message, nil, nil } diff --git a/test/features/imap/message/drafts.feature b/test/features/imap/message/drafts.feature index 6d01d5cb..36f6d274 100644 --- a/test/features/imap/message/drafts.feature +++ b/test/features/imap/message/drafts.feature @@ -25,6 +25,12 @@ Feature: IMAP operations with Drafts When IMAP client fetches body of UID "1" Then IMAP response is "OK" Then IMAP response contains "Nope" + When IMAP client sends command "UID FETCH 1 RFC822.SIZE" + Then IMAP response is "OK" + Then IMAP response contains "495" + When IMAP client sends command "UID FETCH 1 BODYSTRUCTURE" + Then IMAP response is "OK" + Then IMAP response contains "4 14" Given the body of draft "msg1" for "user" has changed to "Yes I am" And the event loop of "user" loops once And mailbox "Drafts" for "user" has 1 messages @@ -32,4 +38,10 @@ Feature: IMAP operations with Drafts Then IMAP response is "OK" Then IMAP response contains "Yes I am" Then IMAP response does not contain "Nope" + When IMAP client sends command "UID FETCH 2 RFC822.SIZE" + Then IMAP response is "OK" + Then IMAP response contains "499" + When IMAP client sends command "UID FETCH 2 BODYSTRUCTURE" + Then IMAP response is "OK" + Then IMAP response contains "8 14" diff --git a/test/store_setup_test.go b/test/store_setup_test.go index c543ff6b..49882039 100644 --- a/test/store_setup_test.go +++ b/test/store_setup_test.go @@ -108,16 +108,15 @@ func thereAreMessagesInMailboxesForAddressOfUser(mailboxNames, bddAddressID, bdd if message.HasLabelID(pmapi.SentLabel) { message.Flags |= pmapi.FlagSent - message.Type = pmapi.MessageTypeSent } else { // some tests (Outlook move by DELETE EXPUNGE APPEND) imply creating hard copies of emails, // and the importMessage() function flags the email as Sent if the 'Received' key in not present in the // header. header.Add("Received", "from dummy.protonmail.com") + message.Flags |= pmapi.FlagReceived } if message.HasLabelID(pmapi.DraftLabel) { - message.Type = pmapi.MessageTypeDraft message.Flags = pmapi.FlagInternal | pmapi.FlagE2E }