Very early NOTIFY support, hopefully fix -password on Windows

This commit is contained in:
Neil Alexander
2021-07-10 11:42:55 +01:00
parent 4c07013a13
commit 63de5e81e4
8 changed files with 141 additions and 31 deletions

View File

@@ -16,6 +16,7 @@ type Backend struct {
Config *config.Config
Log *log.Logger
Storage storage.Storage
Server *IMAPServer
}
func (b *Backend) Login(conn *imap.ConnInfo, username, password string) (backend.User, error) {
@@ -38,6 +39,26 @@ func (b *Backend) Login(conn *imap.ConnInfo, username, password string) (backend
user := &User{
backend: b,
username: username,
conn: conn,
}
return user, nil
}
/*
func (b *Backend) NotifyNew(id int) error {
b.Server.server.ForEachConn(func(conn server.Conn) {
notify := false
for _, cap := range conn.Capabilities() {
if cap == "NOTIFY" {
notify = true
}
}
if !notify {
return
}
conn.WaitReady()
conn.WriteResp()
})
return nil
}
*/

View File

@@ -1,8 +1,12 @@
package imapserver
import (
"log"
"os"
idle "github.com/emersion/go-imap-idle"
"github.com/emersion/go-imap/server"
"github.com/emersion/go-sasl"
)
type IMAPServer struct {
@@ -10,11 +14,27 @@ type IMAPServer struct {
backend *Backend
}
func NewIMAPServer(backend *Backend) (*IMAPServer, error) {
func NewIMAPServer(backend *Backend, addr string, insecure bool) (*IMAPServer, *IMAPNotify, error) {
s := &IMAPServer{
server: server.New(backend),
backend: backend,
}
notify := NewIMAPNotify(s.server, backend.Log)
s.server.Addr = addr
s.server.AllowInsecureAuth = insecure
s.server.Debug = os.Stdout
s.server.Enable(idle.NewExtension())
return s, nil
s.server.Enable(notify)
s.server.EnableAuth(sasl.Login, func(conn server.Conn) sasl.Server {
return sasl.NewLoginServer(func(username, password string) error {
_, err := s.backend.Login(nil, username, password)
return err
})
})
go func() {
if err := s.server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}()
return s, notify, nil
}

View File

@@ -0,0 +1,65 @@
package imapserver
import (
"fmt"
"log"
"github.com/emersion/go-imap"
"github.com/emersion/go-imap/server"
)
type IMAPNotifyHandler struct {
imap.Command
}
func (h *IMAPNotifyHandler) Handle(conn server.Conn) error {
// TODO: Support setting NOTIFY subscriptions or not
return nil
}
type IMAPNotify struct {
server *server.Server
log *log.Logger
}
func (ext *IMAPNotify) Capabilities(c server.Conn) []string {
if c.Context().State&imap.AuthenticatedState != 0 {
return []string{"NOTIFY"}
}
return nil
}
func (ext *IMAPNotify) Command(name string) server.HandlerFactory {
if name != "NOTIFY" {
return nil
}
return func() server.Handler {
return &IMAPNotifyHandler{}
}
}
func (ext *IMAPNotify) NotifyNew(id, count int) error {
ext.server.ForEachConn(func(c server.Conn) {
var resptype imap.StatusRespType
if mailbox := c.Context().Mailbox; mailbox != nil && mailbox.Name() == "INBOX" {
resptype = imap.StatusRespType(
fmt.Sprintf("EXISTS %d", id),
)
} else {
resptype = imap.StatusRespType(
fmt.Sprintf("STATUS INBOX (UIDNEXT %d MESSAGES %d)", id+1, count),
)
}
_ = c.WriteResp(&imap.StatusResp{
Type: resptype,
})
})
return nil
}
func NewIMAPNotify(s *server.Server, log *log.Logger) *IMAPNotify {
return &IMAPNotify{
server: s,
log: log,
}
}

View File

@@ -5,12 +5,14 @@ import (
"errors"
"fmt"
"github.com/emersion/go-imap"
"github.com/emersion/go-imap/backend"
)
type User struct {
backend *Backend
username string
conn *imap.ConnInfo
}
func (u *User) Username() string {