From 1aa2168cc2036ccf502f60986f289495e494c727 Mon Sep 17 00:00:00 2001 From: Etienne Bruines Date: Thu, 25 Jun 2015 20:38:45 +0200 Subject: [PATCH 1/2] Converted all documentation to valid godoc format. --- command.go | 51 +++++++++++++++++++++++++------------------------ command_test.go | 42 +++++++++++++++++----------------------- demo/main.go | 1 - imap.go | 29 ++++++++++++++-------------- lexer.go | 39 +++++++++++++++++++------------------ mailstore.go | 49 +++++++++++++++++++++++++---------------------- parser.go | 37 +++++++++++++++++------------------ response.go | 20 +++++++++---------- session.go | 20 +++++++++---------- 9 files changed, 140 insertions(+), 148 deletions(-) diff --git a/command.go b/command.go index 35339f9..affa9e6 100644 --- a/command.go +++ b/command.go @@ -5,36 +5,37 @@ import ( "strings" ) -// An IMAP command +// command represents an IMAP command type command interface { - // Execute the command and return an imap response + // Execute the command and return an IMAP response execute(s *session) *response } -// Path delimiter const ( + // pathDelimiter is the delimiter used to distinguish between different folders pathDelimiter = '/' ) //------------------------------------------------------------------------------ +// noop is a NOOP command type noop struct { tag string } -// Execute a noop +// execute a NOOP command func (c *noop) execute(s *session) *response { return ok(c.tag, "NOOP Completed") } //------------------------------------------------------------------------------ -// A CAPABILITY command +// capability is a CAPABILITY command type capability struct { tag string } -// Execute a capability +// execute a capability func (c *capability) execute(s *session) *response { // The IMAP server is assumed to be running over SSL and so // STARTTLS is not supported and LOGIN is not disabled @@ -44,14 +45,14 @@ func (c *capability) execute(s *session) *response { //------------------------------------------------------------------------------ -// A LOGIN command +// login is a LOGIN command type login struct { tag string userId string password string } -// Login command +// execute a LOGIN command func (c *login) execute(sess *session) *response { // Has the user already logged in? @@ -73,12 +74,12 @@ func (c *login) execute(sess *session) *response { //------------------------------------------------------------------------------ -// A LOGOUT command +// logout is a LOGOUT command type logout struct { tag string } -// Logout command +// execute a LOGOUT command func (c *logout) execute(sess *session) *response { sess.st = notAuthenticated @@ -89,13 +90,13 @@ func (c *logout) execute(sess *session) *response { //------------------------------------------------------------------------------ -// A SELECT command +// selectMailbox is a SELECT command type selectMailbox struct { tag string mailbox string } -// Select command +// execute a SELECT command func (c *selectMailbox) execute(sess *session) *response { // Is the user authenticated? @@ -129,14 +130,14 @@ func (c *selectMailbox) execute(sess *session) *response { //------------------------------------------------------------------------------ -// A LIST command +// list is a LIST command type list struct { tag string reference string // Context of mailbox name mboxPattern string // The mailbox name pattern } -// List command +// execute a LIST command func (c *list) execute(sess *session) *response { // Is the user authenticated? @@ -155,7 +156,7 @@ func (c *list) execute(sess *session) *response { // Convert the reference and mbox pattern into slices ref := pathToSlice(c.reference) mbox := pathToSlice(c.mboxPattern) - + // Get the list of mailboxes mboxes, err := sess.list(ref, mbox) @@ -172,8 +173,8 @@ func (c *list) execute(sess *session) *response { res := ok(c.tag, "LIST completed") for _, mbox := range mboxes { res.extra(fmt.Sprintf(`LIST (%s) "%s" /%s`, - joinMailboxFlags(mbox), - string(pathDelimiter), + joinMailboxFlags(mbox), + string(pathDelimiter), strings.Join(mbox.Path, string(pathDelimiter)))) } @@ -182,13 +183,13 @@ func (c *list) execute(sess *session) *response { //------------------------------------------------------------------------------ -// An unknown/unsupported command +// unknown is an unknown/unsupported command type unknown struct { tag string cmd string } -// Report an error for an unknown command +// execute reports an error for an unknown command func (c *unknown) execute(s *session) *response { message := fmt.Sprintf("%s unknown command", c.cmd) s.log(message) @@ -197,21 +198,21 @@ func (c *unknown) execute(s *session) *response { //------ Helper functions ------------------------------------------------------ -// Log an error and return an response +// internalError logs an error and return an response func internalError(sess *session, tag string, commandName string, err error) *response { message := commandName + " " + err.Error() sess.log(message) return no(tag, message).shouldClose() } -// Indicate a command is invalid because the user has not authenticated +// mustAuthenticate indicates a command is invalid because the user has not authenticated func mustAuthenticate(sess *session, tag string, commandName string) *response { message := commandName + " not authenticated" sess.log(message) return bad(tag, message) } -// Convert a path to a slice of strings +// pathToSlice converts a path to a slice of strings func pathToSlice(path string) []string { // Split the path @@ -224,7 +225,7 @@ func pathToSlice(path string) []string { // Remove leading and trailing blanks if ret[0] == "" { if len(ret) > 1 { - ret = ret[1:len(ret)] + ret = ret[1:] } else { return []string{} } @@ -240,10 +241,10 @@ func pathToSlice(path string) []string { } return ret - + } -// Return a string of mailbox flags for the given mailbox +// joinMailboxFlags returns a string of mailbox flags for the given mailbox func joinMailboxFlags(m *Mailbox) string { // Convert the mailbox flags into a slice of strings diff --git a/command_test.go b/command_test.go index 9aa94cd..95af832 100644 --- a/command_test.go +++ b/command_test.go @@ -3,9 +3,7 @@ package imapsrv import "testing" import "fmt" - - -func setupTest() (*Server,*session){ +func setupTest() (*Server, *session) { m := &TestMailstore{} s := NewServer( Store(m), @@ -15,13 +13,11 @@ func setupTest() (*Server,*session){ return s, sess } - - -// A test mailstore used for unit testing +// TestMailstore is a dummy mailstore type TestMailstore struct { } -// Get mailbox information +// GetMailbox gets dummy Mailbox information func (m *TestMailstore) GetMailbox(path []string) (*Mailbox, error) { return &Mailbox{ Name: "inbox", @@ -29,17 +25,17 @@ func (m *TestMailstore) GetMailbox(path []string) (*Mailbox, error) { }, nil } -// Get a list of mailboxes at the given path +// GetMailboxes lists dummy Mailboxes func (m *TestMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { if len(path) == 0 { // Root return []*Mailbox{ - &Mailbox{ + { Name: "inbox", Path: []string{"inbox"}, Id: 1, }, - &Mailbox{ + { Name: "spam", Path: []string{"spam"}, Id: 2, @@ -47,7 +43,7 @@ func (m *TestMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { }, nil } else if len(path) == 1 && path[0] == "inbox" { return []*Mailbox{ - &Mailbox{ + { Name: "starred", Path: []string{"inbox", "stared"}, Id: 3, @@ -58,47 +54,43 @@ func (m *TestMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { } } - -// Get the sequence number of the first unseen message +// FirstUnseen gets a dummy number of first unseen messages in an IMAP mailbox func (m *TestMailstore) FirstUnseen(mbox int64) (int64, error) { return 4, nil } -// Get the total number of messages in an IMAP mailbox +// TotalMessages gets a dummy number of messages in an IMAP mailbox func (m *TestMailstore) TotalMessages(mbox int64) (int64, error) { return 8, nil } -// Get the total number of unread messages in an IMAP mailbox +// RecentMessages gets a dummy number of unread messages in an IMAP mailbox func (m *TestMailstore) RecentMessages(mbox int64) (int64, error) { return 4, nil } -// Get the next available uid in an IMAP mailbox +// NextUid gets a dummy next-uid in an IMAP mailbox func (m *TestMailstore) NextUid(mbox int64) (int64, error) { return 9, nil } - - - -func TestCapabilityCommand( t *testing.T){ +// TestCapabilityCommand tests the correctness of the CAPABILITY command +func TestCapabilityCommand(t *testing.T) { _, session := setupTest() cap := &capability{tag: "A00001"} resp := cap.execute(session) - if (resp.tag != "A00001") || (resp.message != "CAPABILITY completed") || (resp.untagged[0] != "CAPABILITY IMAP4rev1"){ + if (resp.tag != "A00001") || (resp.message != "CAPABILITY completed") || (resp.untagged[0] != "CAPABILITY IMAP4rev1") { t.Error("Capability Failed - unexpected response.") fmt.Println(resp) } } - - -func TestLogoutCommand( t *testing.T){ +// TestLogoutCommand tests the correctness of the LOGOUT command +func TestLogoutCommand(t *testing.T) { _, session := setupTest() log := &logout{tag: "A00004"} resp := log.execute(session) - if (resp.tag != "A00004") || (resp.message != "LOGOUT completed") || (resp.untagged[0] != "BYE IMAP4rev1 Server logging out"){ + if (resp.tag != "A00004") || (resp.message != "LOGOUT completed") || (resp.untagged[0] != "BYE IMAP4rev1 Server logging out") { t.Error("Logout Failed - unexpected response.") fmt.Println(resp) } diff --git a/demo/main.go b/demo/main.go index 6468a8a..2fe1067 100644 --- a/demo/main.go +++ b/demo/main.go @@ -25,4 +25,3 @@ func main() { log.Print("IMAP server not started") } } - diff --git a/imap.go b/imap.go index dbd24e4..e89606b 100644 --- a/imap.go +++ b/imap.go @@ -3,27 +3,27 @@ package imapsrv import ( "bufio" + "fmt" "log" "net" - "fmt" ) -// Default listen interface/port +// DefaultListener is the listener that is used if no listener is specified const DefaultListener = "0.0.0.0:143" -// IMAP server configuration +// config is an IMAP server configuration type config struct { maxClients uint listeners []listener mailstore Mailstore } -// Listener config +// listener represents a listener as used by the server type listener struct { addr string } -// An IMAP Server +// Server is an IMAP Server type Server struct { // Server configuration config *config @@ -31,7 +31,7 @@ type Server struct { activeClients uint } -// An IMAP Client as seen by an IMAP server +// client is an IMAP Client as seen by an IMAP server type client struct { conn net.Conn bufin *bufio.Reader @@ -40,7 +40,7 @@ type client struct { config *config } -// Return the default server configuration +// defaultConfig returns the default server configuration func defaultConfig() *config { return &config{ listeners: make([]listener, 0, 4), @@ -48,7 +48,7 @@ func defaultConfig() *config { } } -// Add a mailstore to the config +// Store addd a mailstore to the config func Store(m Mailstore) func(*Server) error { return func(s *Server) error { s.config.mailstore = m @@ -56,7 +56,7 @@ func Store(m Mailstore) func(*Server) error { } } -// Add an interface to listen to +// Listen adds an interface to listen to func Listen(Addr string) func(*Server) error { return func(s *Server) error { l := listener{ @@ -67,7 +67,7 @@ func Listen(Addr string) func(*Server) error { } } -// Set MaxClients config +// MaxClients sets the MaxClients config func MaxClients(max uint) func(*Server) error { return func(s *Server) error { s.config.maxClients = max @@ -75,6 +75,7 @@ func MaxClients(max uint) func(*Server) error { } } +// NewServer creates a new server with the given options func NewServer(options ...func(*Server) error) *Server { // set the default config s := &Server{} @@ -130,7 +131,7 @@ func (s *Server) Start() error { return nil } -// Run a listener +// runListener runs the given listener on a separate goroutine func (s *Server) runListener(listener net.Listener, id int) { log.Printf("IMAP server %d listening on %s", id, listener.Addr().String()) @@ -161,7 +162,7 @@ func (s *Server) runListener(listener net.Listener, id int) { } -// Handle requests from an IMAP client +// handle requests from an IMAP client func (c *client) handle() { // Close the client on exit from this function @@ -212,12 +213,12 @@ func (c *client) handle() { } } -// Close an IMAP client +// close closes an IMAP client func (c *client) close() { c.conn.Close() } -// Log an error +// logError sends a log message to the default Logger func (c *client) logError(err error) { log.Printf("IMAP client %s, %v", c.id, err) } diff --git a/lexer.go b/lexer.go index c174030..2b0cada 100644 --- a/lexer.go +++ b/lexer.go @@ -8,6 +8,7 @@ import ( "strconv" ) +// lexer is responsible for reading input, and making sense of it type lexer struct { // Line based reader reader *textproto.Reader @@ -39,7 +40,7 @@ const ( backslash = 0x5c ) -// char not present in the astring charset +// astringExceptionsChar is a list of chars that are not present in the astring charset var astringExceptionsChar = []byte{ space, leftParenthesis, @@ -50,7 +51,7 @@ var astringExceptionsChar = []byte{ leftCurly, } -// char not present in the tag charset +// tagExceptionsChar is a list of chars that are not present in the tag charset var tagExceptionsChar = []byte{ space, leftParenthesis, @@ -62,7 +63,7 @@ var tagExceptionsChar = []byte{ plus, } -// char not present in the list-mailbox charset +// listMailboxExceptionsChar is a list of chars that are not present in the list-mailbox charset var listMailboxExceptionsChar = []byte{ space, leftParenthesis, @@ -72,7 +73,7 @@ var listMailboxExceptionsChar = []byte{ leftCurly, } -// Create a partially initialised IMAP lexer +// createLexer creates a partially initialised IMAP lexer // lexer.newLine() must be the first call to this lexer func createLexer(in *bufio.Reader) *lexer { return &lexer{reader: textproto.NewReader(in)} @@ -80,7 +81,7 @@ func createLexer(in *bufio.Reader) *lexer { //-------- IMAP tokens --------------------------------------------------------- -// An astring +// astring treats the input as a string func (l *lexer) astring() (bool, string) { l.skipSpace() l.startToken() @@ -88,7 +89,7 @@ func (l *lexer) astring() (bool, string) { return l.generalString("ASTRING", astringExceptionsChar) } -// A tag string +// tag treats the input as a tag string func (l *lexer) tag() (bool, string) { l.skipSpace() l.startToken() @@ -96,7 +97,7 @@ func (l *lexer) tag() (bool, string) { return l.nonquoted("TAG", tagExceptionsChar) } -// A list mailbox +// listMailbox treats the input as a list mailbox func (l *lexer) listMailbox() (bool, string) { l.skipSpace() l.startToken() @@ -106,7 +107,7 @@ func (l *lexer) listMailbox() (bool, string) { //-------- IMAP token helper functions ----------------------------------------- -// Handle a string that can be bare, a literal or quoted +// generalString handles a string that can be bare, a literal or quoted func (l *lexer) generalString(name string, exceptions []byte) (bool, string) { // Consider the first character - this gives the type of argument @@ -122,7 +123,7 @@ func (l *lexer) generalString(name string, exceptions []byte) (bool, string) { } } -// Read a quoted string +// qstring reads a quoted string func (l *lexer) qstring() string { var buffer = make([]byte, 0, 16) @@ -154,7 +155,7 @@ func (l *lexer) qstring() string { return string(buffer) } -// Parse a length tagged literal +// literal parses a length tagged literal // TODO: send a continuation request after the first line is read func (l *lexer) literal() string { @@ -194,7 +195,7 @@ func (l *lexer) literal() string { for { buffer = append(buffer, c) - + // Is this the end of the literal? length -= 1 if length == 0 { @@ -207,7 +208,7 @@ func (l *lexer) literal() string { return string(buffer) } -// A non-quoted string +// nonquoted reads a non-quoted string func (l *lexer) nonquoted(name string, exceptions []byte) (bool, string) { buffer := make([]byte, 0, 16) @@ -231,7 +232,7 @@ func (l *lexer) nonquoted(name string, exceptions []byte) (bool, string) { //-------- Low level lexer functions ------------------------------------------- -// Consume a single byte and return the new character +// consume a single byte and return the new character // Does not go through newlines func (l *lexer) consume() byte { @@ -246,7 +247,7 @@ func (l *lexer) consume() byte { return l.current() } -// Consume a single byte and return the new character +// consumeAll a single byte and return the new character // Goes through newlines func (l *lexer) consumeAll() byte { @@ -261,12 +262,12 @@ func (l *lexer) consumeAll() byte { return l.current() } -// Get the current byte +// current gets the current byte func (l *lexer) current() byte { return l.line[l.idx] } -// Move onto a new line +// newLine moves onto a new line func (l *lexer) newLine() { // Read the line @@ -281,7 +282,7 @@ func (l *lexer) newLine() { l.tokens = make([]int, 0, 8) } -// Skip spaces +// skipSpace skips any spaces func (l *lexer) skipSpace() { c := l.current() @@ -290,12 +291,12 @@ func (l *lexer) skipSpace() { } } -// Mark the start a new token +// startToken marks the start a new token func (l *lexer) startToken() { l.tokens = append(l.tokens, l.idx) } -// Move back one token +// pushBack moves back one token func (l *lexer) pushBack() { last := len(l.tokens) - 1 l.idx = l.tokens[last] diff --git a/mailstore.go b/mailstore.go index 6ff44fd..6c78d8c 100644 --- a/mailstore.go +++ b/mailstore.go @@ -4,7 +4,7 @@ import ( "log" ) -// An IMAP mailbox +// Mailbox represents an IMAP mailbox type Mailbox struct { Name string // The name of the mailbox Path []string // Full mailbox path @@ -14,17 +14,20 @@ type Mailbox struct { // Mailbox flags const ( - // It is not possible for any child levels of hierarchy to exist + // Noinferiors indicates it is not possible for any child levels of hierarchy to exist // under this name; no child levels exist now and none can be // created in the future. Noinferiors = 1 << iota - // It is not possible to use this name as a selectable mailbox. + + // Noselect indicates it is not possible to use this name as a selectable mailbox. Noselect - // The mailbox has been marked "interesting" by the server; the - // mailbox probably contains messages that have been added since + + // Marked indicates that the mailbox has been marked "interesting" by the server; + // the mailbox probably contains messages that have been added since // the last time the mailbox was selected Marked - // The mailbox does not contain any additional messages since the + + // Unmarked indicates the mailbox does not contain any additional messages since the // last time the mailbox was selected. Unmarked ) @@ -36,28 +39,28 @@ var mailboxFlags = map[uint8]string{ Unmarked: "Unmarked", } -// A service that is needed to read mail messages +// Mailstore is a service responsible for I/O with the actual e-mails type Mailstore interface { - // Get IMAP mailbox information + // GetMailbox gets IMAP mailbox information // Returns nil if the mailbox does not exist GetMailbox(path []string) (*Mailbox, error) - // Get a list of mailboxes at the given path + // GetMailboxes gets a list of mailboxes at the given path GetMailboxes(path []string) ([]*Mailbox, error) - // Get the sequence number of the first unseen message + // FirstUnseen gets the sequence number of the first unseen message in an IMAP mailbox FirstUnseen(mbox int64) (int64, error) - // Get the total number of messages in an IMAP mailbox + // TotalMessages gets the total number of messages in an IMAP mailbox TotalMessages(mbox int64) (int64, error) - // Get the total number of unread messages in an IMAP mailbox + // RecentMessages gets the total number of unread messages in an IMAP mailbox RecentMessages(mbox int64) (int64, error) - // Get the next available uid in an IMAP mailbox + // NextUid gets the next available uid in an IMAP mailbox NextUid(mbox int64) (int64, error) } -// A dummy mailstore used for demonstrating the IMAP server +// DummyMailstore is used for demonstrating the IMAP server type DummyMailstore struct { } -// Get mailbox information +// GetMailbox gets mailbox information func (m *DummyMailstore) GetMailbox(path []string) (*Mailbox, error) { return &Mailbox{ Name: "inbox", @@ -66,19 +69,19 @@ func (m *DummyMailstore) GetMailbox(path []string) (*Mailbox, error) { }, nil } -// Get a list of mailboxes at the given path +// GetMailboxes gets a list of mailboxes at the given path func (m *DummyMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { log.Printf("GetMailboxes %v", path) if len(path) == 0 { // Root return []*Mailbox{ - &Mailbox{ + { Name: "inbox", Path: []string{"inbox"}, Id: 1, }, - &Mailbox{ + { Name: "spam", Path: []string{"spam"}, Id: 2, @@ -86,7 +89,7 @@ func (m *DummyMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { }, nil } else if len(path) == 1 && path[0] == "inbox" { return []*Mailbox{ - &Mailbox{ + { Name: "starred", Path: []string{"inbox", "stared"}, Id: 3, @@ -97,22 +100,22 @@ func (m *DummyMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { } } -// Get the sequence number of the first unseen message +// FirstUnseen gets the sequence number of the first unseen message in an IMAP mailbox func (m *DummyMailstore) FirstUnseen(mbox int64) (int64, error) { return 4, nil } -// Get the total number of messages in an IMAP mailbox +// TotalMessages gets the total number of messages in an IMAP mailbox func (m *DummyMailstore) TotalMessages(mbox int64) (int64, error) { return 8, nil } -// Get the total number of unread messages in an IMAP mailbox +// RecentMessages gets the total number of unread messages in an IMAP mailbox func (m *DummyMailstore) RecentMessages(mbox int64) (int64, error) { return 4, nil } -// Get the next available uid in an IMAP mailbox +// DummyMailstore gets the next available uid in an IMAP mailbox func (m *DummyMailstore) NextUid(mbox int64) (int64, error) { return 9, nil } diff --git a/parser.go b/parser.go index 3aca373..1ced332 100644 --- a/parser.go +++ b/parser.go @@ -1,4 +1,3 @@ - package imapsrv import ( @@ -7,29 +6,28 @@ import ( "strings" ) -// An IMAP parser +// parser can parse IMAP commands type parser struct { lexer *lexer } -// An Error from the IMAP parser or lexer +// parseError is an Error from the IMAP parser or lexer type parseError string -// Parse errors satisfy the error interface +// Error returns the string representation of the parseError func (e parseError) Error() string { return string(e) } -// Create an imap parser +// createParser creates a new IMAP parser, reading from the Reader func createParser(in *bufio.Reader) *parser { lexer := createLexer(in) return &parser{lexer: lexer} } - //----- Commands --------------------------------------------------------------- -// Parse the next command +// next attempts to read the next command func (p *parser) next() command { // All commands start on a new line @@ -39,7 +37,6 @@ func (p *parser) next() command { tag := p.expectString(p.lexer.tag) rawCommand := p.expectString(p.lexer.astring) - // Parse the command based on its lowercase value lcCommand := strings.ToLower(rawCommand) @@ -53,7 +50,7 @@ func (p *parser) next() command { case "logout": return p.logout(tag) case "select": - return p.selectC(tag) + return p.selectCmd(tag) case "list": return p.list(tag) default: @@ -61,17 +58,17 @@ func (p *parser) next() command { } } -// Create a NOOP command +// noop creates a NOOP command func (p *parser) noop(tag string) command { return &noop{tag: tag} } -// Create a capability command +// capability creates a CAPABILITY command func (p *parser) capability(tag string) command { return &capability{tag: tag} } -// Create a login command +// login creates a LOGIN command func (p *parser) login(tag string) command { // Get the command arguments @@ -82,13 +79,13 @@ func (p *parser) login(tag string) command { return &login{tag: tag, userId: userId, password: password} } -// Create a logout command +// logout creates a LOGOUT command func (p *parser) logout(tag string) command { return &logout{tag: tag} } -// Create a select command -func (p *parser) selectC(tag string) command { +// selectCmd creates a select command +func (p *parser) selectCmd(tag string) command { // Get the mailbox name mailbox := p.expectString(p.lexer.astring) @@ -96,7 +93,7 @@ func (p *parser) selectC(tag string) command { return &selectMailbox{tag: tag, mailbox: mailbox} } -// Create a list command +// list creates a LIST command func (p *parser) list(tag string) command { // Get the command arguments @@ -110,16 +107,16 @@ func (p *parser) list(tag string) command { return &list{tag: tag, reference: reference, mboxPattern: mailbox} } -// Create a placeholder for an unknown command +// unknown creates a placeholder for an unknown command func (p *parser) unknown(tag string, cmd string) command { return &unknown{tag: tag, cmd: cmd} } //----- Helper functions ------------------------------------------------------- -// Get a string token using the given lexer function -// If the lexing fails then panic -func (p *parser) expectString(lex func () (bool, string)) string { +// expectString gets a string token using the given lexer function +// If the lexing fails, then this will panic +func (p *parser) expectString(lex func() (bool, string)) string { ok, ret := lex() if !ok { msg := fmt.Sprintf("Parser unexpected %q", p.lexer.current()) diff --git a/response.go b/response.go index 04d70c3..8683d1d 100644 --- a/response.go +++ b/response.go @@ -1,11 +1,10 @@ - package imapsrv import ( "bufio" ) -// An IMAP response +// response represents an IMAP response type response struct { // The tag of the command that this is the response for tag string @@ -19,7 +18,7 @@ type response struct { closeConnection bool } -// Create a response +// createResponse creates a response func createResponse(tag string, condition string, message string) *response { return &response{ tag: tag, @@ -29,41 +28,41 @@ func createResponse(tag string, condition string, message string) *response { } } -// Create a OK response +// ok creatse a OK response func ok(tag string, message string) *response { return createResponse(tag, "OK", message) } -// Create an BAD response +// bad creates a BAD response func bad(tag string, message string) *response { return createResponse(tag, "BAD", message) } -// Create a NO response +// no creates a NO response func no(tag string, message string) *response { return createResponse(tag, "NO", message) } -// Write an untagged fatal response +// fatalResponse writes an untagged fatal response (BYE) func fatalResponse(w *bufio.Writer, err error) { resp := createResponse("*", "BYE", err.Error()) resp.closeConnection = true resp.write(w) } -// Add an untagged line to a response +// extra adds an untagged line to a response func (r *response) extra(line string) *response { r.untagged = append(r.untagged, line) return r } -// Mark that a response should close the connection +// shouldClose marks that a response should close the connection func (r *response) shouldClose() *response { r.closeConnection = true return r } -// Write a response to the given writer +// write a response to the given Writer func (r *response) write(w *bufio.Writer) error { // Write untagged lines @@ -83,4 +82,3 @@ func (r *response) write(w *bufio.Writer) error { w.Flush() return nil } - diff --git a/session.go b/session.go index 2ec3635..353d651 100644 --- a/session.go +++ b/session.go @@ -5,7 +5,7 @@ import ( "log" ) -// IMAP session states +// state is the IMAP session state type state int const ( @@ -14,7 +14,7 @@ const ( selected ) -// An IMAP session +// Session represents an IMAP session type session struct { // The client id id string @@ -26,7 +26,7 @@ type session struct { config *config } -// Create a new IMAP session +// createSession creates a new IMAP session func createSession(id string, config *config) *session { return &session{ id: id, @@ -34,7 +34,7 @@ func createSession(id string, config *config) *session { config: config} } -// Log a message with session information +// log writes the info messages to the logger with session information func (s *session) log(info ...interface{}) { preamble := fmt.Sprintf("IMAP (%s) ", s.id) message := []interface{}{preamble} @@ -42,7 +42,7 @@ func (s *session) log(info ...interface{}) { log.Print(message...) } -// Select a mailbox - returns true if the mailbox exists +// selectMailbox selects a mailbox - returns true if the mailbox exists func (s *session) selectMailbox(path []string) (bool, error) { // Lookup the mailbox mailstore := s.config.mailstore @@ -61,7 +61,7 @@ func (s *session) selectMailbox(path []string) (bool, error) { return true, nil } -// List mailboxes matching the given mailbox pattern +// list mailboxes matching the given mailbox pattern func (s *session) list(reference []string, pattern []string) ([]*Mailbox, error) { ret := make([]*Mailbox, 0, 4) @@ -88,10 +88,10 @@ func (s *session) list(reference []string, pattern []string) ([]*Mailbox, error) } // Recursively get a listing - return s.depthFirstMailboxes(ret, path, pattern[wildcard:len(pattern)]) + return s.depthFirstMailboxes(ret, path, pattern[wildcard:]) } -// Add mailbox information to the given response +// addMailboxInfo adds mailbox information to the given response func (s *session) addMailboxInfo(resp *response) error { mailstore := s.config.mailstore @@ -121,14 +121,14 @@ func (s *session) addMailboxInfo(resp *response) error { return nil } -// Copies a slice +// copySlice copies a slice func copySlice(s []string) []string { ret := make([]string, len(s), (len(s)+1)*2) copy(ret, s) return ret } -// Get a recursive mailbox listing +// depthFirstMailboxes gets a recursive mailbox listing // At the moment this doesn't support wildcards such as 'leader%' (are they used in real life?) func (s *session) depthFirstMailboxes( results []*Mailbox, path []string, pattern []string) ([]*Mailbox, error) { From 8e29f4ae303216efb709a242e6db51c63f0c5cc4 Mon Sep 17 00:00:00 2001 From: Etienne Bruines Date: Thu, 25 Jun 2015 20:52:27 +0200 Subject: [PATCH 2/2] Made DummyMailstore private according to #21. --- demo/main.go | 3 --- mailstore.go | 14 +++++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/demo/main.go b/demo/main.go index 2fe1067..d1914f5 100644 --- a/demo/main.go +++ b/demo/main.go @@ -12,12 +12,9 @@ func main() { //s.Start() // More advanced config - m := &imap.DummyMailstore{} - s := imap.NewServer( imap.Listen("127.0.0.1:1193"), imap.Listen("127.0.0.1:1194"), - imap.Store(m), ) err := s.Start() diff --git a/mailstore.go b/mailstore.go index 6c78d8c..eb82fa5 100644 --- a/mailstore.go +++ b/mailstore.go @@ -57,11 +57,11 @@ type Mailstore interface { } // DummyMailstore is used for demonstrating the IMAP server -type DummyMailstore struct { +type dummyMailstore struct { } // GetMailbox gets mailbox information -func (m *DummyMailstore) GetMailbox(path []string) (*Mailbox, error) { +func (m *dummyMailstore) GetMailbox(path []string) (*Mailbox, error) { return &Mailbox{ Name: "inbox", Path: []string{"inbox"}, @@ -70,7 +70,7 @@ func (m *DummyMailstore) GetMailbox(path []string) (*Mailbox, error) { } // GetMailboxes gets a list of mailboxes at the given path -func (m *DummyMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { +func (m *dummyMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { log.Printf("GetMailboxes %v", path) if len(path) == 0 { @@ -101,21 +101,21 @@ func (m *DummyMailstore) GetMailboxes(path []string) ([]*Mailbox, error) { } // FirstUnseen gets the sequence number of the first unseen message in an IMAP mailbox -func (m *DummyMailstore) FirstUnseen(mbox int64) (int64, error) { +func (m *dummyMailstore) FirstUnseen(mbox int64) (int64, error) { return 4, nil } // TotalMessages gets the total number of messages in an IMAP mailbox -func (m *DummyMailstore) TotalMessages(mbox int64) (int64, error) { +func (m *dummyMailstore) TotalMessages(mbox int64) (int64, error) { return 8, nil } // RecentMessages gets the total number of unread messages in an IMAP mailbox -func (m *DummyMailstore) RecentMessages(mbox int64) (int64, error) { +func (m *dummyMailstore) RecentMessages(mbox int64) (int64, error) { return 4, nil } // DummyMailstore gets the next available uid in an IMAP mailbox -func (m *DummyMailstore) NextUid(mbox int64) (int64, error) { +func (m *dummyMailstore) NextUid(mbox int64) (int64, error) { return 9, nil }