// Copyright (c) 2023 Proton AG // // This file is part of Proton Mail Bridge. // // Proton Mail Bridge is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Proton Mail Bridge is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Proton Mail Bridge. If not, see . package smtp import ( "context" "io" "sync" ) type Accounts struct { accountsLock sync.RWMutex accounts map[string]*Service } func NewAccounts() *Accounts { return &Accounts{ accounts: make(map[string]*Service), } } func (s *Accounts) AddAccount(account *Service) { s.accountsLock.Lock() defer s.accountsLock.Unlock() s.accounts[account.UserID()] = account } func (s *Accounts) RemoveAccount(account *Service) { s.accountsLock.Lock() defer s.accountsLock.Unlock() delete(s.accounts, account.UserID()) } func (s *Accounts) CheckAuth(user string, password []byte) (string, string, error) { s.accountsLock.RLock() defer s.accountsLock.RUnlock() for id, service := range s.accounts { addrID, err := service.checkAuth(context.Background(), user, password) if err != nil { continue } service.telemetry.ReportSMTPAuthSuccess(context.Background()) return id, addrID, nil } for _, service := range s.accounts { service.telemetry.ReportSMTPAuthFailed(user) } return "", "", ErrNoSuchUser } func (s *Accounts) SendMail(ctx context.Context, userID, addrID, from string, to []string, r io.Reader) error { if len(to) == 0 { return ErrInvalidRecipient } s.accountsLock.RLock() defer s.accountsLock.RUnlock() service, ok := s.accounts[userID] if !ok { return ErrNoSuchUser } return service.SendMail(ctx, addrID, from, to, r) }