From f9b8aa833dd1a8dddd24709a9c3ef2d9545b0ac6 Mon Sep 17 00:00:00 2001
From: Oliver Wiese <oliver.wiese@fu-berlin.de>
Date: Thu, 1 Oct 2020 17:20:40 +0200
Subject: [PATCH] new data model

---
 enzevalos_iphone.xcodeproj/project.pbxproj    |  62 +++-
 enzevalos_iphone/Certificate.swift            |   2 +-
 .../PersistentMail +CoreDataClass.swift       |   4 +-
 enzevalos_iphone/UserData.swift               |   2 +-
 .../persistentData/CoreAddress.swift          |  23 ++
 .../persistentData/CoreMail.swift             |  49 +++
 .../DataModel.xcdatamodel/contents            |  21 ++
 .../persistentData/DataProvider.swift         | 291 ++++++++++++++++++
 .../persistentData/PersistentDataError.swift  |  19 ++
 enzevalos_iphoneTests/CoreAddressTest.swift   |  36 +++
 enzevalos_iphoneTests/CoreMailTest.swift      |  56 ++++
 enzevalos_iphoneTests/GeneratedMocks.swift    |   4 +-
 12 files changed, 559 insertions(+), 10 deletions(-)
 create mode 100644 enzevalos_iphone/persistentData/CoreAddress.swift
 create mode 100644 enzevalos_iphone/persistentData/CoreMail.swift
 create mode 100644 enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents
 create mode 100644 enzevalos_iphone/persistentData/DataProvider.swift
 create mode 100644 enzevalos_iphone/persistentData/PersistentDataError.swift
 create mode 100644 enzevalos_iphoneTests/CoreAddressTest.swift
 create mode 100644 enzevalos_iphoneTests/CoreMailTest.swift

diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj
index 546e8bc7..aa519c40 100644
--- a/enzevalos_iphone.xcodeproj/project.pbxproj
+++ b/enzevalos_iphone.xcodeproj/project.pbxproj
@@ -194,6 +194,13 @@
 		47F867E02052B47C00AA832F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867DF2052B47C00AA832F /* Security.framework */; };
 		47F867E22052B48E00AA832F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867E12052B48E00AA832F /* libz.tbd */; };
 		47F867E42052B49800AA832F /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867E32052B49800AA832F /* libbz2.tbd */; };
+		47FAE3072524AA4B005A1BCB /* DataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3062524AA4B005A1BCB /* DataProvider.swift */; };
+		47FAE30E2524AA97005A1BCB /* DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE30C2524AA97005A1BCB /* DataModel.xcdatamodeld */; };
+		47FAE3122524BFDB005A1BCB /* PersistentDataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */; };
+		47FAE31C2524C07B005A1BCB /* CoreMail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE31B2524C07B005A1BCB /* CoreMail.swift */; };
+		47FAE3222524C1C0005A1BCB /* CoreMailTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3212524C1C0005A1BCB /* CoreMailTest.swift */; };
+		47FAE33F2524FAD3005A1BCB /* CoreAddressTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE33E2524FAD3005A1BCB /* CoreAddressTest.swift */; };
+		47FAE3492524FB58005A1BCB /* CoreAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3482524FB58005A1BCB /* CoreAddress.swift */; };
 		50F2E7D66366C779705987A7 /* Pods_enzevalos_iphoneUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF67EF30BB065CC9C0D17940 /* Pods_enzevalos_iphoneUITests.framework */; };
 		676C2D3024321F8100B631B3 /* TyposquattingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676C2D2F24321F8100B631B3 /* TyposquattingTests.swift */; };
 		6789425F2430C3B300C746D1 /* MailComparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6789425E2430C3B300C746D1 /* MailComparison.swift */; };
@@ -645,6 +652,13 @@
 		47F867DF2052B47C00AA832F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
 		47F867E12052B48E00AA832F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
 		47F867E32052B49800AA832F /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; };
