diff --git a/internal/app/base/base.go b/internal/app/base/base.go index 6f4296eb..7d2edd58 100644 --- a/internal/app/base/base.go +++ b/internal/app/base/base.go @@ -156,7 +156,14 @@ func New( // nolint[funlen] return nil, err } - cm := pmapi.NewClientManager(pmapi.GetAPIConfig(configName, constants.Version)) + apiConfig := pmapi.GetAPIConfig(configName, constants.Version) + apiConfig.NoConnectionHandler = func() { + eventListener.Emit(events.InternetOffEvent, "") + } + apiConfig.ConnectionHandler = func() { + eventListener.Emit(events.InternetOnEvent, "") + } + cm := pmapi.NewClientManager(apiConfig) cm.SetRoundTripper(pmapi.GetRoundTripper(cm, listener)) cm.SetCookieJar(jar) sentryReporter.SetUserAgentProvider(cm) diff --git a/internal/imap/server.go b/internal/imap/server.go index d338abf0..9001fbcd 100644 --- a/internal/imap/server.go +++ b/internal/imap/server.go @@ -47,6 +47,8 @@ type imapServer struct { eventListener listener.Listener debugClient bool debugServer bool + + on bool } // NewIMAPServer constructs a new IMAP server configured with the given options. @@ -106,6 +108,19 @@ func NewIMAPServer(debugClient, debugServer bool, port int, tls *tls.Config, ima // Starts the server. func (s *imapServer) ListenAndServe() { go s.monitorDisconnectedUsers() + go s.monitorInternetConnection() + + s.listenAndServe() +} + +func (s *imapServer) listenAndServe() { + if s.on { + return + } + s.on = true + defer func() { + s.on = false + }() log.Info("IMAP server listening at ", s.server.Addr) l, err := net.Listen("tcp", s.server.Addr) @@ -136,6 +151,24 @@ func (s *imapServer) Close() { } } +func (s *imapServer) monitorInternetConnection() { + on := make(chan string) + s.eventListener.Add(events.InternetOnEvent, on) + off := make(chan string) + s.eventListener.Add(events.InternetOffEvent, off) + + go func() { + for range on { + s.listenAndServe() + } + }() + go func() { + for range off { + s.Close() + } + }() +} + func (s *imapServer) monitorDisconnectedUsers() { ch := make(chan string) s.eventListener.Add(events.CloseConnectionEvent, ch) diff --git a/pkg/pmapi/client.go b/pkg/pmapi/client.go index 90b91a4e..506b8e3b 100644 --- a/pkg/pmapi/client.go +++ b/pkg/pmapi/client.go @@ -102,6 +102,9 @@ type ClientConfig struct { // MinBytesPerSecond specifies minimum Bytes per second or the request will be canceled. // Zero means no limitation. MinBytesPerSecond int64 + + NoConnectionHandler func() + ConnectionHandler func() } // client is a client of the protonmail API. It implements the Client interface. diff --git a/pkg/pmapi/dialer_proxy.go b/pkg/pmapi/dialer_proxy.go index 5f341a01..df25389e 100644 --- a/pkg/pmapi/dialer_proxy.go +++ b/pkg/pmapi/dialer_proxy.go @@ -37,7 +37,17 @@ func NewProxyTLSDialer(dialer TLSDialer, cm *ClientManager) *ProxyTLSDialer { } // DialTLS dials the given network/address. If it fails, it retries using a proxy. -func (d *ProxyTLSDialer) DialTLS(network, address string) (conn net.Conn, err error) { +func (d *ProxyTLSDialer) DialTLS(network, address string) (net.Conn, error) { + conn, err := d.dialTLS(network, address) + if err != nil { + d.cm.config.NoConnectionHandler() + } else { + d.cm.config.ConnectionHandler() + } + return conn, err +} + +func (d *ProxyTLSDialer) dialTLS(network, address string) (conn net.Conn, err error) { if conn, err = d.dialer.DialTLS(network, address); err == nil { return }