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