+		47FAE3062524AA4B005A1BCB /* DataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataProvider.swift; sourceTree = "<group>"; };
+		47FAE30D2524AA97005A1BCB /* DataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DataModel.xcdatamodel; sourceTree = "<group>"; };
+		47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDataError.swift; sourceTree = "<group>"; };
+		47FAE31B2524C07B005A1BCB /* CoreMail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreMail.swift; sourceTree = "<group>"; };
+		47FAE3212524C1C0005A1BCB /* CoreMailTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreMailTest.swift; sourceTree = "<group>"; };
+		47FAE33E2524FAD3005A1BCB /* CoreAddressTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreAddressTest.swift; sourceTree = "<group>"; };
+		47FAE3482524FB58005A1BCB /* CoreAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreAddress.swift; sourceTree = "<group>"; };
 		48C250BB32BF11B683003BA1 /* Pods-enzevalos_iphone-enzevalos_iphoneUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone-enzevalos_iphoneUITests.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone-enzevalos_iphoneUITests/Pods-enzevalos_iphone-enzevalos_iphoneUITests.debug.xcconfig"; sourceTree = "<group>"; };
 		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>"; };
 		670159DF240FB4E800797FA5 /* enzevalos_iphone 9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "enzevalos_iphone 9.xcdatamodel"; sourceTree = "<group>"; };
@@ -1365,6 +1379,27 @@
 			path = private;
 			sourceTree = "<group>";
 		};
+		47FAE3052524AA30005A1BCB /* persistentData */ = {
+			isa = PBXGroup;
+			children = (
+				47FAE3062524AA4B005A1BCB /* DataProvider.swift */,
+				47FAE30C2524AA97005A1BCB /* DataModel.xcdatamodeld */,
+				47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */,
+				47FAE31B2524C07B005A1BCB /* CoreMail.swift */,
+				47FAE3482524FB58005A1BCB /* CoreAddress.swift */,
+			);
+			path = persistentData;
+			sourceTree = "<group>";
+		};
+		47FAE3202524C1A8005A1BCB /* PersistentDataTest */ = {
+			isa = PBXGroup;
+			children = (
+				47FAE3212524C1C0005A1BCB /* CoreMailTest.swift */,
+				47FAE33E2524FAD3005A1BCB /* CoreAddressTest.swift */,
+			);
+			name = PersistentDataTest;
+			sourceTree = "<group>";
+		};
 		6789425D2430C38800C746D1 /* Phishing */ = {
 			isa = PBXGroup;
 			children = (
@@ -1539,6 +1574,7 @@
 		A13526771D955BDF00D3BFE1 /* enzevalos_iphone */ = {
 			isa = PBXGroup;
 			children = (
+				47FAE3052524AA30005A1BCB /* persistentData */,
 				0EFEF0932417C08B00BB2FF7 /* C Helpers */,
 				6789425D2430C38800C746D1 /* Phishing */,
 				971D40482428C852002FCD31 /* gamification_2 */,
@@ -1585,6 +1621,7 @@
 		A135268F1D955BE000D3BFE1 /* enzevalos_iphoneTests */ = {
 			isa = PBXGroup;
 			children = (
+				47FAE3202524C1A8005A1BCB /* PersistentDataTest */,
 				0ED9072F24338E3C008CF9D0 /* SMIMETests.swift */,
 				71DF0896242151E200162B74 /* phishing */,
 				97C5279D241A9F690030BBC9 /* authentication */,
@@ -2264,6 +2301,7 @@
 				4775D7AC243F18BC0052F2CC /* SecurityBriefingView.swift in Sources */,
 				971D404A2428C87E002FCD31 /* BadgeCaseView.swift in Sources */,
 				47C8225B24379EAE005BCE73 /* MessageViewMain.swift in Sources */,
+				47FAE30E2524AA97005A1BCB /* DataModel.xcdatamodeld in Sources */,
 				8428A8651F436A11007649A5 /* BadgeCaseCollectionViewCell.swift in Sources */,
 				472F39811E1E5347009260FB /* Mail_Address+CoreDataClass.swift in Sources */,
 				A1EB05821D95685B008659C1 /* CollectionDataDelegate.swift in Sources */,
@@ -2331,6 +2369,7 @@
 				A1EB057A1D956829008659C1 /* ContactCell.swift in Sources */,
 				A12FC23120221A1400196008 /* ExportInfoViewController.swift in Sources */,
 				4751C6EE233CA583006B2A4D /* DateExtension.swift in Sources */,
+				47FAE31C2524C07B005A1BCB /* CoreMail.swift in Sources */,
 				477548DE21F5DABE000B22A8 /* MailServerConnectionError.swift in Sources */,
 				475DF47A1F0D54C9009D807F /* Folder+CoreDataProperties.swift in Sources */,
 				475B00431F7BB6D6006CDD41 /* PersistentKey+CoreDataProperties.swift in Sources */,
@@ -2350,6 +2389,7 @@
 				475B00421F7BB6D6006CDD41 /* PersistentKey+CoreDataClass.swift in Sources */,
 				A10DAA5721F37600005D8BBB /* IntroInfoButton.swift in Sources */,
 				47A2A57223599D180013883D /* FeedbackButtonHelper.swift in Sources */,
+				47FAE3072524AA4B005A1BCB /* DataProvider.swift in Sources */,
 				476406842416AA9100C7D426 /* TestOpenSSL.swift in Sources */,
 				3EC35F2420037651008BDF95 /* InvitationHelper.swift in Sources */,
 				A1B49E6421E55ECD00ED86FC /* IntroPageViewController.swift in Sources */,
@@ -2360,6 +2400,7 @@
 				A1EB05841D956867008659C1 /* TableViewDataDelegate.swift in Sources */,
 				8428A85E1F436A05007649A5 /* CircleView.swift in Sources */,
 				A182182C21E5072200918A29 /* IntroDescriptionViewController.swift in Sources */,
+				47FAE3492524FB58005A1BCB /* CoreAddress.swift in Sources */,
 				4775D7AA243F0E260052F2CC /* SimulatorData.swift in Sources */,
 				F1C7AC821FED6473007629DB /* AboutViewController.swift in Sources */,
 				47C8225324379EAE005BCE73 /* AttachmentsViewMain.swift in Sources */,
@@ -2421,6 +2462,7 @@
 				F12041FB1DA3FBF7002E4940 /* ListViewController.swift in Sources */,
 				F18B445E1E7044B70080C041 /* FlipTransition.swift in Sources */,
 				47C8225E24379EAE005BCE73 /* ReadMainView.swift in Sources */,
+				47FAE3122524BFDB005A1BCB /* PersistentDataError.swift in Sources */,
 				472F397E1E1D0B0B009260FB /* EnzevalosContact+CoreDataProperties.swift in Sources */,
 				4751C6FA23449699006B2A4D /* CryptoManagementViewController.swift in Sources */,
 				478154AC21FF6A9600A931EC /* Mailbot.swift in Sources */,
@@ -2437,12 +2479,14 @@
 				676C2D3024321F8100B631B3 /* TyposquattingTests.swift in Sources */,
 				8428A8831F436AC9007649A5 /* GamificationDataUnitTest.swift in Sources */,
 				71DF08982421520D00162B74 /* EmailStringExtensionTests.swift in Sources */,
+				47FAE33F2524FAD3005A1BCB /* CoreAddressTest.swift in Sources */,
 				3EC35F302003838E008BDF95 /* InvitationTests.swift in Sources */,
 				474054982244D7A9007CF83B /* MailServerConfigurationTest.swift in Sources */,
 				678942632430C40600C746D1 /* MailComparisonTests.swift in Sources */,
 				479B5977206914BE00B3944D /* CryptoTests.swift in Sources */,
 				A15D215F223BE6E4003E0CE0 /* MailTest.swift in Sources */,
 				0ED9073024338E3C008CF9D0 /* SMIMETests.swift in Sources */,
+				47FAE3222524C1C0005A1BCB /* CoreMailTest.swift in Sources */,
 				47EABF0F2420C63600774A93 /* AuthenticationTests.swift in Sources */,
 				988C9C5D240D507A006213F0 /* UrlStringExtensionTests.swift in Sources */,
 				4715F637202A0248001BFFD0 /* CoreDataTests.swift in Sources */,
@@ -2643,7 +2687,7 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "-fprofile-instr-generate";
@@ -2699,7 +2743,7 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				OTHER_LDFLAGS = "-fprofile-instr-generate";
 				SDKROOT = iphoneos;
@@ -2746,7 +2790,7 @@
 					"$(SRCROOT)/enzevalos_iphone/OpenSSL/include",
 				);
 				INFOPLIST_FILE = "enzevalos_iphone/PLists/enzevalos-Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
@@ -2825,7 +2869,7 @@
 					"$(SRCROOT)/enzevalos_iphone/OpenSSL/include",
 				);
 				INFOPLIST_FILE = "enzevalos_iphone/PLists/enzevalos-Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
@@ -2989,6 +3033,16 @@
 /* End XCConfigurationList section */
 
 /* Begin XCVersionGroup section */
+		47FAE30C2524AA97005A1BCB /* DataModel.xcdatamodeld */ = {
+			isa = XCVersionGroup;
+			children = (
+				47FAE30D2524AA97005A1BCB /* DataModel.xcdatamodel */,
+			);
+			currentVersion = 47FAE30D2524AA97005A1BCB /* DataModel.xcdatamodel */;
+			path = DataModel.xcdatamodeld;
+			sourceTree = "<group>";
+			versionGroupType = wrapper.xcdatamodel;
+		};
 		A135267F1D955BDF00D3BFE1 /* enzevalos_iphone.xcdatamodeld */ = {
 			isa = XCVersionGroup;
 			children = (
diff --git a/enzevalos_iphone/Certificate.swift b/enzevalos_iphone/Certificate.swift
index 5ad3a33b..6231d85a 100644
--- a/enzevalos_iphone/Certificate.swift
+++ b/enzevalos_iphone/Certificate.swift
@@ -32,7 +32,7 @@ class Certificate {
         
         self.hasPrivateKey = pem.contains("PRIVATE KEY")
         
-        let (fingerPrint, _, errors) = getFingerprintFromPem(pem: pem)
+        let (fingerPrint, _, _) = getFingerprintFromPem(pem: pem)
         
         // if it crashes on this line, you can loop through the errors and see what's wrong
         self.fingerPrint = fingerPrint!
diff --git a/enzevalos_iphone/PersistentMail +CoreDataClass.swift b/enzevalos_iphone/PersistentMail +CoreDataClass.swift
index 4764e26c..170ee700 100644
--- a/enzevalos_iphone/PersistentMail +CoreDataClass.swift	
+++ b/enzevalos_iphone/PersistentMail +CoreDataClass.swift	
@@ -103,7 +103,7 @@ open class PersistentMail: NSManagedObject, Mail {
             } else {
                 flag.insert(MCOMessageFlag.seen)
             }
-            _ = DataHandler.handler.save(during: "set read flag")
+            DataHandler.handler.save(during: "set read flag")
         }
     }
 
@@ -121,7 +121,7 @@ open class PersistentMail: NSManagedObject, Mail {
             } else {
                 flag.insert(MCOMessageFlag.answered)
             }
-            _ = DataHandler.handler.save(during: "set answer flag")
+            DataHandler.handler.save(during: "set answer flag")
         }
     }
 
diff --git a/enzevalos_iphone/UserData.swift b/enzevalos_iphone/UserData.swift
index c86d1ea2..39cf6eeb 100644
--- a/enzevalos_iphone/UserData.swift
+++ b/enzevalos_iphone/UserData.swift
@@ -200,7 +200,7 @@ struct UserManager {
             return attribute.defaultValue
         }
         else {
-            _ = storeUserValue(attribute.defaultValue, attribute: attribute)
+            storeUserValue(attribute.defaultValue, attribute: attribute)
             return attribute.defaultValue
         }
     }
diff --git a/enzevalos_iphone/persistentData/CoreAddress.swift b/enzevalos_iphone/persistentData/CoreAddress.swift
new file mode 100644
index 00000000..2693b4c6
--- /dev/null
+++ b/enzevalos_iphone/persistentData/CoreAddress.swift
@@ -0,0 +1,23 @@
+//
+//  CoreAddress.swift
+//  enzevalos_iphone
+//
+//  Created by Oliver Wiese on 30.09.20.
+//  Copyright © 2020 fu-berlin. All rights reserved.
+//
+
+extension CoreAddress {
+    func update(addressProperties: AddressProperties){
+        email = addressProperties.email
+    }
+}
+
+struct AddressProperties {
+    let email: String
+    
+    var dictionary: [String: Any] {
+        var dic = [String: Any]()
+        dic["email"] = email
+        return dic
+    }
+}
diff --git a/enzevalos_iphone/persistentData/CoreMail.swift b/enzevalos_iphone/persistentData/CoreMail.swift
new file mode 100644
index 00000000..d33f5fff
--- /dev/null
+++ b/enzevalos_iphone/persistentData/CoreMail.swift
@@ -0,0 +1,49 @@
+//
+//  CoreMail.swift
+//  enzevalos_iphone
+//
+//  Created by Oliver Wiese on 30.09.20.
+//  Copyright © 2020 fu-berlin. All rights reserved.
+//
+
+/**
+ Managed object subclass extension for the Quake entity.
+ */
+extension CoreMail {
+    
+    func update(with mailProperties: MailProperties) {
+        messageID = mailProperties.messageID
+        subject = mailProperties.subject
+    }
+}
+
+/**
+ A struct encapsulating the properties of a E-Mail.
+ TODO: Folder, routing information, gmailMessageID, gmailThreadID, ThreadID, signatureKey, decryptionKey, attachments, autocrypt, xMailer
+ 
+ What about attached keys (public, secret keys)
+ */
+struct MailProperties {
+    
+    // Header properties
+    let messageID: String
+    let subject: String
+    let date: Date
+    let flags: Int16
+    
+    // Content properties
+    var body: String = ""
+    
+    // Security properties
+    let signatureState: Int16
+    let encryptionState: Int16
+    
+    
+    
+    var dictionary: [String: Any] {
+        var dic = [String: Any]()
+        dic["messageID"] = messageID
+        dic["subject"] = subject
+        return dic
+    }
+}
diff --git a/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents b/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents
new file mode 100644
index 00000000..07e1b266
--- /dev/null
+++ b/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17192" systemVersion="19H2" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
+    <entity name="CoreAddress" representedClassName="CoreAddress" syncable="YES" codeGenerationType="class">
+        <attribute name="email" attributeType="String"/>
+        <relationship name="inFromField" toMany="YES" deletionRule="Nullify" destinationEntity="CoreMail" inverseName="fromAddress" inverseEntity="CoreMail"/>
+    </entity>
+    <entity name="CoreMail" representedClassName="CoreMail" syncable="YES" codeGenerationType="class">
+        <attribute name="messageID" attributeType="String"/>
+        <attribute name="subject" optional="YES" attributeType="String"/>
+        <relationship name="fromAddress" maxCount="1" deletionRule="Nullify" destinationEntity="CoreAddress" inverseName="inFromField" inverseEntity="CoreAddress"/>
+        <uniquenessConstraints>
+            <uniquenessConstraint>
+                <constraint value="messageID"/>
+            </uniquenessConstraint>
+        </uniquenessConstraints>
+    </entity>
+    <elements>
+        <element name="CoreMail" positionX="-54" positionY="-9" width="128" height="88"/>
+        <element name="CoreAddress" positionX="-36" positionY="27" width="128" height="73"/>
+    </elements>
+</model>
\ No newline at end of file
diff --git a/enzevalos_iphone/persistentData/DataProvider.swift b/enzevalos_iphone/persistentData/DataProvider.swift
new file mode 100644
index 00000000..f701c9ec
--- /dev/null
+++ b/enzevalos_iphone/persistentData/DataProvider.swift
@@ -0,0 +1,291 @@
+//
+//  DataProvider.swift
+//  enzevalos_iphone
+//
+//  Created by Oliver Wiese on 30.09.20.
+//  Copyright © 2020 fu-berlin. All rights reserved.
+//
+
+import CoreData
+let MAILNAME = "CoreMail"
+
+
+/*
+ One Entity needs a name, type, a struct with dict and a update function with the struct...
+ */
+
+public class DataProvider {
+    
+    let fastImport = false
+    
+    // MARK: - Core Data
+    
+    /**
+     A persistent container to set up the Core Data stack.
+    */
+    lazy var persistentContainer: NSPersistentContainer = {
+        let container = NSPersistentContainer(name: "DataModel")
+        
+        // Enable remote notifications
+        guard let description = container.persistentStoreDescriptions.first else {
+            fatalError("Failed to retrieve a persistent store description.")
+        }
+        description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
+    
+        container.loadPersistentStores { storeDesription, error in
+            guard error == nil else {
+                fatalError("Unresolved error \(error!)")
+            }
+        }
+
+        // This sample refreshes UI by refetching data, so doesn't need to merge the changes.
+        container.viewContext.automaticallyMergesChangesFromParent = false
+        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
+        container.viewContext.undoManager = nil
+        container.viewContext.shouldDeleteInaccessibleFaults = true
+        
+        // Observe Core Data remote change notifications.
+        NotificationCenter.default.addObserver(
+            self, selector: #selector(type(of: self).storeRemoteChange(_:)),
+            name: .NSPersistentStoreRemoteChange, object: nil)
+        return container
+    }()
+    
+    /**
+     Creates and configures a private queue context.
+    */
+    private func newTaskContext() -> NSManagedObjectContext {
+        // Create a private queue context.
+        let taskContext = persistentContainer.newBackgroundContext()
+        taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
+        // Set unused undoManager to nil for macOS (it is nil by default on iOS)
+        // to reduce resource requirements.
+        taskContext.undoManager = nil
+        return taskContext
+    }
+    
+    
+    func importMails(from emails: [MailProperties], completionHandler: @escaping (Error?) -> Void, withBIR: Bool = true) {
+        guard !emails.isEmpty else {
+            completionHandler(nil)
+            return
+        }
+        var performError: Error? = nil
+        
+        DispatchQueue.global(qos: .background).async {
+            do {
+                if withBIR {
+                    try self.importMailsUsingBIR(from: emails)
+                }
+                else {
+                    try self.importEmailsBeforeBIR(from: emails)
+                }
+            } catch {
+                performError = error
+            }
+            DispatchQueue.main.asyncAfter(deadline: .now(), execute: {
+                completionHandler(performError)
+            })
+                
+        }
+    }
+
+    
+    /**
+     Uses NSBatchInsertRequest (BIR) to import a list of emails into the Core Data store on a private queue.
+     NSBatchInsertRequest is available since iOS 13 and macOS 10.15.
+    */
+    private func importMailsUsingBIR(from emails: [MailProperties]) throws {
+        var performError: Error?
+        
+        let taskContext = self.newTaskContext()
+        taskContext.performAndWait {
+            let batchInsert = self.newBatchInsertRequest(with: emails)
+            batchInsert.resultType = .statusOnly
+            
+            if let batchInsertResult = try? taskContext.execute(batchInsert) as? NSBatchInsertResult,
+                let success = batchInsertResult.result as? Bool, success {
+                return
+            }
+            performError = PersistentDataError.batchInsertError
+        }
+        if let error = performError {
+            throw error
+        }
+    }
+
+    private func newBatchInsertRequest(with mails: [MailProperties]) -> NSBatchInsertRequest {
+        let batchInsert: NSBatchInsertRequest
+        var index = 0
+        let total = mails.count
+        batchInsert = NSBatchInsertRequest(entityName: MAILNAME, dictionaryHandler: { dictionary in
+            guard index < total else { return true }
+            dictionary.addEntries(from: mails[index].dictionary)
+            index += 1
+            return false
+        })
+        return batchInsert
+    }
+    
+    /**
+     Imports a JSON dictionary into the Core Data store on a private queue,
+     processing the record in batches to avoid a high memory footprint.
+    */
+    private func importEmailsBeforeBIR(from emails: [MailProperties]) throws {
+        guard !emails.isEmpty else { return }
+                
+        // Process records in batches to avoid a high memory footprint.
+        let batchSize = 256
+        let count = emails.count
+        
+        // Determine the total number of batches.
+        var numBatches = count / batchSize
+        numBatches += count % batchSize > 0 ? 1 : 0
+        
+        for batchNumber in 0 ..< numBatches {
+            // Determine the range for this batch.
+            let batchStart = batchNumber * batchSize
+            let batchEnd = batchStart + min(batchSize, count - batchNumber * batchSize)
+            let range = batchStart..<batchEnd
+            
+            // Create a batch for this range from the decoded JSON.
+            // Stop importing if any batch is unsuccessful.
+            try importOneBatch(Array(emails[range]))
+        }
+    }
+    
+    /**
+     Imports one batch of quakes, creating managed objects from the new data,
+     and saving them to the persistent store, on a private queue. After saving,
+     resets the context to clean up the cache and lower the memory footprint.
+     
+     NSManagedObjectContext.performAndWait doesn't rethrow so this function
+     catches throws within the closure and uses a return value to indicate
+     whether the import is successful.
+    */
+    private func importOneBatch(_ emails: [MailProperties]) throws {
+        let taskContext = newTaskContext()
+        var performError: Error?
+        
+        // taskContext.performAndWait runs on the URLSession's delegate queue
+        // so it won’t block the main thread.
+        taskContext.performAndWait {
+            // Create a new record for each quake in the batch.
+            for m in emails {
+                // Create a Quake managed object on the private queue context.
+                guard let email = NSEntityDescription.insertNewObject(forEntityName: MAILNAME, into: taskContext) as? CoreMail else {
+                    performError = PersistentDataError.creationError
+                    return
+                }
+                email.update(with: m)
+            }
+            
+            // Save all insertions and deletions from the context to the store.
+            if taskContext.hasChanges {
+                do {
+                    try taskContext.save()
+                } catch {
+                    performError = error
+                    return
+                }
+                // Reset the taskContext to free the cache and lower the memory footprint.
+                taskContext.reset()
+            }
+        }
+        
+        if let error = performError {
+            throw error
+        }
+    }
+    
+    /**
+     Deletes all the records in the Core Data store.
+    */
+    func deleteAll(completionHandler: @escaping (Error?) -> Void) {
+        let taskContext = newTaskContext()
+        taskContext.perform {
+            let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: MAILNAME)
+            let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
+            batchDeleteRequest.resultType = .resultTypeCount
+            
+            // Execute the batch insert
+            if let batchDeleteResult = try? taskContext.execute(batchDeleteRequest) as? NSBatchDeleteResult,
+                batchDeleteResult.result != nil {
+                completionHandler(nil)
+
+            } else {
+                completionHandler(PersistentDataError.batchDeleteError)
+            }
+        }
+    }
+
+    // MARK: - NSFetchedResultsController
+    
+    /**
+         A fetched results controller delegate to give consumers a chance to update
+         the user interface when content changes.
+         */
+        weak var fetchedResultsControllerDelegate: NSFetchedResultsControllerDelegate?
+        
+        /**
+         A fetched results controller to fetch Quake records sorted by time.
+         */
+        lazy var fetchedResultsController: NSFetchedResultsController<CoreMail> = {
+            
+            // Create a fetch request for the Quake entity sorted by time.
+            let fetchRequest = NSFetchRequest<CoreMail>(entityName: MAILNAME)
+            // Create a fetched results controller and set its fetch request, context, and delegate.
+            fetchRequest.sortDescriptors = [NSSortDescriptor(key: "messageID", ascending: false)]
+            fetchRequest.propertiesToFetch = ["messageID", "subject"]
+            let controller = NSFetchedResultsController(fetchRequest: fetchRequest,
+                                                        managedObjectContext: persistentContainer.viewContext,
+                                                        sectionNameKeyPath: nil, cacheName: nil)
+            controller.delegate = fetchedResultsControllerDelegate
+        
+        // Perform the fetch.
+        do {
+            try controller.performFetch()
+        } catch {
+            fatalError("Unresolved error \(error)")
+        }
+        return controller
+    }()
+    
+    /**
+     Resets viewContext and refetches the data from the store.
+     */
+    func resetAndRefetch() {
+        persistentContainer.viewContext.reset()
+        do {
+            try fetchedResultsController.performFetch()
+        } catch {
+            fatalError("Unresolved error \(error)")
+        }
+    }
+    
+    // MARK: - NSPersistentStoreRemoteChange handler
+
+    /**
+     Handles remote store change notifications (.NSPersistentStoreRemoteChange).
+     storeRemoteChange runs on the queue where the changes were made.
+     */
+    @objc
+    func storeRemoteChange(_ notification: Notification) {
+         //print("\(#function): Got a persistent store remote change notification!")
+    }
+}
+
+extension DispatchQueue {
+
+    static func background(delay: Double = 0.0, background: (()->Void)? = nil, completion: (() -> Void)? = nil) {
+        DispatchQueue.global(qos: .background).async {
+            background?()
+            if let completion = completion {
+                DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: {
+                    completion()
+                })
+            }
+        }
+    }
+
+}
diff --git a/enzevalos_iphone/persistentData/PersistentDataError.swift b/enzevalos_iphone/persistentData/PersistentDataError.swift
new file mode 100644
index 00000000..134b0cee
--- /dev/null
+++ b/enzevalos_iphone/persistentData/PersistentDataError.swift
@@ -0,0 +1,19 @@
+//
+//  PersistentDataError.swift
+//  enzevalos_iphone
+//
+//  Created by Oliver Wiese on 30.09.20.
+//  Copyright © 2020 fu-berlin. All rights reserved.
+//
+
+import Foundation
+
+enum PersistentDataError: Error {
+    case urlError
+    case networkUnavailable
+    case wrongDataFormat
+    case missingData
+    case creationError
+    case batchInsertError
+    case batchDeleteError
+}
diff --git a/enzevalos_iphoneTests/CoreAddressTest.swift b/enzevalos_iphoneTests/CoreAddressTest.swift
new file mode 100644
index 00000000..4f6aaf27
--- /dev/null
+++ b/enzevalos_iphoneTests/CoreAddressTest.swift
@@ -0,0 +1,36 @@
+//
+//  CoreAddressTest.swift
+//  enzevalos_iphoneTests
+//
+//  Created by Oliver Wiese on 30.09.20.
+//  Copyright © 2020 fu-berlin. All rights reserved.
+//
+
+import XCTest
+
+@testable import enzevalos_iphone
+class CoreAddressTest: XCTestCase {
+    var provider = DataProvider()
+
+    override func setUpWithError() throws {
+        provider.deleteAll(completionHandler: {_ in })
+    }
+
+    override func tearDownWithError() throws {
+        provider.deleteAll(completionHandler: {_ in })
+    }
+
+    func testCreateAddress() throws {
+        let addr1 = AddressProperties(email: "vic@example.com")
+        
+        let addresses = [addr1]
+    }
+
+    func testPerformanceExample() throws {
+        // This is an example of a performance test case.
+        self.measure {
+            // Put the code you want to measure the time of here.
+        }
+    }
+
+}
diff --git a/enzevalos_iphoneTests/CoreMailTest.swift b/enzevalos_iphoneTests/CoreMailTest.swift
new file mode 100644
index 00000000..79574a89
--- /dev/null
+++ b/enzevalos_iphoneTests/CoreMailTest.swift
@@ -0,0 +1,56 @@
+//
+//  CoreMailTest.swift
+//  enzevalos_iphoneTests
+//
+//  Created by Oliver Wiese on 30.09.20.
+//  Copyright © 2020 fu-berlin. All rights reserved.
+//
+
+import XCTest
+
+@testable import enzevalos_iphone
+class CoreMailTest: XCTestCase {
+
+    var provider = DataProvider()
+    
+    override func setUpWithError() throws {
+        provider.deleteAll(completionHandler: {_ in })
+    }
+
+    override func tearDownWithError() throws {
+        provider.deleteAll(completionHandler: {_ in })
+    }
+
+    func testImport(withBIR: Bool) {
+        let n = 100
+        
+        var msgs = [MailProperties]()
+        for i in 1...n {
+            let m = MailProperties(messageID: "\(i)", subject: "MSG\(i)", date: Date(), flags: 0, body: "THIS IS MSG\(i)", signatureState: 0, encryptionState: 0)
+            msgs.append(m)
+        }
+        
+        let m = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, body: "THIS IS MY SECOND MSG1", signatureState: 0, encryptionState: 0)
+        msgs.append(m)
+        provider.resetAndRefetch()
+        XCTAssertEqual(provider.fetchedResultsController.fetchedObjects?.count ?? 0, 0, "Too much messages! \(provider.fetchedResultsController.fetchedObjects?.count ?? 0)")
+        let importExpectation = expectation(description: "Import new data!")
+        provider.importMails(from: msgs, completionHandler: {error in
+            if let error = error {
+                XCTFail("Error while importing messages! \(error)")
+            }
+            importExpectation.fulfill()
+        }, withBIR: withBIR)
+        wait(for: [importExpectation], timeout: TimeInterval(20))
+        provider.resetAndRefetch()
+        XCTAssertEqual(provider.fetchedResultsController.fetchedObjects?.count ?? 0, n, "Missing message! \(provider.fetchedResultsController.fetchedObjects?.count ?? 0)")
+    }
+    
+    func testImportWithBIR() {
+        testImport(withBIR: true)
+    }
+    
+    func testImportBeforeBIR() {
+        testImport(withBIR: false)
+    }
+}
diff --git a/enzevalos_iphoneTests/GeneratedMocks.swift b/enzevalos_iphoneTests/GeneratedMocks.swift
index ca02ed66..eaaae2dd 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 2020-04-28 19:16:47 +0000
+// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2020-09-30 17:29:22 +0000
 
 //
 //  AuthenticationModel.swift
@@ -654,7 +654,7 @@ import Foundation
 }
 
 
-// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-04-28 19:16:47 +0000
+// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-09-30 17:29:22 +0000
 
 //
 //  AuthenticationViewModel.swift
-- 
GitLab