198 lines
4.4 KiB
Go
198 lines
4.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"github.com/emersion/go-imap/v2"
|
||
|
"github.com/emersion/go-imap/v2/imapserver"
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
user = User
|
||
|
mailbox = MailboxView
|
||
|
)
|
||
|
|
||
|
// UserSession represents a session tied to a specific user.
|
||
|
//
|
||
|
// UserSession implements imapserver.Session. Typically, a UserSession pointer
|
||
|
// is embedded into a larger struct which overrides Login.
|
||
|
type UserSession struct {
|
||
|
*user // immutable
|
||
|
*mailbox // may be nil
|
||
|
}
|
||
|
|
||
|
var _ imapserver.SessionIMAP4rev2 = (*UserSession)(nil)
|
||
|
|
||
|
// NewUserSession creates a new user session.
|
||
|
func NewUserSession(user *User) *UserSession {
|
||
|
return &UserSession{user: user}
|
||
|
}
|
||
|
|
||
|
type ByteLiteral struct {
|
||
|
io.Reader
|
||
|
size int64
|
||
|
}
|
||
|
|
||
|
func (l *ByteLiteral) Size() int64 {
|
||
|
return l.size
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Append(mboxName string, r imap.LiteralReader, options *imap.AppendOptions) (*imap.AppendData, error) {
|
||
|
mbox, err := sess.user.mailbox(mboxName)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
view := mbox.NewView()
|
||
|
defer func() {
|
||
|
err := view.Close()
|
||
|
if err != nil {
|
||
|
log("Failed to close view: "+err.Error()+", resource leaks may occur", 1)
|
||
|
}
|
||
|
}()
|
||
|
println("INITIAL APPEND ENTRYPOINT SUCCESS")
|
||
|
return view.appendLiteral(&ByteLiteral{Reader: r, size: r.Size()}, options)
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Close() error {
|
||
|
if sess != nil && sess.mailbox != nil {
|
||
|
return sess.mailbox.Close()
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Select(name string, _ *imap.SelectOptions) (*imap.SelectData, error) {
|
||
|
mbox, err := sess.user.mailbox(name)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
sess.mailbox = mbox.NewView()
|
||
|
return mbox.selectData()
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Unselect() error {
|
||
|
err := sess.mailbox.Close()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
sess.mailbox = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Copy(numSet imap.NumSet, destName string) (data *imap.CopyData, fErr error) {
|
||
|
dest, err := sess.user.mailbox(destName)
|
||
|
if err != nil {
|
||
|
return nil, &imap.Error{
|
||
|
Type: imap.StatusResponseTypeNo,
|
||
|
Code: imap.ResponseCodeTryCreate,
|
||
|
Text: "No such mailbox",
|
||
|
}
|
||
|
} else if sess.mailbox != nil && dest == sess.mailbox.Mailbox {
|
||
|
return nil, &imap.Error{
|
||
|
Type: imap.StatusResponseTypeNo,
|
||
|
Text: "Source and destination mailboxes are identical",
|
||
|
}
|
||
|
}
|
||
|
|
||
|
destView := dest.NewView()
|
||
|
defer func() {
|
||
|
err := destView.Close()
|
||
|
if err != nil {
|
||
|
log("Failed to close view: "+err.Error()+", resource leaks may occur", 1)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
var sourceUIDs, destUIDs imap.UIDSet
|
||
|
err = sess.mailbox.forEach(numSet, func(seqNum uint32, msg *message) {
|
||
|
appendData, err := destView.copyMsg(msg)
|
||
|
if err != nil {
|
||
|
fErr = err
|
||
|
return
|
||
|
}
|
||
|
sourceUIDs.AddNum(msg.uid)
|
||
|
destUIDs.AddNum(appendData.UID)
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if fErr != nil {
|
||
|
return nil, fErr
|
||
|
}
|
||
|
|
||
|
return &imap.CopyData{
|
||
|
UIDValidity: dest.UIDValidity,
|
||
|
SourceUIDs: sourceUIDs,
|
||
|
DestUIDs: destUIDs,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Move(w *imapserver.MoveWriter, numSet imap.NumSet, destName string) (fErr error) {
|
||
|
dest, err := sess.user.mailbox(destName)
|
||
|
if err != nil {
|
||
|
return &imap.Error{
|
||
|
Type: imap.StatusResponseTypeNo,
|
||
|
Code: imap.ResponseCodeTryCreate,
|
||
|
Text: "No such mailbox",
|
||
|
}
|
||
|
} else if sess.mailbox != nil && dest == sess.mailbox.Mailbox {
|
||
|
return &imap.Error{
|
||
|
Type: imap.StatusResponseTypeNo,
|
||
|
Text: "Source and destination mailboxes are identical",
|
||
|
}
|
||
|
}
|
||
|
|
||
|
destView := dest.NewView()
|
||
|
defer func() {
|
||
|
err := destView.Close()
|
||
|
if err != nil {
|
||
|
log("Failed to close view: "+err.Error()+", resource leaks may occur", 1)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
var sourceUIDs, destUIDs imap.UIDSet
|
||
|
err = sess.mailbox.forEach(numSet, func(seqNum uint32, msg *message) {
|
||
|
var appendData *imap.AppendData
|
||
|
appendData, fErr = destView.copyMsg(msg)
|
||
|
if fErr != nil {
|
||
|
return
|
||
|
}
|
||
|
sourceUIDs.AddNum(msg.uid)
|
||
|
destUIDs.AddNum(appendData.UID)
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if fErr != nil {
|
||
|
return fErr
|
||
|
}
|
||
|
|
||
|
err = w.WriteCopyData(&imap.CopyData{
|
||
|
UIDValidity: dest.UIDValidity,
|
||
|
SourceUIDs: sourceUIDs,
|
||
|
DestUIDs: destUIDs,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
println(sourceUIDs.String())
|
||
|
err = sess.mailbox.Expunge(nil, &sourceUIDs)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Poll(w *imapserver.UpdateWriter, allowExpunge bool) error {
|
||
|
if sess.mailbox == nil {
|
||
|
return nil
|
||
|
}
|
||
|
return sess.mailbox.Poll(w, allowExpunge)
|
||
|
}
|
||
|
|
||
|
func (sess *UserSession) Idle(w *imapserver.UpdateWriter, stop <-chan struct{}) error {
|
||
|
if sess.mailbox == nil {
|
||
|
return nil // TODO
|
||
|
}
|
||
|
return sess.mailbox.Idle(w, stop)
|
||
|
}
|