255 lines
5.7 KiB
Go
255 lines
5.7 KiB
Go
package client
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/emersion/go-imap"
|
|
"github.com/emersion/go-imap/commands"
|
|
"github.com/emersion/go-imap/responses"
|
|
)
|
|
|
|
// ErrNotLoggedIn is returned if a function that requires the client to be
|
|
// logged in is called then the client isn't.
|
|
var ErrNotLoggedIn = errors.New("Not logged in")
|
|
|
|
func (c *Client) ensureAuthenticated() error {
|
|
state := c.State()
|
|
if state != imap.AuthenticatedState && state != imap.SelectedState {
|
|
return ErrNotLoggedIn
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Select selects a mailbox so that messages in the mailbox can be accessed. Any
|
|
// currently selected mailbox is deselected before attempting the new selection.
|
|
// Even if the readOnly parameter is set to false, the server can decide to open
|
|
// the mailbox in read-only mode.
|
|
func (c *Client) Select(name string, readOnly bool) (*imap.MailboxStatus, error) {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cmd := &commands.Select{
|
|
Mailbox: name,
|
|
ReadOnly: readOnly,
|
|
}
|
|
|
|
mbox := &imap.MailboxStatus{Name: name, Items: make(map[imap.StatusItem]interface{})}
|
|
res := &responses.Select{
|
|
Mailbox: mbox,
|
|
}
|
|
c.locker.Lock()
|
|
c.mailbox = mbox
|
|
c.locker.Unlock()
|
|
|
|
status, err := c.execute(cmd, res)
|
|
if err != nil {
|
|
c.locker.Lock()
|
|
c.mailbox = nil
|
|
c.locker.Unlock()
|
|
return nil, err
|
|
}
|
|
if err := status.Err(); err != nil {
|
|
c.locker.Lock()
|
|
c.mailbox = nil
|
|
c.locker.Unlock()
|
|
return nil, err
|
|
}
|
|
|
|
c.locker.Lock()
|
|
mbox.ReadOnly = (status.Code == imap.CodeReadOnly)
|
|
c.state = imap.SelectedState
|
|
c.locker.Unlock()
|
|
return mbox, nil
|
|
}
|
|
|
|
// Create creates a mailbox with the given name.
|
|
func (c *Client) Create(name string) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd := &commands.Create{
|
|
Mailbox: name,
|
|
}
|
|
|
|
status, err := c.execute(cmd, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|
|
|
|
// Delete permanently removes the mailbox with the given name.
|
|
func (c *Client) Delete(name string) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd := &commands.Delete{
|
|
Mailbox: name,
|
|
}
|
|
|
|
status, err := c.execute(cmd, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|
|
|
|
// Rename changes the name of a mailbox.
|
|
func (c *Client) Rename(existingName, newName string) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd := &commands.Rename{
|
|
Existing: existingName,
|
|
New: newName,
|
|
}
|
|
|
|
status, err := c.execute(cmd, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|
|
|
|
// Subscribe adds the specified mailbox name to the server's set of "active" or
|
|
// "subscribed" mailboxes.
|
|
func (c *Client) Subscribe(name string) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd := &commands.Subscribe{
|
|
Mailbox: name,
|
|
}
|
|
|
|
status, err := c.execute(cmd, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|
|
|
|
// Unsubscribe removes the specified mailbox name from the server's set of
|
|
// "active" or "subscribed" mailboxes.
|
|
func (c *Client) Unsubscribe(name string) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd := &commands.Unsubscribe{
|
|
Mailbox: name,
|
|
}
|
|
|
|
status, err := c.execute(cmd, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|
|
|
|
// List returns a subset of names from the complete set of all names available
|
|
// to the client.
|
|
//
|
|
// An empty name argument is a special request to return the hierarchy delimiter
|
|
// and the root name of the name given in the reference. The character "*" is a
|
|
// wildcard, and matches zero or more characters at this position. The
|
|
// character "%" is similar to "*", but it does not match a hierarchy delimiter.
|
|
func (c *Client) List(ref, name string, ch chan *imap.MailboxInfo) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
defer close(ch)
|
|
|
|
cmd := &commands.List{
|
|
Reference: ref,
|
|
Mailbox: name,
|
|
}
|
|
res := &responses.List{Mailboxes: ch}
|
|
|
|
status, err := c.execute(cmd, res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|
|
|
|
// Lsub returns a subset of names from the set of names that the user has
|
|
// declared as being "active" or "subscribed".
|
|
func (c *Client) Lsub(ref, name string, ch chan *imap.MailboxInfo) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
defer close(ch)
|
|
|
|
cmd := &commands.List{
|
|
Reference: ref,
|
|
Mailbox: name,
|
|
Subscribed: true,
|
|
}
|
|
res := &responses.List{
|
|
Mailboxes: ch,
|
|
Subscribed: true,
|
|
}
|
|
|
|
status, err := c.execute(cmd, res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|
|
|
|
// Status requests the status of the indicated mailbox. It does not change the
|
|
// currently selected mailbox, nor does it affect the state of any messages in
|
|
// the queried mailbox.
|
|
//
|
|
// See RFC 3501 section 6.3.10 for a list of items that can be requested.
|
|
func (c *Client) Status(name string, items []imap.StatusItem) (*imap.MailboxStatus, error) {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cmd := &commands.Status{
|
|
Mailbox: name,
|
|
Items: items,
|
|
}
|
|
res := &responses.Status{
|
|
Mailbox: new(imap.MailboxStatus),
|
|
}
|
|
|
|
status, err := c.execute(cmd, res)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res.Mailbox, status.Err()
|
|
}
|
|
|
|
// Append appends the literal argument as a new message to the end of the
|
|
// specified destination mailbox. This argument SHOULD be in the format of an
|
|
// RFC 2822 message. flags and date are optional arguments and can be set to
|
|
// nil.
|
|
func (c *Client) Append(mbox string, flags []string, date time.Time, msg imap.Literal) error {
|
|
if err := c.ensureAuthenticated(); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd := &commands.Append{
|
|
Mailbox: mbox,
|
|
Flags: flags,
|
|
Date: date,
|
|
Message: msg,
|
|
}
|
|
|
|
status, err := c.execute(cmd, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return status.Err()
|
|
}
|