diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 3f551769a84444ede04fd1138aca3b62b3a9fb54..4493742a874316648e46b389088a291aa4646a88 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ 4707092D2189C74200DF71A3 /* bobSecret.asc in Resources */ = {isa = PBXBuildFile; fileRef = 4707092B2189C74200DF71A3 /* bobSecret.asc */; }; 4707092E2189C74200DF71A3 /* alicePublic.asc in Resources */ = {isa = PBXBuildFile; fileRef = 4707092C2189C74200DF71A3 /* alicePublic.asc */; }; 470709302189E1C100DF71A3 /* enc+signedThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 4707092F2189E1C000DF71A3 /* enc+signedThunderbird.eml */; }; + 4709769626220659002436E2 /* SimpleMailRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4709769526220659002436E2 /* SimpleMailRowView.swift */; }; 47184C3922F0D8F200712A7A /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47184C3822F0D8F200712A7A /* CFNetwork.framework */; }; 471876F7223FACA900912135 /* BobPWTEST1234.asc in Resources */ = {isa = PBXBuildFile; fileRef = 471876F5223FACA900912135 /* BobPWTEST1234.asc */; }; 471876F8223FACA900912135 /* BobWithoutPW.asc in Resources */ = {isa = PBXBuildFile; fileRef = 471876F6223FACA900912135 /* BobWithoutPW.asc */; }; @@ -325,6 +326,7 @@ 4707092B2189C74200DF71A3 /* bobSecret.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bobSecret.asc; sourceTree = "<group>"; }; 4707092C2189C74200DF71A3 /* alicePublic.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = alicePublic.asc; sourceTree = "<group>"; }; 4707092F2189E1C000DF71A3 /* enc+signedThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "enc+signedThunderbird.eml"; sourceTree = "<group>"; }; + 4709769526220659002436E2 /* SimpleMailRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleMailRowView.swift; sourceTree = "<group>"; }; 47184C3822F0D8F200712A7A /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 471876F5223FACA900912135 /* BobPWTEST1234.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BobPWTEST1234.asc; sourceTree = "<group>"; }; 471876F6223FACA900912135 /* BobWithoutPW.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BobWithoutPW.asc; sourceTree = "<group>"; }; @@ -1045,6 +1047,7 @@ isa = PBXGroup; children = ( 477120C1254C676000B28C64 /* ContactView.swift */, + 4709769526220659002436E2 /* SimpleMailRowView.swift */, 32261742260C7CE60068CBD4 /* ContactMailListView.swift */, ); path = Contact; @@ -1977,6 +1980,7 @@ 47FAE3492524FB58005A1BCB /* AddressRecord.swift in Sources */, 4775D7AA243F0E260052F2CC /* SimulatorData.swift in Sources */, 47C8225324379EAE005BCE73 /* AttachmentsViewMain.swift in Sources */, + 4709769626220659002436E2 /* SimpleMailRowView.swift in Sources */, 678942612430C3D600C746D1 /* Typosquatting.swift in Sources */, 47C112CA2531E9B000621A07 /* AttachmentRecord.swift in Sources */, 476406982416B54D00C7D426 /* CircleImage.swift in Sources */, diff --git a/enzevalos_iphone/AuthenticationView.swift b/enzevalos_iphone/AuthenticationView.swift index ca9a99d343125daa2e59bd200054060419e0be5c..69807630a78ba32fbaffbcaaf9dfd12c6f31b332 100644 --- a/enzevalos_iphone/AuthenticationView.swift +++ b/enzevalos_iphone/AuthenticationView.swift @@ -211,12 +211,11 @@ struct LoginAdvancedSection: View{ ForEach(0..<encryptionOptions.count) { i in Text(self.encryptionOptions[i]).tag(i) .onTapGesture { - print("Tap!") - if !s { - self.imapEncryption = i - } else { - self.smtpEncryption = i - } + if !s { + self.imapEncryption = i + } else { + self.smtpEncryption = i + } } } } diff --git a/enzevalos_iphone/ContactHandler.swift b/enzevalos_iphone/ContactHandler.swift index 82c3d01f7102d31d258702353679b575fd4bf130..7c652f9cbb63b0b13f5f830f7df5b1d61da9a192 100644 --- a/enzevalos_iphone/ContactHandler.swift +++ b/enzevalos_iphone/ContactHandler.swift @@ -24,7 +24,7 @@ import SwiftUI // TODO: Mark displayname as from CNContact class ContactHandler { - static var cartoons = true + static var cartoons = false private let store = CNContactStore() static let handler = ContactHandler() diff --git a/enzevalos_iphone/MailHandler.swift b/enzevalos_iphone/MailHandler.swift index 0804f453fb4402150d9c206dfe822b3fe162f2fc..f3e06fee3e624ad0fc8a9062bd9e69c781b770f5 100644 --- a/enzevalos_iphone/MailHandler.swift +++ b/enzevalos_iphone/MailHandler.swift @@ -48,6 +48,10 @@ case postcard } + enum FolderError: Error { + case WrongUidValidity + } + class MailHandler { private static let MAXMAILS = 25 private static let extraHeaders = Autocrypt.EXTRAHEADERS @@ -164,7 +168,7 @@ // TODO SEND MAIL... later... func storeIMAP(mail: OutgoingMail, folder: String, callback: ((MailServerConnectionError?) -> Void)?) { // 1. Test if folder exists - let existFolderController = dataProvider.generateFetchedFolderResultsController(folderpath: folder) + let existFolderController = dataProvider.generateFetchedFolderResultsController(folderpath: folder, moc: nil) if existFolderController.fetchedObjects != nil { // 2. Store Mail in test // We can always store encrypted data on the imap server because the user has a key pair and it is users imap account. @@ -191,7 +195,7 @@ return } // Create folder on local - let folderProperty = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: folder) + let folderProperty = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: folder, flags: 0) dataProvider.importNewData(from: [folderProperty], completionHandler: { error in guard error == nil else { // TODO: Error handling @@ -277,7 +281,7 @@ guard IMAPSession != nil else { return } - if let f = dataProvider.generateFetchedFolderResultsController(folderpath: folderName).fetchedObjects?.first { + if let f = dataProvider.generateFetchedFolderResultsController(folderpath: folderName, moc: nil).fetchedObjects?.first { let folderstatus = IMAPSession?.folderStatusOperation(folderName) folderstatus?.start {[unowned self] (error, status) -> Void in guard error == nil else { @@ -320,7 +324,7 @@ completionCallback(MailServerConnectionError.NoData) return } - if let folder = dataProvider.generateFetchedFolderResultsController(folderpath: MailHandler.INBOX).fetchedObjects?.first { + if let folder = dataProvider.generateFetchedFolderResultsController(folderpath: MailHandler.INBOX, moc: nil).fetchedObjects?.first { let folderstatus = IMAPSession?.folderStatusOperation(folder.path) folderstatus?.start {[unowned self] (error, status) -> Void in guard error == nil else { @@ -344,7 +348,7 @@ completionCallback(0, completionHandler) return } - if let folder = dataProvider.generateFetchedFolderResultsController(folderpath: MailHandler.INBOX).fetchedObjects?.first { + if let folder = dataProvider.generateFetchedFolderResultsController(folderpath: MailHandler.INBOX, moc: nil).fetchedObjects?.first { let folderstatus = IMAPSession?.folderStatusOperation(folder.path) // Work only in background thread.... var backgroundTaskID: Int? @@ -448,79 +452,96 @@ } } } + + + private func createFolders(of paths: [String], completionHandler: @escaping(_ error: Error?) -> Void) { + guard let session = IMAPSession else { + completionHandler(MailServerConnectionError.ConnectionError) + return + } + session.fetchAllFoldersOperation()?.start({error, folders in + guard error != nil else { + completionHandler(error) + return + } + var myError: Error? = nil + var createFolders = [String]() + if let names = folders?.map({$0.path}) { + for path in paths { + if !names.contains(path) { + createFolders.append(path) + } + } + } + let myGroup = DispatchGroup() + let queue = DispatchQueue(label: "com.letterbox.mailhandler") + queue.async { + for path in createFolders { + myGroup.enter() + session.createFolderOperation(path)?.start({error in + myError = error + myGroup.leave() + }) + } + myGroup.notify(queue: queue, execute: { + completionHandler(myError) + }) + } + }) + } + + private func moveOnServer(uidValidity: UInt32, mails: [UInt64], fromPath: String, toPath: String, completionHandler: @escaping(_ error: Error?) -> Void) { + guard let session = IMAPSession else { + completionHandler(MailServerConnectionError.ConnectionError) + return + } + // 1. Check uid valilidity + session.folderInfoOperation(fromPath)?.start({error, infos in + guard error == nil, let infos = infos else { + completionHandler(error) + return + } + guard infos.uidValidity == uidValidity else { + completionHandler(FolderError.WrongUidValidity) + return + } + // 2. Move mails if uid is valid + let uidSet = MCOIndexSet() + mails.forEach({uidSet.add($0)}) + session.moveMessagesOperation(withFolder: fromPath, uids: uidSet, destFolder: toPath)?.start({(error, _) in + guard error == nil else { + session.copyMessagesOperation(withFolder: fromPath, uids: uidSet, destFolder: toPath)?.start({(error, _) in + completionHandler(error) + }) + return + } + completionHandler(nil) + return + }) + }) + } + + func move(mails: [UInt64], fromPath: String, toPath: String) { + // 1. Check if we have to create a folder. + createFolders(of: [fromPath, toPath], completionHandler: {error in + guard error == nil else { + return + } + // 2. Move mail on server + guard let fromFolder = self.dataProvider.generateFetchedFolderResultsController(folderpath: fromPath, moc: nil).fetchedObjects?.first else { + return + } + if let uidValidity = fromFolder.uidValidity as? UInt32 { + self.moveOnServer(uidValidity: uidValidity, mails: mails, fromPath: fromPath, toPath: toPath, completionHandler: {error in + // 3. Move mail in core data + self.dataProvider.moveMails(with: mails, from: fromPath, to: toPath) + }) + + } + }) + } + - /* TODO - func move(mails: [MailRecord], from: String, to: String, folderCreated: Bool = false) { - guard IMAPSession != nil else { - return - } - let uids = MCOIndexSet() - if !DataHandler.handler.existsFolder(with: to) && !folderCreated { - let op = IMAPSession?.createFolderOperation(to) - op?.start({[unowned self] error in - guard error == nil else { - let conError = MailServerConnectionError.findErrorCode(error: error!) - self.errorhandling(error: conError, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil) - return - } - self.move(mails: mails, from: from, to: to, folderCreated: true) - }) - } else { - let folderstatusFrom = IMAPSession?.folderStatusOperation(from) - folderstatusFrom?.start {[unowned self] (error, status) -> Void in - guard error == nil else { - let conerror = MailServerConnectionError.findErrorCode(error: error!) - self.errorhandling(error: conerror, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil) - return - } - if let statusFrom = status { - let uidValidity = statusFrom.uidValidity - let f = DataHandler.handler.findFolder(with: from) - if uidValidity == f.uidvalidity { - for mail in mails { - if mail.uidvalidity == uidValidity { - uids.add(mail.uid) - mail.folder.removeFromMails(mail) - if let record = mail.record { - record.removeFromPersistentMails(mail) - if record.mailsInFolder(folder: f).count == 0 { - f.removeFromKeyRecords(record) - } - } - DataHandler.handler.delete(mail: mail) - } - } - let op = self.IMAPSession?.moveMessagesOperation(withFolder: from, uids: uids, destFolder: to) - op?.start {[unowned self] - (err, vanished) -> Void in - guard err == nil else { - let conerror = MailServerConnectionError.findErrorCode(error: err!) - self.errorhandling(error: conerror, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: { err in - guard err != nil else { - return - } - let op = self.IMAPSession?.copyMessagesOperation(withFolder: from, uids: uids, destFolder: to) - op?.start({[unowned self] error, _ in - guard error == nil else { - return - } - uids.enumerate({uid in - self.setFlag(uid, flags: MCOMessageFlag.deleted, folder: from) - }) - }) - }) - return - } - } - } else { - f.uidvalidity = uidValidity - } - } - } - } - } - - */ func allFolders(_ completion: @escaping (Error?) -> Void) { guard IMAPSession != nil else { completion(MailServerConnectionError.NoData) @@ -536,7 +557,7 @@ if let folders = array { var properities = [FolderProperties]() for folder in folders { - let property = FolderProperties(delimiter: String(Character(UnicodeScalar(UInt8(folder.delimiter)))), uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: folder.path, parent: nil, children: nil) + let property = FolderProperties(delimiter: String(Character(UnicodeScalar(UInt8(folder.delimiter)))), uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: folder.path, parent: nil, children: nil, flags: Int16(folder.flags.rawValue)) properities.append(property) } self.dataProvider.importNewData(from: properities, completionHandler: completion) diff --git a/enzevalos_iphone/New Group/Mailbot.swift b/enzevalos_iphone/New Group/Mailbot.swift index 7ed2e4effdd5ef3dc8c5cd3bb637af5776927a64..a9497e5c19e38c2d029541ed7154818a8a7b6183 100644 --- a/enzevalos_iphone/New Group/Mailbot.swift +++ b/enzevalos_iphone/New Group/Mailbot.swift @@ -93,6 +93,7 @@ class Mailbot { let mail = MailProperties( messageID: UUID().uuidString, + uid: 0, subject: subject, date: Date(), flags: 0, from: sender, @@ -106,7 +107,7 @@ class Mailbot { maxUID: nil, minUID: nil, path: UserManager.backendInboxFolderPath, - parent: nil, children: nil), + parent: nil, children: nil, flags: 0), body: body, attachments: [], signatureState: SignatureState.ValidSignature.rawValue, diff --git a/enzevalos_iphone/OutgoingMail.swift b/enzevalos_iphone/OutgoingMail.swift index 5227d034aed580274f7d0590ba5d6681bdec5d32..56dc93e39f53ebe62239eaac8ccaad8de2c6b068 100644 --- a/enzevalos_iphone/OutgoingMail.swift +++ b/enzevalos_iphone/OutgoingMail.swift @@ -9,7 +9,7 @@ import Foundation class OutgoingMail { - static var OutgoingFolder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "OutgoingMails", parent: nil, children: nil) + static var OutgoingFolder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "OutgoingMails", parent: nil, children: nil, flags: Int16(MCOIMAPFolderFlag.sentMail.rawValue)) private var encAddresses: [MCOAddress] = [] var encReceivers: [MCOAddress] { @@ -162,9 +162,9 @@ class OutgoingMail { let to = self.toAddresses.map({AddressProperties(email: $0.mailbox, name: $0.displayName)}) let sigState = self.cryptoObject?.signatureState.rawValue ?? SignatureState.NoSignature.rawValue let encState = self.cryptoObject?.encryptionState.rawValue ?? EncryptionState.NoEncryption.rawValue - + let uuid = UUID() let from = AddressProperties(email: self.sender.mailbox, name: self.sender.displayName) - let m = MailProperties(messageID: UUID().uuidString, subject: subject, date: Date(), flags: 0, from: from, to: to, cc: cc , bcc: bcc, folder: OutgoingMail.OutgoingFolder, body: body, attachments: attachmentProperties, signatureState: sigState, encryptionState: encState, signatureKey: nil, decryptionKey: nil, autocryptHeaderKey: [], attachedPublicKeys: [], attachedSecretKeys: []) + let m = MailProperties(messageID: uuid.uuidString, uid: UInt64(arc4random()), subject: subject, date: Date(), flags: 0, from: from, to: to, cc: cc , bcc: bcc, folder: OutgoingMail.OutgoingFolder, body: body, attachments: attachmentProperties, signatureState: sigState, encryptionState: encState, signatureKey: nil, decryptionKey: nil, autocryptHeaderKey: [], attachedPublicKeys: [], attachedSecretKeys: []) LetterboxModel.instance.dataProvider.importNewData(from: [m], completionHandler: { _ in }) // TODO Fix crypto stuff (keys etc.) } @@ -190,7 +190,7 @@ class OutgoingMail { func send(informUser: Bool = false) { self.informUser = informUser if let mail = mail { - LetterboxModel.instance.dataProvider.deleteMail(mail: mail) + mail.delete() } LetterboxModel.instance.mailHandler.sendSMTP(mail: self, callback: { error in if error != nil { diff --git a/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift b/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift index 857dac1147386835153d2f16a14dff4997cffa87..048cd4727e756c5bea0070d0c2786f918d1233b7 100644 --- a/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift +++ b/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift @@ -54,53 +54,50 @@ struct ComposeViewHeader: View { .disabled(model.recipientsModel.hasNoRecipients) } - // Encryption toggle - Toggle("", isOn: $model.encryptionOn) - .toggleStyle(EncryptionToggleStyle()) - .labelsHidden() + // Encryption button + encryptionButton } } - /// Custom styling for the encryption toggle in ComposeViewHeader. - struct EncryptionToggleStyle: ToggleStyle { - func makeBody(configuration: Configuration) -> some View { - Button { - configuration.isOn.toggle() - } label: { - // Separate labels required for desired scaling transition between states - if configuration.isOn { - encryptedButtonLabel - } else { - unencryptedButtonLabel - } + + /// Encryption state button view + private var encryptionButton: some View { + Button { + model.toogleEncryption() + } label: { + // Separate labels required for desired scaling transition between states + if model.encryptionOn { + encryptedButtonLabel + } else { + unencryptedButtonLabel } - .frame(width: 40, height: 40) } - - /// Label style for encryption button when encryption is activated. - private var encryptedButtonLabel: some View { - ZStack { - Circle() - .stroke(Color.blue, lineWidth: 2) - - Image(systemName: "lock.fill") - .font(Font.system(size: 24, weight: Font.Weight.light)) - .foregroundColor(.blue) - } - .transition(AnyTransition.opacity.combined(with: .scale)) + .frame(width: 40, height: 40) + } + + /// Label style for encryption button when encryption is activated. + private var encryptedButtonLabel: some View { + ZStack { + Circle() + .stroke(Color.blue, lineWidth: 2) + + Image(systemName: "lock.fill") + .font(Font.system(size: 24, weight: Font.Weight.light)) + .foregroundColor(.blue) } - - /// Label style for encryption button when encryption is deactivated. - private var unencryptedButtonLabel: some View { - ZStack { - Circle() - .fill(Color(UIColor.tertiaryLabel)) - - Image(systemName: "lock.slash.fill") - .font(Font.system(size: 24, weight: Font.Weight.light)) - .foregroundColor(.white) - } - .transition(AnyTransition.opacity.combined(with: .scale)) + .transition(AnyTransition.opacity.combined(with: .scale)) + } + + /// Label style for encryption button when encryption is deactivated. + private var unencryptedButtonLabel: some View { + ZStack { + Circle() + .fill(Color(UIColor.tertiaryLabel)) + + Image(systemName: "lock.slash.fill") + .font(Font.system(size: 24, weight: Font.Weight.light)) + .foregroundColor(.white) } + .transition(AnyTransition.opacity.combined(with: .scale)) } } diff --git a/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift b/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift index e935e59ff73ddace306535ebb806f0248c5b6daa..eeee22b6b2f1566bde566777296a9ac4ff98e13a 100644 --- a/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift +++ b/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift @@ -66,6 +66,15 @@ class ComposeModel: ObservableObject { generateMail().send() } + /// Checks if encryption state can be toggled. + func toogleEncryption() { + if encryptionOn { + encryptionOn = false + } else { + recipientsModel.checkEncryption() + } + } + /// Adds email addresses to given RecipientFieldModel. /// /// - Parameters: @@ -75,6 +84,13 @@ class ComposeModel: ObservableObject { for address in addresses { model.addNewAddress(address) } + let frc = PersistentDataProvider.dataProvider.generateFetchedAddresesWithKeyResultsController(addresses: addresses) + if let records = frc.fetchedObjects { + if encryptionOn && records.count != addresses.count { + encryptionOn = false + } + } + } /// Generates OutgoingMail with given email contents. diff --git a/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift b/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift index 69fcd684bdb276f1c31ac18c2412c769b88dc3c3..512d4da26aa3cfc36d3571a4de6886ff00ad6a58 100644 --- a/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift +++ b/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift @@ -206,7 +206,6 @@ struct RecipientField: View { // and Bcc fields getting collapsed again despite the // first recipient clearly getting rendered as a blue // capsule in the ForEach loop above. 🤔🤔🤔 - print(model.selectedContacts.count) } .frame(width: 200) // TODO: Stretch dynamically over available horizontal space .autocapitalization(.none) // .frame(maxWidth: .infinity) somehow doesn't work diff --git a/enzevalos_iphone/SwiftUI/Compose/RecipientFieldModel.swift b/enzevalos_iphone/SwiftUI/Compose/RecipientFieldModel.swift index 02dc92090dfe594746409d96a12874c499870504..8cb8b83b85856f6c0120ec3d11d4d39028f7e074 100644 --- a/enzevalos_iphone/SwiftUI/Compose/RecipientFieldModel.swift +++ b/enzevalos_iphone/SwiftUI/Compose/RecipientFieldModel.swift @@ -82,6 +82,9 @@ class RecipientFieldModel: ObservableObject { /// - Parameter _: AddressRecord that gets added to array of recipients. func selectContact(_ addressRecord: AddressRecord) { selectedContacts.append(addressRecord) + if !addressRecord.hasPublicKey { + self.parentRecipientModel?.parentComposeModel?.encryptionOn = false + } text = "" suggestions = [] @@ -97,8 +100,12 @@ class RecipientFieldModel: ObservableObject { /// /// - Parameter at: Index of contact to be removed from array of recipients. func deselectContact(at index: Int) { - selectedContacts.remove(at: index) + let addr = selectedContacts[index] + selectedContacts.remove(at: index) + if !addr.hasPublicKey { + parentRecipientModel?.checkEncryption() + } // TODO: See TODO in selectContact. parentRecipientModel?.parentComposeModel?.subject += "" } @@ -132,6 +139,9 @@ class RecipientFieldModel: ObservableObject { if let addresses = frc.fetchedObjects, let addr = addresses.first { self.selectedContacts.append(addr) + if !addr.hasPublicKey { + self.parentRecipientModel?.parentComposeModel?.encryptionOn = false + } } } } diff --git a/enzevalos_iphone/SwiftUI/Compose/RecipientsModel.swift b/enzevalos_iphone/SwiftUI/Compose/RecipientsModel.swift index 9a3e5d2af808e77475ab3c5c4294ecbb76899409..7cad5be8c9bd5ea01301e2816420b79de05ca382 100644 --- a/enzevalos_iphone/SwiftUI/Compose/RecipientsModel.swift +++ b/enzevalos_iphone/SwiftUI/Compose/RecipientsModel.swift @@ -44,9 +44,7 @@ class RecipientsModel: ObservableObject { /// Used to show or hide Bcc field var isEditingCcOrBcc: Bool = false { didSet { - print("isEditingCcOrBcc: \(isEditingCcOrBcc)") updateShowBccField() - print("showBccField: \(showBccField)") } } @@ -91,6 +89,26 @@ class RecipientsModel: ObservableObject { || !bccModel.selectedContacts.isEmpty ccModel.type = showBccField ? .cc : .ccBcc } + + /// Turnes encryption on if all recipients have a key. + func checkEncryption() { + for addr in toModel.selectedContacts { + if !addr.hasPublicKey { + return + } + } + for addr in ccModel.selectedContacts { + if !addr.hasPublicKey { + return + } + } + for addr in bccModel.selectedContacts { + if !addr.hasPublicKey { + return + } + } + parentComposeModel?.encryptionOn = true + } } /// Type of recipient field (to, cc, bcc). diff --git a/enzevalos_iphone/SwiftUI/Contact/ContactMailListView.swift b/enzevalos_iphone/SwiftUI/Contact/ContactMailListView.swift index e2f267ef02286f42341ba8ab82e6606baefeb02c..ea55d3bcf21cadc1aca5fad9eadf3775903dbf45 100644 --- a/enzevalos_iphone/SwiftUI/Contact/ContactMailListView.swift +++ b/enzevalos_iphone/SwiftUI/Contact/ContactMailListView.swift @@ -37,7 +37,7 @@ struct ContactMailListView: View { ForEach (0..<min(3,filteredEmails.count)) { record in NavigationLink( destination: ReadMainView(model: ReadModel(mail: filteredEmails[record]))) { - MailRowView(mail: filteredEmails[record], activateOnTap: false) + SimpleMailRowView(mail: filteredEmails[record]) } if record < min(2, filteredEmails.count - 1) { Divider() diff --git a/enzevalos_iphone/SwiftUI/Contact/ContactView.swift b/enzevalos_iphone/SwiftUI/Contact/ContactView.swift index 310dbf7430ddb30a5ca1cb0d9d3b9c00cd375298..3d56ff55a2db22984632d912d52de4b03502d0fa 100644 --- a/enzevalos_iphone/SwiftUI/Contact/ContactView.swift +++ b/enzevalos_iphone/SwiftUI/Contact/ContactView.swift @@ -30,7 +30,6 @@ struct ContactView <C: DisplayContact>: View { VStack { HStack { avatar - VStack (alignment: .leading) { contactName.padding(.bottom) knownSince @@ -144,7 +143,7 @@ struct ContactView <C: DisplayContact>: View { } label: { Text("\(eachAddress)") .fontWeight(.light) - .font(.title2) + .font(.body) .foregroundColor(.blue) .truncationMode(.middle) .frame(maxWidth: .infinity, @@ -157,32 +156,11 @@ struct ContactView <C: DisplayContact>: View { // This row shows the security rating and a button do display the keys HStack{ rating - Button { - withAnimation{ - properties.emailAddress = eachAddress - properties.showKeysPopup.toggle() - } - - } label: { - ZStack { - Capsule() - .frame(height: 25, alignment: .center) - .shadow(color:.gray, radius:2) - .foregroundColor(contact.addressRating(contact).color) - - HStack{ - Text(Image(systemName: "key.fill")) - .rotationEffect(Angle(degrees: 30)) - - Text(NSLocalizedString("Contact.Key.Description", comment: "Contact.Key.Description")) - .fontWeight(.medium) - - }.foregroundColor(.white) - .font(.body) - } - } + if contact.primaryKey != nil { + showKeyBotton(addr: eachAddress) + } }.padding(.vertical,3) - + if eachAddress != contact.emails.last{ Divider().padding(.top,1) } @@ -193,6 +171,32 @@ struct ContactView <C: DisplayContact>: View { }.padding(.horizontal,5) } + + private func showKeyBotton (addr: String) -> some View { + Button { + withAnimation{ + properties.emailAddress = addr + properties.showKeysPopup.toggle() + } + + } label: { + ZStack { + Capsule() + .frame(height: 25, alignment: .center) + .shadow(color:.gray, radius:2) + .foregroundColor(contact.addressRating(contact).color) + HStack{ + Text(Image(systemName: "key.fill")) + .rotationEffect(Angle(degrees: 30)) + + Text(NSLocalizedString("Contact.Key.Description", comment: "Contact.Key.Description")) + .fontWeight(.medium) + + }.foregroundColor(.white) + .font(.footnote) + } + } + } /// Creates a frame for the address label. /// TODO: Add an addressLabel property to the DisplayContact. @@ -250,11 +254,11 @@ struct ContactView <C: DisplayContact>: View { private var rating: some View { HStack{ Text(Image(systemName: contact.addressRating(contact).shield)) - .font(.title3) + .font(.footnote) Text(contact.addressRating(contact).name) .fontWeight(.medium) - .font(.body) + .font(.footnote) } .foregroundColor(contact.addressRating(contact).color) diff --git a/enzevalos_iphone/SwiftUI/Contact/SimpleMailRowView.swift b/enzevalos_iphone/SwiftUI/Contact/SimpleMailRowView.swift new file mode 100644 index 0000000000000000000000000000000000000000..176daab5779264e063ecf5deed869086f5e7556e --- /dev/null +++ b/enzevalos_iphone/SwiftUI/Contact/SimpleMailRowView.swift @@ -0,0 +1,60 @@ +// +// SimpleMailRowView.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 10.04.21. +// Copyright © 2021 fu-berlin. All rights reserved. +// + +import SwiftUI + +struct SimpleMailRowView <M: DisplayMail>: View { + let mail: M + + private var content: String { + get { + let max = 500 + if mail.subject.count < max { + return mail.subject + "\n" + mail.body.prefix(max - mail.subject.count) + } + return mail.subject + } + } + + var body: some View { + HStack { + VStack(alignment: .leading) { + HStack { + // Attachment indicator if relevant + if !mail.displayAttachments.isEmpty { + Image(systemName: "paperclip") + .font(.caption) + .foregroundColor(.secondary) + } + + Spacer() + + // Arrival time + Text(mail.date.timeAgoText()) + .font(.caption) + } + + HStack { + // Subject + Text(content) + .font(.caption) + .lineLimit(3) + } + } + .foregroundColor(mail.isRead ? .secondary : .primary) + } + .padding(4) + .frame(height: 65) + } +} + +struct SimpleMailRow_Previews: PreviewProvider { + static var previews: some View { + SimpleMailRowView(mail: ProxyData.PlainMail) + } +} diff --git a/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift b/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift index a5630a345a0b07af6450c6a568cd19ff456628c0..9b825c7115387a7a13c0f08b7f588829d6dbeb54 100644 --- a/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift +++ b/enzevalos_iphone/SwiftUI/Inbox/MailListView.swift @@ -68,9 +68,7 @@ struct MailListView: View { MailRowView(mail: email) } } - .onDelete { _ in - // TODO: Perform actual deletion of email - } + .onDelete(perform: deleteMails(at:)) } .listStyle(PlainListStyle()) } @@ -123,6 +121,15 @@ struct MailListView: View { } } + private func deleteMails(at offsets: IndexSet) { + var ids = [UInt64]() + for index in offsets { + let mail = mails[index] + ids.append(UInt64(mail.uID)) + } + MailRecord.delete(with: ids, folderPath: folderPath) + } + /// Filters emails based on search criteria. func filterKeyRecord(keyRecord: MailRecord) -> Bool { if searchText.isEmpty diff --git a/enzevalos_iphone/SwiftUI/Inbox/MailRowView.swift b/enzevalos_iphone/SwiftUI/Inbox/MailRowView.swift index 4d4c6936710b82da2880187db62b422d45b174af..236c419c0b964a584971dcac3eaa36a2d11cd4ef 100644 --- a/enzevalos_iphone/SwiftUI/Inbox/MailRowView.swift +++ b/enzevalos_iphone/SwiftUI/Inbox/MailRowView.swift @@ -28,6 +28,55 @@ struct MailRowView <M: DisplayMail>: View { var activateOnTap: Bool = true var body: some View { + body_v2 + } + + private var content: String { + get { + let max = 500 + if mail.subject.count < max { + return mail.subject + "\n" + mail.body.prefix(max - mail.subject.count) + } + return mail.subject + } + } + + private var body_v2: some View { + VStack(alignment: .leading) { + HStack{ + // Sender name + Text(mail.sender.name) + .fontWeight(mail.isRead ? .regular : .medium) + .lineLimit(2) + + Spacer() + + if !mail.displayAttachments.isEmpty { + Image(systemName: "paperclip") + .font(.caption) + .foregroundColor(.secondary) + } + + // Arrival time + Text(mail.date.timeAgoText()) + .font(.caption) + .padding(.trailing, -20) + } + HStack { + avatar + + // Subject + Text(content) + .font(.caption) + .lineLimit(3) + } + .padding(.top, -7) + .frame(height: 45) + } + .foregroundColor(mail.isRead ? .secondary : .primary) + } + + private var body_v1: some View { HStack { avatar diff --git a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift index 27d7620e3c02924b707cad3652c77f3d7b7e5df3..24d47ee2e117ee3825525540bfc5171db5963f61 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift @@ -18,7 +18,7 @@ import SwiftUI struct ReadMainView <M: DisplayMail>: View { - @ObservedObject var model: ReadModel<M> + @StateObject var model: ReadModel<M> var body: some View { TabView(selection: $model.currentTab) { @@ -32,6 +32,9 @@ struct ReadMainView <M: DisplayMail>: View { } } .navigationBarTitle(subject) + .onDisappear(perform: { + model.onDisappear() + }) } var subject: Text { diff --git a/enzevalos_iphone/SwiftUI/Read/ReadModel.swift b/enzevalos_iphone/SwiftUI/Read/ReadModel.swift index afdf794cf77e05506f3062626cdb772c89903c4b..9ed72bffe5acd58edddbbd9831c413ca1e3960fc 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadModel.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadModel.swift @@ -35,16 +35,39 @@ enum ReadPart { class ReadModel <M: DisplayMail>: ObservableObject { - @Published var dismissView = false - @Published var currentTab = ReadPart.Security.value - + @Published var currentTab = ReadPart.Body.value private var userAction: UserAction? var mail: M init(mail: M) { self.mail = mail + if mail.encryptionState == .UnableToDecrypt || + mail.warnings.count > 0 { + currentTab = ReadPart.Security.value + } + } + + func onDisappear() { + if let action = userAction { + switch action { + case .Delete: + if let mail = mail as? MailRecord { + mail.delete() + } + case .Archive: + if let mail = mail as? MailRecord { + mail.archive() + } + case .Unread: + mail.markAsRead(isRead: false) + default: + mail.markAsRead(isRead: true) + } + } else { + mail.markAsRead(isRead: true) + } } func newUserAction(action: UserAction) -> PreMailData? { diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift index ba80bae93e6bcbd138e6cc8ea85e89ba89b0d2f0..b0d34670751e609279aa710043c93aff737872ea 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift @@ -26,9 +26,13 @@ struct MessageViewMain <M: DisplayMail>: View { self.showExtraButtons = false } FloatingReplyButtons - }.onAppear(perform: {self.model.mail.markAsRead(isRead: true)}) + } .sheet(item: $newMail, content: {mail in ComposeView(preData: mail)}) - + .onChange(of: model.dismissView, perform: { value in + if value { + presentationMode.wrappedValue.dismiss() + } + }) } var Subjectbar: some View{ diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift index 0ad2f406c7523fff623fe6e1f9a461ad47e3ba30..7525dd711a40cca96da08899c7751307d2c8aa6c 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SecurityBriefingView.swift @@ -152,12 +152,7 @@ struct SecurityBriefingView<M: DisplayMail>: View { } func choseAction (action: ButtonAction) { - /* TODO guard let coord = AppDelegate.getAppDelegate().readViewCoordinator else { - print("No coordinator!") - return - } - coord.makeAction(action: action) - */} + } } struct WarningView: View { @@ -217,11 +212,6 @@ struct WarningView: View { } func choseAction (action: ButtonAction) { - /* TODO guard let coord = AppDelegate.getAppDelegate().readViewCoordinator else { - print("No coordinator!") - return - } - coord.makeAction(action: action) */ } } diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift index 22e34c1997ca79d888a6121ed7ab8ed9ff65ef4f..a56b3f8a63a838f4bd65c4f7d7160011afc18e9d 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift @@ -156,11 +156,7 @@ struct SenderViewMain <M: DisplayMail>: View { } private func goToContact(contact: M.C) { - /* guard let con = contact.keyRecord else { - print("No record...") - return - } - AppDelegate.getAppDelegate().readViewCoordinator?.pushContactView(contact: con) */ + // Tbd... } } diff --git a/enzevalos_iphone/mail/IncomingMail.swift b/enzevalos_iphone/mail/IncomingMail.swift index 93e71adf431535a93c2a641cd65428e55276c7ed..ea85118724aaa56e67f29c7ecc113f53d20cb022 100644 --- a/enzevalos_iphone/mail/IncomingMail.swift +++ b/enzevalos_iphone/mail/IncomingMail.swift @@ -264,7 +264,7 @@ class IncomingMail { let ccProperties = cc.map{$0.export()} let bccProperties = bcc.map{$0.export()} - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: self.folderPath) + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: self.folderPath, flags: 0) let from = self.from?.export() ?? nil let sigState = self.cryptoObj?.signatureState.rawValue ?? 0 var sigKey: PublicKeyProperties? = nil @@ -308,7 +308,7 @@ class IncomingMail { } let f = Int16(self.flags.rawValue) - var m = MailProperties(messageID: self.msgID, subject: subject, date: date, flags: f, from: from, to: to, cc: ccProperties, bcc: bccProperties, folder: folder, body: body, signatureState: sigState, encryptionState: encState, signatureKey: sigKey, decryptionKey: nil, autocryptHeaderKey: autocryptPK, attachedPublicKeys: attPK, attachedSecretKeys: []) + var m = MailProperties(messageID: self.msgID, uid: uID, subject: subject, date: date, flags: f, from: from, to: to, cc: ccProperties, bcc: bccProperties, folder: folder, body: body, signatureState: sigState, encryptionState: encState, signatureKey: sigKey, decryptionKey: nil, autocryptHeaderKey: autocryptPK, attachedPublicKeys: attPK, attachedSecretKeys: []) // TODO: FIX KEYS m.to = to m.cc = ccProperties diff --git a/enzevalos_iphone/persistentData/FolderRecord.swift b/enzevalos_iphone/persistentData/FolderRecord.swift index 06db902ecc33a4271253d0f55324c174bfd226fd..37d358782986b92b5b34c21dad3b863982217cba 100644 --- a/enzevalos_iphone/persistentData/FolderRecord.swift +++ b/enzevalos_iphone/persistentData/FolderRecord.swift @@ -13,6 +13,20 @@ import CoreData extension FolderRecord { static var FetchRequest: NSFetchRequest<FolderRecord> { let request: NSFetchRequest<FolderRecord> = NSFetchRequest<FolderRecord>(entityName: FolderRecord.entityName) + request.sortDescriptors = [NSSortDescriptor(key: "flags", ascending: false), NSSortDescriptor(key: "path", ascending: true)] + return request + } + + static var onlySpecialFolderFetchRequest: NSFetchRequest<FolderRecord> { + let request: NSFetchRequest<FolderRecord> = NSFetchRequest<FolderRecord>(entityName: FolderRecord.entityName) + request.predicate = NSPredicate(format: " flags > 0") + request.sortDescriptors = [NSSortDescriptor(key: "flags", ascending: false), NSSortDescriptor(key: "path", ascending: true)] + return request + } + + static var onlyUserDefinedFolderFetchRequest: NSFetchRequest<FolderRecord> { + let request: NSFetchRequest<FolderRecord> = NSFetchRequest<FolderRecord>(entityName: FolderRecord.entityName) + request.predicate = NSPredicate(format: " flags == 0") request.sortDescriptors = [NSSortDescriptor(key: "path", ascending: true)] return request } @@ -37,6 +51,14 @@ extension FolderRecord { if let minUID = properties.minUID { self.minUID = minUID } + if properties.flags != 0 { + self.flags = properties.flags + } + if UserManager.backendInboxFolderPath == properties.path { + var flag = MCOIMAPFolderFlag(rawValue: Int(self.flags)) + flag.formUnion(.inbox) + self.flags = Int16(flag.rawValue) + } path = properties.path } diff --git a/enzevalos_iphone/persistentData/MailRecord.swift b/enzevalos_iphone/persistentData/MailRecord.swift index 57f9e0b7c15e7695fb18acc7dd6023c3701f1f7b..fcca5026491f6bfe63c54b17d0522b4d2d63aba5 100644 --- a/enzevalos_iphone/persistentData/MailRecord.swift +++ b/enzevalos_iphone/persistentData/MailRecord.swift @@ -35,6 +35,7 @@ extension MailRecord { flag = mailProperties.flags subject = mailProperties.subject xMailer = mailProperties.xMailer + uID = Int64(mailProperties.uid) // Content @@ -139,8 +140,20 @@ extension MailRecord: DisplayMail { set { var mcoflag = MCOMessageFlag.init(rawValue: Int(flag)) - mcoflag = mcoflag.update(with: .seen) ?? mcoflag + if newValue { + mcoflag = mcoflag.update(with: .seen) ?? mcoflag + } else { + mcoflag.subtract(.seen) + } + self.flag = Int16(mcoflag.rawValue) + + if let moc = self.managedObjectContext { + try? PersistentDataProvider.dataProvider.save(taskContext: moc) + } + if let folder = self.inFolder?.path { + MailHandler.init().setFlag(UInt64(self.uID), flags: mcoflag, folder: folder) + } } } @@ -202,14 +215,7 @@ extension MailRecord: DisplayMail { } func markAsRead(isRead: Bool) { - - // TODO: FIX! Faults the current objects... -// if let context = self.managedObjectContext { -// var newFlag = self.messageFlag -// newFlag.insert(.seen) -// flag = Int16(newFlag.rawValue) -// try? PersistentDataProvider.dataProvider.save(taskContext: context) // <- later? -// } + self.isRead = isRead return } @@ -248,4 +254,25 @@ extension MailRecord { return request } } +/// Functions to manipulate mails +extension MailRecord { + + static func delete(with ids: [UInt64], folderPath: String) { + MailHandler.init().move(mails: ids, fromPath: folderPath, toPath: UserManager.backendTrashFolderPath) + } + + func archive() { + guard let folder = self.inFolder?.path else { + return + } + MailHandler.init().move(mails: [UInt64(self.uID)], fromPath: folder, toPath: UserManager.backendArchiveFolderPath) + } + + func delete() { + guard let folder = self.inFolder?.path else { + return + } + MailHandler.init().move(mails: [UInt64(self.uID)], fromPath: folder, toPath: UserManager.backendTrashFolderPath) + } +} diff --git a/enzevalos_iphone/persistentData/PersistentDataProvider.swift b/enzevalos_iphone/persistentData/PersistentDataProvider.swift index 7f2994f299ee793b21db39e769a4a1f1d000dbba..ca757f27809c5d8eb5aa4338e5abac3d90ead787 100644 --- a/enzevalos_iphone/persistentData/PersistentDataProvider.swift +++ b/enzevalos_iphone/persistentData/PersistentDataProvider.swift @@ -64,20 +64,20 @@ class PersistentDataProvider { let addr1 = AddressProperties(email: "vic@example.com") let addr2 = AddressProperties(email: "alex@example.com") let addrs = [addr1, addr2] - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Inbox") + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Inbox", flags: 0) var msgs = [MailProperties]() for i in 1...10 { let a = addrs[i%addrs.count] - let msg = MailProperties(messageID: "\(i)", subject: "MSG\(i)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0) + let msg = MailProperties(messageID: "\(i)", uid: UInt64(i), subject: "MSG\(i)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0) msgs.append(msg) } return msgs } private static var proxyFolders: [FolderProperties] { - let f1 = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Folder1") - let f2 = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Folder2") + let f1 = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Folder1", flags: 0) + let f2 = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Folder2", flags: 0) return [f1,f2] } @@ -475,13 +475,23 @@ class PersistentDataProvider { completionHandler(nil) } } - - func deleteMail(mail: MailRecord) { - let taskContext = newTaskContext() - taskContext.perform { - taskContext.delete(mail) - try? self.save(taskContext: taskContext) + + func moveMails(with uids: [UInt64], from: String, to: String) { + guard let rfc = try? lookUp(entityName: MailRecord.entityName, sorting: ["uID": true], equalPredicates: ["inFolder.path": from], differentPredicates: nil, inPredicates: ["uID": uids.map({"\($0)"})]) else { + return + } + guard let toFolder = generateFetchedFolderResultsController(folderpath: to, moc: rfc.managedObjectContext).fetchedObjects?.first else { + importNewData(from: [FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: to, parent: nil, children: nil, flags: 0)], completionHandler: {_ in self.moveMails(with: uids, from: from, to: to)}) + moveMails(with: uids, from: from, to: to) + return } + if let mails = rfc.fetchedObjects as? [MailRecord] { + for mail in mails { + mail.inFolder = toFolder + } + } + try? save(taskContext: rfc.managedObjectContext) + } func reset(){ @@ -677,13 +687,17 @@ class PersistentDataProvider { return generateFetchResultController(entityName: MailRecord.entityName, sortDescriptors: sortDescriptors, predicate: predicate, propertiesToFetch: nil, fetchLimit: PersistentDataProvider.FETCHLIMIT, context: nil) } - func generateFetchedFolderResultsController(folderpath: String) -> NSFetchedResultsController<FolderRecord> { + func generateFetchedFolderResultsController(folderpath: String, moc: NSManagedObjectContext? = nil) -> NSFetchedResultsController<FolderRecord> { + var mymoc = persistentContainer.viewContext + if let moc = moc { + mymoc = moc + } let freq = NSFetchRequest<FolderRecord>(entityName: FolderRecord.entityName) freq.sortDescriptors = [NSSortDescriptor(key: "path", ascending: true)] let predicate = NSPredicate(format: "path == %@", folderpath) freq.predicate = predicate let controller = NSFetchedResultsController(fetchRequest: freq, - managedObjectContext: persistentContainer.viewContext, + managedObjectContext: mymoc , sectionNameKeyPath: nil, cacheName: nil) // Perform the fetch. do { @@ -749,6 +763,13 @@ class PersistentDataProvider { importSecretKeys(secretProperties: [sk], origin: .Generated, completionHandler: completionHandler) return key } + + func delete(object: NSManagedObject) { + if let moc = object.managedObjectContext { + moc.delete(object) + try? save(taskContext: moc) + } + } } diff --git a/enzevalos_iphone/persistentData/Properties.swift b/enzevalos_iphone/persistentData/Properties.swift index 7db6b0d8671576005d7c27737a1a0467b49ae85c..e5c1ba52acd2eae14bf88c352b9ab4352e42b5f2 100644 --- a/enzevalos_iphone/persistentData/Properties.swift +++ b/enzevalos_iphone/persistentData/Properties.swift @@ -22,6 +22,7 @@ struct MailProperties: DataPropertyProtocol { // Header properties let messageID: String + let uid: UInt64 let subject: String let date: Date let flags: Int16 @@ -86,7 +87,8 @@ struct FolderProperties: DataPropertyProtocol{ let path: String var parent: [FolderProperties]? - var children: [FolderProperties]? + var children: [FolderProperties]? + var flags: Int16 func update(m: Any) -> Bool { if let folder = m as? FolderRecord { diff --git a/enzevalos_iphoneTests/AutocryptTest.swift b/enzevalos_iphoneTests/AutocryptTest.swift index d5072f6c8432de15c8a4d3aac58cfa656301ecb6..a9ad4a3bd8ffdf8daba5300ffd6500f11b0b612e 100644 --- a/enzevalos_iphoneTests/AutocryptTest.swift +++ b/enzevalos_iphoneTests/AutocryptTest.swift @@ -67,7 +67,7 @@ class AutocryptTest: XCTestCase { super.setUp() pgp.resetKeychains() let deleteExpectation = expectation(description: "Delete all data!") - PersitentDataProvider.dataProvider.deleteAll(completionHandler: {error in + PersistentDataProvider.dataProvider.deleteAll(completionHandler: {error in if let error = error { XCTFail("Error while importing addresses! \(error)") } @@ -138,7 +138,7 @@ class AutocryptTest: XCTestCase { } func testAutocryptHeader(){ - let outmail = OutgoingMail(toEntrys: ["alice@example.com"], ccEntrys: [], bccEntrys: [], subject: "subject", textContent: "Body", htmlContent: nil) + let outmail = OutgoingMail(toAddresses: ["alice@example.com"], ccAddresses: [], bccAddresses: [], subject: "subject", textContent: "Body", htmlContent: nil) if let parser = MCOMessageParser(data: outmail.plainData), let _ = pgp.exportKey(id: userKeyID, isSecretkey: false, autocrypt: false) { let autocrypt = Autocrypt.init(header: parser.header) XCTAssertEqual(autocrypt.addr, userAdr) diff --git a/enzevalos_iphoneTests/CoreAddressTest.swift b/enzevalos_iphoneTests/CoreAddressTest.swift index c6b1710f5c44d1e45dd112e3dffee76eb7ce1c57..31a98b707aae571c6576378567579695b202d471 100644 --- a/enzevalos_iphoneTests/CoreAddressTest.swift +++ b/enzevalos_iphoneTests/CoreAddressTest.swift @@ -10,10 +10,10 @@ import XCTest @testable import enzevalos_iphone class CoreAddressTest: XCTestCase { - var provider = PersitentDataProvider() + var provider = PersistentDataProvider() private func deleteAll() { - provider = PersitentDataProvider() + provider = PersistentDataProvider() let deleteExpectation = expectation(description: "Delete all data!") provider.deleteAll(completionHandler: {error in if let error = error { @@ -25,7 +25,7 @@ class CoreAddressTest: XCTestCase { provider.reset() let frc = provider.fetchedAddressResultController XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0) - provider = PersitentDataProvider() + provider = PersistentDataProvider() } override func setUpWithError() throws { diff --git a/enzevalos_iphoneTests/CoreKeysTest.swift b/enzevalos_iphoneTests/CoreKeysTest.swift index 3dd09c642c9faff4d46bb0d406851aa6818c92c2..f9fc7001a194ea02f5d0ecc1f606ff1cdc7e35fd 100644 --- a/enzevalos_iphoneTests/CoreKeysTest.swift +++ b/enzevalos_iphoneTests/CoreKeysTest.swift @@ -11,11 +11,11 @@ import XCTest @testable import enzevalos_iphone class CoreKeysTest: XCTestCase { - var provider = PersitentDataProvider() + var provider = PersistentDataProvider() let email = "vic@example.com" private func deleteAll() { - provider = PersitentDataProvider() + provider = PersistentDataProvider() let deleteExpectation = expectation(description: "Delete all data!") provider.deleteAll(completionHandler: {error in if let error = error { @@ -27,7 +27,7 @@ class CoreKeysTest: XCTestCase { provider.reset() let frc = provider.fetchedMailResultsController XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0) - provider = PersitentDataProvider() + provider = PersistentDataProvider() } override func setUpWithError() throws { diff --git a/enzevalos_iphoneTests/CoreMailTest.swift b/enzevalos_iphoneTests/CoreMailTest.swift index d5dc7f150791e1db388bec3cdc61726efb39c6a8..57eb5edcb7ba0d1d4f3895557aac0941d78f635f 100644 --- a/enzevalos_iphoneTests/CoreMailTest.swift +++ b/enzevalos_iphoneTests/CoreMailTest.swift @@ -17,12 +17,12 @@ import XCTest @testable import enzevalos_iphone class CoreMailTest: XCTestCase { - var provider = PersitentDataProvider() + var provider = PersistentDataProvider() let path = "Testfolder" private func deleteAll() { - provider = PersitentDataProvider() + provider = PersistentDataProvider() let deleteExpectation = expectation(description: "Delete all data!") provider.deleteAll(completionHandler: {error in if let error = error { @@ -34,7 +34,7 @@ class CoreMailTest: XCTestCase { provider.reset() let frc = provider.fetchedMailResultsController XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0) - provider = PersitentDataProvider() + provider = PersistentDataProvider() } override func setUpWithError() throws { @@ -51,13 +51,13 @@ class CoreMailTest: XCTestCase { func testImportMail(){ let addr = "vic@example.com" let addr1 = AddressProperties(email: addr) - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil) + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil, flags: 0) let importExpectation = expectation(description: "Import new msg!") - let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0, attachedPublicKeys: [], attachedSecretKeys: []) - let m2 = MailProperties(messageID: "2", subject: "MSG2", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) + let m1 = MailProperties(messageID: "1", uid: UInt64(arc4random()), subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0, attachedPublicKeys: [], attachedSecretKeys: []) + let m2 = MailProperties(messageID: "2", uid: UInt64(arc4random()), subject: "MSG2", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) provider.importNewData(from: [m1,m2], completionHandler: {error in if let error = error { @@ -89,10 +89,10 @@ class CoreMailTest: XCTestCase { func testDuplicateMails() { let addr1 = AddressProperties(email: "vic@example.com") - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil) + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil, flags: 0) - let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) - let m2 = MailProperties(messageID: "1", subject: "Second MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) + let m1 = MailProperties(messageID: "1", uid: UInt64(arc4random()), subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) + let m2 = MailProperties(messageID: "1", uid: UInt64(arc4random()), subject: "Second MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) provider.reset() let frc = provider.fetchedMailResultsController @@ -121,10 +121,10 @@ class CoreMailTest: XCTestCase { func testDuplicateMails2() { let addr1 = AddressProperties(email: "vic@example.com") - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil) + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil, flags: 0) - let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) - let m2 = MailProperties(messageID: "1", subject: "Second MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) + let m1 = MailProperties(messageID: "1", uid: UInt64(arc4random()), subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) + let m2 = MailProperties(messageID: "1", uid: UInt64(arc4random()), subject: "Second MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0) provider.reset() let frc = provider.fetchedMailResultsController @@ -171,13 +171,13 @@ class CoreMailTest: XCTestCase { let addr1 = AddressProperties(email: "vic@example.com") let addr2 = AddressProperties(email: "alex@example.com") let addrs = [addr1, addr2] - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil) + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil, flags: 0) var msgs = [MailProperties]() for i in 1...n { let a = addrs[i%addrs.count] - let m = MailProperties(messageID: "\(i)", subject: "MSG\(i)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0) + let m = MailProperties(messageID: "\(i)", uid: UInt64(arc4random()), subject: "MSG\(i)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0) msgs.append(m) } @@ -212,15 +212,13 @@ class CoreMailTest: XCTestCase { } - private func generateMails() -> Int { - let n = 100 - let m = 10 + private func generateMails(n: Int = 100, m: Int = 10) -> Int { var k = 1 let addr1 = AddressProperties(email: "vic@example.com") let addr2 = AddressProperties(email: "alex@example.com") let addrs = [addr1, addr2] - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil) + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil, flags: 0) var expectations = [XCTestExpectation]() var res = 0 @@ -228,7 +226,7 @@ class CoreMailTest: XCTestCase { var msgs = [MailProperties]() for i in 1...n { let a = addrs[i%addrs.count] - let msg = MailProperties(messageID: "\(k)", subject: "MSG\(k)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0) + let msg = MailProperties(messageID: "\(k)", uid: UInt64(arc4random()), subject: "MSG\(k)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0) k = k + 1 res = res + 1 msgs.append(msg) @@ -279,8 +277,8 @@ class CoreMailTest: XCTestCase { var n = generateMails() let genMails = n // CONSIDER FETCHLIMIT! - if n > PersitentDataProvider.FETCHLIMIT { - n = PersitentDataProvider.FETCHLIMIT + if n > PersistentDataProvider.FETCHLIMIT { + n = PersistentDataProvider.FETCHLIMIT } let frc = provider.generateFetchedMailsInFolderResultsController(folderpath: path) try? frc.performFetch() @@ -302,4 +300,25 @@ class CoreMailTest: XCTestCase { XCTAssertEqual(folder.mailsInFolder?.count ?? -1, genMails) } } + + func testMoveMail() { + let n = generateMails(n: 100, m: 1) + let folderPath2 = "Testfolder2" + let frc = provider.generateFetchedMailsInFolderResultsController(folderpath: path) + try? frc.performFetch() + if let mails = frc.fetchedObjects { + XCTAssertEqual(mails.count, n) + if let mail = mails.first { + provider.moveMails(with: [UInt64(mail.uID)], from: path, to: folderPath2) + try? frc.performFetch() + XCTAssertEqual(frc.fetchedObjects?.count ?? 0,( n - 1)) + let frc2 = provider.generateFetchedMailsInFolderResultsController(folderpath: folderPath2) + XCTAssertEqual(frc2.fetchedObjects?.count ?? 0, 1) + } + } + else { + XCTFail("No mails...") + } + + } } diff --git a/enzevalos_iphoneTests/CryptoTests.swift b/enzevalos_iphoneTests/CryptoTests.swift index 953b95544dbe345e1e815e1df885aafaf0bb809c..4b8d357544ae09657fd2ed37a99aee5773548973 100644 --- a/enzevalos_iphoneTests/CryptoTests.swift +++ b/enzevalos_iphoneTests/CryptoTests.swift @@ -390,7 +390,7 @@ class CryptoTests: XCTestCase { """ private func deleteAll() { - let provider = PersitentDataProvider() + let provider = PersistentDataProvider() let deleteExpectation = expectation(description: "Delete all data!") provider.deleteAll(completionHandler: {error in if let error = error { @@ -533,7 +533,7 @@ class CryptoTests: XCTestCase { func testEncSignedMail() { let body = "signed text" let (senderAddress, senderID) = createPGPUser() - let (userAddr, id2) = createPGPUser() + let (_, id2) = createPGPUser() let senderPGP = SwiftPGP() let encObject = senderPGP.encrypt(plaintext: body, ids: [userKeyID], myId: senderID) @@ -575,7 +575,7 @@ class CryptoTests: XCTestCase { SecretKeyProperties(fingerprint: $0, cryptoProtocol: .PGP, usedAddresses: [AddressProperties(email: userAdr)]) }) let importExpectation = expectation(description: "Import secret keys") - PersitentDataProvider.dataProvider.importNewData(from: properties, completionHandler: {error in + PersistentDataProvider.dataProvider.importNewData(from: properties, completionHandler: {error in if let error = error { XCTFail("Error while importing addresses! \(error)") } @@ -584,7 +584,7 @@ class CryptoTests: XCTestCase { wait(for: [importExpectation], timeout: TimeInterval(20)) if let newPrefId = keys.first { UserManager.storeUserValue(newPrefId as AnyObject, attribute: .prefSecretKeyID) - XCTAssertEqual(PersitentDataProvider.prefKeyID, newPrefId) + XCTAssertEqual(PersistentDataProvider.prefKeyID, newPrefId) } else { XCTFail("No pref. sk!") @@ -609,12 +609,12 @@ class CryptoTests: XCTestCase { func testMail(from: AddressProperties, to: [AddressProperties], body: String, encState: EncryptionState, sigState: SignatureState) -> MailProperties { let subject = "Test mail" - let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil) + let folder = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder", parent: nil, children: nil, flags: 0) - let mail = MailProperties(messageID: "dasdads", subject: subject, date: Date(), flags: 0, from: from, to: to, cc: [], bcc: [], folder: folder, body: body, attachments: [], signatureState: sigState.rawValue, encryptionState: encState.rawValue, signatureKey: nil, decryptionKey: nil, autocryptHeaderKey: [], attachedPublicKeys: [], attachedSecretKeys: []) + let mail = MailProperties(messageID: "dasdads", uid: UInt64(arc4random()), subject: subject, date: Date(), flags: 0, from: from, to: to, cc: [], bcc: [], folder: folder, body: body, attachments: [], signatureState: sigState.rawValue, encryptionState: encState.rawValue, signatureKey: nil, decryptionKey: nil, autocryptHeaderKey: [], attachedPublicKeys: [], attachedSecretKeys: []) let importExpectation = expectation(description: "Import email") - PersitentDataProvider.dataProvider.importNewData(from: [mail], completionHandler: {error in + PersistentDataProvider.dataProvider.importNewData(from: [mail], completionHandler: {error in if let error = error { XCTFail("Error while importing addresses! \(error)") } @@ -650,7 +650,7 @@ class CryptoTests: XCTestCase { // Create test Mail _ = testMail(from: AddressProperties(email: "sender@example.com"),to: [user], body: cipher, encState: .UnableToDecrypt, sigState: .NoSignature) - let controller = PersitentDataProvider.dataProvider.generateFetchedUnableToDecryptMailsResultsController() + let controller = PersistentDataProvider.dataProvider.generateFetchedUnableToDecryptMailsResultsController() do { try controller.performFetch() } @@ -770,7 +770,7 @@ class CryptoTests: XCTestCase { } let model = KeyManagementModel() XCTAssertEqual(model.storedKeys.count, 1) - let skController = PersitentDataProvider.dataProvider.fetchedSecretKeyResultsController + let skController = PersistentDataProvider.dataProvider.fetchedSecretKeyResultsController XCTAssertEqual(skController.fetchedObjects?.count, 0) for key in model.storedKeys { key.password = CryptoTests.importPW @@ -779,7 +779,5 @@ class CryptoTests: XCTestCase { sleep(10) try? skController.performFetch() XCTAssertEqual(skController.fetchedObjects?.count, 1) - - } } diff --git a/enzevalos_iphoneTests/GeneratedMocks.swift b/enzevalos_iphoneTests/GeneratedMocks.swift index 90fd44ce27f9cb8e4141339f0d7a08a2c7135541..7c8e9c91e1d1e7a3a136c78a1b58b39eaa07d191 100644 --- a/enzevalos_iphoneTests/GeneratedMocks.swift +++ b/enzevalos_iphoneTests/GeneratedMocks.swift @@ -1,4 +1,4 @@ -// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2021-03-15 16:18:38 +0000 +// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2021-04-10 11:01:02 +0000 // // AuthenticationModel.swift @@ -654,7 +654,7 @@ import Foundation } -// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2021-03-15 16:18:38 +0000 +// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2021-04-10 11:01:02 +0000 // // AuthenticationViewModel.swift diff --git a/enzevalos_iphoneTests/MailTest.swift b/enzevalos_iphoneTests/MailTest.swift index 0e6a2b95e0ca7cfff9b4c918f7fd03e704d2110e..8172340ff7612b115f65eb5508321e325656c455 100644 --- a/enzevalos_iphoneTests/MailTest.swift +++ b/enzevalos_iphoneTests/MailTest.swift @@ -50,7 +50,7 @@ What about errors and special cases? @testable import enzevalos_iphone class MailTest: XCTestCase { - let dataprovider = PersitentDataProvider.dataProvider + let dataprovider = PersistentDataProvider.dataProvider let mailHandler = LetterboxModel.instance.mailHandler let pgp = SwiftPGP() let userAdr = "bob@enzevalos.de" @@ -86,7 +86,7 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== """ private func deleteAll() { - let provider = PersitentDataProvider() + let provider = PersistentDataProvider() let deleteExpectation = expectation(description: "Delete all data!") provider.deleteAll(completionHandler: {error in if let error = error { @@ -115,7 +115,6 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== } private func storeAndTestMail(mails: [IncomingMail], testFunc: (_ mail: MailRecord) -> ()) { - let oldmails = dataprovider.fetchedMailResultsController.fetchedObjects?.count ?? 0 let importExpectation = expectation(description: "Import new email!") dataprovider.importNewData(from: mails.map({$0.export()}), completionHandler: { error in if let error = error { @@ -143,7 +142,7 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== let bccs = ["bcc1@example.com"] let subject = "subject" let body = "This is the body" - let outMail = OutgoingMail(toEntrys: tos, ccEntrys: ccs, bccEntrys: bccs, subject: subject, textContent: body, htmlContent: nil) + let outMail = OutgoingMail(toAddresses: tos, ccAddresses: ccs, bccAddresses: bccs, subject: subject, textContent: body, htmlContent: nil) if let data = outMail.plainData { // Test parsing! let incMail = IncomingMail(rawData: data, uID: 0, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) @@ -182,7 +181,7 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== https certs will be valid – Microsoft signed. """ body = body.replacingOccurrences(of: "\n", with: "\r\n") - let outMail = OutgoingMail(toEntrys: tos, ccEntrys: ccs, bccEntrys: bccs, subject: subject, textContent: body, htmlContent: nil) + let outMail = OutgoingMail(toAddresses: tos, ccAddresses: ccs, bccAddresses: bccs, subject: subject, textContent: body, htmlContent: nil) if let data = outMail.plainData { // Test parsing! let incMail = IncomingMail(rawData: data, uID: 0, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) @@ -200,7 +199,7 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== let subject = "subject" let body = "body" _ = createPGPUser(adr: encAdr, name: encAdr) - let outMail = OutgoingMail(toEntrys: [userAdr], ccEntrys: [], bccEntrys: [], subject: subject, textContent: body, htmlContent: nil) + let outMail = OutgoingMail(toAddresses: [userAdr], ccAddresses: [], bccAddresses: [], subject: subject, textContent: body, htmlContent: nil) if let data = outMail.pgpData{ let incMail = IncomingMail(rawData: data, uID: 1, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) let b = incMail.export().body @@ -222,7 +221,7 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== let subject = "subject" let body = "body" _ = createPGPUser(adr: encAdr, name: encAdr) - let outMail = OutgoingMail(toEntrys: [plainAdr, userAdr], ccEntrys: [], bccEntrys: [], subject: subject, textContent: body, htmlContent: nil) + let outMail = OutgoingMail(toAddresses: [plainAdr, userAdr], ccAddresses: [], bccAddresses: [], subject: subject, textContent: body, htmlContent: nil) if let data = outMail.pgpData { let incMail = IncomingMail(rawData: data, uID: 2, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) storeAndTestMail(mails: [incMail], testFunc: {mail in @@ -275,11 +274,11 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== func receiveImportKeyMail(file: String, keyID: String, pw: String?, encMail: Bool, attached: Bool = false){ let bundle = Bundle(for: type(of: self)) if let url = bundle.url(forResource: file, withExtension: "asc"), let keyData = try? Data(contentsOf: url), let body = String(data: keyData, encoding: .utf8) { - var mail = OutgoingMail(toEntrys: [userAdr], ccEntrys: [], bccEntrys: [], subject: "New secret key", textContent: body, htmlContent: nil) + var mail = OutgoingMail(toAddresses: [userAdr], ccAddresses: [], bccAddresses: [], subject: "New secret key", textContent: body, htmlContent: nil) if attached, let attachment = MCOAttachment(data: keyData, filename: "secretKey.asc") { attachment.mimeType = "" attachment.charset = "UTF-8" - mail = OutgoingMail(toEntrys: [userAdr], ccEntrys: [], bccEntrys: [], subject: "New attached secret key", textContent: MailTest.body, htmlContent: nil, textparts: 0, sendEncryptedIfPossible: false, attachments: [attachment]) + mail = OutgoingMail(toAddresses: [userAdr], ccAddresses: [], bccAddresses: [], subject: "New attached secret key", textContent: MailTest.body, htmlContent: nil, textparts: 0, sendEncryptedIfPossible: false, attachments: [attachment]) } var data = mail.plainData if encMail { @@ -401,7 +400,7 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== let mailData = MailTest.loadMail(name: "signedSMIMEfromMac") let incMail = IncomingMail(rawData: mailData, uID: 4, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) storeAndTestMail(mails: [incMail], testFunc: {mail in - print("\(mail.subject) \(mail.encryptionState) \(mail.signatureState) keyid: \(mail.signatureKeyID)") + print("\(mail.subject) \(mail.encryptionState) \(mail.signatureState) keyid: \(String(describing: mail.signatureKeyID))") XCTAssertEqual(mail.encryptionState, .NoEncryption) XCTAssertEqual(mail.signatureState, .ValidSignature) }) @@ -428,7 +427,7 @@ n1O3czuVl7rPXrJn0A/MVI2ReKOQeIAYMg== } let incMail = IncomingMail(rawData: mailData, uID: 4, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) storeAndTestMail(mails: [incMail], testFunc: {mail in - print("\(mail.subject) \(mail.encryptionState) \(mail.signatureState) keyid: \(mail.signatureKeyID)") + print("\(mail.subject) \(mail.encryptionState) \(mail.signatureState) keyid: \(String(describing: mail.signatureKeyID))") if let sig = sigState, sig == .ValidSignature{ XCTAssertEqual(mail.signatureKey?.fingerprint, alice) } diff --git a/enzevalos_iphoneTests/SMIMEMailTest.swift b/enzevalos_iphoneTests/SMIMEMailTest.swift index 3388bf5f673ef3495e84a965bb1bec5508f2b77c..cc136f61b182caed92b671753f6963c9c6a90e22 100644 --- a/enzevalos_iphoneTests/SMIMEMailTest.swift +++ b/enzevalos_iphoneTests/SMIMEMailTest.swift @@ -334,7 +334,7 @@ OxeGuSvQoBUdP50ZspBBrf2+simuJLKMQ8kVXx8TuJqXe1FQPvFWDX5lBAf57BET PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO -----END ENCRYPTED PRIVATE KEY----- """ - let provider = PersitentDataProvider() + let provider = PersistentDataProvider() var userAdr = "bob@enzevalos.de" @@ -401,7 +401,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO let fp = smimeObj.importCertForAddress(cert: test_key_other, addr: otherAddr) let createExpectation = expectation(description: "Create public key record!") let property = PublicKeyProperties(fingerprint: fp, cryptoProtocol: .SMIME, origin: .FileTransfer, preferEncryption: nil, lastSeenInAutocryptHeader: nil, lastSeenSignedMail: nil, secretKeyProperty: nil, usedAddresses: [AddressProperties(email: otherAddr)]) - PersitentDataProvider.dataProvider.importNewData(from: [property], completionHandler: {error in + PersistentDataProvider.dataProvider.importNewData(from: [property], completionHandler: {error in if let error = error { XCTFail("Error while creating a new key: \(error)") } @@ -412,7 +412,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO } func testCreateEncSMIMEMail() { - let mail = OutgoingMail(toEntrys: [userAdr], ccEntrys: [], bccEntrys: [], subject: "encrypted smime mail", textContent: "Hello world", htmlContent: nil) + let mail = OutgoingMail(toAddresses: [userAdr], ccAddresses: [], bccAddresses: [], subject: "encrypted smime mail", textContent: "Hello world", htmlContent: nil) guard let data = mail.createEncSMIMEData() else { XCTFail("No signed mail...") return @@ -429,7 +429,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO func testCreateSignedSMIMEMail() { - let mail = OutgoingMail(toEntrys: [otherAddr], ccEntrys: [], bccEntrys: [], subject: "signed smime mail", textContent: "Hello world", htmlContent: nil) + let mail = OutgoingMail(toAddresses: [otherAddr], ccAddresses: [], bccAddresses: [], subject: "signed smime mail", textContent: "Hello world", htmlContent: nil) guard let data = mail.createSignedSMIMEData() else { XCTFail("No signed mail...") return diff --git a/enzevalos_iphoneTests/SMIMETests.swift b/enzevalos_iphoneTests/SMIMETests.swift index 033b57fadea80cca4a3b91dfdd70595ecafac1ff..dffc57907894444f4b3a06f3093515529fa817b7 100644 --- a/enzevalos_iphoneTests/SMIMETests.swift +++ b/enzevalos_iphoneTests/SMIMETests.swift @@ -433,8 +433,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO XCTFail("Could not sign!") } - //if let signedData = signObj?.chiphertext { - if let signedData = signObj?.chiphertext, let signedText = signObj?.chiperString { + if let _ = signObj?.chiphertext, let signedText = signObj?.chiperString { let text = signedText let verifiedObj = smimeObj.verify(data: nil, string: text, email: ourAddr!, isMailNew: true) diff --git a/enzevalos_iphoneTests/phishing/MailComparisonTests.swift b/enzevalos_iphoneTests/phishing/MailComparisonTests.swift index bf017274fd92f27d75eb83b4951c143e9354b0be..2d54cdaa7c0475cbf1202d6c05d782b4a844d604 100644 --- a/enzevalos_iphoneTests/phishing/MailComparisonTests.swift +++ b/enzevalos_iphoneTests/phishing/MailComparisonTests.swift @@ -26,7 +26,7 @@ class MailComparisonTests: XCTestCase { var user_3_2 = AddressProperties(email: "david@1234.com", name: "david") private func deleteAll() { - let provider = PersitentDataProvider() + let provider = PersistentDataProvider() let deleteExpectation = expectation(description: "Delete all data!") provider.deleteAll(completionHandler: {error in if let error = error { @@ -51,7 +51,7 @@ class MailComparisonTests: XCTestCase { super.tearDown() } - func testMail(from: AddressProperties, to: [AddressProperties], cc: [AddressProperties], bcc: [AddressProperties], flags: MCOMessageFlag = MCOMessageFlag.init(rawValue: 0), folder: FolderProperties = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Inbox", parent: nil, children: nil), date: Date = Date(timeIntervalSince1970: TimeInterval(arc4random())), cryptoObject: CryptoObject? = nil, body: String = String.random(length: 20)) -> MailProperties { + func testMail(from: AddressProperties, to: [AddressProperties], cc: [AddressProperties], bcc: [AddressProperties], flags: MCOMessageFlag = MCOMessageFlag.init(rawValue: 0), folder: FolderProperties = FolderProperties(delimiter: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Inbox", parent: nil, children: nil, flags: 0), date: Date = Date(timeIntervalSince1970: TimeInterval(arc4random())), cryptoObject: CryptoObject? = nil, body: String = String.random(length: 20)) -> MailProperties { let subject = String.random(length: 20) let id = UInt64(arc4random()) @@ -66,9 +66,9 @@ class MailComparisonTests: XCTestCase { if let decryptedBody = cryptoObject?.decryptedText { body = decryptedBody } - let mail = MailProperties(messageID: "\(id)", subject: subject, date: date, flags: Int16(flags.rawValue), from: from, to: to, cc: cc, bcc: bcc, folder: folder, body: body, attachments: [], signatureState: sigState.rawValue, encryptionState: encState.rawValue, signatureKey: nil, decryptionKey: nil, autocryptHeaderKey: [], attachedPublicKeys: [], attachedSecretKeys: []) + let mail = MailProperties(messageID: "\(id)", uid: UInt64(arc4random()), subject: subject, date: date, flags: Int16(flags.rawValue), from: from, to: to, cc: cc, bcc: bcc, folder: folder, body: body, attachments: [], signatureState: sigState.rawValue, encryptionState: encState.rawValue, signatureKey: nil, decryptionKey: nil, autocryptHeaderKey: [], attachedPublicKeys: [], attachedSecretKeys: []) - PersitentDataProvider.dataProvider.importNewData(from: [mail], completionHandler: { + PersistentDataProvider.dataProvider.importNewData(from: [mail], completionHandler: { error in print("Done!") })