imap: add User.receiveEvents
This commit is contained in:
parent
60b4122c1d
commit
38af52e857
|
@ -335,7 +335,7 @@ func (ab *addressBook) CreateAddressObject(card vcard.Card) (carddav.AddressObje
|
||||||
func (ab *addressBook) receiveEvents(events <-chan *protonmail.Event) {
|
func (ab *addressBook) receiveEvents(events <-chan *protonmail.Event) {
|
||||||
for event := range events {
|
for event := range events {
|
||||||
ab.locker.Lock()
|
ab.locker.Lock()
|
||||||
if event.Refresh == 1 {
|
if event.Refresh&protonmail.EventRefreshContacts != 0 {
|
||||||
ab.cache = make(map[string]*addressObject)
|
ab.cache = make(map[string]*addressObject)
|
||||||
ab.total = -1
|
ab.total = -1
|
||||||
} else if len(event.Contacts) > 0 {
|
} else if len(event.Contacts) > 0 {
|
||||||
|
|
|
@ -174,3 +174,18 @@ func (mbox *Mailbox) ForEach(f func(seqNum, uid uint32, apiID string) error) err
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mbox *Mailbox) Reset() error {
|
||||||
|
return mbox.u.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
b := tx.Bucket(mailboxesBucket)
|
||||||
|
if b == nil {
|
||||||
|
return errors.New("cannot find mailboxes bucket")
|
||||||
|
}
|
||||||
|
k := []byte(mbox.name)
|
||||||
|
if err := b.DeleteBucket(k); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := b.CreateBucket(k)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -78,6 +78,16 @@ func (u *User) Message(apiID string) (*protonmail.Message, error) {
|
||||||
return msg, err
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) ResetMessages() error {
|
||||||
|
return u.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
return tx.DeleteBucket(messagesBucket)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Close() error {
|
||||||
|
return u.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
func Open(path string) (*User, error) {
|
func Open(path string) (*User, error) {
|
||||||
db, err := bolt.Open(path, 0700, nil)
|
db, err := bolt.Open(path, 0700, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -130,6 +130,15 @@ func (mbox *mailbox) init() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mbox *mailbox) reset() error {
|
||||||
|
mbox.initializedLock.Lock()
|
||||||
|
defer mbox.initializedLock.Unlock()
|
||||||
|
|
||||||
|
mbox.initialized = false
|
||||||
|
|
||||||
|
return mbox.db.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
func (mbox *mailbox) fetchMessage(isUid bool, id uint32, items []imap.FetchItem) (*imap.Message, error) {
|
func (mbox *mailbox) fetchMessage(isUid bool, id uint32, items []imap.FetchItem) (*imap.Message, error) {
|
||||||
var apiID string
|
var apiID string
|
||||||
var err error
|
var err error
|
||||||
|
|
96
imap/user.go
96
imap/user.go
|
@ -1,6 +1,9 @@
|
||||||
package imap
|
package imap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"golang.org/x/crypto/openpgp"
|
"golang.org/x/crypto/openpgp"
|
||||||
"github.com/emersion/go-imap"
|
"github.com/emersion/go-imap"
|
||||||
imapbackend "github.com/emersion/go-imap/backend"
|
imapbackend "github.com/emersion/go-imap/backend"
|
||||||
|
@ -31,6 +34,8 @@ type user struct {
|
||||||
privateKeys openpgp.EntityList
|
privateKeys openpgp.EntityList
|
||||||
|
|
||||||
db *database.User
|
db *database.User
|
||||||
|
|
||||||
|
locker sync.Mutex
|
||||||
mailboxes map[string]*mailbox
|
mailboxes map[string]*mailbox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +44,6 @@ func newUser(c *protonmail.Client, u *protonmail.User, privateKeys openpgp.Entit
|
||||||
c: c,
|
c: c,
|
||||||
u: u,
|
u: u,
|
||||||
privateKeys: privateKeys,
|
privateKeys: privateKeys,
|
||||||
mailboxes: make(map[string]*mailbox),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := database.Open(u.Name+".db")
|
db, err := database.Open(u.Name+".db")
|
||||||
|
@ -48,34 +52,49 @@ func newUser(c *protonmail.Client, u *protonmail.User, privateKeys openpgp.Entit
|
||||||
}
|
}
|
||||||
uu.db = db
|
uu.db = db
|
||||||
|
|
||||||
for _, data := range systemMailboxes {
|
if err := uu.initMailboxes(); err != nil {
|
||||||
mboxDB, err := db.Mailbox(data.label)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
uu.mailboxes[data.label] = &mailbox{
|
// TODO: go uu.receiveEvents(events)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
mboxDB, err := u.db.Mailbox(data.label)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u.mailboxes[data.label] = &mailbox{
|
||||||
name: data.name,
|
name: data.name,
|
||||||
label: data.label,
|
label: data.label,
|
||||||
flags: data.flags,
|
flags: data.flags,
|
||||||
u: uu,
|
u: u,
|
||||||
db: mboxDB,
|
db: mboxDB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
counts, err := c.CountMessages("")
|
counts, err := u.c.CountMessages("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, count := range counts {
|
for _, count := range counts {
|
||||||
if mbox, ok := uu.mailboxes[count.LabelID]; ok {
|
if mbox, ok := u.mailboxes[count.LabelID]; ok {
|
||||||
mbox.total = count.Total
|
mbox.total = count.Total
|
||||||
mbox.unread = count.Unread
|
mbox.unread = count.Unread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return uu, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *user) Username() string {
|
func (u *user) Username() string {
|
||||||
|
@ -83,6 +102,9 @@ func (u *user) Username() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *user) ListMailboxes(subscribed bool) ([]imapbackend.Mailbox, error) {
|
func (u *user) ListMailboxes(subscribed bool) ([]imapbackend.Mailbox, error) {
|
||||||
|
u.locker.Lock()
|
||||||
|
defer u.locker.Unlock()
|
||||||
|
|
||||||
list := make([]imapbackend.Mailbox, 0, len(u.mailboxes))
|
list := make([]imapbackend.Mailbox, 0, len(u.mailboxes))
|
||||||
for _, mbox := range u.mailboxes {
|
for _, mbox := range u.mailboxes {
|
||||||
list = append(list, mbox)
|
list = append(list, mbox)
|
||||||
|
@ -91,6 +113,9 @@ func (u *user) ListMailboxes(subscribed bool) ([]imapbackend.Mailbox, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *user) GetMailbox(name string) (imapbackend.Mailbox, error) {
|
func (u *user) GetMailbox(name string) (imapbackend.Mailbox, error) {
|
||||||
|
u.locker.Lock()
|
||||||
|
defer u.locker.Unlock()
|
||||||
|
|
||||||
for _, mbox := range u.mailboxes {
|
for _, mbox := range u.mailboxes {
|
||||||
if mbox.name == name {
|
if mbox.name == name {
|
||||||
return mbox, nil
|
return mbox, nil
|
||||||
|
@ -112,8 +137,59 @@ func (u *user) RenameMailbox(existingName, newName string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *user) Logout() error {
|
func (u *user) Logout() error {
|
||||||
|
if err := u.db.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
u.c = nil
|
u.c = nil
|
||||||
u.u = nil
|
u.u = nil
|
||||||
u.privateKeys = nil
|
u.privateKeys = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
u.locker.Lock()
|
||||||
|
for _, count := range event.MessageCounts {
|
||||||
|
if mbox, ok := u.mailboxes[count.LabelID]; ok {
|
||||||
|
mbox.total = count.Total
|
||||||
|
mbox.unread = count.Unread
|
||||||
|
// TODO: send update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.locker.Unlock()
|
||||||
|
|
||||||
|
for _, eventMessage := range event.Messages {
|
||||||
|
switch eventMessage.Action {
|
||||||
|
case protonmail.EventCreate:
|
||||||
|
// TODO
|
||||||
|
case protonmail.EventUpdate:
|
||||||
|
// TODO
|
||||||
|
case protonmail.EventUpdateFlags:
|
||||||
|
// TODO
|
||||||
|
case protonmail.EventDelete:
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,17 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EventRefresh int
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventRefreshMail EventRefresh = 1 << iota
|
||||||
|
EventRefreshContacts
|
||||||
|
)
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
ID string `json:"EventID"`
|
ID string `json:"EventID"`
|
||||||
Refresh int
|
Refresh EventRefresh
|
||||||
//Messages
|
Messages []*EventMessage
|
||||||
Contacts []*EventContact
|
Contacts []*EventContact
|
||||||
//ContactEmails
|
//ContactEmails
|
||||||
//Labels
|
//Labels
|
||||||
|
@ -15,7 +22,7 @@ type Event struct {
|
||||||
//Members
|
//Members
|
||||||
//Domains
|
//Domains
|
||||||
//Organization
|
//Organization
|
||||||
//MessageCounts
|
MessageCounts []*MessageCount
|
||||||
//ConversationCounts
|
//ConversationCounts
|
||||||
//UsedSpace
|
//UsedSpace
|
||||||
Notices []string
|
Notices []string
|
||||||
|
@ -27,8 +34,17 @@ const (
|
||||||
EventDelete EventAction = iota
|
EventDelete EventAction = iota
|
||||||
EventCreate
|
EventCreate
|
||||||
EventUpdate
|
EventUpdate
|
||||||
|
|
||||||
|
// For messages
|
||||||
|
EventUpdateFlags
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EventMessage struct {
|
||||||
|
ID string
|
||||||
|
Action EventAction
|
||||||
|
Message *Message
|
||||||
|
}
|
||||||
|
|
||||||
type EventContact struct {
|
type EventContact struct {
|
||||||
ID string
|
ID string
|
||||||
Action EventAction
|
Action EventAction
|
||||||
|
|
Loading…
Reference in New Issue