state

package
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2023 License: MIT Imports: 31 Imported by: 0

Documentation

Index

Constants

View Source
const (
	FetchFlagOpAdd = iota
	FetchFlagOpRem
	FetchFlagOpSet
)

Variables

View Source
var (
	ErrNoSuchMessage = errors.New("no such message")
	ErrNoSuchMailbox = errors.New("no such mailbox")

	ErrExistingMailbox     = errors.New("a mailbox with that name already exists")
	ErrAlreadySubscribed   = errors.New("already subscribed to this mailbox")
	ErrAlreadyUnsubscribed = errors.New("not subscribed to this mailbox")
	ErrSessionNotSelected  = errors.New("session is not selected")

	ErrOperationNotAllowed            = errors.New("operation not allowed")
	ErrMailboxNameBeginsWithSeparator = errors.New("invalid mailbox name: begins with hierarchy separator")
	ErrMailboxNameAdjacentSeparator   = errors.New("invalid mailbox name: has adjacent hierarchy separators")
)
View Source
var ErrKnownRecoveredMessage = errors.New("known recovered message, possible duplication")
View Source
var ErrOutOfOrderUIDInsertion = fmt.Errorf("UIDs must be strictly ascending")

Functions

func IsStateError added in v0.16.0

func IsStateError(err error) bool

func NewExpunge

func NewExpunge(messageID imap.InternalMessageID) *expunge

func NewFetch

func NewFetch(messageID imap.InternalMessageID, flags imap.FlagSet, asUID, asSilent, cameFromDifferentMailbox bool, fetchFlagOp int) *fetch

func NewStateContext

func NewStateContext(ctx context.Context, s *State) context.Context

NewStateContext will annotate a context object with the state's assigned ID. This can later be used to determine whether the current active call came from a state and which one.

Types

type AllStateFilter

type AllStateFilter struct{}

func (*AllStateFilter) Filter

func (*AllStateFilter) Filter(s *State) bool

func (*AllStateFilter) String

func (*AllStateFilter) String() string

type AnyMessageIDStateFilter

type AnyMessageIDStateFilter struct {
	MessageIDs []imap.InternalMessageID
}

func (*AnyMessageIDStateFilter) Filter

func (f *AnyMessageIDStateFilter) Filter(s *State) bool

type AppendOnlyMailbox

type AppendOnlyMailbox interface {
	Append(ctx context.Context, literal []byte, flags imap.FlagSet, date time.Time) (imap.UID, error)
	Flush(ctx context.Context, permitExpunge bool) ([]response.Response, error)
	UIDValidity() imap.UID
	IsDrafts(ctx context.Context) (bool, error)
}

type Connector

