mirror of https://git.sr.ht/~rjarry/aerc
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
3.2 KiB
Go
150 lines
3.2 KiB
Go
package extensions
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/emersion/go-imap"
|
|
"github.com/emersion/go-imap/client"
|
|
"github.com/emersion/go-imap/responses"
|
|
"github.com/emersion/go-imap/utf7"
|
|
)
|
|
|
|
// A LIST-STATUS client
|
|
type ListStatusClient struct {
|
|
c *client.Client
|
|
}
|
|
|
|
func NewListStatusClient(c *client.Client) *ListStatusClient {
|
|
return &ListStatusClient{c}
|
|
}
|
|
|
|
// SupportListStatus checks if the server supports the LIST-STATUS extension.
|
|
func (c *ListStatusClient) SupportListStatus() (bool, error) {
|
|
return c.c.Support("LIST-STATUS")
|
|
}
|
|
|
|
// ListStatus performs a LIST-STATUS command, listing mailboxes and also
|
|
// retrieving the requested status items. A nil channel can be passed in order
|
|
// to only retrieve the STATUS responses
|
|
func (c *ListStatusClient) ListStatus(
|
|
ref string,
|
|
name string,
|
|
items []imap.StatusItem,
|
|
ch chan *imap.MailboxInfo,
|
|
) ([]*imap.MailboxStatus, error) {
|
|
if ch != nil {
|
|
defer close(ch)
|
|
}
|
|
|
|
if c.c.State() != imap.AuthenticatedState && c.c.State() != imap.SelectedState {
|
|
return nil, client.ErrNotLoggedIn
|
|
}
|
|
|
|
cmd := &ListStatusCommand{
|
|
Reference: ref,
|
|
Mailbox: name,
|
|
Items: items,
|
|
}
|
|
res := &ListStatusResponse{Mailboxes: ch}
|
|
|
|
status, err := c.c.Execute(cmd, res)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res.Statuses, status.Err()
|
|
}
|
|
|
|
// ListStatusCommand is a LIST command, as defined in RFC 3501 section 6.3.8. If
|
|
// Subscribed is set to true, LSUB will be used instead. Mailbox statuses will
|
|
// be returned if Items is not nil
|
|
type ListStatusCommand struct {
|
|
Reference string
|
|
Mailbox string
|
|
|
|
Subscribed bool
|
|
Items []imap.StatusItem
|
|
}
|
|
|
|
func (cmd *ListStatusCommand) Command() *imap.Command {
|
|
name := "LIST"
|
|
if cmd.Subscribed {
|
|
name = "LSUB"
|
|
}
|
|
|
|
enc := utf7.Encoding.NewEncoder()
|
|
ref, _ := enc.String(cmd.Reference)
|
|
mailbox, _ := enc.String(cmd.Mailbox)
|
|
|
|
items := make([]string, len(cmd.Items))
|
|
if cmd.Items != nil {
|
|
for i, item := range cmd.Items {
|
|
items[i] = string(item)
|
|
}
|
|
}
|
|
|
|
args := fmt.Sprintf("RETURN (STATUS (%s))", strings.Join(items, " "))
|
|
return &imap.Command{
|
|
Name: name,
|
|
Arguments: []interface{}{ref, mailbox, imap.RawString(args)},
|
|
}
|
|
}
|
|
|
|
// A LIST-STATUS response
|
|
type ListStatusResponse struct {
|
|
Mailboxes chan *imap.MailboxInfo
|
|
Subscribed bool
|
|
Statuses []*imap.MailboxStatus
|
|
}
|
|
|
|
func (r *ListStatusResponse) Name() string {
|
|
if r.Subscribed {
|
|
return "LSUB"
|
|
} else {
|
|
return "LIST"
|
|
}
|
|
}
|
|
|
|
func (r *ListStatusResponse) Handle(resp imap.Resp) error {
|
|
name, _, ok := imap.ParseNamedResp(resp)
|
|
if !ok {
|
|
return responses.ErrUnhandled
|
|
}
|
|
switch name {
|
|
case "LIST":
|
|
if r.Mailboxes == nil {
|
|
return nil
|
|
}
|
|
res := responses.List{Mailboxes: r.Mailboxes}
|
|
return res.Handle(resp)
|
|
case "STATUS":
|
|
res := responses.Status{
|
|
Mailbox: new(imap.MailboxStatus),
|
|
}
|
|
err := res.Handle(resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r.Statuses = append(r.Statuses, res.Mailbox)
|
|
default:
|
|
return responses.ErrUnhandled
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *ListStatusResponse) WriteTo(w *imap.Writer) error {
|
|
respName := r.Name()
|
|
|
|
for mbox := range r.Mailboxes {
|
|
fields := []interface{}{imap.RawString(respName)}
|
|
fields = append(fields, mbox.Format()...)
|
|
|
|
resp := imap.NewUntaggedResp(fields)
|
|
if err := resp.WriteTo(w); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|