forked from Silverfish/proton-bridge
feat(GODT-2576): Forward and $Forward Flag Support
When an IMAP client stores the `Forward` or `$Forward` flags on a message, the forwarded state is now correctly represented on the Proton servers. https://github.com/ProtonMail/go-proton-api/pull/125 https://github.com/ProtonMail/gluon/pull/400
This commit is contained in:
@ -48,4 +48,6 @@ type APIClient interface {
|
||||
DeleteMessage(ctx context.Context, messageIDs ...string) error
|
||||
MarkMessagesRead(ctx context.Context, messageIDs ...string) error
|
||||
MarkMessagesUnread(ctx context.Context, messageIDs ...string) error
|
||||
MarkMessagesForwarded(ctx context.Context, messageIDs ...string) error
|
||||
MarkMessagesUnForwarded(ctx context.Context, messageIDs ...string) error
|
||||
}
|
||||
|
||||
@ -84,9 +84,9 @@ func NewConnector(
|
||||
identityState: identityState,
|
||||
addrID: addrID,
|
||||
showAllMail: b32(showAllMail),
|
||||
flags: defaultFlags,
|
||||
permFlags: defaultPermanentFlags,
|
||||
attrs: defaultAttributes,
|
||||
flags: defaultMailboxFlags(),
|
||||
permFlags: defaultMailboxPermanentFlags(),
|
||||
attrs: defaultMailboxAttributes(),
|
||||
|
||||
client: apiClient,
|
||||
telemetry: telemetry,
|
||||
@ -144,6 +144,18 @@ func (s *Connector) Init(ctx context.Context, cache connector.IMAPState) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retroactively apply the forwarded flags to existing mailboxes so that the IMAP clients can recognize
|
||||
// that they can store these flags now.
|
||||
if err := write.AddFlagsToAllMailboxes(ctx, imap.ForwardFlagList...); err != nil {
|
||||
return fmt.Errorf("failed to add \\Forward flag to all mailboxes:%w", err)
|
||||
}
|
||||
|
||||
// Add forwarded flag as perm flags to all mailboxes.
|
||||
if err := write.AddPermFlagsToAllMailboxes(ctx, imap.ForwardFlagList...); err != nil {
|
||||
return fmt.Errorf("failed to add \\Forward permanent flag to all mailboxes:%w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -487,6 +499,14 @@ func (s *Connector) MarkMessagesFlagged(ctx context.Context, _ connector.IMAPSta
|
||||
return s.client.UnlabelMessages(ctx, usertypes.MapTo[imap.MessageID, string](messageIDs), proton.StarredLabel)
|
||||
}
|
||||
|
||||
func (s *Connector) MarkMessagesForwarded(ctx context.Context, _ connector.IMAPStateWrite, messageIDs []imap.MessageID, flagged bool) error {
|
||||
if flagged {
|
||||
return s.client.MarkMessagesForwarded(ctx, usertypes.MapTo[imap.MessageID, string](messageIDs)...)
|
||||
}
|
||||
|
||||
return s.client.MarkMessagesUnForwarded(ctx, usertypes.MapTo[imap.MessageID, string](messageIDs)...)
|
||||
}
|
||||
|
||||
func (s *Connector) GetUpdates() <-chan imap.Update {
|
||||
return s.updateCh.GetChannel()
|
||||
}
|
||||
@ -501,12 +521,6 @@ func (s *Connector) ShowAllMail(v bool) {
|
||||
atomic.StoreUint32(&s.showAllMail, b32(v))
|
||||
}
|
||||
|
||||
var (
|
||||
defaultFlags = imap.NewFlagSet(imap.FlagSeen, imap.FlagFlagged, imap.FlagDeleted) // nolint:gochecknoglobals
|
||||
defaultPermanentFlags = imap.NewFlagSet(imap.FlagSeen, imap.FlagFlagged, imap.FlagDeleted) // nolint:gochecknoglobals
|
||||
defaultAttributes = imap.NewFlagSet() // nolint:gochecknoglobals
|
||||
)
|
||||
|
||||
const (
|
||||
folderPrefix = "Folders"
|
||||
labelPrefix = "Labels"
|
||||
@ -812,3 +826,18 @@ func fixGODT3003Labels(
|
||||
|
||||
return applied, nil
|
||||
}
|
||||
|
||||
func defaultMailboxFlags() imap.FlagSet {
|
||||
f := imap.NewFlagSet(imap.FlagSeen, imap.FlagFlagged, imap.FlagDeleted)
|
||||
f.AddToSelf(imap.ForwardFlagList...)
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func defaultMailboxPermanentFlags() imap.FlagSet {
|
||||
return defaultMailboxFlags()
|
||||
}
|
||||
|
||||
func defaultMailboxAttributes() imap.FlagSet {
|
||||
return imap.NewFlagSet()
|
||||
}
|
||||
|
||||
@ -68,6 +68,10 @@ func BuildFlagSetFromMessageMetadata(message proton.MessageMetadata) imap.FlagSe
|
||||
flags.AddToSelf(imap.FlagAnswered)
|
||||
}
|
||||
|
||||
if message.IsForwarded {
|
||||
flags.AddToSelf(imap.ForwardFlagList...)
|
||||
}
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
|
||||
@ -32,8 +32,8 @@ func newSystemMailboxCreatedUpdate(labelID imap.MailboxID, labelName string) *im
|
||||
}
|
||||
|
||||
attrs := imap.NewFlagSet(imap.AttrNoInferiors)
|
||||
permanentFlags := defaultPermanentFlags
|
||||
flags := defaultFlags
|
||||
permanentFlags := defaultMailboxPermanentFlags()
|
||||
flags := defaultMailboxFlags()
|
||||
|
||||
switch labelID {
|
||||
case proton.TrashLabel:
|
||||
@ -86,8 +86,8 @@ func newPlaceHolderMailboxCreatedUpdate(labelName string) *imap.MailboxCreated {
|
||||
return imap.NewMailboxCreated(imap.Mailbox{
|
||||
ID: imap.MailboxID(labelName),
|
||||
Name: []string{labelName},
|
||||
Flags: defaultFlags,
|
||||
PermanentFlags: defaultPermanentFlags,
|
||||
Flags: defaultMailboxFlags(),
|
||||
PermanentFlags: defaultMailboxPermanentFlags(),
|
||||
Attributes: imap.NewFlagSet(imap.AttrNoSelect),
|
||||
})
|
||||
}
|
||||
@ -96,8 +96,8 @@ func newMailboxCreatedUpdate(labelID imap.MailboxID, labelName []string) *imap.M
|
||||
return imap.NewMailboxCreated(imap.Mailbox{
|
||||
ID: labelID,
|
||||
Name: labelName,
|
||||
Flags: defaultFlags,
|
||||
PermanentFlags: defaultPermanentFlags,
|
||||
Flags: defaultMailboxFlags(),
|
||||
PermanentFlags: defaultMailboxPermanentFlags(),
|
||||
Attributes: imap.NewFlagSet(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -35,6 +35,44 @@ func (m *MockIMAPStateWrite) EXPECT() *MockIMAPStateWriteMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddFlagsToAllMailboxes mocks base method.
|
||||
func (m *MockIMAPStateWrite) AddFlagsToAllMailboxes(arg0 context.Context, arg1 ...string) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddFlagsToAllMailboxes", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddFlagsToAllMailboxes indicates an expected call of AddFlagsToAllMailboxes.
|
||||
func (mr *MockIMAPStateWriteMockRecorder) AddFlagsToAllMailboxes(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddFlagsToAllMailboxes", reflect.TypeOf((*MockIMAPStateWrite)(nil).AddFlagsToAllMailboxes), varargs...)
|
||||
}
|
||||
|
||||
// AddPermFlagsToAllMailboxes mocks base method.
|
||||
func (m *MockIMAPStateWrite) AddPermFlagsToAllMailboxes(arg0 context.Context, arg1 ...string) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddPermFlagsToAllMailboxes", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddPermFlagsToAllMailboxes indicates an expected call of AddPermFlagsToAllMailboxes.
|
||||
func (mr *MockIMAPStateWriteMockRecorder) AddPermFlagsToAllMailboxes(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPermFlagsToAllMailboxes", reflect.TypeOf((*MockIMAPStateWrite)(nil).AddPermFlagsToAllMailboxes), varargs...)
|
||||
}
|
||||
|
||||
// CreateMailbox mocks base method.
|
||||
func (m *MockIMAPStateWrite) CreateMailbox(arg0 context.Context, arg1 imap.Mailbox) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
Reference in New Issue
Block a user