Added files.
This commit is contained in:
174
imapserver/select.go
Normal file
174
imapserver/select.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package imapserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/emersion/go-imap/v2"
|
||||
"github.com/emersion/go-imap/v2/internal/imapwire"
|
||||
)
|
||||
|
||||
func (c *Conn) handleSelect(tag string, dec *imapwire.Decoder, readOnly bool) error {
|
||||
var mailbox string
|
||||
if !dec.ExpectSP() || !dec.ExpectMailbox(&mailbox) || !dec.ExpectCRLF() {
|
||||
return dec.Err()
|
||||
}
|
||||
|
||||
if err := c.checkState(imap.ConnStateAuthenticated); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.state == imap.ConnStateSelected {
|
||||
if err := c.session.Unselect(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.state = imap.ConnStateAuthenticated
|
||||
err := c.writeStatusResp("", &imap.StatusResponse{
|
||||
Type: imap.StatusResponseTypeOK,
|
||||
Code: "CLOSED",
|
||||
Text: "Previous mailbox is now closed",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := imap.SelectOptions{ReadOnly: readOnly}
|
||||
data, err := c.session.Select(mailbox, &options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.writeExists(data.NumMessages); err != nil {
|
||||
return err
|
||||
}
|
||||
if !c.enabled.Has(imap.CapIMAP4rev2) && c.server.options.caps().Has(imap.CapIMAP4rev1) {
|
||||
if err := c.writeObsoleteRecent(data.NumRecent); err != nil {
|
||||
return err
|
||||
}
|
||||
if data.FirstUnseenSeqNum != 0 {
|
||||
if err := c.writeObsoleteUnseen(data.FirstUnseenSeqNum); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := c.writeUIDValidity(data.UIDValidity); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.writeUIDNext(data.UIDNext); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.writeFlags(data.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.writePermanentFlags(data.PermanentFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
if data.List != nil {
|
||||
if err := c.writeList(data.List); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.state = imap.ConnStateSelected
|
||||
// TODO: forbid write commands in read-only mode
|
||||
|
||||
var (
|
||||
cmdName string
|
||||
code imap.ResponseCode
|
||||
)
|
||||
if readOnly {
|
||||
cmdName = "EXAMINE"
|
||||
code = "READ-ONLY"
|
||||
} else {
|
||||
cmdName = "SELECT"
|
||||
code = "READ-WRITE"
|
||||
}
|
||||
return c.writeStatusResp(tag, &imap.StatusResponse{
|
||||
Type: imap.StatusResponseTypeOK,
|
||||
Code: code,
|
||||
Text: fmt.Sprintf("%v completed", cmdName),
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Conn) handleUnselect(dec *imapwire.Decoder, expunge bool) error {
|
||||
if !dec.ExpectCRLF() {
|
||||
return dec.Err()
|
||||
}
|
||||
|
||||
if err := c.checkState(imap.ConnStateSelected); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if expunge {
|
||||
w := &ExpungeWriter{}
|
||||
if err := c.session.Expunge(w, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.session.Unselect(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.state = imap.ConnStateAuthenticated
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) writeExists(numMessages uint32) error {
|
||||
enc := newResponseEncoder(c)
|
||||
defer enc.end()
|
||||
return enc.Atom("*").SP().Number(numMessages).SP().Atom("EXISTS").CRLF()
|
||||
}
|
||||
|
||||
func (c *Conn) writeObsoleteRecent(n uint32) error {
|
||||
enc := newResponseEncoder(c)
|
||||
defer enc.end()
|
||||
return enc.Atom("*").SP().Number(n).SP().Atom("RECENT").CRLF()
|
||||
}
|
||||
|
||||
func (c *Conn) writeObsoleteUnseen(n uint32) error {
|
||||
enc := newResponseEncoder(c)
|
||||
defer enc.end()
|
||||
enc.Atom("*").SP().Atom("OK").SP()
|
||||
enc.Special('[').Atom("UNSEEN").SP().Number(n).Special(']')
|
||||
enc.SP().Text("First unseen message")
|
||||
return enc.CRLF()
|
||||
}
|
||||
|
||||
func (c *Conn) writeUIDValidity(uidValidity uint32) error {
|
||||
enc := newResponseEncoder(c)
|
||||
defer enc.end()
|
||||
enc.Atom("*").SP().Atom("OK").SP()
|
||||
enc.Special('[').Atom("UIDVALIDITY").SP().Number(uidValidity).Special(']')
|
||||
enc.SP().Text("UIDs valid")
|
||||
return enc.CRLF()
|
||||
}
|
||||
|
||||
func (c *Conn) writeUIDNext(uidNext imap.UID) error {
|
||||
enc := newResponseEncoder(c)
|
||||
defer enc.end()
|
||||
enc.Atom("*").SP().Atom("OK").SP()
|
||||
enc.Special('[').Atom("UIDNEXT").SP().UID(uidNext).Special(']')
|
||||
enc.SP().Text("Predicted next UID")
|
||||
return enc.CRLF()
|
||||
}
|
||||
|
||||
func (c *Conn) writeFlags(flags []imap.Flag) error {
|
||||
enc := newResponseEncoder(c)
|
||||
defer enc.end()
|
||||
enc.Atom("*").SP().Atom("FLAGS").SP().List(len(flags), func(i int) {
|
||||
enc.Flag(flags[i])
|
||||
})
|
||||
return enc.CRLF()
|
||||
}
|
||||
|
||||
func (c *Conn) writePermanentFlags(flags []imap.Flag) error {
|
||||
enc := newResponseEncoder(c)
|
||||
defer enc.end()
|
||||
enc.Atom("*").SP().Atom("OK").SP()
|
||||
enc.Special('[').Atom("PERMANENTFLAGS").SP().List(len(flags), func(i int) {
|
||||
enc.Flag(flags[i])
|
||||
}).Special(']')
|
||||
enc.SP().Text("Permanent flags")
|
||||
return enc.CRLF()
|
||||
}
|
||||
Reference in New Issue
Block a user