imap

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: May 11, 2017 License: GPL-3.0 Imports: 21 Imported by: 4

Documentation

Overview

Package imap implements all three node types a pluto setup consists of: distributor, worker, and storage.

Handler functions for the various implemented IMAP commands usually return a boolean value indicating whether correct communication between pluto and connected clients was achieved but not whether commands were handled correctly according to IMAP semantics. This means that if a fatal error occurred during handling e.g. a LOGIN request which prevents the system with a high probability from handling future commands correctly as well, the responsible handler function will return false. But in case an user error occurred such as a missing name and/or password accompanying the LOGIN command and pluto was able to send back a useful error message to the client, this function returns true because communication went according to planned handling pipeline.

Please refer to https://tools.ietf.org/html/rfc3501#section-3 for full documentation on the states and https://tools.ietf.org/html/rfc3501 for the full IMAP v4 rev1 RFC.

Index

Constants

This section is empty.

Variables

View Source
var SupportedCommands = map[string]bool{
	"CAPABILITY": true,
	"LOGOUT":     true,
	"STARTTLS":   true,
	"LOGIN":      true,
	"SELECT":     true,
	"CREATE":     true,
	"DELETE":     true,
	"LIST":       true,
	"APPEND":     true,
	"EXPUNGE":    true,
	"STORE":      true,
}

SupportedCommands is a quick access map for checking if a supplied IMAP command is supported by pluto.

Functions

func ParseFlags

func ParseFlags(recv string) (map[string]struct{}, error)

ParseFlags takes in the string representation of a parenthesized list of IMAP flags and returns a map containing all found flags.

func ParseSeqNumbers

func ParseSeqNumbers(recv string, lenMailboxContents int) ([]int, error)

ParseSeqNumbers returns complete and normalized list of message sequence numbers for use in e.g. STORE command.

Types

type Connection

type Connection struct {
	IncConn       *tls.Conn
	IncReader     *bufio.Reader
	OutConn       *tls.Conn
	OutReader     *bufio.Reader
	IntlTLSConfig *tls.Config
	IntlConnRetry int
	OutAddr       string
	ClientID      string
	UserName      string
}

Connection carries all information specific to one observed connection on its way through a pluto node that only authenticates and proxies IMAP connections.

func (*Connection) Error

func (c *Connection) Error(msg string, err error)

Error makes use of Terminate but provides an additional error message before terminating.

func (*Connection) InternalReceive added in v0.2.0

func (c *Connection) InternalReceive(inc bool) (string, error)

InternalReceive is used by nodes in the pluto system receive an incoming message and filter out all prior received ping message.

func (*Connection) InternalSend added in v0.2.0

func (c *Connection) InternalSend(inc bool, text string) error

InternalSend is used by nodes of the pluto system to successfully transmit a message to another node or fail definitely if no reconnection is possible. This prevents further handler advancement in case a link failed.

func (*Connection) Receive

func (c *Connection) Receive(inc bool) (string, error)

Receive wraps the main io.Reader function that awaits text until an IMAP newline symbol and deletes the symbols after- wards again. It returns the resulting string or an error.

func (*Connection) Send

func (c *Connection) Send(inc bool, text string) error

Send takes in an answer text from a node as a string and writes it to the connection to the client. In case an error occurs, this method returns it to the calling function.

func (*Connection) SignalAwaitingLiteral

func (c *Connection) SignalAwaitingLiteral(inc bool, awaiting int) error

SignalAwaitingLiteral is used by workers to indicate a proxying distributor node that they are awaiting literal data from a client. The amount of awaited data is sent along this signal.

func (*Connection) SignalSessionDone

func (c *Connection) SignalSessionDone(inc bool) error

SignalSessionDone is either used by the distributor to signal the worker that a client logged out or by any node to indicated that the current operation is done.

func (*Connection) SignalSessionStart added in v0.2.0

func (c *Connection) SignalSessionStart(inc bool) error

SignalSessionStart is used by the distributor node to signal an involved worker node context about future requests.

func (*Connection) SignalSessionStartFailover added in v0.2.0

func (c *Connection) SignalSessionStartFailover(inc bool, recvClientID string, origWorker string) error

SignalSessionStartFailover is used by a failover worker node to signal the storage node context about future requests.

func (*Connection) Terminate

func (c *Connection) Terminate() error

Terminate tears down the state of a connection. This includes closing contained connection items. It returns nil or eventual errors.

type Distributor

