hydroxide-push/imap/user.go

219 lines
5.1 KiB
Go
Raw Normal View History

2017-12-03 16:08:30 +02:00
package imap
import (
2018-01-11 13:39:32 +02:00
"log"
"sync"
2017-12-03 16:08:30 +02:00
"golang.org/x/crypto/openpgp"
"github.com/emersion/go-imap"
2017-12-03 16:08:30 +02:00
imapbackend "github.com/emersion/go-imap/backend"
"github.com/emersion/go-imap-specialuse"
2017-12-03 16:08:30 +02:00
2018-01-08 00:38:13 +02:00
"github.com/emersion/hydroxide/imap/database"
2017-12-03 16:08:30 +02:00
"github.com/emersion/hydroxide/protonmail"
)
var systemMailboxes = []struct{
name string
label string
flags []string
}{
{imap.InboxName, protonmail.LabelInbox, nil},
{"All Mail", protonmail.LabelAllMail, []string{specialuse.All}},
{"Archive", protonmail.LabelArchive, []string{specialuse.Archive}},
{"Drafts", protonmail.LabelDraft, []string{specialuse.Drafts}},
{"Starred", protonmail.LabelStarred, []string{specialuse.Flagged}},
{"Spam", protonmail.LabelSpam, []string{specialuse.Junk}},
{"Sent", protonmail.LabelSent, []string{specialuse.Sent}},
{"Trash", protonmail.LabelTrash, []string{specialuse.Trash}},
}
2017-12-03 16:08:30 +02:00
type user struct {
c *protonmail.Client
u *protonmail.User
privateKeys openpgp.EntityList
2018-01-08 00:38:13 +02:00
db *database.User
2018-01-11 13:39:32 +02:00
locker sync.Mutex
mailboxes map[string]*mailbox
2018-01-12 14:20:17 +02:00
done chan<- struct{}
}
2018-01-12 14:20:17 +02:00
func newUser(be *backend, c *protonmail.Client, u *protonmail.User, privateKeys openpgp.EntityList) (*user, error) {
uu := &user{
c: c,
u: u,
privateKeys: privateKeys,
}
2018-01-08 00:38:13 +02:00
db, err := database.Open(u.Name+".db")
if err != nil {
return nil, err
}
uu.db = db
2018-01-11 13:39:32 +02:00
if err := uu.initMailboxes(); err != nil {
return nil, err
}
2018-01-12 14:20:17 +02:00
done := make(chan struct{})
uu.done = done
ch := make(chan *protonmail.Event)
go uu.receiveEvents(ch)
be.eventsManager.Register(c, u.Name, ch, done)
2018-01-11 13:39:32 +02:00
return uu, nil
}
func (u *user) initMailboxes() error {
u.locker.Lock()
defer u.locker.Unlock()
u.mailboxes = make(map[string]*mailbox)
for _, data := range systemMailboxes {
2018-01-11 13:39:32 +02:00
mboxDB, err := u.db.Mailbox(data.label)
2018-01-08 00:38:13 +02:00
if err != nil {
2018-01-11 13:39:32 +02:00
return err
2018-01-08 00:38:13 +02:00
}
2018-01-11 13:39:32 +02:00
u.mailboxes[data.label] = &mailbox{
name: data.name,
label: data.label,
flags: data.flags,
2018-01-11 13:39:32 +02:00
u: u,
2018-01-08 00:38:13 +02:00
db: mboxDB,
}
}
2018-01-11 13:39:32 +02:00
counts, err := u.c.CountMessages("")
2018-01-08 00:38:13 +02:00
if err != nil {
2018-01-11 13:39:32 +02:00
return err
2018-01-08 00:38:13 +02:00
}
for _, count := range counts {
2018-01-11 13:39:32 +02:00
if mbox, ok := u.mailboxes[count.LabelID]; ok {
2018-01-08 00:38:13 +02:00
mbox.total = count.Total
mbox.unread = count.Unread
}
}
2018-01-11 13:39:32 +02:00
return nil
2017-12-03 16:08:30 +02:00
}
func (u *user) Username() string {
return u.u.Name
2017-12-03 16:08:30 +02:00
}
func (u *user) ListMailboxes(subscribed bool) ([]imapbackend.Mailbox, error) {
2018-01-11 13:39:32 +02:00
u.locker.Lock()
defer u.locker.Unlock()
list := make([]imapbackend.Mailbox, 0, len(u.mailboxes))
for _, mbox := range u.mailboxes {
list = append(list, mbox)
}
return list, nil
2017-12-03 16:08:30 +02:00
}
func (u *user) GetMailbox(name string) (imapbackend.Mailbox, error) {
2018-01-11 13:39:32 +02:00
u.locker.Lock()
defer u.locker.Unlock()
2018-01-08 00:38:13 +02:00
for _, mbox := range u.mailboxes {
if mbox.name == name {
return mbox, nil
}
}
2018-01-08 00:38:13 +02:00
return nil, imapbackend.ErrNoSuchMailbox
2017-12-03 16:08:30 +02:00
}
func (u *user) CreateMailbox(name string) error {
return errNotYetImplemented // TODO
}
func (u *user) DeleteMailbox(name string) error {
return errNotYetImplemented // TODO
}
func (u *user) RenameMailbox(existingName, newName string) error {
return errNotYetImplemented // TODO
}
func (u *user) Logout() error {
2018-01-12 14:20:17 +02:00
close(u.done)
2018-01-11 13:39:32 +02:00
if err := u.db.Close(); err != nil {
return err
}
2017-12-03 16:08:30 +02:00
u.c = nil
u.u = nil
u.privateKeys = nil
return nil
}
2018-01-11 13:39:32 +02:00
func (u *user) receiveEvents(events <-chan *protonmail.Event) {
for event := range events {
if event.Refresh&protonmail.EventRefreshMail != 0 {
log.Println("Reinitializing the whole IMAP database")
u.locker.Lock()
for _, mbox := range u.mailboxes {
if err := mbox.reset(); err != nil {
log.Printf("cannot reset mailbox %s: %v", mbox.name, err)
}
}
u.locker.Unlock()
if err := u.db.ResetMessages(); err != nil {
log.Printf("cannot reset user: %v", err)
}
if err := u.initMailboxes(); err != nil {
log.Printf("cannot reinitialize mailboxes: %v", err)
}
} else {
for _, eventMessage := range event.Messages {
switch eventMessage.Action {
case protonmail.EventCreate:
2018-01-12 14:20:17 +02:00
log.Println("Received create event for message", eventMessage.ID)
2018-01-11 15:40:05 +02:00
if err := u.db.CreateMessage(eventMessage.Created); err != nil {
log.Printf("cannot handle create event for message %s: cannot create message in local DB: %v", eventMessage.ID, err)
break
}
// TODO: send updates
2018-01-12 14:20:17 +02:00
case protonmail.EventUpdate, protonmail.EventUpdateFlags:
log.Println("Received update event for message", eventMessage.ID)
if err := u.db.UpdateMessage(eventMessage.ID, eventMessage.Updated); err != nil {
2018-01-11 15:40:05 +02:00
log.Printf("cannot handle update event for message %s: cannot update message in local DB: %v", eventMessage.ID, err)
break
}
// TODO: send updates
2018-01-11 13:39:32 +02:00
case protonmail.EventDelete:
2018-01-12 14:20:17 +02:00
log.Println("Received delete event for message", eventMessage.ID)
2018-01-11 15:40:05 +02:00
if err := u.db.DeleteMessage(eventMessage.ID); err != nil {
log.Printf("cannot handle delete event for message %s: cannot delete message from local DB: %v", eventMessage.ID, err)
break
}
// TODO: send updates
}
}
u.locker.Lock()
for _, count := range event.MessageCounts {
if mbox, ok := u.mailboxes[count.LabelID]; ok {
mbox.total = count.Total
mbox.unread = count.Unread
2018-01-11 13:39:32 +02:00
}
}
2018-01-11 15:40:05 +02:00
u.locker.Unlock()
2018-01-11 13:39:32 +02:00
}
}
}