forked from Silverfish/proton-bridge
Import/Export backend prep
This commit is contained in:
@ -43,7 +43,7 @@ func (c *appleMail) Name() string {
|
||||
return "Apple Mail"
|
||||
}
|
||||
|
||||
func (c *appleMail) Configure(imapPort, smtpPort int, imapSSL, smtpSSL bool, user types.BridgeUser, addressIndex int) error { //nolint[funlen]
|
||||
func (c *appleMail) Configure(imapPort, smtpPort int, imapSSL, smtpSSL bool, user types.User, addressIndex int) error { //nolint[funlen]
|
||||
var addresses string
|
||||
var displayName string
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ import "github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||
|
||||
type AutoConfig interface {
|
||||
Name() string
|
||||
Configure(imapPort int, smtpPort int, imapSSl, smtpSSL bool, user types.BridgeUser, addressIndex int) error
|
||||
Configure(imapPort int, smtpPort int, imapSSl, smtpSSL bool, user types.User, addressIndex int) error
|
||||
}
|
||||
|
||||
var available []AutoConfig //nolint[gochecknoglobals]
|
||||
|
||||
100
internal/frontend/cli-ie/account_utils.go
Normal file
100
internal/frontend/cli-ie/account_utils.go
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail 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.
|
||||
//
|
||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||
"github.com/abiosoft/ishell"
|
||||
)
|
||||
|
||||
// completeUsernames is a helper to complete usernames as the user types.
|
||||
func (f *frontendCLI) completeUsernames(args []string) (usernames []string) {
|
||||
if len(args) > 1 {
|
||||
return
|
||||
}
|
||||
arg := ""
|
||||
if len(args) == 1 {
|
||||
arg = args[0]
|
||||
}
|
||||
for _, user := range f.ie.GetUsers() {
|
||||
if strings.HasPrefix(strings.ToLower(user.Username()), strings.ToLower(arg)) {
|
||||
usernames = append(usernames, user.Username())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// noAccountWrapper is a decorator for functions which need any account to be properly functional.
|
||||
func (f *frontendCLI) noAccountWrapper(callback func(*ishell.Context)) func(*ishell.Context) {
|
||||
return func(c *ishell.Context) {
|
||||
users := f.ie.GetUsers()
|
||||
if len(users) == 0 {
|
||||
f.Println("No active accounts. Please add account to continue.")
|
||||
} else {
|
||||
callback(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) askUserByIndexOrName(c *ishell.Context) types.User {
|
||||
user := f.getUserByIndexOrName("")
|
||||
if user != nil {
|
||||
return user
|
||||
}
|
||||
|
||||
numberOfAccounts := len(f.ie.GetUsers())
|
||||
indexRange := fmt.Sprintf("number between 0 and %d", numberOfAccounts-1)
|
||||
if len(c.Args) == 0 {
|
||||
f.Printf("Please choose %s or username.\n", indexRange)
|
||||
return nil
|
||||
}
|
||||
arg := c.Args[0]
|
||||
user = f.getUserByIndexOrName(arg)
|
||||
if user == nil {
|
||||
f.Printf("Wrong input '%s'. Choose %s or username.\n", bold(arg), indexRange)
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func (f *frontendCLI) getUserByIndexOrName(arg string) types.User {
|
||||
users := f.ie.GetUsers()
|
||||
numberOfAccounts := len(users)
|
||||
if numberOfAccounts == 0 {
|
||||
return nil
|
||||
}
|
||||
if numberOfAccounts == 1 {
|
||||
return users[0]
|
||||
}
|
||||
if index, err := strconv.Atoi(arg); err == nil {
|
||||
if index < 0 || index >= numberOfAccounts {
|
||||
return nil
|
||||
}
|
||||
return users[index]
|
||||
}
|
||||
for _, user := range users {
|
||||
if user.Username() == arg {
|
||||
return user
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
153
internal/frontend/cli-ie/accounts.go
Normal file
153
internal/frontend/cli-ie/accounts.go
Normal file
@ -0,0 +1,153 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail 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.
|
||||
//
|
||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/abiosoft/ishell"
|
||||
)
|
||||
|
||||
func (f *frontendCLI) listAccounts(c *ishell.Context) {
|
||||
spacing := "%-2d: %-20s (%-15s, %-15s)\n"
|
||||
f.Printf(bold(strings.Replace(spacing, "d", "s", -1)), "#", "account", "status", "address mode")
|
||||
for idx, user := range f.ie.GetUsers() {
|
||||
connected := "disconnected"
|
||||
if user.IsConnected() {
|
||||
connected = "connected"
|
||||
}
|
||||
mode := "split"
|
||||
if user.IsCombinedAddressMode() {
|
||||
mode = "combined"
|
||||
}
|
||||
f.Printf(spacing, idx, user.Username(), connected, mode)
|
||||
}
|
||||
f.Println()
|
||||
}
|
||||
|
||||
func (f *frontendCLI) loginAccount(c *ishell.Context) { // nolint[funlen]
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
loginName := ""
|
||||
if len(c.Args) > 0 {
|
||||
user := f.getUserByIndexOrName(c.Args[0])
|
||||
if user != nil {
|
||||
loginName = user.GetPrimaryAddress()
|
||||
}
|
||||
}
|
||||
|
||||
if loginName == "" {
|
||||
loginName = f.readStringInAttempts("Username", c.ReadLine, isNotEmpty)
|
||||
if loginName == "" {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
f.Println("Username:", loginName)
|
||||
}
|
||||
|
||||
password := f.readStringInAttempts("Password", c.ReadPassword, isNotEmpty)
|
||||
if password == "" {
|
||||
return
|
||||
}
|
||||
|
||||
f.Println("Authenticating ... ")
|
||||
client, auth, err := f.ie.Login(loginName, password)
|
||||
if err != nil {
|
||||
f.processAPIError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if auth.HasTwoFactor() {
|
||||
twoFactor := f.readStringInAttempts("Two factor code", c.ReadLine, isNotEmpty)
|
||||
if twoFactor == "" {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = client.Auth2FA(twoFactor, auth)
|
||||
if err != nil {
|
||||
f.processAPIError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
mailboxPassword := password
|
||||
if auth.HasMailboxPassword() {
|
||||
mailboxPassword = f.readStringInAttempts("Mailbox password", c.ReadPassword, isNotEmpty)
|
||||
}
|
||||
if mailboxPassword == "" {
|
||||
return
|
||||
}
|
||||
|
||||
f.Println("Adding account ...")
|
||||
user, err := f.ie.FinishLogin(client, auth, mailboxPassword)
|
||||
if err != nil {
|
||||
log.WithField("username", loginName).WithError(err).Error("Login was unsuccessful")
|
||||
f.Println("Adding account was unsuccessful:", err)
|
||||
return
|
||||
}
|
||||
|
||||
f.Printf("Account %s was added successfully.\n", bold(user.Username()))
|
||||
}
|
||||
|
||||
func (f *frontendCLI) logoutAccount(c *ishell.Context) {
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
user := f.askUserByIndexOrName(c)
|
||||
if user == nil {
|
||||
return
|
||||
}
|
||||
if f.yesNoQuestion("Are you sure you want to logout account " + bold(user.Username())) {
|
||||
if err := user.Logout(); err != nil {
|
||||
f.printAndLogError("Logging out failed: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) deleteAccount(c *ishell.Context) {
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
user := f.askUserByIndexOrName(c)
|
||||
if user == nil {
|
||||
return
|
||||
}
|
||||
if f.yesNoQuestion("Are you sure you want to " + bold("remove account "+user.Username())) {
|
||||
clearCache := f.yesNoQuestion("Do you want to remove cache for this account")
|
||||
if err := f.ie.DeleteUser(user.ID(), clearCache); err != nil {
|
||||
f.printAndLogError("Cannot delete account: ", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) deleteAccounts(c *ishell.Context) {
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
if !f.yesNoQuestion("Do you really want remove all accounts") {
|
||||
return
|
||||
}
|
||||
for _, user := range f.ie.GetUsers() {
|
||||
if err := f.ie.DeleteUser(user.ID(), false); err != nil {
|
||||
f.printAndLogError("Cannot delete account ", user.Username(), ": ", err)
|
||||
}
|
||||
}
|
||||
c.Println("Keychain cleared")
|
||||
}
|
||||
233
internal/frontend/cli-ie/frontend.go
Normal file
233
internal/frontend/cli-ie/frontend.go
Normal file
@ -0,0 +1,233 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail 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.
|
||||
//
|
||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// Package cli provides CLI interface of the Bridge.
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/ProtonMail/proton-bridge/internal/events"
|
||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/config"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||
|
||||
"github.com/abiosoft/ishell"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
log = logrus.WithField("pkg", "frontend/cli-ie") //nolint[gochecknoglobals]
|
||||
)
|
||||
|
||||
type frontendCLI struct {
|
||||
*ishell.Shell
|
||||
|
||||
config *config.Config
|
||||
eventListener listener.Listener
|
||||
updates types.Updater
|
||||
ie types.ImportExporter
|
||||
|
||||
appRestart bool
|
||||
}
|
||||
|
||||
// New returns a new CLI frontend configured with the given options.
|
||||
func New( //nolint[funlen]
|
||||
panicHandler types.PanicHandler,
|
||||
config *config.Config,
|
||||
eventListener listener.Listener,
|
||||
updates types.Updater,
|
||||
ie types.ImportExporter,
|
||||
) *frontendCLI { //nolint[golint]
|
||||
fe := &frontendCLI{
|
||||
Shell: ishell.New(),
|
||||
|
||||
config: config,
|
||||
eventListener: eventListener,
|
||||
updates: updates,
|
||||
ie: ie,
|
||||
|
||||
appRestart: false,
|
||||
}
|
||||
|
||||
// Clear commands.
|
||||
clearCmd := &ishell.Cmd{Name: "clear",
|
||||
Help: "remove stored accounts and preferences. (alias: cl)",
|
||||
Aliases: []string{"cl"},
|
||||
}
|
||||
clearCmd.AddCmd(&ishell.Cmd{Name: "accounts",
|
||||
Help: "remove all accounts from keychain. (aliases: k, keychain)",
|
||||
Aliases: []string{"a", "k", "keychain"},
|
||||
Func: fe.deleteAccounts,
|
||||
})
|
||||
fe.AddCmd(clearCmd)
|
||||
|
||||
// Check commands.
|
||||
checkCmd := &ishell.Cmd{Name: "check", Help: "check internet connection or new version."}
|
||||
checkCmd.AddCmd(&ishell.Cmd{Name: "updates",
|
||||
Help: "check for Import/Export updates. (aliases: u, v, version)",
|
||||
Aliases: []string{"u", "version", "v"},
|
||||
Func: fe.checkUpdates,
|
||||
})
|
||||
checkCmd.AddCmd(&ishell.Cmd{Name: "internet",
|
||||
Help: "check internet connection. (aliases: i, conn, connection)",
|
||||
Aliases: []string{"i", "con", "connection"},
|
||||
Func: fe.checkInternetConnection,
|
||||
})
|
||||
fe.AddCmd(checkCmd)
|
||||
|
||||
// Print info commands.
|
||||
fe.AddCmd(&ishell.Cmd{Name: "log-dir",
|
||||
Help: "print path to directory with logs. (aliases: log, logs)",
|
||||
Aliases: []string{"log", "logs"},
|
||||
Func: fe.printLogDir,
|
||||
})
|
||||
fe.AddCmd(&ishell.Cmd{Name: "manual",
|
||||
Help: "print URL with instructions. (alias: man)",
|
||||
Aliases: []string{"man"},
|
||||
Func: fe.printManual,
|
||||
})
|
||||
fe.AddCmd(&ishell.Cmd{Name: "release-notes",
|
||||
Help: "print release notes. (aliases: notes, fixed-bugs, bugs, ver, version)",
|
||||
Aliases: []string{"notes", "fixed-bugs", "bugs", "ver", "version"},
|
||||
Func: fe.printLocalReleaseNotes,
|
||||
})
|
||||
fe.AddCmd(&ishell.Cmd{Name: "credits",
|
||||
Help: "print used resources.",
|
||||
Func: fe.printCredits,
|
||||
})
|
||||
|
||||
// Account commands.
|
||||
fe.AddCmd(&ishell.Cmd{Name: "list",
|
||||
Help: "print the list of accounts. (aliases: l, ls)",
|
||||
Func: fe.noAccountWrapper(fe.listAccounts),
|
||||
Aliases: []string{"l", "ls"},
|
||||
})
|
||||
fe.AddCmd(&ishell.Cmd{Name: "login",
|
||||
Help: "login procedure to add or connect account. Optionally use index or account as parameter. (aliases: a, add, con, connect)",
|
||||
Func: fe.loginAccount,
|
||||
Aliases: []string{"add", "a", "con", "connect"},
|
||||
Completer: fe.completeUsernames,
|
||||
})
|
||||
fe.AddCmd(&ishell.Cmd{Name: "logout",
|
||||
Help: "disconnect the account. Use index or account name as parameter. (aliases: d, disconnect)",
|
||||
Func: fe.noAccountWrapper(fe.logoutAccount),
|
||||
Aliases: []string{"d", "disconnect"},
|
||||
Completer: fe.completeUsernames,
|
||||
})
|
||||
fe.AddCmd(&ishell.Cmd{Name: "delete",
|
||||
Help: "remove the account from keychain. Use index or account name as parameter. (aliases: del, rm, remove)",
|
||||
Func: fe.noAccountWrapper(fe.deleteAccount),
|
||||
Aliases: []string{"del", "rm", "remove"},
|
||||
Completer: fe.completeUsernames,
|
||||
})
|
||||
|
||||
// Import/Export commands.
|
||||
importCmd := &ishell.Cmd{Name: "import",
|
||||
Help: "import messages. (alias: imp)",
|
||||
Aliases: []string{"imp"},
|
||||
}
|
||||
importCmd.AddCmd(&ishell.Cmd{Name: "local",
|
||||
Help: "import local messages. (aliases: loc)",
|
||||
Func: fe.noAccountWrapper(fe.importLocalMessages),
|
||||
Aliases: []string{"loc"},
|
||||
})
|
||||
importCmd.AddCmd(&ishell.Cmd{Name: "remote",
|
||||
Help: "import remote messages. (aliases: rem)",
|
||||
Func: fe.noAccountWrapper(fe.importRemoteMessages),
|
||||
Aliases: []string{"rem"},
|
||||
})
|
||||
fe.AddCmd(importCmd)
|
||||
|
||||
exportCmd := &ishell.Cmd{Name: "export",
|
||||
Help: "export messages. (alias: exp)",
|
||||
Aliases: []string{"exp"},
|
||||
}
|
||||
exportCmd.AddCmd(&ishell.Cmd{Name: "eml",
|
||||
Help: "export messages to eml files.",
|
||||
Func: fe.noAccountWrapper(fe.exportMessagesToEML),
|
||||
})
|
||||
exportCmd.AddCmd(&ishell.Cmd{Name: "mbox",
|
||||
Help: "export messages to mbox files.",
|
||||
Func: fe.noAccountWrapper(fe.exportMessagesToMBOX),
|
||||
})
|
||||
fe.AddCmd(exportCmd)
|
||||
|
||||
// System commands.
|
||||
fe.AddCmd(&ishell.Cmd{Name: "restart",
|
||||
Help: "restart the import/export.",
|
||||
Func: fe.restart,
|
||||
})
|
||||
|
||||
go func() {
|
||||
defer panicHandler.HandlePanic()
|
||||
fe.watchEvents()
|
||||
}()
|
||||
fe.eventListener.RetryEmit(events.TLSCertIssue)
|
||||
fe.eventListener.RetryEmit(events.ErrorEvent)
|
||||
return fe
|
||||
}
|
||||
|
||||
func (f *frontendCLI) watchEvents() {
|
||||
errorCh := f.getEventChannel(events.ErrorEvent)
|
||||
internetOffCh := f.getEventChannel(events.InternetOffEvent)
|
||||
internetOnCh := f.getEventChannel(events.InternetOnEvent)
|
||||
addressChangedLogoutCh := f.getEventChannel(events.AddressChangedLogoutEvent)
|
||||
logoutCh := f.getEventChannel(events.LogoutEvent)
|
||||
certIssue := f.getEventChannel(events.TLSCertIssue)
|
||||
for {
|
||||
select {
|
||||
case errorDetails := <-errorCh:
|
||||
f.Println("Import/Export failed:", errorDetails)
|
||||
case <-internetOffCh:
|
||||
f.notifyInternetOff()
|
||||
case <-internetOnCh:
|
||||
f.notifyInternetOn()
|
||||
case address := <-addressChangedLogoutCh:
|
||||
f.notifyLogout(address)
|
||||
case userID := <-logoutCh:
|
||||
user, err := f.ie.GetUser(userID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
f.notifyLogout(user.Username())
|
||||
case <-certIssue:
|
||||
f.notifyCertIssue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) getEventChannel(event string) <-chan string {
|
||||
ch := make(chan string)
|
||||
f.eventListener.Add(event, ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
// IsAppRestarting returns whether the app is currently set to restart.
|
||||
func (f *frontendCLI) IsAppRestarting() bool {
|
||||
return f.appRestart
|
||||
}
|
||||
|
||||
// Loop starts the frontend loop with an interactive shell.
|
||||
func (f *frontendCLI) Loop(credentialsError error) error {
|
||||
if credentialsError != nil {
|
||||
f.notifyCredentialsError()
|
||||
return credentialsError
|
||||
}
|
||||
|
||||
f.Print(`Welcome to ProtonMail Import/Export interactive shell`)
|
||||
f.Run()
|
||||
return nil
|
||||
}
|
||||
222
internal/frontend/cli-ie/importexport.go
Normal file
222
internal/frontend/cli-ie/importexport.go
Normal file
@ -0,0 +1,222 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail 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.
|
||||
//
|
||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||
"github.com/ProtonMail/proton-bridge/internal/transfer"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
"github.com/abiosoft/ishell"
|
||||
)
|
||||
|
||||
func (f *frontendCLI) importLocalMessages(c *ishell.Context) {
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
user, path := f.getUserAndPath(c, false)
|
||||
if user == nil || path == "" {
|
||||
return
|
||||
}
|
||||
|
||||
t, err := f.ie.GetLocalImporter(user.GetPrimaryAddress(), path)
|
||||
f.transfer(t, err, false, true)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) importRemoteMessages(c *ishell.Context) {
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
user := f.askUserByIndexOrName(c)
|
||||
if user == nil {
|
||||
return
|
||||
}
|
||||
|
||||
username := f.readStringInAttempts("IMAP username", c.ReadLine, isNotEmpty)
|
||||
if username == "" {
|
||||
return
|
||||
}
|
||||
password := f.readStringInAttempts("IMAP password", c.ReadPassword, isNotEmpty)
|
||||
if password == "" {
|
||||
return
|
||||
}
|
||||
host := f.readStringInAttempts("IMAP host", c.ReadLine, isNotEmpty)
|
||||
if host == "" {
|
||||
return
|
||||
}
|
||||
port := f.readStringInAttempts("IMAP port", c.ReadLine, isNotEmpty)
|
||||
if port == "" {
|
||||
return
|
||||
}
|
||||
|
||||
t, err := f.ie.GetRemoteImporter(user.GetPrimaryAddress(), username, password, host, port)
|
||||
f.transfer(t, err, false, true)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) exportMessagesToEML(c *ishell.Context) {
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
user, path := f.getUserAndPath(c, true)
|
||||
if user == nil || path == "" {
|
||||
return
|
||||
}
|
||||
|
||||
t, err := f.ie.GetEMLExporter(user.GetPrimaryAddress(), path)
|
||||
f.transfer(t, err, true, false)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) exportMessagesToMBOX(c *ishell.Context) {
|
||||
f.ShowPrompt(false)
|
||||
defer f.ShowPrompt(true)
|
||||
|
||||
user, path := f.getUserAndPath(c, true)
|
||||
if user == nil || path == "" {
|
||||
return
|
||||
}
|
||||
|
||||
t, err := f.ie.GetMBOXExporter(user.GetPrimaryAddress(), path)
|
||||
f.transfer(t, err, true, false)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) getUserAndPath(c *ishell.Context, createPath bool) (types.User, string) {
|
||||
user := f.askUserByIndexOrName(c)
|
||||
if user == nil {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
path := f.readStringInAttempts("Path of EML and MBOX files", c.ReadLine, isNotEmpty)
|
||||
if path == "" {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
if createPath {
|
||||
_ = os.Mkdir(path, os.ModePerm)
|
||||
}
|
||||
|
||||
return user, path
|
||||
}
|
||||
|
||||
func (f *frontendCLI) transfer(t *transfer.Transfer, err error, askSkipEncrypted bool, askGlobalMailbox bool) {
|
||||
if err != nil {
|
||||
f.printAndLogError("Failed to init transferrer: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if askSkipEncrypted {
|
||||
skipEncryptedMessages := f.yesNoQuestion("Skip encrypted messages")
|
||||
t.SetSkipEncryptedMessages(skipEncryptedMessages)
|
||||
}
|
||||
|
||||
if !f.setTransferRules(t) {
|
||||
return
|
||||
}
|
||||
|
||||
if askGlobalMailbox {
|
||||
if err := f.setTransferGlobalMailbox(t); err != nil {
|
||||
f.printAndLogError("Failed to create global mailbox: ", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
progress := t.Start()
|
||||
for range progress.GetUpdateChannel() {
|
||||
f.printTransferProgress(progress)
|
||||
}
|
||||
f.printTransferResult(progress)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) setTransferGlobalMailbox(t *transfer.Transfer) error {
|
||||
labelName := fmt.Sprintf("Imported %s", time.Now().Format("Jan-02-2006 15:04"))
|
||||
|
||||
useGlobalLabel := f.yesNoQuestion("Use global label " + labelName)
|
||||
if !useGlobalLabel {
|
||||
return nil
|
||||
}
|
||||
|
||||
globalMailbox, err := t.CreateTargetMailbox(transfer.Mailbox{
|
||||
Name: labelName,
|
||||
Color: pmapi.LabelColors[0],
|
||||
IsExclusive: false,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.SetGlobalMailbox(&globalMailbox)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *frontendCLI) setTransferRules(t *transfer.Transfer) bool {
|
||||
f.Println("Rules:")
|
||||
for _, rule := range t.GetRules() {
|
||||
if !rule.Active {
|
||||
continue
|
||||
}
|
||||
targets := strings.Join(rule.TargetMailboxNames(), ", ")
|
||||
if rule.HasTimeLimit() {
|
||||
f.Printf(" %-30s → %s (%s - %s)\n", rule.SourceMailbox.Name, targets, rule.FromDate(), rule.ToDate())
|
||||
} else {
|
||||
f.Printf(" %-30s → %s\n", rule.SourceMailbox.Name, targets)
|
||||
}
|
||||
}
|
||||
|
||||
return f.yesNoQuestion("Proceed")
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printTransferProgress(progress *transfer.Progress) {
|
||||
failed, imported, exported, added, total := progress.GetCounts()
|
||||
f.Println(fmt.Sprintf("Progress update: %d (%d / %d) / %d, failed: %d", imported, exported, added, total, failed))
|
||||
|
||||
if progress.IsPaused() {
|
||||
f.Printf("Transfer is paused bacause %s", progress.PauseReason())
|
||||
if !f.yesNoQuestion("Continue (y) or stop (n)") {
|
||||
progress.Stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printTransferResult(progress *transfer.Progress) {
|
||||
err := progress.GetFatalError()
|
||||
if err != nil {
|
||||
f.Println("Transfer failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
statuses := progress.GetFailedMessages()
|
||||
if len(statuses) == 0 {
|
||||
f.Println("Transfer finished!")
|
||||
return
|
||||
}
|
||||
|
||||
f.Println("Transfer finished with errors:")
|
||||
for _, messageStatus := range statuses {
|
||||
f.Printf(
|
||||
" %-17s | %-30s | %-30s\n %s: %s\n",
|
||||
messageStatus.Time.Format("Jan 02 2006 15:04"),
|
||||
messageStatus.From,
|
||||
messageStatus.Subject,
|
||||
messageStatus.SourceID,
|
||||
messageStatus.GetErrorMessage(),
|
||||
)
|
||||
}
|
||||
}
|
||||
50
internal/frontend/cli-ie/system.go
Normal file
50
internal/frontend/cli-ie/system.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail 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.
|
||||
//
|
||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/abiosoft/ishell"
|
||||
)
|
||||
|
||||
var (
|
||||
currentPort = "" //nolint[gochecknoglobals]
|
||||
)
|
||||
|
||||
func (f *frontendCLI) restart(c *ishell.Context) {
|
||||
if f.yesNoQuestion("Are you sure you want to restart the Import/Export") {
|
||||
f.Println("Restarting Import/Export...")
|
||||
f.appRestart = true
|
||||
f.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) checkInternetConnection(c *ishell.Context) {
|
||||
if f.ie.CheckConnection() == nil {
|
||||
f.Println("Internet connection is available.")
|
||||
} else {
|
||||
f.Println("Can not contact the server, please check you internet connection.")
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printLogDir(c *ishell.Context) {
|
||||
f.Println("Log files are stored in\n\n ", f.config.GetLogDir())
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printManual(c *ishell.Context) {
|
||||
f.Println("More instructions about the Import/Export can be found at\n\n https://protonmail.com/support/categories/import-export/")
|
||||
}
|
||||
65
internal/frontend/cli-ie/updates.go
Normal file
65
internal/frontend/cli-ie/updates.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail 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.
|
||||
//
|
||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/internal/bridge"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/updates"
|
||||
"github.com/abiosoft/ishell"
|
||||
)
|
||||
|
||||
func (f *frontendCLI) checkUpdates(c *ishell.Context) {
|
||||
isUpToDate, latestVersionInfo, err := f.updates.CheckIsUpToDate()
|
||||
if err != nil {
|
||||
f.printAndLogError("Cannot retrieve version info: ", err)
|
||||
f.checkInternetConnection(c)
|
||||
return
|
||||
}
|
||||
if isUpToDate {
|
||||
f.Println("Your version is up to date.")
|
||||
} else {
|
||||
f.notifyNeedUpgrade()
|
||||
f.Println("")
|
||||
f.printReleaseNotes(latestVersionInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printLocalReleaseNotes(c *ishell.Context) {
|
||||
localVersion := f.updates.GetLocalVersion()
|
||||
f.printReleaseNotes(localVersion)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printReleaseNotes(versionInfo updates.VersionInfo) {
|
||||
f.Println(bold("ProtonMail Bridge "+versionInfo.Version), "\n")
|
||||
if versionInfo.ReleaseNotes != "" {
|
||||
f.Println(bold("Release Notes"))
|
||||
f.Println(versionInfo.ReleaseNotes)
|
||||
}
|
||||
if versionInfo.ReleaseFixedBugs != "" {
|
||||
f.Println(bold("Fixed bugs"))
|
||||
f.Println(versionInfo.ReleaseFixedBugs)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printCredits(c *ishell.Context) {
|
||||
for _, pkg := range strings.Split(bridge.Credits, ";") {
|
||||
f.Println(pkg)
|
||||
}
|
||||
}
|
||||
123
internal/frontend/cli-ie/utils.go
Normal file
123
internal/frontend/cli-ie/utils.go
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.
|
||||
//
|
||||
// ProtonMail 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.
|
||||
//
|
||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const (
|
||||
maxInputRepeat = 2
|
||||
)
|
||||
|
||||
var (
|
||||
bold = color.New(color.Bold).SprintFunc() //nolint[gochecknoglobals]
|
||||
)
|
||||
|
||||
func isNotEmpty(val string) bool {
|
||||
return val != ""
|
||||
}
|
||||
|
||||
func (f *frontendCLI) yesNoQuestion(question string) bool {
|
||||
f.Print(question, "? yes/"+bold("no")+": ")
|
||||
yes := "yes"
|
||||
answer := strings.ToLower(f.ReadLine())
|
||||
for i := 0; i < len(answer); i++ {
|
||||
if i >= len(yes) || answer[i] != yes[i] {
|
||||
return false // Everything else is false.
|
||||
}
|
||||
}
|
||||
return len(answer) > 0 // Empty is false.
|
||||
}
|
||||
|
||||
func (f *frontendCLI) readStringInAttempts(title string, readFunc func() string, isOK func(string) bool) (value string) {
|
||||
f.Printf("%s: ", title)
|
||||
value = readFunc()
|
||||
title = strings.ToLower(string(title[0])) + title[1:]
|
||||
for i := 0; !isOK(value); i++ {
|
||||
if i >= maxInputRepeat {
|
||||
f.Println("Too many attempts")
|
||||
return ""
|
||||
}
|
||||
f.Printf("Please fill %s: ", title)
|
||||
value = readFunc()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printAndLogError(args ...interface{}) {
|
||||
log.Error(args...)
|
||||
f.Println(args...)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) processAPIError(err error) {
|
||||
log.Warn("API error: ", err)
|
||||
switch err {
|
||||
case pmapi.ErrAPINotReachable:
|
||||
f.notifyInternetOff()
|
||||
case pmapi.ErrUpgradeApplication:
|
||||
f.notifyNeedUpgrade()
|
||||
default:
|
||||
f.Println("Server error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) notifyInternetOff() {
|
||||
f.Println("Internet connection is not available.")
|
||||
}
|
||||
|
||||
func (f *frontendCLI) notifyInternetOn() {
|
||||
f.Println("Internet connection is available again.")
|
||||
}
|
||||
|
||||
func (f *frontendCLI) notifyLogout(address string) {
|
||||
f.Printf("Account %s is disconnected. Login to continue using this account with email client.", address)
|
||||
}
|
||||
|
||||
func (f *frontendCLI) notifyNeedUpgrade() {
|
||||
f.Println("Please download and install the newest version of application from", f.updates.GetDownloadLink())
|
||||
}
|
||||
|
||||
func (f *frontendCLI) notifyCredentialsError() {
|
||||
// Print in 80-column width.
|
||||
f.Println("ProtonMail Bridge is not able to detect a supported password manager")
|
||||
f.Println("(pass, gnome-keyring). Please install and set up a supported password manager")
|
||||
f.Println("and restart the application.")
|
||||
}
|
||||
|
||||
func (f *frontendCLI) notifyCertIssue() {
|
||||
// Print in 80-column width.
|
||||
f.Println(`Connection security error: Your network connection to Proton services may
|
||||
be insecure.
|
||||
|
||||
Description:
|
||||
ProtonMail Bridge was not able to establish a secure connection to Proton
|
||||
servers due to a TLS certificate error. This means your connection may
|
||||
potentially be insecure and susceptible to monitoring by third parties.
|
||||
|
||||
Recommendation:
|
||||
* If you trust your network operator, you can continue to use ProtonMail
|
||||
as usual.
|
||||
* If you don't trust your network operator, reconnect to ProtonMail over a VPN
|
||||
(such as ProtonVPN) which encrypts your Internet connection, or use
|
||||
a different network to access ProtonMail.
|
||||
`)
|
||||
}
|
||||
@ -55,7 +55,7 @@ func (f *frontendCLI) noAccountWrapper(callback func(*ishell.Context)) func(*ish
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) askUserByIndexOrName(c *ishell.Context) types.BridgeUser {
|
||||
func (f *frontendCLI) askUserByIndexOrName(c *ishell.Context) types.User {
|
||||
user := f.getUserByIndexOrName("")
|
||||
if user != nil {
|
||||
return user
|
||||
@ -76,7 +76,7 @@ func (f *frontendCLI) askUserByIndexOrName(c *ishell.Context) types.BridgeUser {
|
||||
return user
|
||||
}
|
||||
|
||||
func (f *frontendCLI) getUserByIndexOrName(arg string) types.BridgeUser {
|
||||
func (f *frontendCLI) getUserByIndexOrName(arg string) types.User {
|
||||
users := f.bridge.GetUsers()
|
||||
numberOfAccounts := len(users)
|
||||
if numberOfAccounts == 0 {
|
||||
|
||||
@ -63,7 +63,7 @@ func (f *frontendCLI) showAccountInfo(c *ishell.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frontendCLI) showAccountAddressInfo(user types.BridgeUser, address string) {
|
||||
func (f *frontendCLI) showAccountAddressInfo(user types.User, address string) {
|
||||
smtpSecurity := "STARTTLS"
|
||||
if f.preferences.GetBool(preferences.SMTPSSLKey) {
|
||||
smtpSecurity = "SSL"
|
||||
|
||||
@ -43,7 +43,7 @@ func (f *frontendCLI) checkInternetConnection(c *ishell.Context) {
|
||||
if f.bridge.CheckConnection() == nil {
|
||||
f.Println("Internet connection is available.")
|
||||
} else {
|
||||
f.Println("Can not contact server please check you internet connection.")
|
||||
f.Println("Can not contact the server, please check you internet connection.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ import (
|
||||
)
|
||||
|
||||
func (f *frontendCLI) checkUpdates(c *ishell.Context) {
|
||||
isUpToDate, latestVersionInfo, err := f.updates.CheckIsBridgeUpToDate()
|
||||
isUpToDate, latestVersionInfo, err := f.updates.CheckIsUpToDate()
|
||||
if err != nil {
|
||||
f.printAndLogError("Cannot retrieve version info: ", err)
|
||||
f.checkInternetConnection(c)
|
||||
@ -47,7 +47,7 @@ func (f *frontendCLI) printLocalReleaseNotes(c *ishell.Context) {
|
||||
}
|
||||
|
||||
func (f *frontendCLI) printReleaseNotes(versionInfo updates.VersionInfo) {
|
||||
f.Println(bold("ProtonMail Bridge "+versionInfo.Version), "\n")
|
||||
f.Println(bold("ProtonMail Import/Export "+versionInfo.Version), "\n")
|
||||
if versionInfo.ReleaseNotes != "" {
|
||||
f.Println(bold("Release Notes"))
|
||||
f.Println(versionInfo.ReleaseNotes)
|
||||
|
||||
@ -22,8 +22,10 @@ import (
|
||||
"github.com/0xAX/notificator"
|
||||
"github.com/ProtonMail/proton-bridge/internal/bridge"
|
||||
"github.com/ProtonMail/proton-bridge/internal/frontend/cli"
|
||||
cliie "github.com/ProtonMail/proton-bridge/internal/frontend/cli-ie"
|
||||
"github.com/ProtonMail/proton-bridge/internal/frontend/qt"
|
||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||
"github.com/ProtonMail/proton-bridge/internal/importexport"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/config"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -86,3 +88,37 @@ func new(
|
||||
return qt.New(version, buildVersion, showWindowOnStart, panicHandler, config, preferences, eventListener, updates, bridge, noEncConfirmator)
|
||||
}
|
||||
}
|
||||
|
||||
// NewImportExport returns initialized frontend based on `frontendType`, which can be `cli` or `qt`.
|
||||
func NewImportExport(
|
||||
version,
|
||||
buildVersion,
|
||||
frontendType string,
|
||||
panicHandler types.PanicHandler,
|
||||
config *config.Config,
|
||||
eventListener listener.Listener,
|
||||
updates types.Updater,
|
||||
ie *importexport.ImportExport,
|
||||
) Frontend {
|
||||
ieWrap := types.NewImportExportWrap(ie)
|
||||
return newImportExport(version, buildVersion, frontendType, panicHandler, config, eventListener, updates, ieWrap)
|
||||
}
|
||||
|
||||
func newImportExport(
|
||||
version,
|
||||
buildVersion,
|
||||
frontendType string,
|
||||
panicHandler types.PanicHandler,
|
||||
config *config.Config,
|
||||
eventListener listener.Listener,
|
||||
updates types.Updater,
|
||||
ie types.ImportExporter,
|
||||
) Frontend {
|
||||
switch frontendType {
|
||||
case "cli":
|
||||
return cliie.New(panicHandler, config, eventListener, updates, ie)
|
||||
default:
|
||||
return cliie.New(panicHandler, config, eventListener, updates, ie)
|
||||
//return qt.New(panicHandler, config, eventListener, updates, ie)
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,7 +410,7 @@ func (s *FrontendQt) isNewVersionAvailable(showMessage bool) {
|
||||
go func() {
|
||||
defer s.panicHandler.HandlePanic()
|
||||
defer s.Qml.ProcessFinished()
|
||||
isUpToDate, latestVersionInfo, err := s.updates.CheckIsBridgeUpToDate()
|
||||
isUpToDate, latestVersionInfo, err := s.updates.CheckIsUpToDate()
|
||||
if err != nil {
|
||||
log.Warn("Can not retrieve version info: ", err)
|
||||
s.checkInternet()
|
||||
|
||||
@ -20,6 +20,8 @@ package types
|
||||
|
||||
import (
|
||||
"github.com/ProtonMail/proton-bridge/internal/bridge"
|
||||
"github.com/ProtonMail/proton-bridge/internal/importexport"
|
||||
"github.com/ProtonMail/proton-bridge/internal/transfer"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/updates"
|
||||
)
|
||||
@ -31,7 +33,7 @@ type PanicHandler interface {
|
||||
|
||||
// Updater is an interface for handling Bridge upgrades.
|
||||
type Updater interface {
|
||||
CheckIsBridgeUpToDate() (isUpToDate bool, latestVersion updates.VersionInfo, err error)
|
||||
CheckIsUpToDate() (isUpToDate bool, latestVersion updates.VersionInfo, err error)
|
||||
GetDownloadLink() string
|
||||
GetLocalVersion() updates.VersionInfo
|
||||
StartUpgrade(currentStatus chan<- updates.Progress)
|
||||
@ -41,24 +43,19 @@ type NoEncConfirmator interface {
|
||||
ConfirmNoEncryption(string, bool)
|
||||
}
|
||||
|
||||
// Bridger is an interface of bridge needed by frontend.
|
||||
type Bridger interface {
|
||||
GetCurrentClient() string
|
||||
SetCurrentOS(os string)
|
||||
// UserManager is an interface of users needed by frontend.
|
||||
type UserManager interface {
|
||||
Login(username, password string) (pmapi.Client, *pmapi.Auth, error)
|
||||
FinishLogin(client pmapi.Client, auth *pmapi.Auth, mailboxPassword string) (BridgeUser, error)
|
||||
GetUsers() []BridgeUser
|
||||
GetUser(query string) (BridgeUser, error)
|
||||
FinishLogin(client pmapi.Client, auth *pmapi.Auth, mailboxPassword string) (User, error)
|
||||
GetUsers() []User
|
||||
GetUser(query string) (User, error)
|
||||
DeleteUser(userID string, clearCache bool) error
|
||||
ReportBug(osType, osVersion, description, accountName, address, emailClient string) error
|
||||
ClearData() error
|
||||
AllowProxy()
|
||||
DisallowProxy()
|
||||
CheckConnection() error
|
||||
}
|
||||
|
||||
// BridgeUser is an interface of user needed by frontend.
|
||||
type BridgeUser interface {
|
||||
// User is an interface of user needed by frontend.
|
||||
type User interface {
|
||||
ID() string
|
||||
Username() string
|
||||
IsConnected() bool
|
||||
@ -70,6 +67,17 @@ type BridgeUser interface {
|
||||
Logout() error
|
||||
}
|
||||
|
||||
// Bridger is an interface of bridge needed by frontend.
|
||||
type Bridger interface {
|
||||
UserManager
|
||||
|
||||
GetCurrentClient() string
|
||||
SetCurrentOS(os string)
|
||||
ReportBug(osType, osVersion, description, accountName, address, emailClient string) error
|
||||
AllowProxy()
|
||||
DisallowProxy()
|
||||
}
|
||||
|
||||
type bridgeWrap struct {
|
||||
*bridge.Bridge
|
||||
}
|
||||
@ -81,17 +89,55 @@ func NewBridgeWrap(bridge *bridge.Bridge) *bridgeWrap { //nolint[golint]
|
||||
return &bridgeWrap{Bridge: bridge}
|
||||
}
|
||||
|
||||
func (b *bridgeWrap) FinishLogin(client pmapi.Client, auth *pmapi.Auth, mailboxPassword string) (BridgeUser, error) {
|
||||
func (b *bridgeWrap) FinishLogin(client pmapi.Client, auth *pmapi.Auth, mailboxPassword string) (User, error) {
|
||||
return b.Bridge.FinishLogin(client, auth, mailboxPassword)
|
||||
}
|
||||
|
||||
func (b *bridgeWrap) GetUsers() (users []BridgeUser) {
|
||||
func (b *bridgeWrap) GetUsers() (users []User) {
|
||||
for _, user := range b.Bridge.GetUsers() {
|
||||
users = append(users, user)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bridgeWrap) GetUser(query string) (BridgeUser, error) {
|
||||
func (b *bridgeWrap) GetUser(query string) (User, error) {
|
||||
return b.Bridge.GetUser(query)
|
||||
}
|
||||
|
||||
// ImportExporter is an interface of import/export needed by frontend.
|
||||
type ImportExporter interface {
|
||||
UserManager
|
||||
|
||||
GetLocalImporter(string, string) (*transfer.Transfer, error)
|
||||
GetRemoteImporter(string, string, string, string, string) (*transfer.Transfer, error)
|
||||
GetEMLExporter(string, string) (*transfer.Transfer, error)
|
||||
GetMBOXExporter(string, string) (*transfer.Transfer, error)
|
||||
}
|
||||
|
||||
type importExportWrap struct {
|
||||
*importexport.ImportExport
|
||||
}
|
||||
|
||||
// NewImportExportWrap wraps import/export struct into local importExportWrap
|
||||
// to implement local interface.
|
||||
// The problem is that Import/Export returns the importexport package's User
|
||||
// type. Every method which returns User therefore has to be overridden to
|
||||
// fulfill the interface.
|
||||
func NewImportExportWrap(ie *importexport.ImportExport) *importExportWrap { //nolint[golint]
|
||||
return &importExportWrap{ImportExport: ie}
|
||||
}
|
||||
|
||||
func (b *importExportWrap) FinishLogin(client pmapi.Client, auth *pmapi.Auth, mailboxPassword string) (User, error) {
|
||||
return b.ImportExport.FinishLogin(client, auth, mailboxPassword)
|
||||
}
|
||||
|
||||
func (b *importExportWrap) GetUsers() (users []User) {
|
||||
for _, user := range b.ImportExport.GetUsers() {
|
||||
users = append(users, user)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *importExportWrap) GetUser(query string) (User, error) {
|
||||
return b.ImportExport.GetUser(query)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user