type Distributor struct {
	Socket        net.Listener
	IntlTLSConfig *tls.Config
	AuthAdapter   PlainAuthenticator
	Connections   map[string]*tls.Conn
	Config        *config.Config
	// contains filtered or unexported fields
}

Distributor struct bundles information needed in operation of a distributor node.

func InitDistributor

func InitDistributor(logger log.Logger, config *config.Config, auth PlainAuthenticator) (*Distributor, error)

InitDistributor listens for TLS connections on a TCP socket opened up on supplied IP address and port as well as initializes connections to involved worker nodes. It returns those information bundled in above Distributor struct.

func (*Distributor) Capability

func (distr *Distributor) Capability(c *Connection, req *Request) bool

Capability handles the IMAP CAPABILITY command. It outputs the supported actions in the current state.

func (*Distributor) HandleConnection

func (distr *Distributor) HandleConnection(conn net.Conn)

HandleConnection acts as the main loop for requests targeted at IMAP functions implemented in distributor node. It parses incoming requests and executes command specific handlers matching the parsed data.

func (*Distributor) Login

func (distr *Distributor) Login(c *Connection, req *Request) bool

Login performs the authentication mechanism specified as part of the distributor config.

func (*Distributor) Logout

func (distr *Distributor) Logout(c *Connection, req *Request) bool

Logout correctly ends a connection with a client. Also necessarily created management structures will get shut down gracefully.

func (*Distributor) Proxy

func (distr *Distributor) Proxy(c *Connection, rawReq string) bool

Proxy forwards one request between the distributor node and the responsible worker node.

func (*Distributor) Run

func (distr *Distributor) Run() error

Run loops over incoming requests at distributor and dispatches each one to a goroutine taking care of the commands supplied.

func (*Distributor) StartTLS

func (distr *Distributor) StartTLS(c *Connection, req *Request) bool

StartTLS states on IMAP STARTTLS command that current connection is already encrypted.

type FailoverWorker

type FailoverWorker struct {
	Name          string
	MailSocket    net.Listener
	IntlTLSConfig *tls.Config
	Connections   map[string]*tls.Conn
	Config        *config.Config
	ShutdownChan  chan struct{}
	// contains filtered or unexported fields
}

FailoverWorker represents a reduced IMAPNode that simply writes through traffic to storage node.

func InitFailoverWorker

func InitFailoverWorker(config *config.Config, workerName string) (*FailoverWorker, error)

InitFailoverWorker initializes a worker node that acts as a passthrough-failover of the worker node specified via workerName. This results in a "dumb" proxy node that forwards all received traffic from distributor directly to storage node.

func (*FailoverWorker) HandleFailover

func (failWorker *FailoverWorker) HandleFailover(conn net.Conn)

HandleFailover is the function new IMAP connections incoming at a failover worker node are dispatched into in. It takes care of message forwarding to storage and reply return to distributor.

func (*FailoverWorker) RunFailover

func (failWorker *FailoverWorker) RunFailover() error

RunFailover is the main method called when starting a failover worker node. It accepts IMAP connections and dispatches them into own goroutines.

type IMAPConnection added in v0.2.0

type IMAPConnection struct {
	*Connection
	IMAPState       IMAPState
	UserCRDTPath    string
	UserMaildirPath string
	SelectedMailbox string
}

IMAPConnection contains additional elements needed for performing the actual IMAP operations for an authenticated client.

func (*IMAPConnection) UpdateClientContext added in v0.2.0

func (c *IMAPConnection) UpdateClientContext(clientIDRaw string, CRDTLayerRoot string, MaildirRoot string) (string, error)

UpdateClientContext expects the initial client information string sent when the proxying node opened a connection to a worker node. It updates the existing connection with the contained information.

type IMAPNode

type IMAPNode struct {
	MailSocket       net.Listener
	SyncSocket       net.Listener
	Connections      map[string]*tls.Conn
	MailboxStructure map[string]map[string]*crdt.ORSet
	MailboxContents  map[string]map[string][]string
	CRDTLayerRoot    string
	MaildirRoot      string
	Config           *config.Config
	ShutdownChan     chan struct{}
	// contains filtered or unexported fields
}

IMAPNode unifies needed management elements for nodes types worker and storage. This allows for one single place to define behaviour of handling IMAP as well as CRDT update requests.

func (*IMAPNode) Append

func (node *IMAPNode) Append(c *IMAPConnection, req *Request, syncChan chan string) bool

Append puts supplied message into specified mailbox.

func (*IMAPNode) ApplyCRDTUpd

func (node *IMAPNode) ApplyCRDTUpd(applyChan chan string, doneChan chan struct{})

