mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-17 23:56:56 +00:00
GODT-35: Finish all details and make tests pass
This commit is contained in:
@ -90,7 +90,7 @@ func getLabelPrefix(l *pmapi.Label) string {
|
||||
switch {
|
||||
case pmapi.IsSystemLabel(l.ID):
|
||||
return ""
|
||||
case l.Exclusive == 1:
|
||||
case bool(l.Exclusive):
|
||||
return UserFoldersPrefix
|
||||
default:
|
||||
return UserLabelsPrefix
|
||||
|
||||
@ -37,8 +37,8 @@ func TestNotifyChangeCreateOrUpdateMessage(t *testing.T) {
|
||||
m.newStoreNoEvents(true)
|
||||
m.store.SetChangeNotifier(m.changeNotifier)
|
||||
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
}
|
||||
|
||||
func TestNotifyChangeCreateOrUpdateMessages(t *testing.T) {
|
||||
@ -52,8 +52,8 @@ func TestNotifyChangeCreateOrUpdateMessages(t *testing.T) {
|
||||
m.newStoreNoEvents(true)
|
||||
m.store.SetChangeNotifier(m.changeNotifier)
|
||||
|
||||
msg1 := getTestMessage("msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
msg2 := getTestMessage("msg2", "Test message 2", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
msg1 := getTestMessage("msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
msg2 := getTestMessage("msg2", "Test message 2", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
require.Nil(t, m.store.createOrUpdateMessagesEvent([]*pmapi.Message{msg1, msg2}))
|
||||
}
|
||||
|
||||
@ -63,8 +63,8 @@ func TestNotifyChangeDeleteMessage(t *testing.T) {
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
|
||||
m.changeNotifier.EXPECT().DeleteMessage(addr1, "All Mail", uint32(2))
|
||||
m.changeNotifier.EXPECT().DeleteMessage(addr1, "All Mail", uint32(1))
|
||||
|
||||
@ -81,7 +81,7 @@ func (loop *eventLoop) client() pmapi.Client {
|
||||
func (loop *eventLoop) setFirstEventID() (err error) {
|
||||
loop.log.Info("Setting first event ID")
|
||||
|
||||
event, err := loop.client().GetEvent(context.TODO(), "")
|
||||
event, err := loop.client().GetEvent(context.Background(), "")
|
||||
if err != nil {
|
||||
loop.log.WithError(err).Error("Could not get latest event ID")
|
||||
return
|
||||
@ -222,8 +222,7 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
|
||||
// We only want to consider invalid tokens as real errors because all other errors might fix themselves eventually
|
||||
// (e.g. no internet, ulimit reached etc.)
|
||||
defer func() {
|
||||
// FIXME(conman): How to handle errors of different types?
|
||||
if errors.Is(err, pmapi.ErrNoConnection) {
|
||||
if errors.Cause(err) == pmapi.ErrNoConnection {
|
||||
l.Warn("Internet unavailable")
|
||||
err = nil
|
||||
}
|
||||
@ -234,20 +233,17 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
|
||||
err = nil
|
||||
}
|
||||
|
||||
// FIXME(conman): Handle force upgrade.
|
||||
/*
|
||||
if errors.Cause(err) == pmapi.ErrUpgradeApplication {
|
||||
l.Warn("Need to upgrade application")
|
||||
err = nil
|
||||
}
|
||||
*/
|
||||
if errors.Cause(err) == pmapi.ErrUpgradeApplication {
|
||||
l.Warn("Need to upgrade application")
|
||||
err = nil
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
loop.errCounter = 0
|
||||
}
|
||||
|
||||
// All errors except ErrUnauthorized (which is not possible to recover from) are ignored.
|
||||
if !errors.Is(err, pmapi.ErrUnauthorized) {
|
||||
if err != nil && errors.Cause(err) != pmapi.ErrUnauthorized {
|
||||
l.WithError(err).WithField("errors", loop.errCounter).Error("Error skipped")
|
||||
loop.errCounter++
|
||||
if loop.errCounter == errMaxSentry {
|
||||
@ -268,7 +264,7 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
|
||||
loop.pollCounter++
|
||||
|
||||
var event *pmapi.Event
|
||||
if event, err = loop.client().GetEvent(context.TODO(), loop.currentEventID); err != nil {
|
||||
if event, err = loop.client().GetEvent(context.Background(), loop.currentEventID); err != nil {
|
||||
return false, errors.Wrap(err, "failed to get event")
|
||||
}
|
||||
|
||||
@ -295,7 +291,7 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
|
||||
}
|
||||
}
|
||||
|
||||
return event.More == 1, err
|
||||
return bool(event.More), err
|
||||
}
|
||||
|
||||
func (loop *eventLoop) processEvent(event *pmapi.Event) (err error) {
|
||||
@ -354,7 +350,7 @@ func (loop *eventLoop) processAddresses(log *logrus.Entry, addressEvents []*pmap
|
||||
// Get old addresses for comparisons before updating user.
|
||||
oldList := loop.client().Addresses()
|
||||
|
||||
if err = loop.user.UpdateUser(); err != nil {
|
||||
if err = loop.user.UpdateUser(context.Background()); err != nil {
|
||||
if logoutErr := loop.user.Logout(); logoutErr != nil {
|
||||
log.WithError(logoutErr).Error("Failed to logout user after failed update")
|
||||
}
|
||||
@ -465,16 +461,12 @@ func (loop *eventLoop) processMessages(eventLog *logrus.Entry, messages []*pmapi
|
||||
|
||||
msgLog.WithError(err).Warning("Message was not present in DB. Trying fetch...")
|
||||
|
||||
if msg, err = loop.client().GetMessage(context.TODO(), message.ID); err != nil {
|
||||
// FIXME(conman): How to handle error of this particular type?
|
||||
|
||||
/*
|
||||
if _, ok := err.(*pmapi.ErrUnprocessableEntity); ok {
|
||||
msgLog.WithError(err).Warn("Skipping message update because message exists neither in local DB nor on API")
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
*/
|
||||
if msg, err = loop.client().GetMessage(context.Background(), message.ID); err != nil {
|
||||
if _, ok := err.(pmapi.ErrUnprocessableEntity); ok {
|
||||
msgLog.WithError(err).Warn("Skipping message update because message exists neither in local DB nor on API")
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "failed to get message from API for updating")
|
||||
}
|
||||
|
||||
@ -42,15 +42,15 @@ func TestEventLoopProcessMoreEvents(t *testing.T) {
|
||||
// next event if there is `More` of them.
|
||||
m.client.EXPECT().GetEvent(gomock.Any(), "latestEventID").Return(&pmapi.Event{
|
||||
EventID: "event50",
|
||||
More: 1,
|
||||
More: true,
|
||||
}, nil),
|
||||
m.client.EXPECT().GetEvent(gomock.Any(), "event50").Return(&pmapi.Event{
|
||||
EventID: "event70",
|
||||
More: 0,
|
||||
More: false,
|
||||
}, nil),
|
||||
m.client.EXPECT().GetEvent(gomock.Any(), "event70").Return(&pmapi.Event{
|
||||
EventID: "event71",
|
||||
More: 0,
|
||||
More: false,
|
||||
}, nil),
|
||||
)
|
||||
m.newStoreNoEvents(true)
|
||||
@ -188,7 +188,7 @@ func TestEventLoopUpdateMessage(t *testing.T) {
|
||||
msg := &pmapi.Message{
|
||||
ID: "msg1",
|
||||
Subject: "old",
|
||||
Unread: 0,
|
||||
Unread: false,
|
||||
Flags: 10,
|
||||
Sender: address1,
|
||||
ToList: []*mail.Address{address2},
|
||||
@ -200,7 +200,7 @@ func TestEventLoopUpdateMessage(t *testing.T) {
|
||||
newMsg := &pmapi.Message{
|
||||
ID: "msg1",
|
||||
Subject: "new",
|
||||
Unread: 1,
|
||||
Unread: true,
|
||||
Flags: 11,
|
||||
Sender: address2,
|
||||
ToList: []*mail.Address{address1},
|
||||
|
||||
@ -129,17 +129,10 @@ func (mc *mailboxCounts) getPMLabel() *pmapi.Label {
|
||||
Color: mc.Color,
|
||||
Order: mc.Order,
|
||||
Type: pmapi.LabelTypeMailbox,
|
||||
Exclusive: mc.isExclusive(),
|
||||
Exclusive: pmapi.Boolean(mc.IsFolder),
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *mailboxCounts) isExclusive() int {
|
||||
if mc.IsFolder {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// createOrUpdateMailboxCountsBuckets will not change the on-API-counts.
|
||||
func (store *Store) createOrUpdateMailboxCountsBuckets(labels []*pmapi.Label) error {
|
||||
// Don't forget about system folders.
|
||||
@ -162,7 +155,7 @@ func (store *Store) createOrUpdateMailboxCountsBuckets(labels []*pmapi.Label) er
|
||||
mailbox.LabelName = label.Path
|
||||
mailbox.Color = label.Color
|
||||
mailbox.Order = label.Order
|
||||
mailbox.IsFolder = label.Exclusive == 1
|
||||
mailbox.IsFolder = bool(label.Exclusive)
|
||||
|
||||
// Write.
|
||||
if err = mailbox.txWriteToBucket(countsBkt); err != nil {
|
||||
|
||||
@ -75,7 +75,7 @@ func TestMailboxNames(t *testing.T) {
|
||||
newLabel(100, "labelID1", "Label1"),
|
||||
newLabel(1000, "folderID1", "Folder1"),
|
||||
}
|
||||
foldersAndLabels[1].Exclusive = 1
|
||||
foldersAndLabels[1].Exclusive = true
|
||||
|
||||
for _, counts := range getSystemFolders() {
|
||||
foldersAndLabels = append(foldersAndLabels, counts.getPMLabel())
|
||||
|
||||
@ -37,10 +37,10 @@ func TestGetSequenceNumberAndGetUID(t *testing.T) {
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.ArchiveLabel})
|
||||
insertMessage(t, m, "msg3", "Test message 3", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg4", "Test message 4", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, false, []string{pmapi.AllMailLabel, pmapi.ArchiveLabel})
|
||||
insertMessage(t, m, "msg3", "Test message 3", addrID1, false, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg4", "Test message 4", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
|
||||
checkAllMessageIDs(t, m, []string{"msg1", "msg2", "msg3", "msg4"})
|
||||
|
||||
@ -82,20 +82,20 @@ func TestGetUIDByHeader(t *testing.T) { //nolint[funlen]
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
|
||||
tstMsg := getTestMessage("msg1", "Without external ID", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
tstMsg := getTestMessage("msg1", "Without external ID", addrID1, false, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
require.Nil(t, m.store.createOrUpdateMessageEvent(tstMsg))
|
||||
|
||||
tstMsg = getTestMessage("msg2", "External ID with spaces", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
tstMsg = getTestMessage("msg2", "External ID with spaces", addrID1, false, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
tstMsg.ExternalID = " externalID-non-pm-com "
|
||||
require.Nil(t, m.store.createOrUpdateMessageEvent(tstMsg))
|
||||
|
||||
tstMsg = getTestMessage("msg3", "External ID with <>", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
tstMsg = getTestMessage("msg3", "External ID with <>", addrID1, false, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
tstMsg.ExternalID = "<externalID@pm.me>"
|
||||
tstMsg.Header = mail.Header{"References": []string{"wrongID", "externalID-non-pm-com", "msg2"}}
|
||||
require.Nil(t, m.store.createOrUpdateMessageEvent(tstMsg))
|
||||
|
||||
// Not sure if this is a real-world scenario but we should be able to address this properly.
|
||||
tstMsg = getTestMessage("msg4", "External ID with <> and spaces and special characters", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
tstMsg = getTestMessage("msg4", "External ID with <> and spaces and special characters", addrID1, false, []string{pmapi.AllMailLabel, pmapi.SentLabel})
|
||||
tstMsg.ExternalID = " < external.()+*[]ID@another.pm.me > "
|
||||
require.Nil(t, m.store.createOrUpdateMessageEvent(tstMsg))
|
||||
|
||||
|
||||
@ -18,8 +18,6 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -43,7 +41,7 @@ func (storeMailbox *Mailbox) GetMessage(apiID string) (*Message, error) {
|
||||
// FetchMessage fetches the message with the given `apiID`, stores it in the database, and returns a new store message
|
||||
// wrapping it.
|
||||
func (storeMailbox *Mailbox) FetchMessage(apiID string) (*Message, error) {
|
||||
msg, err := storeMailbox.client().GetMessage(context.TODO(), apiID)
|
||||
msg, err := storeMailbox.client().GetMessage(exposeContextForIMAP(), apiID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -70,7 +68,7 @@ func (storeMailbox *Mailbox) ImportMessage(msg *pmapi.Message, body []byte, labe
|
||||
Message: body,
|
||||
}
|
||||
|
||||
res, err := storeMailbox.client().Import(context.TODO(), pmapi.ImportMsgReqs{importReqs})
|
||||
res, err := storeMailbox.client().Import(exposeContextForIMAP(), pmapi.ImportMsgReqs{importReqs})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -99,7 +97,7 @@ func (storeMailbox *Mailbox) LabelMessages(apiIDs []string) error {
|
||||
return ErrAllMailOpNotAllowed
|
||||
}
|
||||
defer storeMailbox.pollNow()
|
||||
return storeMailbox.client().LabelMessages(context.TODO(), apiIDs, storeMailbox.labelID)
|
||||
return storeMailbox.client().LabelMessages(exposeContextForIMAP(), apiIDs, storeMailbox.labelID)
|
||||
}
|
||||
|
||||
// UnlabelMessages removes the label by calling an API.
|
||||
@ -112,7 +110,7 @@ func (storeMailbox *Mailbox) UnlabelMessages(apiIDs []string) error {
|
||||
return ErrAllMailOpNotAllowed
|
||||
}
|
||||
defer storeMailbox.pollNow()
|
||||
return storeMailbox.client().UnlabelMessages(context.TODO(), apiIDs, storeMailbox.labelID)
|
||||
return storeMailbox.client().UnlabelMessages(exposeContextForIMAP(), apiIDs, storeMailbox.labelID)
|
||||
}
|
||||
|
||||
// MarkMessagesRead marks the message read by calling an API.
|
||||
@ -132,14 +130,14 @@ func (storeMailbox *Mailbox) MarkMessagesRead(apiIDs []string) error {
|
||||
// Therefore we do not issue API update if the message is already read.
|
||||
ids := []string{}
|
||||
for _, apiID := range apiIDs {
|
||||
if message, _ := storeMailbox.store.getMessageFromDB(apiID); message == nil || message.Unread == 1 {
|
||||
if message, _ := storeMailbox.store.getMessageFromDB(apiID); message == nil || message.Unread {
|
||||
ids = append(ids, apiID)
|
||||
}
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
return storeMailbox.client().MarkMessagesRead(context.TODO(), ids)
|
||||
return storeMailbox.client().MarkMessagesRead(exposeContextForIMAP(), ids)
|
||||
}
|
||||
|
||||
// MarkMessagesUnread marks the message unread by calling an API.
|
||||
@ -151,7 +149,7 @@ func (storeMailbox *Mailbox) MarkMessagesUnread(apiIDs []string) error {
|
||||
"mailbox": storeMailbox.Name,
|
||||
}).Trace("Marking messages as unread")
|
||||
defer storeMailbox.pollNow()
|
||||
return storeMailbox.client().MarkMessagesUnread(context.TODO(), apiIDs)
|
||||
return storeMailbox.client().MarkMessagesUnread(exposeContextForIMAP(), apiIDs)
|
||||
}
|
||||
|
||||
// MarkMessagesStarred adds the Starred label by calling an API.
|
||||
@ -164,7 +162,7 @@ func (storeMailbox *Mailbox) MarkMessagesStarred(apiIDs []string) error {
|
||||
"mailbox": storeMailbox.Name,
|
||||
}).Trace("Marking messages as starred")
|
||||
defer storeMailbox.pollNow()
|
||||
return storeMailbox.client().LabelMessages(context.TODO(), apiIDs, pmapi.StarredLabel)
|
||||
return storeMailbox.client().LabelMessages(exposeContextForIMAP(), apiIDs, pmapi.StarredLabel)
|
||||
}
|
||||
|
||||
// MarkMessagesUnstarred removes the Starred label by calling an API.
|
||||
@ -177,7 +175,7 @@ func (storeMailbox *Mailbox) MarkMessagesUnstarred(apiIDs []string) error {
|
||||
"mailbox": storeMailbox.Name,
|
||||
}).Trace("Marking messages as unstarred")
|
||||
defer storeMailbox.pollNow()
|
||||
return storeMailbox.client().UnlabelMessages(context.TODO(), apiIDs, pmapi.StarredLabel)
|
||||
return storeMailbox.client().UnlabelMessages(exposeContextForIMAP(), apiIDs, pmapi.StarredLabel)
|
||||
}
|
||||
|
||||
// MarkMessagesDeleted adds local flag \Deleted. This is not propagated to API
|
||||
@ -261,11 +259,11 @@ func (storeMailbox *Mailbox) RemoveDeleted(apiIDs []string) error {
|
||||
}
|
||||
case pmapi.DraftLabel:
|
||||
storeMailbox.log.WithField("ids", apiIDs).Warn("Deleting drafts")
|
||||
if err := storeMailbox.client().DeleteMessages(context.TODO(), apiIDs); err != nil {
|
||||
if err := storeMailbox.client().DeleteMessages(exposeContextForIMAP(), apiIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := storeMailbox.client().UnlabelMessages(context.TODO(), apiIDs, storeMailbox.labelID); err != nil {
|
||||
if err := storeMailbox.client().UnlabelMessages(exposeContextForIMAP(), apiIDs, storeMailbox.labelID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -303,13 +301,13 @@ func (storeMailbox *Mailbox) deleteFromTrashOrSpam(apiIDs []string) error {
|
||||
}
|
||||
}
|
||||
if len(messageIDsToUnlabel) > 0 {
|
||||
if err := storeMailbox.client().UnlabelMessages(context.TODO(), messageIDsToUnlabel, storeMailbox.labelID); err != nil {
|
||||
if err := storeMailbox.client().UnlabelMessages(exposeContextForIMAP(), messageIDsToUnlabel, storeMailbox.labelID); err != nil {
|
||||
l.WithError(err).Warning("Cannot unlabel before deleting")
|
||||
}
|
||||
}
|
||||
if len(messageIDsToDelete) > 0 {
|
||||
storeMailbox.log.WithField("ids", messageIDsToDelete).Warn("Deleting messages")
|
||||
if err := storeMailbox.client().DeleteMessages(context.TODO(), messageIDsToDelete); err != nil {
|
||||
if err := storeMailbox.client().DeleteMessages(exposeContextForIMAP(), messageIDsToDelete); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
context "context"
|
||||
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockPanicHandler is a mock of PanicHandler interface
|
||||
@ -207,17 +207,17 @@ func (mr *MockBridgeUserMockRecorder) Logout() *gomock.Call {
|
||||
}
|
||||
|
||||
// UpdateUser mocks base method
|
||||
func (m *MockBridgeUser) UpdateUser() error {
|
||||
func (m *MockBridgeUser) UpdateUser(arg0 context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateUser")
|
||||
ret := m.ctrl.Call(m, "UpdateUser", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateUser indicates an expected call of UpdateUser
|
||||
func (mr *MockBridgeUserMockRecorder) UpdateUser() *gomock.Call {
|
||||
func (mr *MockBridgeUserMockRecorder) UpdateUser(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockBridgeUser)(nil).UpdateUser))
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockBridgeUser)(nil).UpdateUser), arg0)
|
||||
}
|
||||
|
||||
// MockChangeNotifier is a mock of ChangeNotifier interface
|
||||
|
||||
@ -5,10 +5,9 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockListener is a mock of Listener interface
|
||||
@ -58,6 +57,20 @@ func (mr *MockListenerMockRecorder) Emit(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Emit", reflect.TypeOf((*MockListener)(nil).Emit), arg0, arg1)
|
||||
}
|
||||
|
||||
// ProvideChannel mocks base method
|
||||
func (m *MockListener) ProvideChannel(arg0 string) <-chan string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ProvideChannel", arg0)
|
||||
ret0, _ := ret[0].(<-chan string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ProvideChannel indicates an expected call of ProvideChannel
|
||||
func (mr *MockListenerMockRecorder) ProvideChannel(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvideChannel", reflect.TypeOf((*MockListener)(nil).ProvideChannel), arg0)
|
||||
}
|
||||
|
||||
// Remove mocks base method
|
||||
func (m *MockListener) Remove(arg0 string, arg1 chan<- string) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@ -101,6 +101,18 @@ var (
|
||||
ErrNoSuchSeqNum = errors.New("no such sequence number") //nolint[gochecknoglobals]
|
||||
)
|
||||
|
||||
// exposeContextForIMAP should be replaced once with context passed
|
||||
// as an argument from IMAP package and IMAP library should cancel
|
||||
// context when IMAP client cancels the request.
|
||||
func exposeContextForIMAP() context.Context {
|
||||
return context.TODO()
|
||||
}
|
||||
|
||||
// exposeContextForSMTP is the same as above but for SMTP.
|
||||
func exposeContextForSMTP() context.Context {
|
||||
return context.TODO()
|
||||
}
|
||||
|
||||
// Store is local user storage, which handles the synchronization between IMAP and PM API.
|
||||
type Store struct {
|
||||
sentryReporter *sentry.Reporter
|
||||
@ -278,7 +290,7 @@ func (store *Store) client() pmapi.Client {
|
||||
// initCounts initialises the counts for each label. It tries to use the API first to fetch the labels but if
|
||||
// the API is unavailable for whatever reason it tries to fetch the labels locally.
|
||||
func (store *Store) initCounts() (labels []*pmapi.Label, err error) {
|
||||
if labels, err = store.client().ListLabels(context.TODO()); err != nil {
|
||||
if labels, err = store.client().ListLabels(context.Background()); err != nil {
|
||||
store.log.WithError(err).Warn("Could not list API labels. Trying with local labels.")
|
||||
if labels, err = store.getLabelsFromLocalStorage(); err != nil {
|
||||
store.log.WithError(err).Error("Cannot list local labels")
|
||||
|
||||
@ -184,8 +184,8 @@ func (mocks *mocksForStore) newStoreNoEvents(combinedMode bool, msgs ...*pmapi.M
|
||||
mocks.user.EXPECT().GetClient().AnyTimes().Return(mocks.client)
|
||||
|
||||
mocks.client.EXPECT().Addresses().Return(pmapi.AddressList{
|
||||
{ID: addrID1, Email: addr1, Type: pmapi.OriginalAddress, Receive: pmapi.CanReceive},
|
||||
{ID: addrID2, Email: addr2, Type: pmapi.AliasAddress, Receive: pmapi.CanReceive},
|
||||
{ID: addrID1, Email: addr1, Type: pmapi.OriginalAddress, Receive: true},
|
||||
{ID: addrID2, Email: addr2, Type: pmapi.AliasAddress, Receive: true},
|
||||
})
|
||||
mocks.client.EXPECT().ListLabels(gomock.Any()).AnyTimes()
|
||||
mocks.client.EXPECT().CountMessages(gomock.Any(), "")
|
||||
|
||||
@ -148,7 +148,7 @@ func getSplitIDAndCount(labelID string, api messageLister, page int) (string, in
|
||||
Limit: 1,
|
||||
}
|
||||
// If the page does not exist, an empty page instead of an error is returned.
|
||||
messages, total, err := api.ListMessages(context.TODO(), filter)
|
||||
messages, total, err := api.ListMessages(context.Background(), filter)
|
||||
if err != nil {
|
||||
return "", 0, errors.Wrap(err, "failed to list messages")
|
||||
}
|
||||
@ -190,7 +190,7 @@ func syncBatch( //nolint[funlen]
|
||||
|
||||
log.WithField("begin", filter.BeginID).WithField("end", filter.EndID).Debug("Fetching page")
|
||||
|
||||
messages, _, err := api.ListMessages(context.TODO(), filter)
|
||||
messages, _, err := api.ListMessages(context.Background(), filter)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list messages")
|
||||
}
|
||||
|
||||
@ -17,7 +17,11 @@
|
||||
|
||||
package store
|
||||
|
||||
import "github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
)
|
||||
|
||||
type PanicHandler interface {
|
||||
HandlePanic()
|
||||
@ -32,7 +36,7 @@ type BridgeUser interface {
|
||||
GetPrimaryAddress() string
|
||||
GetStoreAddresses() []string
|
||||
GetClient() pmapi.Client
|
||||
UpdateUser() error
|
||||
UpdateUser(context.Context) error
|
||||
CloseAllConnections()
|
||||
CloseConnection(string)
|
||||
Logout() error
|
||||
|
||||
@ -17,8 +17,6 @@
|
||||
|
||||
package store
|
||||
|
||||
import "context"
|
||||
|
||||
// UserID returns user ID.
|
||||
func (store *Store) UserID() string {
|
||||
return store.user.ID()
|
||||
@ -26,7 +24,7 @@ func (store *Store) UserID() string {
|
||||
|
||||
// GetSpace returns used and total space in bytes.
|
||||
func (store *Store) GetSpace() (usedSpace, maxSpace uint, err error) {
|
||||
apiUser, err := store.client().CurrentUser(context.TODO())
|
||||
apiUser, err := store.client().CurrentUser(exposeContextForIMAP())
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
@ -35,7 +33,7 @@ func (store *Store) GetSpace() (usedSpace, maxSpace uint, err error) {
|
||||
|
||||
// GetMaxUpload returns max size of message + all attachments in bytes.
|
||||
func (store *Store) GetMaxUpload() (int64, error) {
|
||||
apiUser, err := store.client().CurrentUser(context.TODO())
|
||||
apiUser, err := store.client().CurrentUser(exposeContextForIMAP())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ func (store *Store) createOrUpdateAddressInfo(addressList pmapi.AddressList) (er
|
||||
// filterAddresses filters out inactive addresses and ensures the original address is listed first.
|
||||
func filterAddresses(addressList pmapi.AddressList) (filteredList pmapi.AddressList) {
|
||||
for _, address := range addressList {
|
||||
if address.Receive != pmapi.CanReceive {
|
||||
if !address.Receive {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -39,14 +38,14 @@ func (store *Store) createMailbox(name string) error {
|
||||
|
||||
color := store.leastUsedColor()
|
||||
|
||||
var exclusive int
|
||||
var exclusive bool
|
||||
switch {
|
||||
case strings.HasPrefix(name, UserLabelsPrefix):
|
||||
name = strings.TrimPrefix(name, UserLabelsPrefix)
|
||||
exclusive = 0
|
||||
exclusive = false
|
||||
case strings.HasPrefix(name, UserFoldersPrefix):
|
||||
name = strings.TrimPrefix(name, UserFoldersPrefix)
|
||||
exclusive = 1
|
||||
exclusive = true
|
||||
default:
|
||||
// Ideally we would throw an error here, but then Outlook for
|
||||
// macOS keeps trying to make an IMAP Drafts folder and popping
|
||||
@ -56,10 +55,10 @@ func (store *Store) createMailbox(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := store.client().CreateLabel(context.TODO(), &pmapi.Label{
|
||||
_, err := store.client().CreateLabel(exposeContextForIMAP(), &pmapi.Label{
|
||||
Name: name,
|
||||
Color: color,
|
||||
Exclusive: exclusive,
|
||||
Exclusive: pmapi.Boolean(exclusive),
|
||||
Type: pmapi.LabelTypeMailbox,
|
||||
})
|
||||
return err
|
||||
@ -126,7 +125,7 @@ func (store *Store) leastUsedColor() string {
|
||||
func (store *Store) updateMailbox(labelID, newName, color string) error {
|
||||
defer store.eventLoop.pollNow()
|
||||
|
||||
_, err := store.client().UpdateLabel(context.TODO(), &pmapi.Label{
|
||||
_, err := store.client().UpdateLabel(exposeContextForIMAP(), &pmapi.Label{
|
||||
ID: labelID,
|
||||
Name: newName,
|
||||
Color: color,
|
||||
@ -143,15 +142,15 @@ func (store *Store) deleteMailbox(labelID, addressID string) error {
|
||||
var err error
|
||||
switch labelID {
|
||||
case pmapi.SpamLabel:
|
||||
err = store.client().EmptyFolder(context.TODO(), pmapi.SpamLabel, addressID)
|
||||
err = store.client().EmptyFolder(exposeContextForIMAP(), pmapi.SpamLabel, addressID)
|
||||
case pmapi.TrashLabel:
|
||||
err = store.client().EmptyFolder(context.TODO(), pmapi.TrashLabel, addressID)
|
||||
err = store.client().EmptyFolder(exposeContextForIMAP(), pmapi.TrashLabel, addressID)
|
||||
default:
|
||||
err = fmt.Errorf("cannot empty mailbox %v", labelID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return store.client().DeleteLabel(context.TODO(), labelID)
|
||||
return store.client().DeleteLabel(exposeContextForIMAP(), labelID)
|
||||
}
|
||||
|
||||
func (store *Store) createLabelsIfMissing(affectedLabelIDs map[string]bool) error {
|
||||
@ -166,7 +165,7 @@ func (store *Store) createLabelsIfMissing(affectedLabelIDs map[string]bool) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
labels, err := store.client().ListLabels(context.TODO())
|
||||
labels, err := store.client().ListLabels(exposeContextForIMAP())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -58,7 +57,7 @@ func (store *Store) CreateDraft(
|
||||
}
|
||||
|
||||
draftAction := store.getDraftAction(message)
|
||||
draft, err := store.client().CreateDraft(context.TODO(), message, parentID, draftAction)
|
||||
draft, err := store.client().CreateDraft(exposeContextForSMTP(), message, parentID, draftAction)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to create draft")
|
||||
}
|
||||
@ -70,7 +69,7 @@ func (store *Store) CreateDraft(
|
||||
for _, att := range attachments {
|
||||
att.attachment.MessageID = draft.ID
|
||||
|
||||
createdAttachment, err := store.client().CreateAttachment(context.TODO(), att.attachment, att.encReader, att.sigReader)
|
||||
createdAttachment, err := store.client().CreateAttachment(exposeContextForSMTP(), att.attachment, att.encReader, att.sigReader)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to create attachment")
|
||||
}
|
||||
@ -184,7 +183,7 @@ func (store *Store) getDraftAction(message *pmapi.Message) int {
|
||||
// SendMessage sends the message.
|
||||
func (store *Store) SendMessage(messageID string, req *pmapi.SendMessageReq) error {
|
||||
defer store.eventLoop.pollNow()
|
||||
_, _, err := store.client().SendMessage(context.TODO(), messageID, req)
|
||||
_, _, err := store.client().SendMessage(exposeContextForSMTP(), messageID, req)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
"github.com/golang/mock/gomock"
|
||||
a "github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -34,10 +35,10 @@ func TestGetAllMessageIDs(t *testing.T) {
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.ArchiveLabel})
|
||||
insertMessage(t, m, "msg3", "Test message 3", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg4", "Test message 4", addrID1, 0, []string{})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, false, []string{pmapi.AllMailLabel, pmapi.ArchiveLabel})
|
||||
insertMessage(t, m, "msg3", "Test message 3", addrID1, false, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg4", "Test message 4", addrID1, false, []string{})
|
||||
|
||||
checkAllMessageIDs(t, m, []string{"msg1", "msg2", "msg3", "msg4"})
|
||||
}
|
||||
@ -47,7 +48,7 @@ func TestGetMessageFromDB(t *testing.T) {
|
||||
defer clear()
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
|
||||
tests := []struct{ msgID, wantErr string }{
|
||||
{"msg1", ""},
|
||||
@ -72,7 +73,7 @@ func TestCreateOrUpdateMessageMetadata(t *testing.T) {
|
||||
defer clear()
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
|
||||
msg, err := m.store.getMessageFromDB("msg1")
|
||||
require.Nil(t, err)
|
||||
@ -104,7 +105,7 @@ func TestCreateOrUpdateMessageMetadata(t *testing.T) {
|
||||
a.Equal(t, wantHeader, msg.Header)
|
||||
|
||||
// Check calculated data are not overridden by reinsert.
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
|
||||
msg, err = m.store.getMessageFromDB("msg1")
|
||||
require.Nil(t, err)
|
||||
@ -118,8 +119,8 @@ func TestDeleteMessage(t *testing.T) {
|
||||
defer clear()
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, 0, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, false, []string{pmapi.AllMailLabel})
|
||||
|
||||
require.Nil(t, m.store.deleteMessageEvent("msg1"))
|
||||
|
||||
@ -127,17 +128,17 @@ func TestDeleteMessage(t *testing.T) {
|
||||
checkMailboxMessageIDs(t, m, pmapi.AllMailLabel, []wantID{{"msg2", 2}})
|
||||
}
|
||||
|
||||
func insertMessage(t *testing.T, m *mocksForStore, id, subject, sender string, unread pmapi.Boolean, labelIDs []string) { //nolint[unparam]
|
||||
func insertMessage(t *testing.T, m *mocksForStore, id, subject, sender string, unread bool, labelIDs []string) { //nolint[unparam]
|
||||
msg := getTestMessage(id, subject, sender, unread, labelIDs)
|
||||
require.Nil(t, m.store.createOrUpdateMessageEvent(msg))
|
||||
}
|
||||
|
||||
func getTestMessage(id, subject, sender string, unread pmapi.Boolean, labelIDs []string) *pmapi.Message {
|
||||
func getTestMessage(id, subject, sender string, unread bool, labelIDs []string) *pmapi.Message {
|
||||
address := &mail.Address{Address: sender}
|
||||
return &pmapi.Message{
|
||||
ID: id,
|
||||
Subject: subject,
|
||||
Unread: unread,
|
||||
Unread: pmapi.Boolean(unread),
|
||||
Sender: address,
|
||||
ToList: []*mail.Address{address},
|
||||
LabelIDs: labelIDs,
|
||||
@ -162,7 +163,7 @@ func TestCreateDraftCheckMessageSize(t *testing.T) {
|
||||
defer clear()
|
||||
|
||||
m.newStoreNoEvents(false)
|
||||
m.client.EXPECT().CurrentUser().Return(&pmapi.User{
|
||||
m.client.EXPECT().CurrentUser(gomock.Any()).Return(&pmapi.User{
|
||||
MaxUpload: 100, // Decrypted message 5 chars, encrypted 500+.
|
||||
}, nil)
|
||||
|
||||
@ -181,7 +182,7 @@ func TestCreateDraftCheckMessageWithAttachmentSize(t *testing.T) {
|
||||
defer clear()
|
||||
|
||||
m.newStoreNoEvents(false)
|
||||
m.client.EXPECT().CurrentUser().Return(&pmapi.User{
|
||||
m.client.EXPECT().CurrentUser(gomock.Any()).Return(&pmapi.User{
|
||||
MaxUpload: 800, // Decrypted message 5 chars + 5 chars of attachment, encrypted 500+ + 300+.
|
||||
}, nil)
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ const syncIDsToBeDeletedKey = "ids_to_be_deleted"
|
||||
|
||||
// updateCountsFromServer will download and set the counts.
|
||||
func (store *Store) updateCountsFromServer() error {
|
||||
counts, err := store.client().CountMessages(context.TODO(), "")
|
||||
counts, err := store.client().CountMessages(context.Background(), "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot update counts from server")
|
||||
}
|
||||
|
||||
@ -31,8 +31,8 @@ func TestLoadSaveSyncState(t *testing.T) {
|
||||
defer clear()
|
||||
|
||||
m.newStoreNoEvents(true)
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, 0, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg1", "Test message 1", addrID1, false, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
insertMessage(t, m, "msg2", "Test message 2", addrID1, false, []string{pmapi.AllMailLabel, pmapi.InboxLabel})
|
||||
|
||||
// Clear everything.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user