type Connector interface {
	// SetConnMetadataValue sets a metadata value associated with the current connector.
	SetConnMetadataValue(key string, value any)

	// ClearConnMetadataValue clears a metadata value associated with the current connector.
	ClearConnMetadataValue(key string)

	// ClearAllConnMetadata clears all metadata values associated with the current connector.
	ClearAllConnMetadata()

	// CreateMailbox creates a new mailbox with the given name.
	CreateMailbox(ctx context.Context, name []string) (imap.Mailbox, error)

	// UpdateMailbox sets the name of the mailbox with the given ID to the given new name.
	UpdateMailbox(ctx context.Context, mboxID imap.MailboxID, newName []string) error

	// DeleteMailbox deletes the mailbox with the given ID and name.
	DeleteMailbox(ctx context.Context, mboxID imap.MailboxID) error

	// CreateMessage appends a message literal to the mailbox with the given ID.
	CreateMessage(
		ctx context.Context,
		mboxID imap.MailboxID,
		literal []byte,
		flags imap.FlagSet,
		date time.Time,
	) (imap.InternalMessageID, imap.Message, []byte, error)

	// GetMessageLiteral retrieves the message literal from the connector.
	// Note: this can get called from different go routines.
	GetMessageLiteral(ctx context.Context, id imap.MessageID) ([]byte, error)

	// AddMessagesToMailbox adds the message with the given ID to the mailbox with the given ID.
	AddMessagesToMailbox(
		ctx context.Context,
		messageIDs []imap.MessageID,
		mboxID imap.MailboxID,
	) error

	// RemoveMessagesFromMailbox removes the message with the given ID from the mailbox with the given ID.
	RemoveMessagesFromMailbox(
		ctx context.Context,
		messageIDs []imap.MessageID,
		mboxID imap.MailboxID,
	) error

	// MoveMessagesFromMailbox removes the message with the given ID from the mailbox with the given ID.
	MoveMessagesFromMailbox(
		ctx context.Context,
		messageIDs []imap.MessageID,
		mboxFromID imap.MailboxID,
		mboxToID imap.MailboxID,
	) (bool, error)

	// SetMessagesSeen marks the message with the given ID as seen or unseen.
	SetMessagesSeen(ctx context.Context, messageIDs []imap.MessageID, seen bool) error

	// SetMessagesFlagged marks the message with the given ID as seen or unseen.
	SetMessagesFlagged(ctx context.Context, messageIDs []imap.MessageID, flagged bool) error

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

Connector interface for State differs slightly from the connector.Connector interface as it needs the ability to generate internal IDs for each request as well as track local metadata associated with each state. The local metadata (e.g.: IMAP ID extension info) should be injected into the context before each call to ensure the connector.Connector can receive this information. Sadly, due to Go's cyclic dependencies, this needs to be an interface. The implementation of this interface is available in the backend package.

type ExistsStateUpdate

type ExistsStateUpdate struct {
	MBoxIDStateFilter
	// contains filtered or unexported fields
}

ExistsStateUpdate needs to be a separate update since it has to deal with a Recent flag propagation. If a session with a selected state appends a message, only that state should see the recent flag. If a message is appended to a non-selected mailbox or arrives from remote, the first state with the selected mailbox should get the flag. See ExistsStateUpdate.Apply() for more info.

func (*ExistsStateUpdate) Apply

func (e *ExistsStateUpdate) Apply(ctx context.Context, tx db.Transaction, s *State) error

func (*ExistsStateUpdate) String

func (e *ExistsStateUpdate) String() string

type MBoxIDStateFilter

type MBoxIDStateFilter struct {
	MboxID imap.InternalMailboxID
}

func (*MBoxIDStateFilter) Filter

func (f *MBoxIDStateFilter) Filter(s *State) bool

func (*MBoxIDStateFilter) String

func (f *MBoxIDStateFilter) String() string

type Mailbox

type Mailbox struct {
	// contains filtered or unexported fields
}

func (*Mailbox) Append

func (m *Mailbox) Append(ctx context.Context, literal []byte, flags imap.FlagSet, date time.Time) (imap.UID, error)

func (*Mailbox) AppendRegular added in v0.14.0

func (m *Mailbox) AppendRegular(ctx context.Context, literal []byte, flags imap.FlagSet, date time.Time) (imap.UID, error)

func (*Mailbox) Attributes

func (m *Mailbox) Attributes(ctx context.Context) (imap.FlagSet, error)

func (*Mailbox) Close

func (m *Mailbox) Close(ctx context.Context) error

func (*Mailbox) Copy

func (m *Mailbox) Copy(ctx context.Context, seq []command.SeqRange, name string) (response.Item, error)

Copy copies the messages represented by the given sequence set into the mailbox with the given name. If the context is a UID context, the sequence set refers to message UIDs. If no items are copied the response object will be nil.

func (*Mailbox) Count

func (m *Mailbox) Count() int

func (*Mailbox) Expunge

func (m *Mailbox) Expunge(ctx context.Context, seq []command.SeqRange) error

func (*Mailbox) ExpungeIssued

func (m *Mailbox) ExpungeIssued() bool

func (*Mailbox) Fetch

func (m *Mailbox) Fetch(ctx context.Context, cmd *command.Fetch, ch chan response.Response) error

func (*Mailbox) Flags

func (m *Mailbox) Flags(ctx context.Context) (imap.FlagSet, error)

func (*Mailbox) Flush

func (m *Mailbox) Flush(ctx context.Context, permitExpunge bool) ([]response.Response, error)

func (*Mailbox) GetFirstMessageWithFlag

func (m *Mailbox) GetFirstMessageWithFlag(flag string) (snapMsgWithSeq, bool)

func (*Mailbox) GetFirstMessageWithoutFlag

func (m *Mailbox) GetFirstMessageWithoutFlag(flag string) (snapMsgWithSeq, bool)

func (*Mailbox) GetMessagesWithFlag

func (m *Mailbox) GetMessagesWithFlag(flag string) []imap.SeqID

func (*Mailbox) GetMessagesWithFlagCount

func (m *Mailbox) GetMessagesWithFlagCount(flag string) int

func (*Mailbox) GetMessagesWithoutFlag

func (m *Mailbox) GetMessagesWithoutFlag(flag string) []imap.SeqID

func (*Mailbox) GetMessagesWithoutFlagCount

func (m *Mailbox) GetMessagesWithoutFlagCount(flag string) int

func (*Mailbox) IsDrafts added in v0.17.0

func (m *Mailbox) IsDrafts(ctx context.Context) (bool, error)

func (*Mailbox) Move

func (m *Mailbox) Move(ctx context.Context, seq []command.SeqRange, name string) (response.Item, error)

Move moves the messages represented by the given sequence set into the mailbox with the given name. If the context is a UID context, the sequence set refers to message UIDs. If no items are moved the response object will be nil.

func (*Mailbox) Name

func (m *Mailbox) Name() string

func (*Mailbox) PermanentFlags

func (m *Mailbox) PermanentFlags(ctx context.Context) (imap.FlagSet, error)

func (*Mailbox) ReadOnly

func (m *Mailbox) ReadOnly() bool

func (*Mailbox) Search

func (m *Mailbox) Search(ctx context.Context, keys []command.SearchKey, decoder *encoding.Decoder) ([]uint32, error)

func (*Mailbox) Selected

func (m *Mailbox) Selected() bool

func (*Mailbox) Store

func (m *Mailbox) Store(ctx context.Context, seqSet []command.SeqRange, action command.StoreAction, flags imap.FlagSet) error

func (*Mailbox) Subscribed

func (m *Mailbox) Subscribed() bool

func (*Mailbox) UIDNext

func (m *Mailbox) UIDNext(ctx context.Context) (imap.UID, error)

func (*Mailbox) UIDValidity

func (m *Mailbox) UIDValidity() imap.UID

type Match

type Match struct {
	Name      string
	Delimiter string
	Atts      imap.FlagSet
}

type MessageAndMBoxIDStateFilter

type MessageAndMBoxIDStateFilter struct {
	MessageID imap.InternalMessageID
	MBoxID    imap.InternalMailboxID
}

func (*MessageAndMBoxIDStateFilter) Filter

func (f *MessageAndMBoxIDStateFilter) Filter(s *State) bool

func (*MessageAndMBoxIDStateFilter) String

func (f *MessageAndMBoxIDStateFilter) String() string

type MessageIDStateFilter

type MessageIDStateFilter struct {
	MessageID imap.InternalMessageID
}

func (*MessageIDStateFilter) Filter

func (f *MessageIDStateFilter) Filter(s *State) bool

func (*MessageIDStateFilter) String

func (f *MessageIDStateFilter) String() string

type RemoteAddMessageFlagsStateUpdate

type RemoteAddMessageFlagsStateUpdate struct {
	MessageIDStateFilter
	// contains filtered or unexported fields
}

func (*RemoteAddMessageFlagsStateUpdate) Apply

func (*RemoteAddMessageFlagsStateUpdate) String

type RemoteMessageDeletedStateUpdate

type RemoteMessageDeletedStateUpdate struct {
	MessageIDStateFilter
	// contains filtered or unexported fields
}

type RemoteRemoveMessageFlagsStateUpdate

type RemoteRemoveMessageFlagsStateUpdate struct {
	MessageIDStateFilter
	// contains filtered or unexported fields
}

func (*RemoteRemoveMessageFlagsStateUpdate) Apply

func (*RemoteRemoveMessageFlagsStateUpdate) String

type Responder

type Responder interface {
	String() string
	// contains filtered or unexported methods
}

type SeqInterval

type SeqInterval struct {
	// contains filtered or unexported fields
}

type SnapFilter

type SnapFilter interface {
	Filter(s *State) bool
	String() string
}

func NewAllStateFilter

func NewAllStateFilter() SnapFilter

func NewMBoxIDStateFilter

func NewMBoxIDStateFilter(mboxID imap.InternalMailboxID) SnapFilter

func NewMessageAndMBoxIDStateFilter

func NewMessageAndMBoxIDStateFilter(msgID imap.InternalMessageID, mboxID imap.InternalMailboxID) SnapFilter

func NewMessageIDStateFilter

func NewMessageIDStateFilter(msgID imap.InternalMessageID) SnapFilter

type State

type State struct {
	StateID StateID
	// contains filtered or unexported fields
}

State represents the active session's state after a user has been authenticated. This code is expected to run on one single goroutine/thread and should some interaction be required with other states from other session, they shall happen through updates (state.Update) which are queued via the UserInterface. Similarly, the state also accepts incoming updates via the ApplyUpdate method.

func NewState

func NewState(user UserInterface, delimiter string, imapLimits limits.IMAP, panicHandler async.PanicHandler) *State

func (*State) AppendOnlyMailbox

func (state *State) AppendOnlyMailbox(ctx context.Context, name string, fn func(AppendOnlyMailbox, bool) error) error

AppendOnlyMailbox does not guarantee that the mailbox snapshot is loaded data from the database and passes true into the function if the currently selected mailbox matches the requested mailbox. It can only be used for appending.

func (*State) ApplyUpdate

func (state *State) ApplyUpdate(ctx context.Context, update Update) error

func (*State) Close

func (state *State) Close(ctx context.Context) error

func (*State) Create

func (state *State) Create(ctx context.Context, name string) error

func (*State) Delete

func (state *State) Delete(ctx context.Context, name string) (bool, error)

Delete returns true if the mailbox that was deleted was the same as the one that was currently selected.

func (*State) Done

func (state *State) Done() <-chan struct{}

func (*State) Examine

func (state *State) Examine(ctx context.Context, name string, fn func(*Mailbox) error) error

func (*State) GetStateUpdatesCh

func (state *State) GetStateUpdatesCh() <-chan Update

func (*State) HasMessage

func (state *State) HasMessage(id imap.InternalMessageID) bool

func (*State) Idle

func (state *State) Idle(ctx context.Context, fn func([]response.Response, chan response.Response) error) error

func (*State) IsSelected

func (state *State) IsSelected() bool

func (*State) IsValid

func (state *State) IsValid() bool

func (*State) List

func (state *State) List(ctx context.Context, ref, pattern string, lsub bool, fn func(map[string]Match) error) error

func (*State) Mailbox

func (state *State) Mailbox(ctx context.Context, name string, fn func(*Mailbox) error) error

func (*State) PushResponder

func (state *State) PushResponder(ctx context.Context, tx db.Transaction, responder ...Responder) error

func (*State) QueueUpdates

func (state *State) QueueUpdates(updates ...Update) bool

func (*State) ReleaseState

func (state *State) ReleaseState(ctx context.Context) error

func (*State) Rename

func (state *State) Rename(ctx context.Context, oldName, newName string) error

func (*State) Select

func (state *State) Select(ctx context.Context, name string, fn func(*Mailbox) error) error

func (*State) Selected

func (state *State) Selected(ctx context.Context, fn func(*Mailbox) error) error

func (*State) SetConnMetadataKeyValue

func (state *State) SetConnMetadataKeyValue(key string, value any)

func (*State) SignalClose

func (state *State) SignalClose()

func (*State) Subscribe

func (state *State) Subscribe(ctx context.Context, name string) error

func (*State) Unsubscribe

func (state *State) Unsubscribe(ctx context.Context, name string) error

func (*State) UpdateMailboxRemoteID

func (state *State) UpdateMailboxRemoteID(internalID imap.InternalMailboxID, remoteID imap.MailboxID) error

func (*State) UpdateMessageRemoteID

func (state *State) UpdateMessageRemoteID(internalID imap.InternalMessageID, remoteID imap.MessageID) error

func (*State) UserID

func (state *State) UserID() string

type StateID

type StateID int64

func GetStateIDFromContext

func GetStateIDFromContext(ctx context.Context) (StateID, bool)

type UIDInterval

type UIDInterval struct {
	// contains filtered or unexported fields
}

type Update

type Update interface {
	// Filter returns true when the state can be passed into A.
	Filter(s *State) bool
	// Apply the update to a given state.
	Apply(cxt context.Context, tx db.Transaction, s *State) error

	String() string
}

func AddMessagesToMailbox

func AddMessagesToMailbox(ctx context.Context,
	tx db.Transaction,
	mboxID imap.InternalMailboxID,
	messageIDs []db.MessageIDPair,
	s *State,
	imapLimits limits.IMAP) ([]db.UIDWithFlags, Update, error)

AddMessagesToMailbox adds the messages to the given mailbox.

func MoveMessagesFromMailbox

func MoveMessagesFromMailbox(
	ctx context.Context,
	tx db.Transaction,
	mboxFromID, mboxToID imap.InternalMailboxID,
	messageIDPairs []db.MessageIDPair,
	messageIDsInternal []imap.InternalMessageID,
	s *State,
	imapLimits limits.IMAP,
	removeOldMessages bool,
) ([]db.UIDWithFlags, []Update, error)

MoveMessagesFromMailbox moves messages from one mailbox to the other.

func NewMailboxDeletedStateUpdate

func NewMailboxDeletedStateUpdate(mboxID imap.InternalMailboxID) Update

func NewMailboxIDResponderStateUpdate

func NewMailboxIDResponderStateUpdate(id imap.InternalMailboxID, responders ...Responder) Update

func NewMailboxRemoteIDUpdateStateUpdate

func NewMailboxRemoteIDUpdateStateUpdate(internalID imap.InternalMailboxID, remoteID imap.MailboxID) Update

func NewMessageFlagsRemovedStateUpdate

func NewMessageFlagsRemovedStateUpdate(flags imap.FlagSet, mboxID db.MailboxIDPair, messageIDs []imap.InternalMessageID, stateID StateID) Update

func NewMessageFlagsSetStateUpdate

func NewMessageFlagsSetStateUpdate(flags imap.FlagSet, mboxID db.MailboxIDPair, messageIDs []imap.InternalMessageID, stateID StateID) Update

func NewMessageIDAndMailboxIDResponderStateUpdate

func NewMessageIDAndMailboxIDResponderStateUpdate(messageID imap.InternalMessageID, mboxID imap.InternalMailboxID, responders ...Responder) Update

func NewMessageIDResponderStateUpdate

func NewMessageIDResponderStateUpdate(id imap.InternalMessageID, responders ...Responder) Update

func NewRemoteAddMessageFlagsStateUpdate

func NewRemoteAddMessageFlagsStateUpdate(messageID imap.InternalMessageID, flag string) Update

func NewRemoteRemoveMessageFlagsStateUpdate

func NewRemoteRemoveMessageFlagsStateUpdate(messageID imap.InternalMessageID, flag string) Update

func NewUIDValidityBumpedStateUpdate added in v0.14.0

func NewUIDValidityBumpedStateUpdate() Update

func RemoveMessagesFromMailbox

func RemoveMessagesFromMailbox(ctx context.Context, tx db.Transaction, mboxID imap.InternalMailboxID, messageIDs []imap.InternalMessageID) ([]Update, error)

RemoveMessagesFromMailbox removes the messages from the given mailbox.

type UserInterface

type UserInterface interface {
	GetUserID() string

	GetDelimiter() string

	GetDB() db.Client

	GetRemote() Connector

	GetStore() *store.WriteControlledStore

	QueueOrApplyStateUpdate(ctx context.Context, tx db.Transaction, update ...Update) error

	ReleaseState(ctx context.Context, st *State) error

	GetRecoveryMailboxID() db.MailboxIDPair

	GenerateUIDValidity() (imap.UID, error)

	GetRecoveredMessageHashesMap() *utils.MessageHashesMap
}

UserInterface represents the expected behaviour for interacting with a remote user. Sadly, due to Go's cyclic dependencies, this needs to be an interface. The implementation of this interface is available in the backend package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL