imap

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Dec 23, 2016 License: GPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

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

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 could been handled correct 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 to handle future commands correctly as well, the responsible handler function would 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 would still return true because communications 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

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, mailboxContents []string) ([]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 {
	Conn      *tls.Conn
	Worker    string
	Reader    *bufio.Reader
	UserToken string
	UserName  string
}

Connection carries all information specific to one observed connection on its way through the IMAP server.

func NewConnection

func NewConnection(c *tls.Conn) *Connection

NewConnection creates a new element of above connection struct and fills it with content from a supplied, real IMAP connection.

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) ErrorLogOnly

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

ErrorLogOnly is used by nodes to log and indicate fatal errors but without closing the permanent connection to other nodes, e.g. the distributor.

func (*Connection) Receive

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

Receive wraps the main io.Reader function that awaits text until a newline symbol and deletes that symbol afterwards again. It returns the resulting string or an error.

func (*Connection) Send

func (c *Connection) Send(text string) error

Send takes in an answer text from server 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(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(node *tls.Conn) 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) SignalSessionError

func (c *Connection) SignalSessionError(node *tls.Conn) error

SignalSessionError can be used by distributor or worker nodes to signal other nodes that an fatal error occurred during processing a request.

func (*Connection) SignalSessionPrefixStorage

func (c *Connection) SignalSessionPrefixStorage(clientID string, conn *tls.Conn, name string, remoteName string, remoteIP string, remotePort string, tlsConfig *tls.Config, timeout int, retry int) (*tls.Conn, error)

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

func (*Connection) SignalSessionPrefixWorker

func (c *Connection) SignalSessionPrefixWorker(conn *tls.Conn, name string, remoteName string, remoteIP string, remotePort string, tlsConfig *tls.Config, timeout int, retry int) (*tls.Conn, error)

SignalSessionPrefixWorker is used by the distributor node to signal an involved worker 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 Context

type Context struct {
	ClientID        string
	IMAPState       IMAPState
	UserName        string
	UserCRDTPath    string
	UserMaildirPath string
	SelectedMailbox string
}

Context carries session-identifying information sent from distributor to worker node.

type Distributor

type Distributor struct {
	Socket        net.Listener
	IntlTLSConfig *tls.Config
	AuthAdapter   auth.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(config *config.Config) (*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 bundeled 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) ExtractClientContext

func (failWorker *FailoverWorker) ExtractClientContext(clientIDRaw string) (string, error)

ExtractClientContext simply extracts the contained client ID from a prefix sent by distributor.

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 IMAPNode

type IMAPNode struct {
	MailSocket       net.Listener
	SyncSocket       net.Listener
	Connections      map[string]*tls.Conn
	Contexts         map[string]*Context
	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 *Connection, req *Request, clientID string, 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 *Connection, req *Request, clientID string, 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 *Connection, req *Request, clientID string, 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 *Connection, req *Request, clientID string, 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 *Connection, req *Request, clientID string, 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 *Connection, req *Request, clientID string, 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 *Connection, req *Request, clientID string, 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 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.

func (*Storage) UpdateClientContext

func (storage *Storage) UpdateClientContext(clientIDRaw string) (string, string, error)

UpdateClientContext takes in received raw clientID string, verifies, parses it, checks for existing client context and if successful, returns the clientID. Storage version.

type Worker

type Worker struct {
	*IMAPNode
	Name         string
	SyncSendChan chan string
}

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

func InitWorker

func InitWorker(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.

func (*Worker) UpdateClientContext

func (worker *Worker) UpdateClientContext(clientIDRaw string) (string, error)

UpdateClientContext takes in received raw clientID string, verifies, parses it, checks for existing client context and if successful, returns the clientID. Worker version.

Jump to

Keyboard shortcuts

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