Files
proton-bridge/internal/services/imapservice/service_address_events.go
2024-01-02 15:06:05 +01:00

197 lines
5.3 KiB
Go

// Copyright (c) 2024 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 <https://www.gnu.org/licenses/>.
package imapservice
import (
"context"
"fmt"
"github.com/ProtonMail/go-proton-api"
"github.com/ProtonMail/proton-bridge/v3/internal/services/useridentity"
"github.com/ProtonMail/proton-bridge/v3/internal/usertypes"
"github.com/sirupsen/logrus"
)
func (s *Service) HandleAddressEvents(ctx context.Context, events []proton.AddressEvent) error {
s.log.Debug("handling address event")
if s.addressMode == usertypes.AddressModeCombined {
oldPrimaryAddr, err := s.identityState.GetPrimaryAddress()
if err != nil {
return fmt.Errorf("failed to get primary addr: %w", err)
}
if err := s.identityState.Write(func(identity *useridentity.State) error {
identity.OnAddressEvents(events)
return nil
}); err != nil {
s.log.WithError(err).Error("Failed to apply address events to identity state")
return err
}
newPrimaryAddr, err := s.identityState.GetPrimaryAddress()
if err != nil {
return fmt.Errorf("failed to get primary addr after update: %w", err)
}
if oldPrimaryAddr.ID == newPrimaryAddr.ID {
return nil
}
connector, ok := s.connectors[oldPrimaryAddr.ID]
if !ok {
return fmt.Errorf("could not find old primary addr conncetor after default address change")
}
s.connectors[newPrimaryAddr.ID] = connector
delete(s.connectors, oldPrimaryAddr.ID)
s.log.WithFields(logrus.Fields{
"old": oldPrimaryAddr.Email,
"new": newPrimaryAddr.Email,
}).Debug("Primary address changed")
return nil
}
for _, event := range events {
switch event.Action {
case proton.EventCreate:
var status useridentity.AddressUpdate
if err := s.identityState.Write(func(identity *useridentity.State) error {
status = identity.OnAddressCreated(event)
return nil
}); err != nil {
return fmt.Errorf("failed to update identity state: %w", err)
}
if status == useridentity.AddressUpdateCreated {
if err := addNewAddressSplitMode(ctx, s, event.Address.ID); err != nil {
return err
}
}
case proton.EventUpdateFlags, proton.EventUpdate:
var addr proton.Address
var status useridentity.AddressUpdate
if err := s.identityState.Write(func(identity *useridentity.State) error {
addr, status = identity.OnAddressUpdated(event)
return nil
}); err != nil {
return fmt.Errorf("failed to update identity state: %w", err)
}
// nolint:exhaustive
switch status {
case useridentity.AddressUpdateCreated:
if err := addNewAddressSplitMode(ctx, s, addr.ID); err != nil {
return err
}
case useridentity.AddressUpdateDisabled:
if err := removeAddressSplitMode(ctx, s, addr.ID); err != nil {
return err
}
case useridentity.AddressUpdateEnabled:
if err := addNewAddressSplitMode(ctx, s, addr.ID); err != nil {
return err
}
default:
continue
}
case proton.EventDelete:
var status useridentity.AddressUpdate
if err := s.identityState.Write(func(identity *useridentity.State) error {
_, status = identity.OnAddressDeleted(event)
return nil
}); err != nil {
return fmt.Errorf("failed to update identity state: %w", err)
}
if status == useridentity.AddressUpdateDeleted {
if err := removeAddressSplitMode(ctx, s, event.ID); err != nil {
return err
}
}
default:
return fmt.Errorf("unknown event action: %v", event.Action)
}
}
return nil
}
func addNewAddressSplitMode(ctx context.Context, s *Service, addrID string) error {
connector := NewConnector(
addrID,
s.client,
s.labels,
s.identityState,
s.addressMode,
s.sendRecorder,
s.panicHandler,
s.telemetry,
s.showAllMail,
s.syncStateProvider,
)
if err := s.serverManager.AddIMAPUser(ctx, connector, connector.addrID, s.gluonIDProvider, s.syncStateProvider); err != nil {
return fmt.Errorf("failed to add new account to server: %w", err)
}
s.connectors[connector.addrID] = connector
updates, err := syncLabels(ctx, s.labels.GetLabelMap(), []*Connector{connector})
if err != nil {
return fmt.Errorf("failed to create labels updates for new address: %w", err)
}
if err := waitOnIMAPUpdates(ctx, updates); err != nil {
return fmt.Errorf("failed to sync labels for new address: %w", err)
}
return nil
}
func removeAddressSplitMode(ctx context.Context, s *Service, addrID string) error {
connector, ok := s.connectors[addrID]
if !ok {
s.log.Warnf("Could not find connector ")
return nil
}
if err := s.serverManager.RemoveIMAPUser(ctx, true, s.gluonIDProvider, addrID); err != nil {
return fmt.Errorf("failed to remove user from server: %w", err)
}
connector.StateClose()
delete(s.connectors, addrID)
return nil
}