diff --git a/EnzevalosContact+CoreDataClass.swift b/EnzevalosContact+CoreDataClass.swift index e2fe6f8440a6c4ab4f9f80bcca656a129e6edd5f..7ee748fd03621548dc5e459f333952c442be981c 100644 --- a/EnzevalosContact+CoreDataClass.swift +++ b/EnzevalosContact+CoreDataClass.swift @@ -147,30 +147,10 @@ open class EnzevalosContact: NSManagedObject, Contact, Comparable { open var records: [KeyRecord] { get { - var myrecords = [KeyRecord]() - - let insecureRecord = KeyRecord(contact: self, folder: nil) - myrecords.append(insecureRecord) - - if self.hasKey{ - if self.isAddress(mailadr: UserManager.loadUserValue(Attribute.userAddr) as! String){ - // consider secret keys - let userKeys = DataHandler.handler.findSecretKeys() - for sk in userKeys{ - let secureRecord = KeyRecord(keyID: sk.keyID!, contact: self, folder:nil) - if !myrecords.contains(secureRecord){ - myrecords.append(secureRecord) - } - } - } - for pk in publicKeys{ - let secureRecord = KeyRecord(keyID: pk.keyID, contact: self, folder: nil) - if !myrecords.contains(secureRecord){ - myrecords.append(secureRecord) - } - } - } - return myrecords + if let krecords = self.keyrecords as? Set<KeyRecord>{ + return Array(krecords) + } + return [] } } diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 3047c266b7b62a9a6a9431b37249251661763556..574666c75483ce54e05554feae8bf7b864c08341 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -249,8 +249,6 @@ 472F398C1E2519C8009260FB /* CNContactExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472F398B1E2519C8009260FB /* CNContactExtension.swift */; }; 472F398E1E251B8D009260FB /* MailAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472F398D1E251B8D009260FB /* MailAddress.swift */; }; 472F39901E252470009260FB /* CNMailAddressesExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472F398F1E252470009260FB /* CNMailAddressesExtension.swift */; }; - 4739019520348BCB00DF25F4 /* Record+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4739019320348BCB00DF25F4 /* Record+CoreDataClass.swift */; }; - 4739019620348BCB00DF25F4 /* Record+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4739019420348BCB00DF25F4 /* Record+CoreDataProperties.swift */; }; 473AC39320054D07006EB8A6 /* PGPUserAttributeImageSubpacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 473AC39120054D06006EB8A6 /* PGPUserAttributeImageSubpacket.m */; }; 473AC39420054D07006EB8A6 /* PGPUserAttributeImageSubpacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 473AC39120054D06006EB8A6 /* PGPUserAttributeImageSubpacket.m */; }; 473AC39720054D29006EB8A6 /* NSArray+PGPUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 473AC39620054D29006EB8A6 /* NSArray+PGPUtils.m */; }; @@ -288,6 +286,8 @@ 47CD5AAB2012368D00E771A1 /* bitcoinde.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47CD5AA92012368D00E771A1 /* bitcoinde.asc */; }; 47CD5AAD2012369400E771A1 /* support_pk.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47CD5AAC2012369300E771A1 /* support_pk.asc */; }; 47D1302B1F7CEE6D007B14DF /* DebugSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47D1302A1F7CEE6D007B14DF /* DebugSettings.swift */; }; + 47F79240203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F7923E203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift */; }; + 47F79241203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F7923F203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift */; }; 5DC190F2042BE7D956F796BE /* Pods_enzevalos_iphone_AdHoc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1F4458FC892EBE555836F55 /* Pods_enzevalos_iphone_AdHoc.framework */; }; 8428A8531F4369C0007649A5 /* Gamification.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8428A8521F4369C0007649A5 /* Gamification.storyboard */; }; 8428A8551F4369CF007649A5 /* GamificationElements.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8428A8541F4369CF007649A5 /* GamificationElements.xcassets */; }; @@ -543,8 +543,6 @@ 472F398B1E2519C8009260FB /* CNContactExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CNContactExtension.swift; sourceTree = "<group>"; }; 472F398D1E251B8D009260FB /* MailAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MailAddress.swift; sourceTree = "<group>"; }; 472F398F1E252470009260FB /* CNMailAddressesExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CNMailAddressesExtension.swift; sourceTree = "<group>"; }; - 4739019320348BCB00DF25F4 /* Record+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Record+CoreDataClass.swift"; sourceTree = "<group>"; }; - 4739019420348BCB00DF25F4 /* Record+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Record+CoreDataProperties.swift"; sourceTree = "<group>"; }; 473AC39120054D06006EB8A6 /* PGPUserAttributeImageSubpacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGPUserAttributeImageSubpacket.m; sourceTree = "<group>"; }; 473AC39220054D07006EB8A6 /* PGPUserAttributeImageSubpacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PGPUserAttributeImageSubpacket.h; sourceTree = "<group>"; }; 473AC39520054D29006EB8A6 /* NSArray+PGPUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+PGPUtils.h"; sourceTree = "<group>"; }; @@ -586,6 +584,8 @@ 47CD5AA92012368D00E771A1 /* bitcoinde.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = bitcoinde.asc; path = keys/bitcoinde.asc; sourceTree = "<group>"; }; 47CD5AAC2012369300E771A1 /* support_pk.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = support_pk.asc; path = keys/support_pk.asc; sourceTree = "<group>"; }; 47D1302A1F7CEE6D007B14DF /* DebugSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugSettings.swift; sourceTree = "<group>"; }; + 47F7923E203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyRecord+CoreDataClass.swift"; sourceTree = "<group>"; }; + 47F7923F203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyRecord+CoreDataProperties.swift"; sourceTree = "<group>"; }; 48FB10FF406523D174F4202A /* Pods_enzevalos_iphoneUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_enzevalos_iphoneUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4AE42F42E91A1BFBF1D5BF6A /* Pods_enzevalos_iphone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_enzevalos_iphone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 66E758F271CD65AB3E5FE7A7 /* Pods-enzevalos_iphoneUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphoneUITests.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphoneUITests/Pods-enzevalos_iphoneUITests.debug.xcconfig"; sourceTree = "<group>"; }; @@ -984,8 +984,8 @@ 47B91AC01EC0C1CF000AE3EE /* coredata */ = { isa = PBXGroup; children = ( - 4739019320348BCB00DF25F4 /* Record+CoreDataClass.swift */, - 4739019420348BCB00DF25F4 /* Record+CoreDataProperties.swift */, + 47F7923E203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift */, + 47F7923F203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift */, 475B00401F7BB6D6006CDD41 /* PersistentKey+CoreDataClass.swift */, 475B00411F7BB6D6006CDD41 /* PersistentKey+CoreDataProperties.swift */, 472F39781E1D0B0B009260FB /* PersistentMail +CoreDataProperties.swift */, @@ -2020,7 +2020,6 @@ 472F39861E1FA34E009260FB /* Record.swift in Sources */, 471BC9101F960B7C00D64416 /* PGPPacket.m in Sources */, 471BC9281F960B7C00D64416 /* PGPKeyID.m in Sources */, - 4739019620348BCB00DF25F4 /* Record+CoreDataProperties.swift in Sources */, 471BC9311F960B7C00D64416 /* NSData+compression.m in Sources */, A1C3270E1DB907D900CE2ED5 /* TextFormatter.swift in Sources */, 471BC91A1F960B7C00D64416 /* PGPSymmetricallyEncryptedDataPacket.m in Sources */, @@ -2081,6 +2080,7 @@ 471BC9241F960B7C00D64416 /* PGPFingerprint.m in Sources */, F1866C86201F707200B72453 /* EmailHelper.m in Sources */, 471BC9221F960B7C00D64416 /* PGPBigNum.m in Sources */, + 47F79241203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift in Sources */, A10DE4201EFAA2CE005E8189 /* FolderViewController.swift in Sources */, 473AC39720054D29006EB8A6 /* NSArray+PGPUtils.m in Sources */, 3EB4FA9F2012007C001D0625 /* DialogViewController.swift in Sources */, @@ -2123,7 +2123,7 @@ 37FE84A92028C40E001B7230 /* AuthStateDelegate.m in Sources */, 8428A85C1F436A05007649A5 /* ArrowView.swift in Sources */, A1EB05961D956939008659C1 /* InboxTableViewCell.swift in Sources */, - 4739019520348BCB00DF25F4 /* Record+CoreDataClass.swift in Sources */, + 47F79240203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift in Sources */, A1083A541E8BFEA6003666B7 /* Onboarding.swift in Sources */, A111F6AD1FA77B170060AFDE /* Logger.swift in Sources */, A13526791D955BDF00D3BFE1 /* AppDelegate.swift in Sources */, diff --git a/enzevalos_iphone/DataHandler.swift b/enzevalos_iphone/DataHandler.swift index d62c97a65c562c84f06b474bc700dc2002b802f6..c7cc45d05128fbf1cec55739bc5c7fbd728230a1 100644 --- a/enzevalos_iphone/DataHandler.swift +++ b/enzevalos_iphone/DataHandler.swift @@ -549,6 +549,46 @@ class DataHandler { } return false } + + func getKeyRecord(addr: String, keyID: String?) -> KeyRecord{ + if let id = keyID{ + if let key = findKey(keyID: id){ + if let record = key.record{ + return record + } + // Create KeyRecord + let record = NSEntityDescription.insertNewObject(forEntityName: "KeyRecord", into: managedObjectContext) as! KeyRecord + record.key = key + if let contact = getContact(keyID: id){ + record.contact = contact + } + else{ + record.contact = getContactByAddress(addr) + } + save(during: "create keyRecord with key") + return record + } + } + + if let address = findMailAddress(adr: addr){ + if let contact = address.contact{ + for record in contact.records{ + if !record.hasKey{ + for a in record.addresses{ + if a.mailAddress == addr{ + return record + } + } + } + } + } + } + // create KeyRecord + let record = NSEntityDescription.insertNewObject(forEntityName: "KeyRecord", into: managedObjectContext) as! KeyRecord + record.contact = getContactByAddress(addr) + save(during: "create keyRecord without key") + return record + } // -------- Handle mail addresses --------- func getMailAddress(_ address: String, temporary: Bool) -> MailAddress { @@ -842,11 +882,17 @@ class DataHandler { if mail.uid > myfolder.maxID { myfolder.maxID = mail.uid } - myfolder.updateRecords(mail: mail) + var record = getKeyRecord(addr: mail.from.mailAddress, keyID: nil) + if let signedID = mail.signedKey?.keyID{ + record = getKeyRecord(addr: mail.from.mailAddress, keyID: signedID) + } + record.addToPersistentMails(mail) + mail.folder.addToKeyRecords(record) save(during: "new mail") return mail } + private func readMails() -> [PersistentMail] { var mails = [PersistentMail]() let result = findAll("PersistentMail") @@ -858,6 +904,7 @@ class DataHandler { } return mails } + func getAddresses() -> [MailAddress] { var adrs = [MailAddress]() diff --git a/enzevalos_iphone/EnzevalosContact+CoreDataProperties.swift b/enzevalos_iphone/EnzevalosContact+CoreDataProperties.swift index 98fdf171399f34784d62812d673072e6540e2f34..c5f4d942a4543685e73eac57d31b8736a02eeb74 100644 --- a/enzevalos_iphone/EnzevalosContact+CoreDataProperties.swift +++ b/enzevalos_iphone/EnzevalosContact+CoreDataProperties.swift @@ -20,6 +20,7 @@ extension EnzevalosContact { @NSManaged public var cnidentifier: String? @NSManaged public var color: UIColor? @NSManaged public var addresses: NSSet + @NSManaged public var keyrecords: NSSet? } @@ -41,4 +42,21 @@ extension EnzevalosContact { } +// MARK: Generated accessors for mailaddress +extension EnzevalosContact { + + @objc(addKeyrecordsObject:) + @NSManaged public func addToKeyrecords(_ value: KeyRecord) + + @objc(removeKeyrecordsObject:) + @NSManaged public func removeFromKeyrecords(_ value: KeyRecord) + + @objc(addKeyrecords:) + @NSManaged public func addToKeyrecords(_ values: NSSet) + + @objc(removeKeyrecords:) + @NSManaged public func removeFromKeyrecords(_ values: NSSet) + +} + diff --git a/enzevalos_iphone/Folder+CoreDataClass.swift b/enzevalos_iphone/Folder+CoreDataClass.swift index 0a6524069ff443506f2bc8b69d4482f5a240e559..4d8e496a0daa0c8ae6aed6be0404dd006e9cf634 100644 --- a/enzevalos_iphone/Folder+CoreDataClass.swift +++ b/enzevalos_iphone/Folder+CoreDataClass.swift @@ -47,33 +47,14 @@ public class Folder: NSManagedObject { } } - private var liveRecords: [KeyRecord]{ - get{ - var records = [KeyRecord]() - for mail in mailsOfFolder{ - var found = false - for r in records{ - if r.matchMail(mail: mail){ - found = true - } - } - if !found{ - let record = KeyRecord(keyID: mail.keyID, contact: mail.from.contact!, folder: self) - records.append(record) - } - } - return records.sorted() - } - } - - private var storedRecords: [KeyRecord]? = nil - + + var records: [KeyRecord]{ get{ - if storedRecords == nil{ - updateRecords() + if let keyRecords = keyRecords as? Set<KeyRecord>{ + return Array(keyRecords).sorted() } - return storedRecords! + return [] } } @@ -106,11 +87,7 @@ public class Folder: NSManagedObject { } } - //write value of liveRecords to records - public func updateRecords() { - storedRecords = liveRecords - } - + /* func updateRecords(mail: PersistentMail){ if let reccords = storedRecords{ if reccords.count <= 2{ @@ -120,7 +97,7 @@ public class Folder: NSManagedObject { var founded = false for i in 1..<reccords.count { let r = reccords[i] - if r.matchMail(mail: mail){ + if r.match(mail: mail){ founded = true if r.mailsInFolder(folder: self).first == mail { if reccords[i-1] > r { @@ -164,4 +141,5 @@ public class Folder: NSManagedObject { } } } + */ } diff --git a/enzevalos_iphone/Folder+CoreDataProperties.swift b/enzevalos_iphone/Folder+CoreDataProperties.swift index 489d2702a088381396f6fd4c9d79ad9aac9db0f4..69c50246cee6a35a77cdef76c65fc3d48b68dec2 100644 --- a/enzevalos_iphone/Folder+CoreDataProperties.swift +++ b/enzevalos_iphone/Folder+CoreDataProperties.swift @@ -19,6 +19,7 @@ extension Folder { @NSManaged public var parent: Folder? @NSManaged public var subfolder: NSSet? @NSManaged public var mails: NSSet? + @NSManaged public var keyRecords: NSSet? @NSManaged public var path: String @NSManaged public var lastUpdate: Date? @NSManaged public var pseudonym: String @@ -98,6 +99,12 @@ extension Folder { @objc(removeSubfolderObject:) @NSManaged public func removeFromSubfolder(_ value: Folder) + + @objc(addKeyRecordsObject:) + @NSManaged public func addToKeyRecords(_ value: KeyRecord) + + @objc(removeKeyRecordsObject:) + @NSManaged public func removeFromKeyRecords(_ value: KeyRecord) @objc(addMails:) @NSManaged public func addToMails(_ values: NSSet) @@ -110,6 +117,12 @@ extension Folder { @objc(removeSubfolder:) @NSManaged public func removeFromSubfolder(_ values: NSSet) + + @objc(addKeyRecords:) + @NSManaged public func addToKeyRecords(_ values: NSSet) + + @objc(removeKeyRecords:) + @NSManaged public func removeFromKeyRecords(_ values: NSSet) } diff --git a/enzevalos_iphone/InboxViewController.swift b/enzevalos_iphone/InboxViewController.swift index 629de6694c28f6151f9facdf6d2db37094ade4a7..52e94098ec8c5dd0cf10c054657f7be9d3a867c7 100644 --- a/enzevalos_iphone/InboxViewController.swift +++ b/enzevalos_iphone/InboxViewController.swift @@ -73,6 +73,10 @@ class InboxViewController: UITableViewController, InboxCellDelegator { tableView.register(UINib(nibName: "InboxTableViewCell", bundle: nil), forCellReuseIdentifier: "inboxCell") AppDelegate.getAppDelegate().mailHandler.startIMAPIdleIfSupported(addNewMail: addNewMail) + NotificationCenter.default.addObserver(forName: Notification.Name.NSManagedObjectContextDidSave, object: nil, queue: nil, using: { + [weak self] notification in + self?.tableView.reloadData() + }) } func refresh(_ refreshControl: UIRefreshControl) { @@ -83,10 +87,7 @@ class InboxViewController: UITableViewController, InboxCellDelegator { } func addNewMail(mail: PersistentMail?) { - if let m = mail { - folder.updateRecords(mail: m) - } - tableView.reloadData() + //tableView.reloadData() } func getMailCompleted(_ error: Bool) { @@ -97,8 +98,7 @@ class InboxViewController: UITableViewController, InboxCellDelegator { rc.endRefreshing() lastUpdateText = lastUpdate != nil ? "\(NSLocalizedString("LastUpdate", comment: "When the last update occured")): \(dateFormatter.string(from: lastUpdate!))" : NSLocalizedString("NeverUpdated", comment: "No internet connection since last launch") - folder.updateRecords() - self.tableView.reloadData() + // self.tableView.reloadData() } } @@ -208,9 +208,10 @@ class InboxViewController: UITableViewController, InboxCellDelegator { DestinationViewController.keyRecord = record } else { let keyID = UserManager.loadUserValue(Attribute.prefSecretKeyID) as! String - let folderName = UserManager.backendInboxFolderPath - let folder = DataHandler.handler.findFolder(with: folderName) - DestinationViewController.keyRecord = KeyRecord(keyID: keyID, folder: folder) + let addr = UserManager.loadUserValue(Attribute.userAddr) as! String + //let folderName = UserManager.backendInboxFolderPath + //let folder = DataHandler.handler.findFolder(with: folderName) + DestinationViewController.keyRecord = DataHandler.handler.getKeyRecord(addr: addr, keyID: keyID) } } } @@ -240,14 +241,16 @@ class InboxViewController: UITableViewController, InboxCellDelegator { } if scope == 1 || scope == 3 { records += folder.records.filter({ ( record: KeyRecord) -> Bool in - return record.mails.filter({ (mail: PersistentMail) -> Bool in + let mails = record.inboxMails + return mails.filter({ (mail: PersistentMail) -> Bool in mail.subject?.lowercased().contains(searchText.lowercased()) ?? false }).count > 0 }) } if scope == 2 || scope == 3 { records += folder.records.filter({ ( record: KeyRecord) -> Bool in - return record.mails.filter({ (mail: PersistentMail) -> Bool in + let mails = record.inboxMails + return mails.filter({ (mail: PersistentMail) -> Bool in if let decryptedBody = mail.decryptedBody { return decryptedBody.lowercased().contains(searchText.lowercased()) } else if !mail.isEncrypted { diff --git a/enzevalos_iphone/KeyRecord+CoreDataClass.swift b/enzevalos_iphone/KeyRecord+CoreDataClass.swift new file mode 100644 index 0000000000000000000000000000000000000000..0c7a0feb520c17ddf1c366ad4a3839fcc171fa31 --- /dev/null +++ b/enzevalos_iphone/KeyRecord+CoreDataClass.swift @@ -0,0 +1,218 @@ +// +// KeyRecord+CoreDataClass.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 14.02.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// +// + +import Foundation +import CoreData +import Contacts +import UIKit + +@objc(KeyRecord) +public class KeyRecord: NSManagedObject, Record { + + + public var name: String{ + get{ + return self.ezContact.name + } + } + + public var hasKey: Bool{ + get{ + return key != nil + } + } + + public var isSecure: Bool{ + get{ + return hasKey + } + } + + public var isVerified: Bool{ + get{ + if let k = key{ + return k.isVerified() + } + return false + } + } + + public var keyID: String?{ + if let k = key{ + return k.keyID + } + return nil + } + + public var cryptoscheme: CryptoScheme{ + get{ + if let k = key{ + return k.encryptionType + } + return CryptoScheme.UNKNOWN + } + } + + public var fingerprint: String?{ + get{ + if let k = pgpKey{ + if let pk = k.publicKey{ + return pk.fingerprint.description() + } + else if let sk = k.secretKey{ + return sk.fingerprint.description() + } + return k.keyID.longIdentifier + } + return nil + } + } + + private var pgpKey: Key?{ + get{ + if let id = key?.keyID{ + let pgp = SwiftPGP() + return pgp.loadKey(id: id) + } + return nil + } + } + + public var ezContact: EnzevalosContact{ + get{ + return contact + } + } + + public var mails: [PersistentMail]{ + get{ + if let m = persistentMails as? Set<PersistentMail>{ + return Array(m).sorted() + } + return [] + } + } + + public var cnContact: CNContact?{ + get{ + return contact.cnContact + } + } + + public var color: UIColor{ + get{ + return contact.getColor() + } + } + + public var image: UIImage{ + get{ + return contact.getImageOrDefault() + + } + } + + public var addresses: [MailAddress]{ + get{ + if let k = key{ + if let addrs = k.mailaddress as? Set<Mail_Address>{ + return Array(addrs) + } + return [] + } + if let addrs = contact.addresses as? Set<Mail_Address>{ + return Array(addrs) + } + return [] + } + } + + var addressNames:[String]{ + get{ + let adrs = addresses + var names = [String]() + for adr in adrs{ + names.append(adr.mailAddress) + } + return names + } + } + + public func verify(){ + if let k = key{ + k.verify() + } + } + + public func match(mail: PersistentMail) -> Bool{ + if mail.folder == folder{ + if let recordFingerprint = fingerprint, let signedKey = mail.signedKey{ + let pgp = SwiftPGP() + if let key = pgp.loadKey(id: signedKey.keyID)?.publicKey{ + return key.fingerprint.description() == recordFingerprint + } + return false + } + if !hasKey && !mail.isSigned{ + for addr in addresses{ + if mail.from.mailAddress == addr.mailAddress{ + return true + } + } + return false + } + } + return false + } + + public func mailsInFolder(folder: Folder) -> [PersistentMail]{ + let folderMails = DataHandler.handler.allMailsInFolder(key: keyID, contact: ezContact, folder: folder, isSecure: isSecure) + return folderMails.sorted() + } + + + public var inboxMails: [PersistentMail]{ + get{ + let inbox = DataHandler.handler.findFolder(with: UserManager.backendInboxFolderPath) + return mailsInFolder(folder: inbox) + } + } + + +} + + +private func isEmpty(_ contact: KeyRecord) -> Bool { + return contact.mails.count == 0 +} + + +public func == (lhs: KeyRecord, rhs: KeyRecord) -> Bool { + if lhs.hasKey && rhs.hasKey{ + if let keyLHS = lhs.key, let keyRHS = rhs.key{ + return keyLHS.keyID == keyRHS.keyID + } + } + if lhs.hasKey != rhs.hasKey{ + return false + } + return lhs.contact == rhs.contact + //return lhs.mails.first!.date == rhs.mails.first!.date && lhs.hasKey == rhs.hasKey && lhs.keyID == rhs.keyID +} + +public func < (lhs: KeyRecord, rhs: KeyRecord) -> Bool { + if isEmpty(lhs) { + return true + } + if isEmpty(rhs) { + return false + } + return lhs.mails.first!.date > rhs.mails.first!.date +} + diff --git a/enzevalos_iphone/KeyRecord+CoreDataProperties.swift b/enzevalos_iphone/KeyRecord+CoreDataProperties.swift new file mode 100644 index 0000000000000000000000000000000000000000..f04abfc529a35a88aabf47b30123e5c016087521 --- /dev/null +++ b/enzevalos_iphone/KeyRecord+CoreDataProperties.swift @@ -0,0 +1,42 @@ +// +// KeyRecord+CoreDataProperties.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 14.02.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// +// + +import Foundation +import CoreData + + +extension KeyRecord { + + @nonobjc public class func fetchRequest() -> NSFetchRequest<KeyRecord> { + return NSFetchRequest<KeyRecord>(entityName: "KeyRecord") + } + + @NSManaged public var contact: EnzevalosContact + @NSManaged public var folder: Folder + @NSManaged public var key: PersistentKey? + @NSManaged public var persistentMails: NSSet? + +} + +// MARK: Generated accessors for persitentMails +extension KeyRecord { + + @objc(addPersistentMailsObject:) + @NSManaged public func addToPersistentMails(_ value: PersistentMail) + + @objc(removePersistentMailsObject:) + @NSManaged public func removeFromPersistentMails(_ value: PersistentMail) + + @objc(addPersistentMails:) + @NSManaged public func addToPersistentMails(_ values: NSSet) + + @objc(removePersistentMails:) + @NSManaged public func removeFromPersistentMails(_ values: NSSet) + +} diff --git a/enzevalos_iphone/KeyViewController.swift b/enzevalos_iphone/KeyViewController.swift index 64333150318dc3dea84849720f2fbcdfd5d60036..889c24bfc0e276d1098d42e6af2d44ae7ae1751a 100644 --- a/enzevalos_iphone/KeyViewController.swift +++ b/enzevalos_iphone/KeyViewController.swift @@ -118,7 +118,7 @@ extension KeyViewController: UITableViewDataSource { formatter.locale = Locale.current formatter.dateStyle = .medium formatter.timeStyle = .medium - if let discoveryDate = record?.storedKey?.discoveryDate{ + if let discoveryDate = record?.key?.discoveryDate{ cell.detailTextLabel?.text = formatter.string(from: discoveryDate as Date) } @@ -131,7 +131,7 @@ extension KeyViewController: UITableViewDataSource { } else if toRowType(indexPath) == .verified { let cell = tableView.dequeueReusableCell(withIdentifier: "VerifiedCell")! - cell.textLabel?.text = NSLocalizedString("KeyIsVerified", comment: "The Key is verified. The time when the Key was verified") + "\(String(describing: record?.storedKey?.verifiedDate))" + cell.textLabel?.text = NSLocalizedString("KeyIsVerified", comment: "The Key is verified. The time when the Key was verified") + "\(String(describing: record?.key?.verifiedDate))" return cell } else if toRowType(indexPath) == .revoked { @@ -167,7 +167,7 @@ extension KeyViewController: UITableViewDataSource { } func numberOfSections(in tableView: UITableView) -> Int { - if let key = record?.storedKey { + if let key = record?.key { var sections = 1 if key.mailaddress != nil{ sections += 1 @@ -203,7 +203,7 @@ extension KeyViewController: UITableViewDataSource { func toSectionType(_ sectionNumber: Int) -> KeyViewSectionType { var returnValue: KeyViewSectionType = .noKey - if record?.storedKey != nil { + if record?.key != nil { returnValue = .keyDetails//.KeyID //addresses if sectionNumber != 0 { @@ -216,7 +216,7 @@ extension KeyViewController: UITableViewDataSource { func toRowType(_ index: IndexPath) -> KeyViewRowType { var returnValue: KeyViewRowType = .noKey var row = index.row - if let key = record?.storedKey, toSectionType(index.section) == .keyDetails { + if let key = record?.key, toSectionType(index.section) == .keyDetails { returnValue = .keyID //Fingerprint if row != 0 { diff --git a/enzevalos_iphone/MailHandler.swift b/enzevalos_iphone/MailHandler.swift index 24e9de0e2e78997d9db1b7349db7fcd61be36b46..34f74ecc381ecdb9fa56a039fddcdd1be9f58084 100644 --- a/enzevalos_iphone/MailHandler.swift +++ b/enzevalos_iphone/MailHandler.swift @@ -1086,6 +1086,12 @@ class MailHandler { for mail in mails { 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) diff --git a/enzevalos_iphone/PersistentKey+CoreDataProperties.swift b/enzevalos_iphone/PersistentKey+CoreDataProperties.swift index 70fb66376809c077f686470c6afd0b29f2f9b5d3..65f0d6b0539ffc6340142516173a770ef6d57721 100644 --- a/enzevalos_iphone/PersistentKey+CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentKey+CoreDataProperties.swift @@ -26,7 +26,7 @@ extension PersistentKey { @NSManaged public var pseudonym: String @NSManaged public var sentOwnPublicKey: Bool @NSManaged public var signedMails: NSSet? - + @NSManaged public var record: KeyRecord? public var prefer_encryption: EncState{ set { @@ -95,3 +95,5 @@ extension PersistentKey { @NSManaged public func removeSignedMails(_ values: NSSet) } + + diff --git a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift index 5ef0ea99dd84f054ad7d7b4312cef6ff0d0d52d5..0ab76436677834b3b99bd6646e692c2bac292476 100644 --- a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift @@ -21,6 +21,8 @@ extension PersistentMail { @NSManaged public var decryptedBody: String? @NSManaged public var date: Date @NSManaged public var secretKey: String? + @NSManaged public var record: KeyRecord? + public var flag: MCOMessageFlag{ set { if newValue != flag{ diff --git a/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents b/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents index 17abb25b1f4fbc7b55ff4564f5b497dd9af37c74..5312b66fce41811ddcf402cf6cdf60fbbdb0cb2f 100644 --- a/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents +++ b/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents @@ -34,7 +34,7 @@ <attribute name="color" optional="YES" attributeType="Transformable" customClassName="UIColor" syncable="YES"/> <attribute name="displayname" attributeType="String" syncable="YES"/> <relationship name="addresses" toMany="YES" deletionRule="Nullify" destinationEntity="Mail_Address" inverseName="contact" inverseEntity="Mail_Address" syncable="YES"/> - <relationship name="keyrecords" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Record" inverseName="contact" inverseEntity="Record" syncable="YES"/> + <relationship name="keyrecords" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="KeyRecord" inverseName="contact" inverseEntity="KeyRecord" syncable="YES"/> </entity> <entity name="Folder" representedClassName="Folder" syncable="YES"> <attribute name="delimiter" optional="YES" attributeType="String" syncable="YES"/> @@ -45,11 +45,17 @@ <attribute name="path" attributeType="String" syncable="YES"/> <attribute name="pseudonym" attributeType="String" syncable="YES"/> <attribute name="uidvalidity" optional="YES" attributeType="Decimal" defaultValueString="0.0" syncable="YES"/> + <relationship name="keyRecords" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="KeyRecord" inverseName="folder" inverseEntity="KeyRecord" syncable="YES"/> <relationship name="mails" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PersistentMail" inverseName="folder" inverseEntity="PersistentMail" syncable="YES"/> <relationship name="parent" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Folder" inverseName="subfolder" inverseEntity="Folder" syncable="YES"/> - <relationship name="records" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="Record" inverseName="folder" inverseEntity="Record" syncable="YES"/> <relationship name="subfolder" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Folder" inverseName="parent" inverseEntity="Folder" syncable="YES"/> </entity> + <entity name="KeyRecord" representedClassName="KeyRecord" syncable="YES"> + <relationship name="contact" maxCount="1" deletionRule="Nullify" destinationEntity="EnzevalosContact" inverseName="keyrecords" inverseEntity="EnzevalosContact" syncable="YES"/> + <relationship name="folder" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Folder" inverseName="keyRecords" inverseEntity="Folder" syncable="YES"/> + <relationship name="key" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PersistentKey" inverseName="record" inverseEntity="PersistentKey" syncable="YES"/> + <relationship name="persistentMails" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PersistentMail" inverseName="record" inverseEntity="PersistentMail" syncable="YES"/> + </entity> <entity name="Mail_Address" representedClassName="Mail_Address" syncable="YES"> <attribute name="address" attributeType="String" defaultValueString="""" syncable="YES"/> <attribute name="invitations" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/> @@ -77,7 +83,7 @@ <attribute name="verifiedDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/> <relationship name="firstMail" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PersistentMail" inverseName="attachedKeys" inverseEntity="PersistentMail" syncable="YES"/> <relationship name="mailaddress" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Mail_Address" inverseName="keys" inverseEntity="Mail_Address" syncable="YES"/> - <relationship name="records" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Record" inverseName="key" inverseEntity="Record" syncable="YES"/> + <relationship name="record" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="KeyRecord" inverseName="key" inverseEntity="KeyRecord" syncable="YES"/> <relationship name="signedMails" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PersistentMail" inverseName="signedKey" inverseEntity="PersistentMail" syncable="YES"/> </entity> <entity name="PersistentMail" representedClassName="PersistentMail" syncable="YES"> @@ -110,7 +116,7 @@ <relationship name="decryptedKey" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SecretKey" inverseName="decryptedMails" inverseEntity="SecretKey" syncable="YES"/> <relationship name="folder" maxCount="1" deletionRule="Nullify" destinationEntity="Folder" inverseName="mails" inverseEntity="Folder" syncable="YES"/> <relationship name="from" maxCount="1" deletionRule="Nullify" destinationEntity="Mail_Address" inverseName="from" inverseEntity="Mail_Address" syncable="YES"/> - <relationship name="record" maxCount="1" deletionRule="Nullify" destinationEntity="Record" inverseName="mails" inverseEntity="Record" syncable="YES"/> + <relationship name="record" maxCount="1" deletionRule="Nullify" destinationEntity="KeyRecord" inverseName="persistentMails" inverseEntity="KeyRecord" syncable="YES"/> <relationship name="referenceMails" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PersistentMail" inverseName="referenceMails" inverseEntity="PersistentMail" syncable="YES"/> <relationship name="signedKey" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PersistentKey" inverseName="signedMails" inverseEntity="PersistentKey" syncable="YES"/> <relationship name="to" toMany="YES" deletionRule="Nullify" destinationEntity="Mail_Address" inverseName="to" inverseEntity="Mail_Address" syncable="YES"/> @@ -118,12 +124,6 @@ <fetchIndexElement property="date" type="Binary" order="ascending"/> </fetchIndex> </entity> - <entity name="Record" representedClassName="Record" syncable="YES" codeGenerationType="class"> - <relationship name="contact" maxCount="1" deletionRule="Nullify" destinationEntity="EnzevalosContact" inverseName="keyrecords" inverseEntity="EnzevalosContact" syncable="YES"/> - <relationship name="folder" maxCount="1" deletionRule="Nullify" destinationEntity="Folder" inverseName="records" inverseEntity="Folder" syncable="YES"/> - <relationship name="key" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PersistentKey" inverseName="records" inverseEntity="PersistentKey" syncable="YES"/> - <relationship name="mails" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PersistentMail" inverseName="record" inverseEntity="PersistentMail" syncable="YES"/> - </entity> <entity name="SecretKey" representedClassName="SecretKey" syncable="YES" codeGenerationType="class"> <attribute name="exported" optional="YES" attributeType="Boolean" usesScalarValueType="YES" syncable="YES"/> <attribute name="importedDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/> @@ -150,8 +150,8 @@ <element name="Mail_Address" positionX="-297" positionY="-18" width="128" height="210"/> <element name="PersistentKey" positionX="-315" positionY="-36" width="128" height="270"/> <element name="PersistentMail" positionX="-416" positionY="-189" width="128" height="540"/> + <element name="KeyRecord" positionX="-315" positionY="-36" width="128" height="105"/> <element name="SecretKey" positionX="-306" positionY="-27" width="128" height="135"/> <element name="Server" positionX="-306" positionY="-27" width="128" height="135"/> - <element name="Record" positionX="-315" positionY="-36" width="128" height="105"/> </elements> </model> \ No newline at end of file