From ebe0fa8dbe2475614fa09505e96da58e8517f940 Mon Sep 17 00:00:00 2001
From: Oliver Wiese <oliver.wiese@fu-berlin.de>
Date: Tue, 15 Aug 2017 14:51:31 +0200
Subject: [PATCH] update keyrecords

---
 enzevalos_iphone/AddressHandler.swift         |   9 +-
 enzevalos_iphone/DataHandler.swift            | 120 +++++++++++++---
 enzevalos_iphone/Folder+CoreDataClass.swift   |  72 ++--------
 enzevalos_iphone/KeyRecord.swift              | 134 ++++++------------
 enzevalos_iphone/MailAddress.swift            |   3 +-
 .../PersistentMail +CoreDataProperties.swift  |   2 +-
 enzevalos_iphone/Record.swift                 |   4 -
 enzevalos_iphone/SendViewController.swift     |   2 +-
 enzevalos_iphone/UserData.swift               |  16 +--
 9 files changed, 178 insertions(+), 184 deletions(-)

diff --git a/enzevalos_iphone/AddressHandler.swift b/enzevalos_iphone/AddressHandler.swift
index af8b9850..749d64e3 100644
--- a/enzevalos_iphone/AddressHandler.swift
+++ b/enzevalos_iphone/AddressHandler.swift
@@ -162,7 +162,7 @@ class AddressHandler {
                 }
             }
             catch {
-                print("exception")
+                print("exception in contact IN")
             }
         } else {
             print("no Access!")
@@ -172,6 +172,9 @@ class AddressHandler {
 
 
     static func getContact(_ name: String) -> [CNContact] {
+        if name == ""{
+            return []
+        }
         AppDelegate.getAppDelegate().requestForAccess({ access in })
         let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts)
         if authorizationStatus == CNAuthorizationStatus.authorized {
@@ -180,7 +183,7 @@ class AddressHandler {
                 return conList
             }
             catch {
-                print("exception")
+                print("exception in contacts get for name: \(name)")
             }
         } else {
             print("no Access!")
@@ -199,7 +202,7 @@ class AddressHandler {
                 return conList
             }
             catch {
-                print("exception")
+                print("exception in contacts")
             }
         } else {
             print("no Access!")
diff --git a/enzevalos_iphone/DataHandler.swift b/enzevalos_iphone/DataHandler.swift
index 975e88a4..d1d28893 100644
--- a/enzevalos_iphone/DataHandler.swift
+++ b/enzevalos_iphone/DataHandler.swift
@@ -37,6 +37,7 @@ fileprivate func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
 //TODO: TO Felder mit Strings
 // KeyRecord mergen?? IMAP Snyc?
 
+typealias requestTuple = (request: String, value: Any)
 
 class DataHandler {
     static let handler: DataHandler = DataHandler()
@@ -46,6 +47,8 @@ class DataHandler {
     private let MaxRecords = 50
     private let MaxMailsPerRecord = 100
     
+    
+    
     var allFolders: [Folder]{
         get{
             var folders = [Folder]()
@@ -90,8 +93,93 @@ class DataHandler {
             done(false)
         }
     }
+    
+    
+    func allAddressesInFolder(folder: Folder, withoutSecure: Bool) -> [MailAddress]{
+        let fReq = NSFetchRequest<NSFetchRequestResult>(entityName: "PersistentMail")
+        fReq.predicate = NSPredicate(format: "folder = %@", folder)
+       // fReq.resultType = NSFetchRequestResultType.dictionaryResultType
+        fReq.propertiesToFetch = ["from"]
+        //fReq.returnsDistinctResults = true
+        var addresses = Set<Mail_Address>()
+        //TODO: improve https://stackoverflow.com/questions/24432895/swift-core-data-request-with-distinct-results#24433996
+        
+        if let result = (try? self.managedObjectContext.fetch(fReq)) as? [PersistentMail]{
+            for object in result {
+                if let adr = object.from as? Mail_Address{
+                    if !(withoutSecure && object.isSecure){
+                        addresses.insert(adr)
+                    }
+                }
+           }
+        }
+        return Array(addresses)
+    }
+    
+    func allKeysInFolder(folder: Folder) -> [String]{
+        let fReq = NSFetchRequest<NSFetchRequestResult>(entityName: "PersistentMail")
+        var predicates = [NSPredicate]()
+        predicates.append(NSPredicate(format: "folder = %@", folder))
+        predicates.append(NSPredicate(format: "keyID != nil"))
+        let andPredicates = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
+        
+        fReq.predicate = andPredicates
+        // fReq.resultType = NSFetchRequestResultType.dictionaryResultType
+        fReq.propertiesToFetch = ["keyID"]
+        // Add KEYID CONTAINS -!
+        //fReq.returnsDistinctResults = true
+        var keys = Set<String>()
+        //TODO: improve https://stackoverflow.com/questions/24432895/swift-core-data-request-with-distinct-results#24433996
+        
+        if let result = (try? self.managedObjectContext.fetch(fReq)) as? [PersistentMail]{
+            print("Key not empty! \(result.count)")
+            for object in result {
+                if let key = object.keyID{
+                    if object.isSecure && key != ""{
+                        keys.insert(key)
+                        print("My key: \(key)")
+                    }
+                }
+            }
+        }
+        print("#keys: \(keys.count)")
+        return Array(keys)
+    }
+    
+    
+    func allMailsInFolder(key :String?, contact :EnzevalosContact?, folder: Folder?, isSecure: Bool) -> [PersistentMail]{
+        let fReq = NSFetchRequest<NSFetchRequestResult>(entityName: "PersistentMail")
+        var predicates = [NSPredicate]()
+        if let k = key{
+            predicates.append(NSPredicate(format:"keyID MATCHES %@", k))
+        }
+        if let c = contact{
+            let adr: Mail_Address =   c.getMailAddresses()[0] as! Mail_Address
+            predicates.append(NSPredicate(format:"from == %@", adr))
+            
+        }
+        if let f = folder{
+            predicates.append(NSPredicate(format:"folder == %@", f))
+        }
+        let andPredicates = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
 
-
+        fReq.predicate = andPredicates
+        fReq.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
+        if let result = (try? self.managedObjectContext.fetch(fReq)) as? [PersistentMail]{
+            
+            if isSecure{
+                let secureMails = result.filter({
+                    return $0.isSecure
+                })
+                return secureMails
+            }
+            
+            return result
+        }
+        return []
+    }
+        
+  
     init() {
         // This resource is the same name as your xcdatamodeld contained in your project.
         guard let modelURL = Bundle.main.url(forResource: "enzevalos_iphone", withExtension: "momd") else {
@@ -362,6 +450,7 @@ class DataHandler {
             return contact
         }
 
+        
 
         func getContact(_ name: String, address: String, key: String, prefer_enc: Bool) -> EnzevalosContact {
             let contact = getContactByAddress(address)
@@ -436,13 +525,6 @@ class DataHandler {
         
         if let tmpMails = finding as? [PersistentMail] {
             mails = tmpMails
-            print(mails)
-        }
-        if uid == 2 {
-            print(sender)
-            print(time)
-            print(subject)
-            print(body)
         }
         
         if finding == nil || finding!.count == 0 || mails.filter( { $0.folder.path == folderPath }).count == 0 {
@@ -468,14 +550,11 @@ class DataHandler {
                 handleCCAddresses(cc, mail: mail)
 
                 mail.unableToDecrypt = false
-                if decryptedData == nil{
-                    // Maybe PGPInline?
-                    // TODO: Refactoring!
-                    mail.decryptIfPossible()
-                }
-                else{
-                    let encState: EncryptionState = (decryptedData?.encryptionState)!
-                    let signState: SignatureState = (decryptedData?.signatureState)!
+            
+                if let decData = decryptedData{
+                    let encState: EncryptionState = decData.encryptionState
+                    let signState: SignatureState = decData.signatureState
+                    mail.keyID = decData.keyID
                     
                     switch encState {
                     case EncryptionState.NoEncryption:
@@ -505,6 +584,12 @@ class DataHandler {
                     }
                     mail.decryptedBody = body
                     print("Mail from \(mail.from.mailAddress) about \(String(describing: mail.subject)) has states: enc: \(mail.isEncrypted) and sign: \(mail.isSigned), correct signed: \(mail.isCorrectlySigned) has troubles:\(mail.trouble) and is secure? \(mail.isSecure) unable to decrypt? \(mail.unableToDecrypt)")
+            
+                }
+                else{
+                    // Maybe PGPInline?
+                    // TODO: Refactoring!
+                    mail.decryptIfPossible()
                 }
             }
             else {
@@ -523,9 +608,6 @@ class DataHandler {
 
 
             save()
-            if let r = record {
-                _ = r.addNewMail(mail)
-            }
         }
 
         private func readMails() -> [PersistentMail] {
diff --git a/enzevalos_iphone/Folder+CoreDataClass.swift b/enzevalos_iphone/Folder+CoreDataClass.swift
index 5537c3bd..15a4aada 100644
--- a/enzevalos_iphone/Folder+CoreDataClass.swift
+++ b/enzevalos_iphone/Folder+CoreDataClass.swift
@@ -41,15 +41,22 @@ public class Folder: NSManagedObject {
     var liveRecords: [KeyRecord]{
         get{
             var records = [KeyRecord]()
-            let mails = self.mailsOfFolder
-            for m in mails {
-                addToRecords(m, records: &records)
+            // Get all Keys, get all 
+            let keys = DataHandler.handler.allKeysInFolder(folder: self)
+            let adrs = DataHandler.handler.allAddressesInFolder(folder: self, withoutSecure: true)
+            
+            for key in keys{
+                let record = KeyRecord(keyID: key, folder: self)
+                records.append(record)
             }
-            for r in records {
-                r.mails.sort()
+            for adr in adrs{
+                if let ec = adr.contact{
+                    let record = KeyRecord(contact: ec, folder: self)
+                    records.append(record)
+                }
+
             }
-            records.sort()
-            print("Folder: \(self.name) with #KeyRecords: \(records.count) and \(mails.count) mails")
+            
             return records
         }
     }
@@ -80,57 +87,6 @@ public class Folder: NSManagedObject {
         }
     }
     
-    private func addToRecords(_ m: PersistentMail, records: inout [KeyRecord]) {
-        
-        var found = false
-        for r in records {
-            if r.addNewMail(m) {
-                found = true
-                records.sort()
-                break
-            }
-        }
-        if !found {
-            let r = KeyRecord(mail: m)
-            mergeRecords(newRecord: r, records: &records)
-            records.append(r)
-            records.sort()
-        }
-    }
-    
-    
-    private func mergeRecords(newRecord: KeyRecord, records: inout[KeyRecord]) {
-        var j = 0
-        if !newRecord.hasKey {
-            return
-        }
-        while j < records.count {
-            let r = records[j]
-            if !r.hasKey && r.ezContact == newRecord.ezContact {
-                var i = 0
-                while i < r.mails.count {
-                    let mail = r.mails[i]
-                    var remove = false
-                    if mail.from.keyID == newRecord.key {
-                        remove = newRecord.addNewMail(mail)
-                        if remove {
-                            r.mails.remove(at: i)
-                        }
-                    }
-                    if !remove {
-                        i = i + 1
-                    }
-                }
-                if r.mails.count == 0 {
-                    records.remove(at: j)
-                } else {
-                    j = j + 1
-                }
-            } else {
-                j = j + 1
-            }
-        }
-    }
     
     //write value of liveRecords to records
     func updateRecords() {
diff --git a/enzevalos_iphone/KeyRecord.swift b/enzevalos_iphone/KeyRecord.swift
index fca1e605..88e2abbf 100644
--- a/enzevalos_iphone/KeyRecord.swift
+++ b/enzevalos_iphone/KeyRecord.swift
@@ -19,8 +19,21 @@ open class KeyRecord: Record {
      */
 
     let key: String?
+    
+    let folder: Folder
+    
+    open var mails: [PersistentMail] {
+        get{
+            return mailsInFolder(folder: folder)
+        }
+    }
 
-    open var addresses: [MailAddress] = [MailAddress]()
+    open var addresses: [MailAddress] {
+        if let adr = ezContact.addresses{
+            return Array(adr) as! [MailAddress]
+        }
+        return []
+    }
 
     open var name: String {
         return ezContact.name
@@ -42,10 +55,6 @@ open class KeyRecord: Record {
         return false
     }
 
-
-    open var mails: [PersistentMail] = [PersistentMail]()
-
-
     open var ezContact: EnzevalosContact
 
     open var cnContact: CNContact? {
@@ -60,57 +69,47 @@ open class KeyRecord: Record {
     }
 
 
-    public init(mail: PersistentMail) {
-        self.isSecure = mail.isSecure
-        if(mail.isSecure && mail.from.hasKey) {
-            self.key = mail.from.keyID
-        }
-        else {
-            self.key = nil
+    public init(keyID: String?, contact: EnzevalosContact, folder: Folder) {
+        key = keyID
+        ezContact = contact
+        self.folder = folder
+        if key != nil{
+            isSecure = true
         }
-        mails.append(mail)
-        mails.sort()
-        self.ezContact = mail.from.contact!
-        _ = addNewAddress(mail.from)
     }
-
-    open static func deleteRecordFromRecordArray(_ records: [KeyRecord], delRecord: KeyRecord) -> [KeyRecord] {
-        var myrecords = [KeyRecord](records)
-        let index = indexInRecords(myrecords, record: delRecord)
-        if index >= 0 {
-            myrecords.remove(at: index)
-        }
-        return myrecords
+    
+    public init(contact: EnzevalosContact, folder: Folder){
+        key = nil
+        ezContact = contact
+        self.folder = folder
+        isSecure = false
     }
-
-    open static func indexInRecords(_ records: [KeyRecord], record: KeyRecord) -> Int {
-        for (index, r) in records.enumerated() {
-            if (matchAddresses(r, record2: record) && r.hasKey == record.hasKey && r.key == record.key) {
-                return index
+    
+    public init (keyID: String, folder: Folder){
+        key = keyID
+        self.folder = folder
+        isSecure = true
+        let mails = DataHandler.handler.allMailsInFolder(key: keyID, contact: nil, folder: folder, isSecure: isSecure)
+        if mails.count > 0{
+            if let c = mails[0].from.contact{
+                ezContact = c
+            }
+            else{
+                ezContact = DataHandler.handler.getContact("", address: "", key: "", prefer_enc: false)
             }
         }
-        return -1
-    }
-
-    private func isInRecords(_ records: [KeyRecord]) -> Bool {
-        if KeyRecord.indexInRecords(records, record: self) >= 0 {
-            return true
+        else{
+            ezContact = DataHandler.handler.getContact("", address: "", key: "", prefer_enc: false)
         }
-        return false
     }
+    
 
-
-    private static func matchAddresses(_ record1: KeyRecord, record2: KeyRecord) -> Bool {
-        for adr1 in record1.addresses {
-            for adr2 in record2.addresses {
-                if adr1.mailAddress == adr2.mailAddress {
-                    return true
-                }
-            }
-        }
-        return false
+    
+    func mailsInFolder(folder: Folder?) -> [PersistentMail]{
+        return DataHandler.handler.allMailsInFolder(key: key, contact: ezContact, folder: folder, isSecure: isSecure)
     }
 
+   
 
 
 
@@ -121,49 +120,6 @@ open class KeyRecord: Record {
         print("subj: \(String(describing: mails.first?.subject?.capitalized))")
     }
 
-    open func addNewAddress(_ adr: MailAddress) -> Bool {
-        for a in addresses {
-            if a.mailAddress == adr.mailAddress {
-                return false
-            }
-        }
-        addresses.append(adr)
-        return true
-    }
-
-    open func addNewMail(_ mail: PersistentMail) -> Bool {
-        // TODO: signed only mails are dropped ??
-        if mail.isSecure && self.isSecure {
-            if mail.from.keyID == self.key {
-                mails.append(mail)
-                mails.sort()
-                _ = addNewAddress(mail.from)
-                return true
-            }
-            return false
-
-        }
-        else if mail.isSecure != self.isSecure {
-            return false
-        }
-
-        if ezContact.getAddress(mail.from.mailAddress) != nil {
-            for m in mails {
-                if m.uid == mail.uid {
-                    return true
-                }
-                    else if m.uid < mail.uid {
-                    break
-                }
-            }
-            mails.append(mail)
-            mails.sort()
-            _ = addNewAddress(mail.from)
-            return true
-        }
-        return false
-    }
-
     open func getImageOrDefault() -> UIImage {
         return ezContact.getImageOrDefault()
     }
diff --git a/enzevalos_iphone/MailAddress.swift b/enzevalos_iphone/MailAddress.swift
index 4067663e..fd1b0a91 100644
--- a/enzevalos_iphone/MailAddress.swift
+++ b/enzevalos_iphone/MailAddress.swift
@@ -64,7 +64,7 @@ public enum EncState {
 
 }
 
-public protocol MailAddress { 
+public protocol MailAddress {
     var mailAddress:String{get}
     var label: CNLabeledValue<NSString>{get} //FIXME: ist der NSString hier wirklich richtig? (http://stackoverflow.com/questions/39648830/how-to-add-new-email-to-cnmutablecontact-in-swift-3)
     var prefEnc: EncState{get set}
@@ -73,3 +73,4 @@ public protocol MailAddress {
     var keyID: String?{get}
     var contact: EnzevalosContact?{get}
 }
+
diff --git a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift
index 1cc95d50..6098b58a 100644
--- a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift	
+++ b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift	
@@ -46,7 +46,7 @@ extension PersistentMail {
     @NSManaged public var isEncrypted: Bool
     @NSManaged public var isSigned: Bool
     @NSManaged public var isCorrectlySigned: Bool
-    @NSManaged public var keyID: String
+    @NSManaged public var keyID: String?
     @NSManaged public var unableToDecrypt: Bool
     @NSManaged public var subject: String?
     @NSManaged public var folder: Folder
diff --git a/enzevalos_iphone/Record.swift b/enzevalos_iphone/Record.swift
index 7da8e203..8484dfbf 100644
--- a/enzevalos_iphone/Record.swift
+++ b/enzevalos_iphone/Record.swift
@@ -22,8 +22,4 @@ public protocol Record: Comparable {
     var color: UIColor { get }
     var image: UIImage { get }
     var addresses: [MailAddress] { get }
-
-
-    func addNewAddress(_ adr: MailAddress) -> Bool
-    func addNewMail(_ mail:PersistentMail) -> Bool
 }
diff --git a/enzevalos_iphone/SendViewController.swift b/enzevalos_iphone/SendViewController.swift
index 47506801..d7f2f98d 100644
--- a/enzevalos_iphone/SendViewController.swift
+++ b/enzevalos_iphone/SendViewController.swift
@@ -351,7 +351,7 @@ class SendViewController: UIViewController {
                 tableview.reloadData()
             }
             catch {
-                print("exception")
+                print("exception in contacts search")
             }
         } else {
             print("no Access!")
diff --git a/enzevalos_iphone/UserData.swift b/enzevalos_iphone/UserData.swift
index 539baec6..ad7a70b3 100644
--- a/enzevalos_iphone/UserData.swift
+++ b/enzevalos_iphone/UserData.swift
@@ -40,8 +40,8 @@ enum Attribute: Int{
         case .imapAuthType:
             return MCOAuthType.saslPlain.rawValue as AnyObject?
         case .smtpConnectionType:
-             return MCOConnectionType.TLS.rawValue as AnyObject?//startTLS.rawValue
-            //return MCOConnectionType.startTLS.rawValue as AnyObject?//startTLS.rawValue
+             //return MCOConnectionType.TLS.rawValue as AnyObject?//startTLS.rawValue
+            return MCOConnectionType.startTLS.rawValue as AnyObject?//startTLS.rawValue
         case .sentFolderPath:
             return NSLocalizedString("Sent", comment: "Default name for the sentFolder") as AnyObject?
         case .draftFolderPath:
@@ -62,8 +62,8 @@ enum Attribute: Int{
     }
     
     static let allAttributes = [accountname, userName, userAddr, userPW, smtpHostname, smtpPort, imapHostname, imapPort, prefEncryption, publicKey, autocryptType]
-    //static var name = "Alice2005@web.de"//"Ullimuelle@web.de"
-    //static var pw = "WJ$CE:EtUo3E$"//"dun3bate"
+    static var name = "Alice2005@web.de"//"Ullimuelle@web.de"
+    static var pw = "WJ$CE:EtUo3E$"//"dun3bate"
     
     //static let name = "Ullimuelle@web.de"
     //static let pw =  "dun3bate"
@@ -71,11 +71,11 @@ enum Attribute: Int{
    // static let pw = "VagotOshaicceov"
    // static let name = "alice"
     //static let pw = "egOavOpeecOntew"
-    static let name = "charlie"
-    static let pw = "tydpawdAwIdPyuc"
+    //static let name = "charlie"
+    //static let pw = "tydpawdAwIdPyuc"
     static var attributeValues:
-    //[Attribute : AnyObject?] = [.accountname : name as AnyObject?, .userName : name as Optional<AnyObject>, .userAddr : name as Optional<AnyObject>, .userPW : pw as Optional<AnyObject>, .smtpHostname : "smtp.web.de" as Optional<AnyObject>, .smtpPort : 587 as Optional<AnyObject>, .imapHostname : "imap.web.de" as Optional<AnyObject>, .imapPort : 993 as AnyObject?, .prefEncryption : "yes" as AnyObject?, .autocryptType : "p" as AnyObject?, .publicKey : "" as AnyObject?]
-        [Attribute : AnyObject?] = [.accountname : name as AnyObject?, .userName : name as Optional<AnyObject>, .userAddr : name+"@enzevalos.de" as Optional<AnyObject>, .userPW : pw as Optional<AnyObject>, .smtpHostname : "mail.enzevalos.de" as Optional<AnyObject>, .smtpPort : 465 as Optional<AnyObject>, .imapHostname : "mail.enzevalos.de" as Optional<AnyObject>, .imapPort : 993 as AnyObject?, .prefEncryption : "yes" as AnyObject?, .autocryptType : "p" as AnyObject?, .publicKey : "" as AnyObject?]
+    [Attribute : AnyObject?] = [.accountname : name as AnyObject?, .userName : name as Optional<AnyObject>, .userAddr : name as Optional<AnyObject>, .userPW : pw as Optional<AnyObject>, .smtpHostname : "smtp.web.de" as Optional<AnyObject>, .smtpPort : 587 as Optional<AnyObject>, .imapHostname : "imap.web.de" as Optional<AnyObject>, .imapPort : 993 as AnyObject?, .prefEncryption : "yes" as AnyObject?, .autocryptType : "p" as AnyObject?, .publicKey : "" as AnyObject?]
+        //[Attribute : AnyObject?] = [.accountname : name as AnyObject?, .userName : name as Optional<AnyObject>, .userAddr : name+"@enzevalos.de" as Optional<AnyObject>, .userPW : pw as Optional<AnyObject>, .smtpHostname : "mail.enzevalos.de" as Optional<AnyObject>, .smtpPort : 465 as Optional<AnyObject>, .imapHostname : "mail.enzevalos.de" as Optional<AnyObject>, .imapPort : 993 as AnyObject?, .prefEncryption : "yes" as AnyObject?, .autocryptType : "p" as AnyObject?, .publicKey : "" as AnyObject?]
     
 
 }
-- 
GitLab