ApplyCRDTUpd receives strings representing CRDT update operations from receiver and executes them.

func (*IMAPNode) Create

func (node *IMAPNode) Create(c *IMAPConnection, req *Request, syncChan chan string) bool

Create attempts to create a mailbox with name taken from payload of request.

func (*IMAPNode) Delete

func (node *IMAPNode) Delete(c *IMAPConnection, req *Request, syncChan chan string) bool

Delete attempts to remove an existing mailbox with all included content in CRDT as well as file system.

func (*IMAPNode) Expunge

func (node *IMAPNode) Expunge(c *IMAPConnection, req *Request, syncChan chan string) bool

Expunge deletes messages permanently from currently selected mailbox that have been flagged as Deleted prior to calling this function.

func (*IMAPNode) List

func (node *IMAPNode) List(c *IMAPConnection, req *Request, syncChan chan string) bool

List allows clients to learn about the mailboxes available and also returns the hierarchy delimiter.

func (*IMAPNode) Select

func (node *IMAPNode) Select(c *IMAPConnection, req *Request, syncChan chan string) bool

Select sets the current mailbox based on supplied payload to user-instructed value. A return value of this function does not indicate whether the command was successfully handled according to IMAP semantics, but rather whether a fatal error occurred or a complete answer could been sent. So, in case of an user error (e.g. a missing mailbox to select) but otherwise correct handling, this function would send a useful message to the client and still return true.

func (*IMAPNode) Store

func (node *IMAPNode) Store(c *IMAPConnection, req *Request, syncChan chan string) bool

Store takes in message sequence numbers and some set of flags to change in those messages and changes the attributes for these mails throughout the system.

type IMAPState

type IMAPState int

IMAPState represents the integer value associated with one of the implemented IMAP states a connection can be in.

const (
	ANY IMAPState = iota
	NOT_AUTHENTICATED
	AUTHENTICATED
	MAILBOX
	LOGOUT
)

Integer counter for IMAP states.

type PlainAuthenticator added in v0.4.1

type PlainAuthenticator interface {

	// GetWorkerForUser allows us to route an IMAP request to the
	// worker node responsible for a specific user.
	GetWorkerForUser(workers map[string]config.Worker, id int) (string, error)

	// AuthenticatePlain will be implemented by each of the
	// authentication methods of type PLAIN to perform the
	// actual part of checking supplied credentials.
	AuthenticatePlain(username string, password string, clientAddr string) (int, string, error)
}

PlainAuthenticator defines the methods required to perform an IMAP AUTH=PLAIN authentication in order to reach authenticated state (also LOGIN).

type Request

type Request struct {
	Tag     string
	Command string
	Payload string
}

Request represents the parsed content of a client command line sent to pluto. Payload will be examined further in command specific functions.

func ParseRequest

func ParseRequest(req string) (*Request, error)

ParseRequest takes in a raw string representing a received IMAP request and parses it into the defined request structure above. Any error encountered is handled useful to the IMAP protocol.

type Storage

type Storage struct {
	*IMAPNode
	SyncSendChans map[string]chan string
}

Storage struct bundles information needed in operation of a storage node.

func InitStorage

func InitStorage(config *config.Config) (*Storage, error)

InitStorage listens for TLS connections on a TCP socket opened up on supplied IP address. It returns those information bundeled in above Storage struct.

func (*Storage) HandleConnection

func (storage *Storage) HandleConnection(conn net.Conn)

HandleConnection is the main storage routine where all incoming requests against this storage node have to go through.

func (*Storage) Run

func (storage *Storage) Run() error

Run loops over incoming requests at storage and dispatches each one to a goroutine taking care of the commands supplied.

type Worker

type Worker struct {
	*IMAPNode
	Name         string
	SyncSendChan chan string
	// contains filtered or unexported fields
}

Worker struct bundles information needed in operation of a worker node.

func InitWorker

func InitWorker(logger log.Logger, config *config.Config, workerName string) (*Worker, error)

InitWorker listens for TLS connections on a TCP socket opened up on supplied IP address and port as well as connects to involved storage node. It returns those information bundeled in above Worker struct.

func (*Worker) HandleConnection

func (worker *Worker) HandleConnection(conn net.Conn)

HandleConnection is the main worker routine where all incoming requests against worker nodes have to go through.

func (*Worker) Run

func (worker *Worker) Run() error

Run loops over incoming requests at worker and dispatches each one to a goroutine taking care of the commands supplied.

Jump to

Keyboard shortcuts

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