pEpForiOS/UI/Settings/Setting/AccountSettings/ViewModel/AccountSettingsViewModel.swift
author Dirk Zimmermann <dz@pep.security>
Fri, 08 Mar 2019 09:27:22 +0100
branchexp_IOS-1480
changeset 7914 f3cdfb75ad41
parent 7644 1748d97a99fa
child 7999 eb9680b63e70
permissions -rw-r--r--
IOS-1480 Avoid names like MessageModel.
     1 //
     2 //  AccountSettingsViewModel.swift
     3 //  pEpForiOS
     4 //
     5 //  Created by Xavier Algarra on 13/06/2017.
     6 //  Copyright © 2017 p≡p Security S.A. All rights reserved.
     7 //
     8 
     9 import Foundation
    10 import MessageModel
    11 import pEpIOSToolbox
    12 
    13 public class AccountSettingsViewModel {
    14     public struct ServerViewModel {
    15         var address: String?
    16         var port: String?
    17         var transport: String?
    18     }
    19 
    20     public struct SecurityViewModel {
    21         var options = Server.Transport.toArray()
    22         var size : Int {
    23             get {
    24                 return options.count
    25             }
    26         }
    27 
    28         subscript(option: Int) -> String {
    29             get {
    30                 return options[option].asString()
    31             }
    32         }
    33     }
    34 
    35     private (set) var account: Account
    36     private let headers = [
    37         NSLocalizedString("Account", comment: "Account settings"),
    38         NSLocalizedString("IMAP Settings", comment: "Account settings title IMAP"),
    39         NSLocalizedString("SMTP Settings", comment: "Account settings title SMTP")
    40     ]
    41     private var controlWord = "noRealPassword"
    42 
    43     public let svm = SecurityViewModel()
    44     public let isOAuth2: Bool
    45 
    46     public init(account: Account) {
    47         // We are using a copy here. The outside world must not know changed settings until they
    48         // have been verified.
    49         self.account = Account(withDataFrom: account)
    50         isOAuth2 = account.server(with: .imap)?.authMethod == AuthMethod.saslXoauth2.rawValue
    51     }
    52 
    53     var email: String {
    54         get {
    55             return account.user.address
    56         }
    57     }
    58 
    59     var loginName: String {
    60         get {
    61             // the email model is based on the assumption that imap.loginName == smtp.loginName
    62             return account.server(with: .imap)?.credentials.loginName ?? ""
    63         }
    64     }
    65 
    66     var name: String {
    67         get {
    68             return account.user.userName ?? ""
    69         }
    70     }
    71 
    72     var smtpServer: ServerViewModel {
    73         get {
    74             if let server = account.smtpServer {
    75                 return ServerViewModel(address: server.address,
    76                                        port: "\(server.port)",
    77                     transport: server.transport?.asString())
    78             }
    79             return ServerViewModel()
    80         }
    81     }
    82 
    83     var imapServer: ServerViewModel {
    84         get {
    85             if let server = account.imapServer {
    86                 return ServerViewModel(address: server.address,
    87                                        port: "\(server.port)",
    88                     transport: server.transport?.asString())
    89             }
    90             return ServerViewModel()
    91         }
    92     }
    93 
    94     var messageSyncService: MessageSyncServiceProtocol?
    95     weak var delegate: AccountVerificationResultDelegate?
    96 
    97     //Currently we assume imap and smtp servers exist already (update).
    98     // If we run into problems here modify to updateOrCreate
    99     func update(loginName: String, name: String, password: String? = nil, imap: ServerViewModel,
   100                 smtp: ServerViewModel) {
   101         guard let serverImap = account.imapServer,
   102             let serverSmtp = account.smtpServer else {
   103                 Logger.frontendLogger.errorAndCrash("Account misses imap or smtp server.")
   104                 return
   105         }
   106         let pass : String?
   107         if let p = password {
   108             pass = p
   109         } else {
   110             pass = serverImap.credentials.password
   111         }
   112         guard let editedServerImap = server(from: imap, serverType: .imap,
   113                                             loginName: loginName,
   114                                             password: pass,
   115                                             key: serverImap.credentials.key),
   116             let editedServerSmtp = server(from: smtp,
   117                                           serverType: .smtp,
   118                                           loginName: loginName,
   119                                           password: pass,
   120                                           key: serverSmtp.credentials.key)
   121             else {
   122                 Logger.frontendLogger.errorAndCrash("Invalid input.")
   123                 return
   124         }
   125 
   126         serverImap.updateValues(with: editedServerImap)
   127         serverSmtp.updateValues(with: editedServerSmtp)
   128 
   129         self.account.user.userName = name
   130 
   131         guard let ms = messageSyncService else {
   132             Logger.frontendLogger.errorAndCrash("no MessageSyncService")
   133             return
   134         }
   135         ms.requestVerification(account: account, delegate: self)
   136     }
   137 
   138     func sectionIsValid(section: Int) -> Bool {
   139         return section >= 0 && section < headers.count
   140     }
   141 
   142     var count: Int {
   143         get {
   144             return headers.count
   145         }
   146     }
   147 
   148     subscript(section: Int) -> String {
   149         get {
   150             assert(sectionIsValid(section: section), "Section out of range")
   151             return headers[section]
   152         }
   153     }
   154 
   155     private func server(from viewModel:ServerViewModel, serverType:Server.ServerType,
   156                         loginName: String, password: String?, key: String? = nil) -> Server? {
   157         guard let viewModelPort = viewModel.port,
   158             let port = UInt16(viewModelPort),
   159             let address = viewModel.address else {
   160                 Logger.frontendLogger.errorAndCrash("viewModel misses required data.")
   161                 return nil
   162         }
   163         let transport = Server.Transport(fromString: viewModel.transport)
   164 
   165         let credentials = ServerCredentials.create(loginName: loginName, key: key)
   166         if password != nil && password != "" {
   167             credentials.password = password
   168         }
   169 
   170         let server = Server.create(serverType: serverType, port: port, address: address,
   171                                    transport: transport, credentials: credentials)
   172 
   173         return server
   174     }
   175 
   176     func updateToken(accessToken: OAuth2AccessTokenProtocol) {
   177         guard let imapServer = account.imapServer,
   178             let smtpServer = account.smtpServer else {
   179                 return
   180         }
   181         let password = accessToken.persistBase64Encoded()
   182         imapServer.credentials.password = password
   183         smtpServer.credentials.password = password
   184     }
   185 }
   186 
   187 // MARK: - AccountVerificationServiceDelegate
   188 
   189 extension AccountSettingsViewModel: AccountVerificationServiceDelegate {
   190     func verified(account: Account,
   191                   service: AccountVerificationServiceProtocol,
   192                   result: AccountVerificationResult) {
   193         if result == .ok {
   194             MessageModelUtil.performAndWait {
   195                 account.save()
   196             }
   197         }
   198         GCD.onMainWait { [weak self] in
   199             guard let me = self else {
   200                 Logger.frontendLogger.lostMySelf()
   201                 return
   202             }
   203             me.delegate?.didVerify(result: result, accountInput: nil)
   204         }
   205     }
   206 }