Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/godt 2576 #400

Merged
merged 2 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions benchmarks/gluon_bench/gluon_benchmarks/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ func init() {

type nullIMAPStateWriter struct{}

func (n nullIMAPStateWriter) AddFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
panic("implement me")
}

func (n nullIMAPStateWriter) AddPermFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
panic("implement me")
}

func (n nullIMAPStateWriter) GetSettings(ctx context.Context) (string, bool, error) {
return "", false, nil
}
Expand Down
3 changes: 3 additions & 0 deletions connector/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ type Connector interface {
// MarkMessagesFlagged sets the flagged value of the given messages.
MarkMessagesFlagged(ctx context.Context, cache IMAPStateWrite, messageIDs []imap.MessageID, flagged bool) error

// MarkMessagesForwarded sets the forwarded value of the give messages.
MarkMessagesForwarded(ctx context.Context, cache IMAPStateWrite, messageIDs []imap.MessageID, forwarded bool) error

// GetUpdates returns a stream of updates that the gluon server should apply.
GetUpdates() <-chan imap.Update

Expand Down
13 changes: 13 additions & 0 deletions connector/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ func (conn *Dummy) MarkMessagesFlagged(_ context.Context, _ IMAPStateWrite, mess
return nil
}

func (conn *Dummy) MarkMessagesForwarded(ctx context.Context, cache IMAPStateWrite, messageIDs []imap.MessageID, forwarded bool) error {
for _, messageID := range messageIDs {
conn.state.setForwarded(messageID, forwarded)

conn.pushUpdate(imap.NewMessageFlagsUpdated(
messageID,
conn.state.getMessageFlags(messageID),
))
}

return nil
}

func (conn *Dummy) Sync(ctx context.Context) error {
for _, mailbox := range conn.state.getMailboxes() {
update := imap.NewMailboxCreated(mailbox)
Expand Down
25 changes: 19 additions & 6 deletions connector/dummy_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ type dummyMailbox struct {
}

type dummyMessage struct {
literal []byte
parsed *imap.ParsedMessage
seen bool
flagged bool
date time.Time
flags imap.FlagSet
literal []byte
parsed *imap.ParsedMessage
seen bool
flagged bool
forwarded bool
date time.Time
flags imap.FlagSet

mboxIDs map[imap.MailboxID]struct{}
}
Expand Down Expand Up @@ -256,6 +257,13 @@ func (state *dummyState) setFlagged(messageID imap.MessageID, flagged bool) {
state.messages[messageID].flagged = flagged
}

func (state *dummyState) setForwarded(messageID imap.MessageID, forwarded bool) {
state.lock.Lock()
defer state.lock.Unlock()

state.messages[messageID].forwarded = forwarded
}

func (state *dummyState) isSeen(messageID imap.MessageID) bool {
state.lock.Lock()
defer state.lock.Unlock()
Expand Down Expand Up @@ -294,6 +302,11 @@ func (state *dummyState) getMessageFlags(messageID imap.MessageID) imap.FlagSet
flags.AddToSelf(imap.FlagFlagged)
}

if msg.forwarded {
flags.AddToSelf(imap.XFlagForwarded)
flags.AddToSelf(imap.XFlagDollarForwarded)
}

return flags
}

Expand Down
4 changes: 4 additions & 0 deletions connector/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,8 @@ type IMAPStateWrite interface {
// transformation necessary to ensure that new parent or child mailboxes are created as expected by a regular
// IMAP rename operation.
PatchMailboxHierarchyWithoutTransforms(ctx context.Context, id imap.MailboxID, newName []string) error

AddFlagsToAllMailboxes(ctx context.Context, flags ...string) error

AddPermFlagsToAllMailboxes(ctx context.Context, flags ...string) error
}
4 changes: 4 additions & 0 deletions db/ops_mailbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ type MailboxWriteOps interface {
UpdateRemoteMailboxID(ctx context.Context, mobxID imap.InternalMailboxID, remoteID imap.MailboxID) error

SetMailboxUIDValidity(ctx context.Context, mboxID imap.InternalMailboxID, uidValidity imap.UID) error

AddFlagsToAllMailboxes(ctx context.Context, flags ...string) error

AddPermFlagsToAllMailboxes(ctx context.Context, flags ...string) error
}

type SnapshotMessageResult struct {
Expand Down
2 changes: 1 addition & 1 deletion imap/command/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (s Store) String() string {
silentStr = ".SILENT"
}

return fmt.Sprintf("STORE %v%v %v", s.Action.String(), silentStr, s.Flags)
return fmt.Sprintf("STORE %v %v%v %v", s.SeqSet, s.Action.String(), silentStr, s.Flags)
}

func (s Store) SanitizedString() string {
Expand Down
46 changes: 34 additions & 12 deletions imap/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,37 @@ import (
)

const (
FlagSeen = `\Seen`
FlagAnswered = `\Answered`
FlagFlagged = `\Flagged`
FlagDeleted = `\Deleted`
FlagDraft = `\Draft`
FlagRecent = `\Recent` // Read-only!.
FlagSeen = `\Seen`
FlagAnswered = `\Answered`
FlagFlagged = `\Flagged`
FlagDeleted = `\Deleted`
FlagDraft = `\Draft`
FlagRecent = `\Recent` // Read-only!.
XFlagDollarForwarded = "$Forwarded" // Non-Standard flag
XFlagForwarded = "Forwarded" // Non-Standard flag
)

const (
FlagSeenLowerCase = `\seen`
FlagAnsweredLowerCase = `\answered`
FlagFlaggedLowerCase = `\flagged`
FlagDeletedLowerCase = `\deleted`
FlagDraftLowerCase = `\draft`
FlagRecentLowerCase = `\recent` // Read-only!.
FlagSeenLowerCase = `\seen`
FlagAnsweredLowerCase = `\answered`
FlagFlaggedLowerCase = `\flagged`
FlagDeletedLowerCase = `\deleted`
FlagDraftLowerCase = `\draft`
FlagRecentLowerCase = `\recent` // Read-only!.
XFlagDollarForwardedLowerCase = "$forwarded"
XFlagForwardedLowerCase = "forwarded"
)

var ForwardFlagList = []string{
XFlagDollarForwarded,
XFlagForwarded,
}

var ForwardFlagListLowerCase = []string{
XFlagDollarForwardedLowerCase,
XFlagForwardedLowerCase,
}

// FlagSet represents a set of IMAP flags. Flags are case-insensitive and no duplicates are allowed.
type FlagSet map[string]string

Expand Down Expand Up @@ -89,6 +103,14 @@ func (fs FlagSet) ContainsAny(flags ...string) bool {
}) >= 0
}

// ContainsAnyUnchecked returns true if and only if any of the flags are in the set. The flag list is not converted to
// lower case.
func (fs FlagSet) ContainsAnyUnchecked(flags ...string) bool {
return xslices.IndexFunc(flags, func(f string) bool {
return fs.ContainsUnchecked(f)
}) >= 0
}

// ContainsAll returns true if and only if all of the flags are in the set.
func (fs FlagSet) ContainsAll(flags ...string) bool {
return xslices.IndexFunc(flags, func(f string) bool {
Expand Down
8 changes: 8 additions & 0 deletions internal/backend/connector_state_write.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ func (d *DBIMAPStateWrite) PatchMailboxHierarchyWithoutTransforms(ctx context.Co
return d.tx.RenameMailboxWithRemoteID(ctx, id, combined)
}

func (d *DBIMAPStateWrite) AddFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
return d.tx.AddFlagsToAllMailboxes(ctx, flags...)
}

func (d *DBIMAPStateWrite) AddPermFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
return d.tx.AddPermFlagsToAllMailboxes(ctx, flags...)
}

func (d *DBIMAPStateWrite) wrapStateUpdates(ctx context.Context, f func(ctx context.Context, tx db.Transaction) ([]state.Update, error)) error {
updates, err := f(ctx, d.tx)
if err == nil {
Expand Down
17 changes: 17 additions & 0 deletions internal/backend/state_connector_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,23 @@ func (sc *stateConnectorImpl) GetMailboxVisibility(ctx context.Context,
return sc.connector.GetMailboxVisibility(ctx, id)
}

func (sc *stateConnectorImpl) SetMessagesForwarded(
ctx context.Context,
tx db.Transaction,
messageIDs []imap.MessageID,
forwarded bool,
) ([]state.Update, error) {
ctx = sc.newContextWithMetadata(ctx)

cache := sc.newDBIMAPWrite(tx)

if err := sc.connector.MarkMessagesForwarded(ctx, &cache, messageIDs, forwarded); err != nil {
return nil, err
}

return cache.stateUpdates, nil
}

func (sc *stateConnectorImpl) getMetadataValue(key string) any {
v, ok := sc.metadata[key]
if !ok {
Expand Down
12 changes: 12 additions & 0 deletions internal/db_impl/sqlite3/utils/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,15 @@ func (w WriteTracer) StoreConnectorSettings(ctx context.Context, settings string

return w.TX.StoreConnectorSettings(ctx, settings)
}

func (w WriteTracer) AddFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
w.Entry.Tracef("AddFlagsToAllMailboxes")

return w.TX.AddFlagsToAllMailboxes(ctx, flags...)
}

func (w WriteTracer) AddPermFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
w.Entry.Tracef("AddPermFlagsToAllMailboxes")

return w.TX.AddPermFlagsToAllMailboxes(ctx, flags...)
}
40 changes: 40 additions & 0 deletions internal/db_impl/sqlite3/write_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -669,3 +669,43 @@ func (w writeOps) StoreConnectorSettings(ctx context.Context, settings string) e

return err
}

func (w writeOps) AddFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
flagsJoined := strings.Join(xslices.Map(flags, func(s string) string {
return "('" + s + "')"
}), ",")

queryInsert := fmt.Sprintf(
"INSERT OR IGNORE INTO %v (`%v`, `%v`) SELECT `%v`,`value` FROM %v CROSS JOIN (WITH T(value) AS (VALUES %v) SELECT * FROM T)",
v1.MailboxFlagsTableName,
v1.MailboxFlagsFieldMailboxID,
v1.MailboxFlagsFieldValue,
v1.MailboxesFieldID,
v1.MailboxesTableName,
flagsJoined,
)

_, err := utils.ExecQuery(ctx, w.qw, queryInsert)

return err
}

func (w writeOps) AddPermFlagsToAllMailboxes(ctx context.Context, flags ...string) error {
flagsJoined := strings.Join(xslices.Map(flags, func(s string) string {
return "('" + s + "')"
}), ",")

queryInsert := fmt.Sprintf(
"INSERT OR IGNORE INTO %v (`%v`, `%v`) SELECT `%v`,`value` FROM %v CROSS JOIN (WITH T(value) AS (VALUES %v) SELECT * FROM T)",
v1.MailboxPermFlagsTableName,
v1.MailboxPermFlagsFieldMailboxID,
v1.MailboxPermFlagsFieldValue,
v1.MailboxesFieldID,
v1.MailboxesTableName,
flagsJoined,
)

_, err := utils.ExecQuery(ctx, w.qw, queryInsert)

return err
}
3 changes: 3 additions & 0 deletions internal/state/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,7 @@ type Connector interface {

// GetMailboxVisibility retrieves the visibility status of a mailbox for a client.
GetMailboxVisibility(ctx context.Context, id imap.MailboxID) imap.MailboxVisibility

// SetMessagesForwarded marks the message with the given ID as forwarded.
SetMessagesForwarded(ctx context.Context, tx db.Transaction, messageIDs []imap.MessageID, forwarded bool) ([]Update, error)
}
Loading