2017-12-03 16:08:30 +02:00
|
|
|
package imap
|
|
|
|
|
|
|
|
import (
|
2018-01-11 13:39:32 +02:00
|
|
|
"log"
|
2020-02-29 12:28:04 +02:00
|
|
|
"strings"
|
2018-01-11 13:39:32 +02:00
|
|
|
"sync"
|
|
|
|
|
2020-12-29 19:47:20 +02:00
|
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
2017-12-03 17:05:24 +02:00
|
|
|
"github.com/emersion/go-imap"
|
2018-10-21 13:15:20 +03:00
|
|
|
imapbackend "github.com/emersion/go-imap/backend"
|
2018-01-13 12:35:10 +02:00
|
|
|
"github.com/emersion/hydroxide/events"
|
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"
|
|
|
|
)
|
|
|
|
|
2018-10-21 13:15:20 +03:00
|
|
|
var systemMailboxes = []struct {
|
|
|
|
name string
|
2017-12-03 17:05:24 +02:00
|
|
|
label string
|
2020-02-29 11:50:23 +02:00
|
|
|
attrs []string
|
2017-12-03 17:05:24 +02:00
|
|
|
}{
|
|
|
|
{imap.InboxName, protonmail.LabelInbox, nil},
|
2022-08-21 15:59:40 +03:00
|
|
|
{"All Mail", protonmail.LabelAllMail, []string{imap.AllAttr}},
|
|
|
|
{"Archive", protonmail.LabelArchive, []string{imap.ArchiveAttr}},
|
|
|
|
{"Drafts", protonmail.LabelDraft, []string{imap.DraftsAttr}},
|
|
|
|
{"Starred", protonmail.LabelStarred, []string{imap.FlaggedAttr}},
|
|
|
|
{"Spam", protonmail.LabelSpam, []string{imap.JunkAttr}},
|
|
|
|
{"Sent", protonmail.LabelSent, []string{imap.SentAttr}},
|
|
|
|
{"Trash", protonmail.LabelTrash, []string{imap.TrashAttr}},
|
2017-12-03 17:05:24 +02:00
|
|
|
}
|
|
|
|
|
2020-02-29 12:43:24 +02:00
|
|
|
var systemFlags = []struct {
|
|
|
|
name string
|
|
|
|
label string
|
|
|
|
}{
|
|
|
|
{imap.FlaggedFlag, protonmail.LabelStarred},
|
|
|
|
{imap.DraftFlag, protonmail.LabelDraft},
|
2020-02-29 12:28:04 +02:00
|
|
|
}
|
|
|
|
|
2017-12-03 16:08:30 +02:00
|
|
|
type user struct {
|
2020-02-29 13:06:09 +02:00
|
|
|
username string
|
2020-01-27 20:35:40 +02:00
|
|
|
backend *backend
|
2017-12-03 16:08:30 +02:00
|
|
|
c *protonmail.Client
|
|
|
|
u *protonmail.User
|
|
|
|
privateKeys openpgp.EntityList
|
2018-10-21 13:24:56 +03:00
|
|
|
addrs []*protonmail.Address
|
2017-12-03 17:05:24 +02:00
|
|
|
|
2018-10-21 13:15:20 +03:00
|
|
|
db *database.User
|
2018-01-13 12:35:10 +02:00
|
|
|
eventsReceiver *events.Receiver
|
2018-01-11 13:39:32 +02:00
|
|
|
|
2018-10-21 13:15:20 +03:00
|
|
|
done chan<- struct{}
|
2018-01-13 12:35:10 +02:00
|
|
|
eventSent chan struct{}
|
2020-02-29 12:59:15 +02:00
|
|
|
|
|
|
|
sync.Mutex // protects everything below
|
|
|
|
|
|
|
|
numClients int
|
|
|
|
mailboxes map[string]*mailbox // indexed by label ID
|
|
|
|
flags map[string]string // indexed by label ID
|
2017-12-03 17:05:24 +02:00
|
|
|
}
|
|
|
|
|
2020-01-27 20:35:40 +02:00
|
|
|
func getUser(be *backend, username string, c *protonmail.Client, privateKeys openpgp.EntityList) (*user, error) {
|
2020-02-29 13:13:32 +02:00
|
|
|
// TODO: logging a user in may take some time, find a way not to lock all
|
|
|
|
// other logins during this time
|
|
|
|
be.Lock()
|
|
|
|
defer be.Unlock()
|
|
|
|
|
2020-01-27 20:35:40 +02:00
|
|
|
if u, ok := be.users[username]; ok {
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
2020-01-27 20:35:40 +02:00
|
|
|
u.numClients++
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Unlock()
|
2020-01-27 20:35:40 +02:00
|
|
|
return u, nil
|
|
|
|
} else {
|
2020-02-29 13:06:09 +02:00
|
|
|
u, err := newUser(be, username, c, privateKeys)
|
2020-01-27 20:35:40 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
be.users[username] = u
|
|
|
|
return u, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-29 13:06:09 +02:00
|
|
|
func newUser(be *backend, username string, c *protonmail.Client, privateKeys openpgp.EntityList) (*user, error) {
|
|
|
|
u, err := c.GetCurrentUser()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
addrs, err := c.ListAddresses()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-12-03 17:05:24 +02:00
|
|
|
uu := &user{
|
2020-02-29 13:06:09 +02:00
|
|
|
username: username,
|
2020-01-27 20:35:40 +02:00
|
|
|
backend: be,
|
2018-10-21 13:15:20 +03:00
|
|
|
c: c,
|
|
|
|
u: u,
|
2017-12-03 17:05:24 +02:00
|
|
|
privateKeys: privateKeys,
|
2018-10-21 13:24:56 +03:00
|
|
|
addrs: addrs,
|
2018-10-21 13:15:20 +03:00
|
|
|
eventSent: make(chan struct{}),
|
2020-01-27 20:35:40 +02:00
|
|
|
numClients: 1,
|
2017-12-03 17:05:24 +02:00
|
|
|
}
|
|
|
|
|
2018-10-21 13:15:20 +03:00
|
|
|
db, err := database.Open(u.Name + ".db")
|
2018-01-08 00:38:13 +02:00
|
|
|
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)
|
2018-01-12 16:16:26 +02:00
|
|
|
go uu.receiveEvents(be.updates, ch)
|
2018-01-13 12:35:10 +02:00
|
|
|
uu.eventsReceiver = be.eventsManager.Register(c, u.Name, ch, done)
|
2018-01-11 13:39:32 +02:00
|
|
|
|
2020-01-27 20:35:40 +02:00
|
|
|
log.Printf("User %q logged in via IMAP", u.Name)
|
2018-01-11 13:39:32 +02:00
|
|
|
return uu, nil
|
|
|
|
}
|
|
|
|
|
2020-02-29 12:28:04 +02:00
|
|
|
func labelNameToFlag(s string) string {
|
|
|
|
var sb strings.Builder
|
|
|
|
var lastValid bool
|
|
|
|
for _, r := range s {
|
|
|
|
// See atom-specials in RFC 3501
|
|
|
|
var valid bool
|
|
|
|
switch r {
|
|
|
|
case '(', ')', '{':
|
|
|
|
case ' ', '\t': // SP
|
|
|
|
case '%', '*': // list-wildcards
|
|
|
|
case '"', '\\': // quoted-specials
|
|
|
|
case ']': // resp-specials
|
|
|
|
default:
|
|
|
|
valid = r <= '~' && r > 31
|
|
|
|
}
|
|
|
|
if !valid {
|
|
|
|
if !lastValid {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
r = '_'
|
|
|
|
}
|
|
|
|
sb.WriteRune(r)
|
|
|
|
lastValid = valid
|
|
|
|
}
|
|
|
|
return sb.String()
|
|
|
|
}
|
|
|
|
|
2018-01-11 13:39:32 +02:00
|
|
|
func (u *user) initMailboxes() error {
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
|
|
|
defer u.Unlock()
|
2018-01-11 13:39:32 +02:00
|
|
|
|
|
|
|
u.mailboxes = make(map[string]*mailbox)
|
2017-12-03 17:05:24 +02:00
|
|
|
for _, data := range systemMailboxes {
|
2020-01-29 15:59:45 +02:00
|
|
|
var err error
|
2020-02-29 11:50:23 +02:00
|
|
|
u.mailboxes[data.label], err = newMailbox(data.name, data.label, data.attrs, u)
|
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
|
|
|
}
|
2020-01-29 15:59:45 +02:00
|
|
|
}
|
|
|
|
|
2020-02-29 12:28:04 +02:00
|
|
|
u.flags = make(map[string]string)
|
2020-02-29 12:43:24 +02:00
|
|
|
for _, data := range systemFlags {
|
|
|
|
u.flags[data.label] = data.name
|
2020-02-29 12:28:04 +02:00
|
|
|
}
|
|
|
|
|
2020-01-29 15:59:45 +02:00
|
|
|
labels, err := u.c.ListLabels()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-01-08 00:38:13 +02:00
|
|
|
|
2020-01-29 15:59:45 +02:00
|
|
|
for _, label := range labels {
|
2020-02-29 12:28:04 +02:00
|
|
|
if label.Exclusive == 1 {
|
|
|
|
if _, ok := u.mailboxes[label.ID]; ok {
|
|
|
|
continue
|
|
|
|
}
|
2020-01-29 15:59:45 +02:00
|
|
|
|
2020-02-29 12:28:04 +02:00
|
|
|
u.mailboxes[label.ID], err = newMailbox(label.Name, label.ID, nil, u)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if _, ok := u.flags[label.ID]; ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
u.flags[label.ID] = labelNameToFlag(label.Name)
|
2018-01-08 00:38:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
2017-12-03 17:05:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-11 13:39:32 +02:00
|
|
|
return nil
|
2017-12-03 16:08:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *user) Username() string {
|
2017-12-03 17:05:24 +02:00
|
|
|
return u.u.Name
|
2017-12-03 16:08:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *user) ListMailboxes(subscribed bool) ([]imapbackend.Mailbox, error) {
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
|
|
|
defer u.Unlock()
|
2018-01-11 13:39:32 +02:00
|
|
|
|
2017-12-03 17:05:24 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-01-12 16:16:26 +02:00
|
|
|
func (u *user) getMailboxByLabel(labelID string) *mailbox {
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
|
|
|
defer u.Unlock()
|
2018-01-12 16:16:26 +02:00
|
|
|
return u.mailboxes[labelID]
|
|
|
|
}
|
|
|
|
|
2018-01-13 12:35:10 +02:00
|
|
|
func (u *user) getMailbox(name string) *mailbox {
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
|
|
|
defer u.Unlock()
|
2018-01-11 13:39:32 +02:00
|
|
|
|
2018-01-08 00:38:13 +02:00
|
|
|
for _, mbox := range u.mailboxes {
|
|
|
|
if mbox.name == name {
|
2018-01-13 12:35:10 +02:00
|
|
|
return mbox
|
2018-01-08 00:38:13 +02:00
|
|
|
}
|
2017-12-03 17:05:24 +02:00
|
|
|
}
|
2018-01-13 12:35:10 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *user) GetMailbox(name string) (imapbackend.Mailbox, error) {
|
|
|
|
mbox := u.getMailbox(name)
|
|
|
|
if mbox == nil {
|
|
|
|
return nil, imapbackend.ErrNoSuchMailbox
|
|
|
|
}
|
|
|
|
return mbox, nil
|
2017-12-03 16:08:30 +02:00
|
|
|
}
|
|
|
|
|
2020-02-29 12:43:24 +02:00
|
|
|
func (u *user) getFlag(name string) string {
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
|
|
|
defer u.Unlock()
|
2020-02-29 12:43:24 +02:00
|
|
|
|
|
|
|
for label, flag := range u.flags {
|
|
|
|
if flag == name {
|
|
|
|
return label
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
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 {
|
2020-02-29 13:13:32 +02:00
|
|
|
u.backend.Lock()
|
|
|
|
defer u.backend.Unlock()
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
|
|
|
defer u.Unlock()
|
|
|
|
|
2020-01-27 20:35:40 +02:00
|
|
|
if u.numClients <= 0 {
|
|
|
|
panic("unreachable")
|
|
|
|
}
|
|
|
|
u.numClients--
|
|
|
|
if u.numClients > 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-29 13:06:09 +02:00
|
|
|
delete(u.backend.users, u.username)
|
2020-01-27 20:35:40 +02:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-01-27 20:35:40 +02:00
|
|
|
log.Printf("User %q logged out via IMAP", u.u.Name)
|
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
|
|
|
|
2018-01-13 12:35:10 +02:00
|
|
|
func (u *user) poll() {
|
|
|
|
go u.eventsReceiver.Poll()
|
|
|
|
<-u.eventSent
|
|
|
|
}
|
|
|
|
|
2018-01-14 12:21:34 +02:00
|
|
|
func (u *user) receiveEvents(updates chan<- imapbackend.Update, events <-chan *protonmail.Event) {
|
2018-01-11 13:39:32 +02:00
|
|
|
for event := range events {
|
2018-01-14 12:21:34 +02:00
|
|
|
var eventUpdates []imapbackend.Update
|
2018-01-13 12:35:10 +02:00
|
|
|
|
2018-01-11 13:39:32 +02:00
|
|
|
if event.Refresh&protonmail.EventRefreshMail != 0 {
|
|
|
|
log.Println("Reinitializing the whole IMAP database")
|
|
|
|
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
2018-01-11 13:39:32 +02:00
|
|
|
for _, mbox := range u.mailboxes {
|
|
|
|
if err := mbox.reset(); err != nil {
|
|
|
|
log.Printf("cannot reset mailbox %s: %v", mbox.name, err)
|
|
|
|
}
|
|
|
|
}
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Unlock()
|
2018-01-11 13:39:32 +02:00
|
|
|
|
|
|
|
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-12 16:16:26 +02:00
|
|
|
seqNums, err := u.db.CreateMessage(eventMessage.Created)
|
|
|
|
if err != nil {
|
2018-01-11 15:40:05 +02:00
|
|
|
log.Printf("cannot handle create event for message %s: cannot create message in local DB: %v", eventMessage.ID, err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2018-01-12 16:16:26 +02:00
|
|
|
// TODO: what if the message was already in the local DB?
|
|
|
|
for labelID, seqNum := range seqNums {
|
|
|
|
if mbox := u.getMailboxByLabel(labelID); mbox != nil {
|
|
|
|
update := new(imapbackend.MailboxUpdate)
|
2018-01-14 12:21:34 +02:00
|
|
|
update.Update = imapbackend.NewUpdate(u.u.Name, mbox.name)
|
2018-01-12 16:16:26 +02:00
|
|
|
update.MailboxStatus = imap.NewMailboxStatus(mbox.name, []imap.StatusItem{imap.StatusMessages})
|
|
|
|
update.MailboxStatus.Messages = seqNum
|
2018-01-13 12:35:10 +02:00
|
|
|
eventUpdates = append(eventUpdates, update)
|
2018-01-12 16:16:26 +02:00
|
|
|
}
|
|
|
|
}
|
2018-01-12 14:20:17 +02:00
|
|
|
case protonmail.EventUpdate, protonmail.EventUpdateFlags:
|
|
|
|
log.Println("Received update event for message", eventMessage.ID)
|
2018-01-12 16:16:26 +02:00
|
|
|
createdSeqNums, deletedSeqNums, err := u.db.UpdateMessage(eventMessage.ID, eventMessage.Updated)
|
|
|
|
if 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
|
|
|
|
}
|
|
|
|
|
2018-01-12 16:16:26 +02:00
|
|
|
for labelID, seqNum := range createdSeqNums {
|
|
|
|
if mbox := u.getMailboxByLabel(labelID); mbox != nil {
|
|
|
|
update := new(imapbackend.MailboxUpdate)
|
2018-01-14 12:21:34 +02:00
|
|
|
update.Update = imapbackend.NewUpdate(u.u.Name, mbox.name)
|
2018-01-12 16:16:26 +02:00
|
|
|
update.MailboxStatus = imap.NewMailboxStatus(mbox.name, []imap.StatusItem{imap.StatusMessages})
|
|
|
|
update.MailboxStatus.Messages = seqNum
|
2018-01-13 12:35:10 +02:00
|
|
|
eventUpdates = append(eventUpdates, update)
|
2018-01-12 16:16:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for labelID, seqNum := range deletedSeqNums {
|
|
|
|
if mbox := u.getMailboxByLabel(labelID); mbox != nil {
|
|
|
|
update := new(imapbackend.ExpungeUpdate)
|
2018-01-14 12:21:34 +02:00
|
|
|
update.Update = imapbackend.NewUpdate(u.u.Name, mbox.name)
|
2018-01-12 16:16:26 +02:00
|
|
|
update.SeqNum = seqNum
|
2018-01-13 12:35:10 +02:00
|
|
|
eventUpdates = append(eventUpdates, update)
|
2018-01-12 16:16:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send message updates
|
|
|
|
msg, err := u.db.Message(eventMessage.ID)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("cannot handle update event for message %s: cannot get updated message from local DB: %v", eventMessage.ID, err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
for _, labelID := range msg.LabelIDs {
|
|
|
|
if _, created := createdSeqNums[labelID]; created {
|
|
|
|
// This message has been added to the label's mailbox
|
|
|
|
// No need to send a message update
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if mbox := u.getMailboxByLabel(labelID); mbox != nil {
|
|
|
|
seqNum, _, err := mbox.db.FromApiID(eventMessage.ID)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("cannot handle update event for message %s: cannot get message sequence number in %s: %v", eventMessage.ID, mbox.name, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
update := new(imapbackend.MessageUpdate)
|
2018-01-14 12:21:34 +02:00
|
|
|
update.Update = imapbackend.NewUpdate(u.u.Name, mbox.name)
|
2018-01-12 16:16:26 +02:00
|
|
|
update.Message = imap.NewMessage(seqNum, []imap.FetchItem{imap.FetchFlags})
|
2020-02-29 12:28:04 +02:00
|
|
|
update.Message.Flags = mbox.fetchFlags(msg)
|
2018-01-13 12:35:10 +02:00
|
|
|
eventUpdates = append(eventUpdates, update)
|
2018-01-12 16:16:26 +02:00
|
|
|
}
|
|
|
|
}
|
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-12 16:16:26 +02:00
|
|
|
seqNums, err := u.db.DeleteMessage(eventMessage.ID)
|
|
|
|
if err != nil {
|
2018-01-11 15:40:05 +02:00
|
|
|
log.Printf("cannot handle delete event for message %s: cannot delete message from local DB: %v", eventMessage.ID, err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2018-01-12 16:16:26 +02:00
|
|
|
for labelID, seqNum := range seqNums {
|
|
|
|
if mbox := u.getMailboxByLabel(labelID); mbox != nil {
|
|
|
|
update := new(imapbackend.ExpungeUpdate)
|
2018-01-14 12:21:34 +02:00
|
|
|
update.Update = imapbackend.NewUpdate(u.u.Name, mbox.name)
|
2018-01-12 16:16:26 +02:00
|
|
|
update.SeqNum = seqNum
|
2018-01-13 12:35:10 +02:00
|
|
|
eventUpdates = append(eventUpdates, update)
|
2018-01-12 16:16:26 +02:00
|
|
|
}
|
|
|
|
}
|
2018-01-11 15:40:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Lock()
|
2018-01-11 15:40:05 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2020-02-29 12:59:15 +02:00
|
|
|
u.Unlock()
|
2018-01-11 13:39:32 +02:00
|
|
|
}
|
2018-01-13 12:35:10 +02:00
|
|
|
|
|
|
|
for _, update := range eventUpdates {
|
|
|
|
updates <- update
|
|
|
|
}
|
|
|
|
go func() {
|
2018-01-14 12:21:34 +02:00
|
|
|
for _, update := range eventUpdates {
|
|
|
|
<-update.Done()
|
|
|
|
}
|
|
|
|
|
2018-01-13 12:35:10 +02:00
|
|
|
select {
|
|
|
|
case u.eventSent <- struct{}{}:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}()
|
2018-01-11 13:39:32 +02:00
|
|
|
}
|
|
|
|
}
|