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

Updated godoc #27

Closed
wants to merge 2 commits into from
Closed
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
51 changes: 26 additions & 25 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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?
Expand All @@ -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
Expand All @@ -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?
Expand Down Expand Up @@ -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?
Expand All @@ -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)

Expand All @@ -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))))
}

Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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{}
}
Expand All @@ -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
Expand Down
42 changes: 17 additions & 25 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package imapsrv
import "testing"
import "fmt"



func setupTest() (*Server,*session){
func setupTest() (*Server, *session) {
m := &TestMailstore{}
s := NewServer(
Store(m),
Expand All @@ -15,39 +13,37 @@ 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",
Id: 1,
}, 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,
},
}, nil
} else if len(path) == 1 && path[0] == "inbox" {
return []*Mailbox{
&Mailbox{
{
Name: "starred",
Path: []string{"inbox", "stared"},
Id: 3,
Expand All @@ -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)
}
Expand Down
4 changes: 0 additions & 4 deletions demo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,13 @@ 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()
if err != nil {
log.Print("IMAP server not started")
}
}

Loading