From 7f22d1ff6d4fe708116542e1fcb6fb95dd768ba8 Mon Sep 17 00:00:00 2001
From: Oliver Wiese <oliver.wiese@fu-berlin.de>
Date: Thu, 5 Oct 2017 15:53:55 +0200
Subject: [PATCH] add new functions in mailhandler

---
 enzevalos_iphone/AppDelegate.swift            |   1 -
 .../Folder+CoreDataProperties.swift           |   2 +
 enzevalos_iphone/ListViewController.swift     |   4 +-
 enzevalos_iphone/MailHandler.swift            | 160 ++++++++++++------
 .../enzevalos_iphone.xcdatamodel/contents     |   3 +-
 5 files changed, 114 insertions(+), 56 deletions(-)

diff --git a/enzevalos_iphone/AppDelegate.swift b/enzevalos_iphone/AppDelegate.swift
index d2971e68..339fe456 100644
--- a/enzevalos_iphone/AppDelegate.swift
+++ b/enzevalos_iphone/AppDelegate.swift
@@ -202,7 +202,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 
     func presentInboxViewController() {
         let rootViewController = (self.window?.rootViewController! as! UINavigationController)
-        mailHandler.allContacts(inbox: "INBOX")
 
         for vc in rootViewController.viewControllers {
             if let id = vc.restorationIdentifier, id == "folderViewController" {
diff --git a/enzevalos_iphone/Folder+CoreDataProperties.swift b/enzevalos_iphone/Folder+CoreDataProperties.swift
index ca845025..e409429a 100644
--- a/enzevalos_iphone/Folder+CoreDataProperties.swift
+++ b/enzevalos_iphone/Folder+CoreDataProperties.swift
@@ -19,6 +19,8 @@ extension Folder {
     @NSManaged public var parent: Folder?
     @NSManaged public var mails: NSSet?
     @NSManaged public var path: String
+    @NSManaged public var lastUpdate: Date?
+
     @NSManaged public var delimiter: String
     public var flags: MCOIMAPFolderFlag{
         get {
diff --git a/enzevalos_iphone/ListViewController.swift b/enzevalos_iphone/ListViewController.swift
index 150c8b6b..872d6a37 100644
--- a/enzevalos_iphone/ListViewController.swift
+++ b/enzevalos_iphone/ListViewController.swift
@@ -52,7 +52,7 @@ class ListViewController: UITableViewController {
             self.title = contact!.name
             if contact!.mails.count < 20 {
                 loading = true
-                AppDelegate.getAppDelegate().mailHandler.loadMoreMails(contact!, folderPath: UserManager.backendInboxFolderPath, newMailCallback: addNewMail, completionCallback: doneLoading)
+                AppDelegate.getAppDelegate().mailHandler.loadMailsForRecord(contact!, folderPath: UserManager.backendInboxFolderPath, newMailCallback: addNewMail, completionCallback: doneLoading)
             }
         }
     }
@@ -211,7 +211,7 @@ class ListViewController: UITableViewController {
         if y > h + reload_distance && !loading {
             print("loading new mail because we scrolled to the bottom")
             loading = true
-            AppDelegate.getAppDelegate().mailHandler.loadMoreMails(contact!, folderPath: UserManager.backendInboxFolderPath, newMailCallback: addNewMail, completionCallback: doneLoading)
+            AppDelegate.getAppDelegate().mailHandler.loadMailsForRecord(contact!, folderPath: UserManager.backendInboxFolderPath, newMailCallback: addNewMail, completionCallback: doneLoading)
             tableView.reloadData()
         }
     }
diff --git a/enzevalos_iphone/MailHandler.swift b/enzevalos_iphone/MailHandler.swift
index f9b6721a..9f023a20 100644
--- a/enzevalos_iphone/MailHandler.swift
+++ b/enzevalos_iphone/MailHandler.swift
@@ -133,7 +133,7 @@ class MailHandler {
 
     var delegate: MailHandlerDelegator?
 
-    fileprivate static let MAXMAILS: UInt32 = 50
+    fileprivate static let MAXMAILS = 25
 
     fileprivate let concurrentMailServer = DispatchQueue(label: "com.enzevalos.mailserverQueue", attributes: DispatchQueue.Attributes.concurrent)
 
@@ -372,7 +372,6 @@ class MailHandler {
     }
 
     func startIMAPIdleIfSupported(addNewMail: @escaping (() -> ())) {
-        return
         if let supported = IMAPIdleSupported {
             if supported && IMAPIdleSession == nil {
                 IMAPIdleSession = setupIMAPSession()
@@ -385,7 +384,8 @@ class MailHandler {
 
                     print("Something happened while idleing!")
                     self.IMAPIdleSession = nil
-                    self.receiveAll(newMailCallback: addNewMail, completionCallback: { _ in self.startIMAPIdleIfSupported(addNewMail: addNewMail) })
+                    //self.receiveAll(newMailCallback: addNewMail, completionCallback: { _ in self.startIMAPIdleIfSupported(addNewMail: addNewMail) })
+                    self.initInbox(inbox: "Inbox", newMailCallback: addNewMail, completionCallback: { _ in self.startIMAPIdleIfSupported(addNewMail: addNewMail) })
                 })
             }
         } else {
@@ -461,7 +461,7 @@ class MailHandler {
             self.loadMessagesFromServer(uids, folderPath: folderPath, record: nil, newMailCallback: newMailCallback, completionCallback: completionCallback)
         
         }*/
-        completionCallback(true)
+        self.initInbox(inbox: folderPath, newMailCallback: newMailCallback, completionCallback: completionCallback)
         return
         getUIDs(for: folderPath) {allUIDs in
             let loadUIDs = allUIDs.suffix(Int(MailHandler.MAXMAILS))
@@ -524,7 +524,7 @@ class MailHandler {
         }
     }
 
-    private func loadMessagesFromServer(_ uids: MCOIndexSet, folderPath: String, maxLoad: UInt32 = MailHandler.MAXMAILS,record: KeyRecord?, newMailCallback: @escaping (() -> ()), completionCallback: @escaping ((_ error: Bool) -> ())) {
+    private func loadMessagesFromServer(_ uids: MCOIndexSet, folderPath: String, maxLoad: Int = MailHandler.MAXMAILS,record: KeyRecord?, newMailCallback: @escaping (() -> ()), completionCallback: @escaping ((_ error: Bool) -> ())) {
         let requestKind = MCOIMAPMessagesRequestKind(rawValue: MCOIMAPMessagesRequestKind.headers.rawValue | MCOIMAPMessagesRequestKind.flags.rawValue)
 
         let fetchOperation: MCOIMAPFetchMessagesOperation = self.IMAPSession.fetchMessagesOperation(withFolder: folderPath, requestKind: requestKind, uids: uids)
@@ -536,7 +536,7 @@ class MailHandler {
                 completionCallback(true)
                 return
             }
-            var calledMails: UInt32 = 0
+            var calledMails = 0
             if let msgs = msg {
                 let dispatchGroup = DispatchGroup()
                 for m in msgs.reversed() {
@@ -722,35 +722,6 @@ class MailHandler {
     }
 
 
-    func findMaxUID(_ folder: String, callback: @escaping ((_ maxUID: UInt64) -> ())) {
-        //TODO: NSP!!!
-        var maxUID: UInt64 = 0
-        let requestKind = MCOIMAPMessagesRequestKind(rawValue: MCOIMAPMessagesRequestKind.headers.rawValue)
-        let uids = MCOIndexSet(range: MCORangeMake(1, UINT64_MAX))
-        let dispatchGroup = DispatchGroup()
-        dispatchGroup.enter()
-
-        let fetchOperation: MCOIMAPFetchMessagesOperation = self.IMAPSession.fetchMessagesOperation(withFolder: folder, requestKind: requestKind, uids: uids)
-        fetchOperation.start { (err, msg, vanished) -> Void in
-            guard err == nil else {
-                print("Error while fetching inbox: \(String(describing: err))")
-                return
-            }
-            if let msgs = msg {
-                for m in msgs {
-                    let message: MCOIMAPMessage = m as! MCOIMAPMessage
-                    let id = UInt64(message.uid)
-                    if id > maxUID {
-                        maxUID = id
-                    }
-                }
-            }
-            dispatchGroup.leave()
-        }
-        dispatchGroup.notify(queue: DispatchQueue.main) {
-            callback(maxUID)
-        }
-    }
     
     func getUIDs(for folderPath: String, callback: @escaping ((_ uids: [UInt64]) -> ())) {
         //TODO: NSP!!!
@@ -829,11 +800,6 @@ class MailHandler {
         }
     }
     
-    /*func delete(mails: [PersistentMail]) {
-        for mail in mails {
-            DataHandler.handler.deleteMail(with: mail.uid)
-        }
-    }*/
     
     func allFolders(_ completion: @escaping (Error?, [Any]?) -> Void){
     
@@ -842,29 +808,119 @@ class MailHandler {
     }
     
     
-    func initInbox(inbox: String, newMailCallback: @escaping (() -> ()),completionCallback: @escaping ((Bool) -> ()) ){
-        let searchExp = MCOIMAPSearchExpression.search(since: Calendar.current.date(byAdding: .month, value: -1, to: Date()))
-        let searchOperation = self.IMAPSession.searchExpressionOperation(withFolder: inbox, expression: searchExp)
+    func initFolder(folderPath: String, newMailCallback: @escaping (() -> ()),completionCallback: @escaping ((Bool) -> ())){
+        let requestKind = MCOIMAPMessagesRequestKind(rawValue: MCOIMAPMessagesRequestKind.headers.rawValue)
+        let uids = MCOIndexSet(range: MCORangeMake(1, UINT64_MAX))
+        let toFetchIDs  = MCOIndexSet()
         
-        searchOperation?.start{(err, uids)-> Void in
-            guard err == nil else{
-                print("Error while searching inbox: \(String(describing: err))")
+        let fetchOperation: MCOIMAPFetchMessagesOperation = self.IMAPSession.fetchMessagesOperation(withFolder: folderPath, requestKind: requestKind, uids: uids)
+        fetchOperation.start { (err, msg, vanished) -> Void in
+            guard err == nil else {
+                print("Error while fetching inbox: \(String(describing: err))")
+                completionCallback(true)
                 return
             }
-            if let ids = uids{
-                self.loadMessagesFromServer(ids, folderPath: inbox, maxLoad: 500, record: nil, newMailCallback: newMailCallback, completionCallback: completionCallback)
+            if let msgs = msg {
+                let folder = DataHandler.handler.findFolder(with: folderPath)
+                folder.lastUpdate = Date()
+                for m in msgs {
+                    if let message = m as? MCOIMAPMessage{
+                        toFetchIDs.add(UInt64(message.uid))
+                    }
+                }
+                self.loadMessagesFromServer(toFetchIDs, folderPath: folderPath, maxLoad: 300, record: nil, newMailCallback: newMailCallback, completionCallback: completionCallback)
             }
+            else{
+                completionCallback(true)
+            }
+        }
+    }
+    
+    /*
+     
+     We call mails of the last month (at most 500)
+     */
+    func initInbox(inbox: String, newMailCallback: @escaping (() -> ()),completionCallback: @escaping ((Bool) -> ()) ){
+        if let date = Calendar.current.date(byAdding: .month, value: -1, to: Date()){
+            loadMailsSinceDate(folderpath: inbox, since: date, newMailCallback: newMailCallback, completionCallback: completionCallback)
+        }
+        else{
+            initFolder(folderPath: inbox, newMailCallback: newMailCallback, completionCallback: completionCallback)
         }
+        
     }
     
+    func updateFolder(folderpath: String, newMailCallback: @escaping (() -> ()),completionCallback: @escaping ((Bool) -> ())){
+        let folder = DataHandler.handler.findFolder(with: folderpath)
+        if let date = folder.lastUpdate{
+            loadMailsSinceDate(folderpath: folderpath, since: date, newMailCallback: newMailCallback, completionCallback: completionCallback)
+        }
+        else{
+            initFolder(folderPath: folderpath, newMailCallback: newMailCallback, completionCallback: completionCallback)
+        }
+    }
     
+    func olderMails(folderpath: String, newMailCallback: @escaping (() -> ()),completionCallback: @escaping ((Bool) -> ())){
+        let folder = DataHandler.handler.findFolder(with: folderpath)
+        if let mails = folder.mails{
+            var oldestDate:Date?
+            for m in mails{
+                if let mail = m as? PersistentMail{
+                    if oldestDate == nil || mail.date < oldestDate{
+                        oldestDate = mail.date
+                    }
+                }
+            }
+            if let date = oldestDate{
+                let searchExp = MCOIMAPSearchExpression.search(before: date)
+                let searchOperation = self.IMAPSession.searchExpressionOperation(withFolder: folderpath, expression: searchExp)
+                
+                searchOperation?.start{(err, uids)-> Void in
+                    guard err == nil else{
+                        print("Error while searching inbox: \(String(describing: err))")
+                        completionCallback(true)
+                        return
+                    }
+                    if let ids = uids{
+                        let folder = DataHandler.handler.findFolder(with: folderpath)
+                        folder.lastUpdate = Date()
+                        self.loadMessagesFromServer(ids, folderPath: folderpath, record: nil, newMailCallback: newMailCallback, completionCallback: completionCallback)
+                    }
+                    else{
+                        completionCallback(true)
+                    }
+                }
+            }
+            else{
+                initFolder(folderPath: folderpath, newMailCallback: newMailCallback, completionCallback: completionCallback)
+            }
+        }
+        else{
+            initFolder(folderPath: folderpath, newMailCallback: newMailCallback, completionCallback: completionCallback)
+        }
     
-    private func finish(){
-            print("All contacts loaded!")
     }
     
-    private func com(b: Bool){
-        print("All contacts loaded!")
+    
+    private func loadMailsSinceDate(folderpath: String, since: Date, maxLoad: Int = MailHandler.MAXMAILS, newMailCallback: @escaping (() -> ()),completionCallback: @escaping ((Bool) -> ())){
+        let searchExp = MCOIMAPSearchExpression.search(since: since)
+        let searchOperation = self.IMAPSession.searchExpressionOperation(withFolder: folderpath, expression: searchExp)
         
+        searchOperation?.start{(err, uids)-> Void in
+            guard err == nil else{
+                print("Error while searching inbox: \(String(describing: err))")
+                completionCallback(true)
+                return
+            }
+            if let ids = uids{
+                let folder = DataHandler.handler.findFolder(with: folderpath)
+                folder.lastUpdate = Date()
+                self.loadMessagesFromServer(ids, folderPath: folderpath, maxLoad: maxLoad, record: nil, newMailCallback: newMailCallback, completionCallback: completionCallback)
+            }
+            else{
+                completionCallback(true)
+            }
+        }
+
     }
 }
diff --git a/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents b/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents
index c2565491..434ff284 100644
--- a/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents
+++ b/enzevalos_iphone/enzevalos_iphone.xcdatamodeld/enzevalos_iphone.xcdatamodel/contents
@@ -18,6 +18,7 @@
         <attribute name="delimiter" optional="YES" attributeType="String" syncable="YES"/>
         <attribute name="flags" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
         <attribute name="lastID" optional="YES" attributeType="Decimal" defaultValueString="1" syncable="YES"/>
+        <attribute name="lastUpdate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
         <attribute name="maxID" optional="YES" attributeType="Decimal" defaultValueString="1" syncable="YES"/>
         <attribute name="path" attributeType="String" syncable="YES"/>
         <relationship name="mails" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PersistentMail" inverseName="folder" inverseEntity="PersistentMail" syncable="YES"/>
@@ -82,7 +83,7 @@
     <elements>
         <element name="Account" positionX="-288" positionY="-9" width="128" height="150"/>
         <element name="EnzevalosContact" positionX="-209" positionY="198" width="128" height="90"/>
-        <element name="Folder" positionX="-297" positionY="-18" width="128" height="150"/>
+        <element name="Folder" positionX="-297" positionY="-18" width="128" height="165"/>
         <element name="Mail_Address" positionX="-297" positionY="-18" width="128" height="150"/>
         <element name="PersistentKey" positionX="-315" positionY="-36" width="128" height="180"/>
         <element name="PersistentMail" positionX="-416" positionY="-189" width="128" height="315"/>
-- 
GitLab