/* * Copyright (c) 2021 Neil Alexander * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package imapserver import ( "fmt" "log" "github.com/emersion/go-imap" "github.com/emersion/go-imap/backend" "github.com/neilalexander/yggmail/internal/account" "github.com/neilalexander/yggmail/internal/config" "github.com/neilalexander/yggmail/internal/notify" nfremote "github.com/neilalexander/yggmail/internal/notify/remote" "github.com/neilalexander/yggmail/internal/storage" "github.com/neilalexander/yggmail/internal/storage/remote" "github.com/neilalexander/yggmail/internal/transport" "github.com/neilalexander/yggmail/internal/utils" ) type Backend struct { Config *config.Config Log *log.Logger Storage storage.Storage Server *IMAPServer Account *account.Manager Transport transport.Transport Notify *notify.Notify updates chan backend.Update } func NewBackend( config *config.Config, log *log.Logger, storage storage.Storage, // server *IMAPServer, account *account.Manager, transport transport.Transport, notify *notify.Notify, ) *Backend { b := &Backend{ Config: config, Log: log, Storage: storage, //Server: server, Account: account, Transport: transport, Notify: notify, updates: make(chan backend.Update, 100), } b.listenUpdates() return b } func (b *Backend) Updates() <-chan backend.Update { b.Log.Println("Updates is loaded!") return b.updates } func (b *Backend) Login(conn *imap.ConnInfo, username, password string) (backend.User, error) { // If our username is email-like, then take just the localpart dPk, _, err := utils.ParseAddress(username) if err != nil { return nil, fmt.Errorf("Failed ") } remoteDomain := !dPk.Equal(b.Config.PublicKey) session, err := b.Account.Login(username, password) if err != nil { return nil, fmt.Errorf("IMAP: Error to authenticate: %w", err) } defer b.Log.Printf("IMAP: Authenticated user from %s as %q\n", conn.RemoteAddr.String(), username) var storage storage.Storage if remoteDomain { storage = remote.NewRemoteStorage(dPk, session, b.Transport) notifer := nfremote.NewRemoteNotifer(dPk, session.Publickey(), session.Sign, b.Transport) notifer.StartRemoteNotifer(b.Notify, session.Publickey(), "INBOX") } else { storage = b.Storage } user := &User{ storage: storage, username: session.Username(), session: session, conn: conn, log: b.Log, } 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 } */