merges default IOS-1028
authorbuff <andreas@pep-project.org>
Thu, 26 Jul 2018 13:41:45 +0200
branchIOS-1028
changeset 56299bc6edaa5eef
parent 5551 e6e3ed9eec77
parent 5628 54976f907da8
child 5631 e910b70faf62
merges default
.hgtags
pEpForiOS.xcodeproj/project.pbxproj
pEpForiOS/Background/SyncFlagsToServerOperation.swift
pEpForiOS/Background/SyncFoldersFromServerOperation.swift
pEpForiOS/Base.lproj/AccountCreation.storyboard
pEpForiOS/Base.lproj/FolderViews.storyboard
pEpForiOS/Base.lproj/Main.storyboard
pEpForiOS/Base.lproj/Settings.storyboard
pEpForiOS/Models/Account+Extentions.swift
pEpForiOS/Models/CdAccount+Extension.swift
pEpForiOS/Network/ConnectInfo.swift
pEpForiOS/Network/EmailConnectInfo+Extension.swift
pEpForiOS/Network/EmailConnectInfo.swift
pEpForiOS/Network/Service/LoginSmtpOperation.swift
pEpForiOS/Network/Service/NetworkServiceWorker.swift
pEpForiOS/Network/Service/ServiceUtil.swift
pEpForiOS/UI/Base.lproj/FolderViews.storyboard
pEpForiOS/UI/EmailDisplayList/EmailListViewController.swift
pEpForiOS/UI/EmailDisplayList/EmailListViewModel.swift
pEpForiOS/UI/Folder/FolderTableViewController.swift
pEpForiOS/UI/Login/LoginTableViewController.swift
pEpForiOS/UI/Settings/OptionsViewController/LogViewController.swift
pEpForiOSTests/Background/FetchMessagesOperationTest.swift
pEpForiOSTests/Background/MoveToFolderOperationTest.swift
pEpForiOSTests/Background/SyncFlagsToServerOperationTest.swift
pEpForiOSTests/ContentDispositionTest.swift
pEpForiOSTests/Features/ReUploadTest.swift
pEpForiOSTests/MessageReevalutionTests.swift
pEpForiOSTests/NetworkServiceTests.swift
pEpForiOSTests/TestUtils/CdAccount+TestUtils.swift
pEpForiOSTests/TestUtils/CoreDataDrivenTestBase.swift
pEpForiOSTests/TestUtils/TestUtil.swift
pEpForiOSTests/Util/ComposeUtilTest.swift
pEpForiOSTests/Util/KeyImport/KeyImportServiceTest.swift
     1.1 --- a/.hgtags	Fri Jul 20 14:07:19 2018 +0200
     1.2 +++ b/.hgtags	Thu Jul 26 13:41:45 2018 +0200
     1.3 @@ -42,3 +42,4 @@
     1.4  43014b42fc125d241a28fdc3412f7c16c5ec56af v0.0.32
     1.5  0000000000000000000000000000000000000000 v0.0.32
     1.6  303423d0a02566e2c5c8feb198f543c9dc73b802 v0.0.32
     1.7 +f7607bcfa3808383a10a69c7b095ff97f1963b8d v0.0.33
     2.1 --- a/CHANGESETS	Fri Jul 20 14:07:19 2018 +0200
     2.2 +++ b/CHANGESETS	Thu Jul 26 13:41:45 2018 +0200
     2.3 @@ -1,12 +1,12 @@
     2.4 -v0.0.32
     2.5 -pEpEngine 3cc1716b444e
     2.6 -pEpObjCAdapter 0954976b8da9
     2.7 -netpgp-et 737d62543a48
     2.8 -MessageModel f8bd6c70e390
     2.9 -pantomime-iOS d9edf9be50dd
    2.10 -libAccountSettings 50391d70b149
    2.11 +v0.0.33
    2.12 +pEpEngine 7618e2247a78
    2.13 +pEpObjCAdapter 19ca3f566cfa
    2.14 +netpgp-et 25876c9c5ef2
    2.15 +MessageModel 54e1a515db22
    2.16 +pantomime-iOS 661c003408a3
    2.17 +libAccountSettings 8228a1e993d5
    2.18  ldns abee8f894c3373bf64c0f94d00a6c66ac224e66d
    2.19  OpenSSL-for-iPhone 10019638e80e8a8a5fc19642a840d8a69fac7349
    2.20 -libetpan cc4c5c5e3eb3d294fc58710d10821de4748b4df2
    2.21 +libetpan af2aad552dd0ecc6a943f78e5c77dc03ebbc0028
    2.22  AppAuth-iOS 135f99d2cb4e9d18d310ac2588b905e612461561
    2.23 -SwipeCellKit 48f026d269715b41cec5c70e26eb722088659c12
    2.24 +SwipeCellKit 7af389b47ae280b257dff2abdb623e0778bfe94a
     3.1 --- a/pEpForiOS.xcodeproj/project.pbxproj	Fri Jul 20 14:07:19 2018 +0200
     3.2 +++ b/pEpForiOS.xcodeproj/project.pbxproj	Thu Jul 26 13:41:45 2018 +0200
     3.3 @@ -32,6 +32,8 @@
     3.4  		00EB89AB20E3A27C00CDFA0D /* ThreadViewcontroller+SizeClasses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00EB89AA20E3A27C00CDFA0D /* ThreadViewcontroller+SizeClasses.swift */; };
     3.5  		00EB89AD20E3D3C200CDFA0D /* ThreadedEmailViewModel+MoveToFolderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00EB89AC20E3D3C200CDFA0D /* ThreadedEmailViewModel+MoveToFolderDelegate.swift */; };
     3.6  		00EB89AF20E3E4A000CDFA0D /* ReplyAlertCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00EB89AE20E3E4A000CDFA0D /* ReplyAlertCreator.swift */; };
     3.7 +		00FD0CE62101F7D700BA0C56 /* ScreenComposerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00FD0CE52101F7D700BA0C56 /* ScreenComposerProtocol.swift */; };
     3.8 +		00FD0CE82102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00FD0CE72102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift */; };
     3.9  		1500199D1F2B2C73003E670A /* Notification+CWServiceClientNotificationParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1500199C1F2B2C73003E670A /* Notification+CWServiceClientNotificationParsing.swift */; };
    3.10  		1500199F1F2BA2EF003E670A /* SyncFlagsToServerOperationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1500199E1F2BA2EF003E670A /* SyncFlagsToServerOperationTest.swift */; };
    3.11  		150707DA20FFC31E00AA213F /* ComposeUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150707D920FFC31E00AA213F /* ComposeUtil.swift */; };
    3.12 @@ -73,6 +75,9 @@
    3.13  		1541D7FA1FCC18E100D52A5D /* AttachmentCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1541D7F91FCC18E100D52A5D /* AttachmentCell.xib */; };
    3.14  		1541D7FC1FCC199B00D52A5D /* AttachmentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1541D7FB1FCC199B00D52A5D /* AttachmentCell.swift */; };
    3.15  		1547509A1FE7C0B4000D8004 /* FetchNumberOfNewMailsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154750991FE7C0B4000D8004 /* FetchNumberOfNewMailsOperation.swift */; };
    3.16 +		15484B682105D5AA00F9D962 /* ConnectInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15484B672105D5AA00F9D962 /* ConnectInfo.swift */; };
    3.17 +		15484B6A2105D5C500F9D962 /* EmailConnectInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15484B692105D5C500F9D962 /* EmailConnectInfo.swift */; };
    3.18 +		15484B6C2105E26600F9D962 /* LegacyConnectInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15484B6B2105E26600F9D962 /* LegacyConnectInfoProvider.swift */; };
    3.19  		154D92CF20AC1745009A5868 /* MoveToFolderOperationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154D92CE20AC1744009A5868 /* MoveToFolderOperationTest.swift */; };
    3.20  		154F0A802085FC7D00C77D72 /* CdAttachment+Pantomime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154F0A7F2085FC7D00C77D72 /* CdAttachment+Pantomime.swift */; };
    3.21  		154F0A8220874B3E00C77D72 /* ContentDispositionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154F0A8120874B3E00C77D72 /* ContentDispositionTest.swift */; };
    3.22 @@ -166,8 +171,6 @@
    3.23  		431144B51CC0FCA40007639D /* StoreFolderOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431144B41CC0FCA40007639D /* StoreFolderOperation.swift */; };
    3.24  		431144B71CC11D6A0007639D /* BaseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431144B61CC11D6A0007639D /* BaseOperation.swift */; };
    3.25  		431144B91CC11DF30007639D /* StorePrefetchedMailOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431144B81CC11DF30007639D /* StorePrefetchedMailOperation.swift */; };
    3.26 -		43122B171DF5B48B00610253 /* ConnectInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43122B121DF5B48B00610253 /* ConnectInfo.swift */; };
    3.27 -		43122B181DF5B48B00610253 /* EmailConnectInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43122B131DF5B48B00610253 /* EmailConnectInfo.swift */; };
    3.28  		43122B191DF5B48B00610253 /* EmailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43122B141DF5B48B00610253 /* EmailService.swift */; };
    3.29  		43122B1A1DF5B48B00610253 /* ImapService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43122B151DF5B48B00610253 /* ImapService.swift */; };
    3.30  		43122B1B1DF5B48B00610253 /* SmtpService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43122B161DF5B48B00610253 /* SmtpService.swift */; };
    3.31 @@ -426,6 +429,8 @@
    3.32  		43FE8030209995AD00E97AB3 /* QualifyServerIsLocalServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FE802F209995AD00E97AB3 /* QualifyServerIsLocalServiceTest.swift */; };
    3.33  		43FE80322099F62400E97AB3 /* SubjectComposeTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FE80312099F62400E97AB3 /* SubjectComposeTextView.swift */; };
    3.34  		4902244F20E50488000E8D7C /* ThreadNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4902244E20E50488000E8D7C /* ThreadNavigationDelegate.swift */; };
    3.35 +		490CEBA72100EAD500E8579C /* SelfDismissable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490CEBA62100EAD500E8579C /* SelfDismissable.swift */; };
    3.36 +		490CEBA921020BF900E8579C /* LoginViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490CEBA821020BF900E8579C /* LoginViewController+Keyboard.swift */; };
    3.37  		4918EBFC1E783C70006207FC /* CdMessage+PantomimeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4918EBFA1E783C70006207FC /* CdMessage+PantomimeTest.swift */; };
    3.38  		491B656220CFE0FD00C2ADDA /* Thread.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 491B656020CFE0FD00C2ADDA /* Thread.storyboard */; };
    3.39  		49228A5320D3D29900A51E9D /* ThreadViewController+SegueHandlerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49228A5220D3D29900A51E9D /* ThreadViewController+SegueHandlerType.swift */; };
    3.40 @@ -442,6 +447,8 @@
    3.41  		496C0EEB20BC4B370009B5B9 /* EmailListViewModel+EmailDisplayDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 496C0EEA20BC4B360009B5B9 /* EmailListViewModel+EmailDisplayDelegate.swift */; };
    3.42  		49C2750120C04DDB0075F6FF /* EmailViewController+DisplayedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C2750020C04DDB0075F6FF /* EmailViewController+DisplayedMessage.swift */; };
    3.43  		49C34AF620E4F649009D11CC /* CellDetailTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C34AF520E4F649009D11CC /* CellDetailTransition.swift */; };
    3.44 +		49D292A320F3ABA600F33C78 /* CredentialTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D292A220F3ABA600F33C78 /* CredentialTextField.swift */; };
    3.45 +		49D3BECC20F8F7330043E05D /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D3BECB20F8F7330043E05D /* LoginViewController.swift */; };
    3.46  		49D521541E73E1C20097987B /* MessageModel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D521531E73E1C20097987B /* MessageModel.framework */; };
    3.47  		49D521551E73E1C20097987B /* MessageModel.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 49D521531E73E1C20097987B /* MessageModel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
    3.48  		5D039A9C1D0EE7F900AD59EC /* PEPUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D039A9B1D0EE7F900AD59EC /* PEPUtil.swift */; };
    3.49 @@ -553,6 +560,8 @@
    3.50  		00EB89AA20E3A27C00CDFA0D /* ThreadViewcontroller+SizeClasses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadViewcontroller+SizeClasses.swift"; sourceTree = "<group>"; };
    3.51  		00EB89AC20E3D3C200CDFA0D /* ThreadedEmailViewModel+MoveToFolderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadedEmailViewModel+MoveToFolderDelegate.swift"; sourceTree = "<group>"; };
    3.52  		00EB89AE20E3E4A000CDFA0D /* ReplyAlertCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyAlertCreator.swift; sourceTree = "<group>"; };
    3.53 +		00FD0CE52101F7D700BA0C56 /* ScreenComposerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenComposerProtocol.swift; sourceTree = "<group>"; };
    3.54 +		00FD0CE72102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PrimarySplitViewcontroller+ScreenComposerProtocol.swift"; sourceTree = "<group>"; };
    3.55  		1500199C1F2B2C73003E670A /* Notification+CWServiceClientNotificationParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Notification+CWServiceClientNotificationParsing.swift"; sourceTree = "<group>"; };
    3.56  		1500199E1F2BA2EF003E670A /* SyncFlagsToServerOperationTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncFlagsToServerOperationTest.swift; sourceTree = "<group>"; };
    3.57  		150707D920FFC31E00AA213F /* ComposeUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeUtil.swift; sourceTree = "<group>"; };
    3.58 @@ -595,6 +604,9 @@
    3.59  		1541D7F91FCC18E100D52A5D /* AttachmentCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AttachmentCell.xib; sourceTree = "<group>"; };
    3.60  		1541D7FB1FCC199B00D52A5D /* AttachmentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentCell.swift; sourceTree = "<group>"; };
    3.61  		154750991FE7C0B4000D8004 /* FetchNumberOfNewMailsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchNumberOfNewMailsOperation.swift; sourceTree = "<group>"; };
    3.62 +		15484B672105D5AA00F9D962 /* ConnectInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectInfo.swift; sourceTree = "<group>"; };
    3.63 +		15484B692105D5C500F9D962 /* EmailConnectInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailConnectInfo.swift; sourceTree = "<group>"; };
    3.64 +		15484B6B2105E26600F9D962 /* LegacyConnectInfoProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyConnectInfoProvider.swift; sourceTree = "<group>"; };
    3.65  		154D92CE20AC1744009A5868 /* MoveToFolderOperationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveToFolderOperationTest.swift; sourceTree = "<group>"; };
    3.66  		154F0A7F2085FC7D00C77D72 /* CdAttachment+Pantomime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CdAttachment+Pantomime.swift"; sourceTree = "<group>"; };
    3.67  		154F0A8120874B3E00C77D72 /* ContentDispositionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentDispositionTest.swift; sourceTree = "<group>"; };
    3.68 @@ -684,8 +696,6 @@
    3.69  		431144B41CC0FCA40007639D /* StoreFolderOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoreFolderOperation.swift; sourceTree = "<group>"; };
    3.70  		431144B61CC11D6A0007639D /* BaseOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseOperation.swift; sourceTree = "<group>"; };
    3.71  		431144B81CC11DF30007639D /* StorePrefetchedMailOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorePrefetchedMailOperation.swift; sourceTree = "<group>"; };
    3.72 -		43122B121DF5B48B00610253 /* ConnectInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectInfo.swift; sourceTree = "<group>"; };
    3.73 -		43122B131DF5B48B00610253 /* EmailConnectInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailConnectInfo.swift; sourceTree = "<group>"; };
    3.74  		43122B141DF5B48B00610253 /* EmailService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailService.swift; sourceTree = "<group>"; };
    3.75  		43122B151DF5B48B00610253 /* ImapService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImapService.swift; sourceTree = "<group>"; };
    3.76  		43122B161DF5B48B00610253 /* SmtpService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SmtpService.swift; sourceTree = "<group>"; };
    3.77 @@ -975,6 +985,8 @@
    3.78  		43FE802F209995AD00E97AB3 /* QualifyServerIsLocalServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QualifyServerIsLocalServiceTest.swift; sourceTree = "<group>"; };
    3.79  		43FE80312099F62400E97AB3 /* SubjectComposeTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SubjectComposeTextView.swift; path = ../Util/SubjectComposeTextView.swift; sourceTree = "<group>"; };
    3.80  		4902244E20E50488000E8D7C /* ThreadNavigationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadNavigationDelegate.swift; sourceTree = "<group>"; };
    3.81 +		490CEBA62100EAD500E8579C /* SelfDismissable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelfDismissable.swift; sourceTree = "<group>"; };
    3.82 +		490CEBA821020BF900E8579C /* LoginViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoginViewController+Keyboard.swift"; sourceTree = "<group>"; };
    3.83  		4918EBFA1E783C70006207FC /* CdMessage+PantomimeTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CdMessage+PantomimeTest.swift"; sourceTree = "<group>"; };
    3.84  		491B656120CFE0FD00C2ADDA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Thread.storyboard; sourceTree = "<group>"; };
    3.85  		49228A5220D3D29900A51E9D /* ThreadViewController+SegueHandlerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadViewController+SegueHandlerType.swift"; sourceTree = "<group>"; };
    3.86 @@ -992,6 +1004,8 @@
    3.87  		496C0EEA20BC4B360009B5B9 /* EmailListViewModel+EmailDisplayDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmailListViewModel+EmailDisplayDelegate.swift"; sourceTree = "<group>"; };
    3.88  		49C2750020C04DDB0075F6FF /* EmailViewController+DisplayedMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmailViewController+DisplayedMessage.swift"; sourceTree = "<group>"; };
    3.89  		49C34AF520E4F649009D11CC /* CellDetailTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellDetailTransition.swift; sourceTree = "<group>"; };
    3.90 +		49D292A220F3ABA600F33C78 /* CredentialTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialTextField.swift; sourceTree = "<group>"; };
    3.91 +		49D3BECB20F8F7330043E05D /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = "<group>"; };
    3.92  		49D521531E73E1C20097987B /* MessageModel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MessageModel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
    3.93  		49D521561E73E1C70097987B /* ServerConfig.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ServerConfig.framework; sourceTree = BUILT_PRODUCTS_DIR; };
    3.94  		5D039A9B1D0EE7F900AD59EC /* PEPUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PEPUtil.swift; sourceTree = "<group>"; };
    3.95 @@ -1085,7 +1099,9 @@
    3.96  			isa = PBXGroup;
    3.97  			children = (
    3.98  				00D3CD3D20B58976009ABBC9 /* PrimarySplitViewController.swift */,
    3.99 +				00FD0CE72102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift */,
   3.100  				00BEC89620B85FD300A36E60 /* NoMessagesViewController.swift */,
   3.101 +				00FD0CE52101F7D700BA0C56 /* ScreenComposerProtocol.swift */,
   3.102  			);
   3.103  			path = SplitView;
   3.104  			sourceTree = "<group>";
   3.105 @@ -1196,6 +1212,25 @@
   3.106  			path = IMAP;
   3.107  			sourceTree = "<group>";
   3.108  		};
   3.109 +		15484B652105D55600F9D962 /* ConnectInfo */ = {
   3.110 +			isa = PBXGroup;
   3.111 +			children = (
   3.112 +				15484B662105D58800F9D962 /* deprecated */,
   3.113 +				15484B672105D5AA00F9D962 /* ConnectInfo.swift */,
   3.114 +				43D755FB1F26382B006F933A /* EmailConnectInfo+Extension.swift */,
   3.115 +				15484B692105D5C500F9D962 /* EmailConnectInfo.swift */,
   3.116 +			);
   3.117 +			path = ConnectInfo;
   3.118 +			sourceTree = "<group>";
   3.119 +		};
   3.120 +		15484B662105D58800F9D962 /* deprecated */ = {
   3.121 +			isa = PBXGroup;
   3.122 +			children = (
   3.123 +				15484B6B2105E26600F9D962 /* LegacyConnectInfoProvider.swift */,
   3.124 +			);
   3.125 +			path = deprecated;
   3.126 +			sourceTree = "<group>";
   3.127 +		};
   3.128  		1569AEA320E14DC2002102A0 /* Features */ = {
   3.129  			isa = PBXGroup;
   3.130  			children = (
   3.131 @@ -1404,11 +1439,9 @@
   3.132  		43122B111DF5B48B00610253 /* Network */ = {
   3.133  			isa = PBXGroup;
   3.134  			children = (
   3.135 +				15484B652105D55600F9D962 /* ConnectInfo */,
   3.136  				43122B3A1DF5B75000610253 /* Service */,
   3.137 -				43122B121DF5B48B00610253 /* ConnectInfo.swift */,
   3.138  				4315E4BE2011FD6900F68763 /* AuthMethod.swift */,
   3.139 -				43122B131DF5B48B00610253 /* EmailConnectInfo.swift */,
   3.140 -				43D755FB1F26382B006F933A /* EmailConnectInfo+Extension.swift */,
   3.141  				43122B141DF5B48B00610253 /* EmailService.swift */,
   3.142  				43122B151DF5B48B00610253 /* ImapService.swift */,
   3.143  				43122B161DF5B48B00610253 /* SmtpService.swift */,
   3.144 @@ -1820,6 +1853,7 @@
   3.145  		43AA82511E9B925000ABD5A8 /* Util */ = {
   3.146  			isa = PBXGroup;
   3.147  			children = (
   3.148 +				49D292A220F3ABA600F33C78 /* CredentialTextField.swift */,
   3.149  				150DF6D12052A99800A9DCF7 /* SecureWebViewController */,
   3.150  				43AAC2281F7A5AED00F435F4 /* BaseTableViewController.swift */,
   3.151  				43AAC2291F7A5AEE00F435F4 /* BaseViewController.swift */,
   3.152 @@ -1845,6 +1879,7 @@
   3.153  				150DF6D22052ED4800A9DCF7 /* UIView+Autolayout.swift */,
   3.154  				4341980420AB037E0062F7F6 /* CGImageSource+Extension.swift */,
   3.155  				4395CDEB20AAB2E9003FC5F1 /* UIImage+GIF.swift */,
   3.156 +				490CEBA62100EAD500E8579C /* SelfDismissable.swift */,
   3.157  				B761A80920F5F0A6000832C2 /* UIBarButtonItem+Extension.swift */,
   3.158  			);
   3.159  			path = Util;
   3.160 @@ -2165,6 +2200,8 @@
   3.161  			children = (
   3.162  				B70D32AB205BCCDD0094A92A /* ViewModel */,
   3.163  				B714C4841ED437A7000BC84D /* LoginTableViewController.swift */,
   3.164 +				49D3BECB20F8F7330043E05D /* LoginViewController.swift */,
   3.165 +				490CEBA821020BF900E8579C /* LoginViewController+Keyboard.swift */,
   3.166  			);
   3.167  			path = Login;
   3.168  			sourceTree = "<group>";
   3.169 @@ -2763,10 +2800,11 @@
   3.170  				4360282F1ED6F33400C95FC4 /* ImapSyncError.swift in Sources */,
   3.171  				222B35561DF962D7007A1F82 /* ComposeHelpers.swift in Sources */,
   3.172  				220DCE361E0AB5CC002FE716 /* MessageSenderCell.swift in Sources */,
   3.173 +				15484B6A2105D5C500F9D962 /* EmailConnectInfo.swift in Sources */,
   3.174 +				49D292A320F3ABA600F33C78 /* CredentialTextField.swift in Sources */,
   3.175  				4341EBCF2089F674004CE6B8 /* QualifyServerIsLocalOperation.swift in Sources */,
   3.176  				43425EDF1FE3E052004A2728 /* OAuth2ProviderFactory.swift in Sources */,
   3.177  				43E657E01F3C74030014CBEC /* AXHTMLParser.m in Sources */,
   3.178 -				43122B181DF5B48B00610253 /* EmailConnectInfo.swift in Sources */,
   3.179  				B76CF8B320D2739B002429A8 /* MoveToFolderViewModel.swift in Sources */,
   3.180  				155050F61FEAB082009CEAD2 /* ErrorContainer.swift in Sources */,
   3.181  				151F71D22029FA1B0057C74D /* PantomimeFolderAttribute+Extensions.swift in Sources */,
   3.182 @@ -2812,6 +2850,7 @@
   3.183  				43FE802E209992B800E97AB3 /* QualifyServerIsLocalService.swift in Sources */,
   3.184  				4351C2D41F4441190053381F /* iterator.c in Sources */,
   3.185  				43AA825B1E9BC5FF00ABD5A8 /* AttachmentViewContainer.swift in Sources */,
   3.186 +				490CEBA921020BF900E8579C /* LoginViewController+Keyboard.swift in Sources */,
   3.187  				4326D3FF1EFBC8DB0016AB0D /* FolderInfoOperation.swift in Sources */,
   3.188  				43122B3C1DF5B75000610253 /* NetworkService.swift in Sources */,
   3.189  				43ED53711CC77F95006AB156 /* IMAPSettingsTableViewController.swift in Sources */,
   3.190 @@ -2926,7 +2965,6 @@
   3.191  				43FAA0D21EC9972B005BFC4B /* Tuple.swift in Sources */,
   3.192  				430A2EEC1E81357A00878837 /* CdImapFlags+Pantomime.swift in Sources */,
   3.193  				4395CDEC20AAB2E9003FC5F1 /* UIImage+GIF.swift in Sources */,
   3.194 -				43122B171DF5B48B00610253 /* ConnectInfo.swift in Sources */,
   3.195  				436C232F1E02A52D00071430 /* LimitedOperationQueue.swift in Sources */,
   3.196  				434F40941EB0B173002FBF0D /* ObservableValue.swift in Sources */,
   3.197  				430D73651E9CBD4E00EA6FA9 /* AttachmentsViewOperation.swift in Sources */,
   3.198 @@ -2937,6 +2975,7 @@
   3.199  				4351C2CD1F4441190053381F /* commonmark.c in Sources */,
   3.200  				B722EC651E5B49BA00A2B9D5 /* FolderSectionViewModel.swift in Sources */,
   3.201  				150B84C620A5DD0600D8B288 /* UIDCopyOperation.swift in Sources */,
   3.202 +				490CEBA72100EAD500E8579C /* SelfDismissable.swift in Sources */,
   3.203  				1560D1701F6FC99B00A75B39 /* FetchOlderImapMessagesOperation.swift in Sources */,
   3.204  				43ED53701CC77F95006AB156 /* EmailListViewController.swift in Sources */,
   3.205  				432DA7441EE01E3300B30BAA /* MessageSyncServiceProtocol.swift in Sources */,
   3.206 @@ -2976,11 +3015,13 @@
   3.207  				434BF39320C6B6D300FCBCCA /* ThreadAwareFolderProtocol.swift in Sources */,
   3.208  				431B04821DE583A000E40CD3 /* CdAttachment+Extension.swift in Sources */,
   3.209  				B716BE031EF01EB900523453 /* AccountSettingsViewModel.swift in Sources */,
   3.210 +				49D3BECC20F8F7330043E05D /* LoginViewController.swift in Sources */,
   3.211  				4340F5F91D363BE6006A5C82 /* ContactCell.swift in Sources */,
   3.212  				43425EDB1FE3DE6E004A2728 /* OAuth2ProviderProtocol.swift in Sources */,
   3.213  				43F8D80420C538740038ABD5 /* ThreadUnAwareFolderFactory.swift in Sources */,
   3.214  				43106A192045716000693144 /* OAuth2ConfigurationProtocol+Extension.swift in Sources */,
   3.215  				432142661E8FD6A400FBE987 /* ServiceUtil.swift in Sources */,
   3.216 +				15484B6C2105E26600F9D962 /* LegacyConnectInfoProvider.swift in Sources */,
   3.217  				43C322051EA89EED005073FB /* HandshakePartnerTableViewCell.swift in Sources */,
   3.218  				43E0CA2A1F4AB81600D9BB7E /* Attachment+Extension.swift in Sources */,
   3.219  				15BA536C20A08D270090F126 /* UnifiedInbox.swift in Sources */,
   3.220 @@ -3003,6 +3044,7 @@
   3.221  				15AA6016207CD71D00D57DB4 /* ImapFlags+Pantomime.swift in Sources */,
   3.222  				49228A5520D4035100A51E9D /* DetailCellSegue.swift in Sources */,
   3.223  				4307C4701ED81F3100A276A4 /* DefaultImapSyncDelegate.swift in Sources */,
   3.224 +				00FD0CE82102014C00BA0C56 /* PrimarySplitViewcontroller+ScreenComposerProtocol.swift in Sources */,
   3.225  				434E5A1B20DB9C4600D7F88A /* EmailListViewModel+MessageFolderDelegate.swift in Sources */,
   3.226  				431E58F61ED57F6500EFA77F /* AccountVerificationServiceProtocol.swift in Sources */,
   3.227  				434BF38D20C6742D00FCBCCA /* ThreadedFolder.swift in Sources */,
   3.228 @@ -3013,6 +3055,7 @@
   3.229  				B75CF47A20DBEA0000184F33 /* ThreadedSettingViewModel.swift in Sources */,
   3.230  				150B8E981FCDACBB00374438 /* ErrorPropagator.swift in Sources */,
   3.231  				49691B1520D7FD0200CA9367 /* MessageViewModelConfigurable.swift in Sources */,
   3.232 +				15484B682105D5AA00F9D962 /* ConnectInfo.swift in Sources */,
   3.233  				0038494C20D2587F008000EA /* PepPictureComposer.swift in Sources */,
   3.234  				43980EE01CBD24B000A7FC3C /* Log.swift in Sources */,
   3.235  				228038681DC9DE6D00F1CB45 /* TextfieldResponder.swift in Sources */,
   3.236 @@ -3026,6 +3069,7 @@
   3.237  				B78CF8291E76E0F1008C1739 /* FilterViewModel.swift in Sources */,
   3.238  				43293EFB1EB9DD6700EEE010 /* UIViewController+Extension.swift in Sources */,
   3.239  				4341EBD1208A0961004CE6B8 /* QualifyServerIsLocalServiceProtocol.swift in Sources */,
   3.240 +				00FD0CE62101F7D700BA0C56 /* ScreenComposerProtocol.swift in Sources */,
   3.241  				4351C2D81F4441190053381F /* references.c in Sources */,
   3.242  				432645811F4C26CF002E3EF8 /* NSAttributedString+Parsing.swift in Sources */,
   3.243  				000D3C2F20D12BFD006B11B2 /* MessageViewModel.swift in Sources */,
   3.244 @@ -3171,7 +3215,6 @@
   3.245  				151DE7E51FC5D41600CDC273 /* Base */,
   3.246  			);
   3.247  			name = FolderViews.storyboard;
   3.248 -			path = UI;
   3.249  			sourceTree = "<group>";
   3.250  		};
   3.251  		155F2DA020530798001B4B1C /* Reusable.storyboard */ = {
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/pEpForiOS/Assets.xcassets/Message List/compose.imageset/Contents.json	Thu Jul 26 13:41:45 2018 +0200
     4.3 @@ -0,0 +1,12 @@
     4.4 +{
     4.5 +  "images" : [
     4.6 +    {
     4.7 +      "idiom" : "universal",
     4.8 +      "filename" : "pEpForiOS-icon-compose.pdf"
     4.9 +    }
    4.10 +  ],
    4.11 +  "info" : {
    4.12 +    "version" : 1,
    4.13 +    "author" : "xcode"
    4.14 +  }
    4.15 +}
    4.16 \ No newline at end of file
     5.1 Binary file pEpForiOS/Assets.xcassets/Message List/compose.imageset/pEpForiOS-icon-compose.pdf has changed
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/pEpForiOS/Assets.xcassets/Message List/reply.imageset/Contents.json	Thu Jul 26 13:41:45 2018 +0200
     6.3 @@ -0,0 +1,15 @@
     6.4 +{
     6.5 +  "images" : [
     6.6 +    {
     6.7 +      "idiom" : "universal",
     6.8 +      "filename" : "pEpForiOS-icon-reply.pdf"
     6.9 +    }
    6.10 +  ],
    6.11 +  "info" : {
    6.12 +    "version" : 1,
    6.13 +    "author" : "xcode"
    6.14 +  },
    6.15 +  "properties" : {
    6.16 +    "preserves-vector-representation" : true
    6.17 +  }
    6.18 +}
    6.19 \ No newline at end of file
     7.1 Binary file pEpForiOS/Assets.xcassets/Message List/reply.imageset/pEpForiOS-icon-reply.pdf has changed
     8.1 --- a/pEpForiOS/Background/DeleteFolderOperation.swift	Fri Jul 20 14:07:19 2018 +0200
     8.2 +++ b/pEpForiOS/Background/DeleteFolderOperation.swift	Thu Jul 26 13:41:45 2018 +0200
     8.3 @@ -16,7 +16,7 @@
     8.4      var account: CdAccount!
     8.5      var syncDelegate: DeleteFolderSyncDelegate?
     8.6  
     8.7 -    public init(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
     8.8 +    init(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
     8.9                  imapSyncData: ImapSyncData, account: CdAccount,
    8.10                  folderName: String) {
    8.11          self.accountID = account.objectID
     9.1 --- a/pEpForiOS/Background/DeleteFoldersOperation.swift	Fri Jul 20 14:07:19 2018 +0200
     9.2 +++ b/pEpForiOS/Background/DeleteFoldersOperation.swift	Thu Jul 26 13:41:45 2018 +0200
     9.3 @@ -17,7 +17,7 @@
     9.4      var currentFolderName: String?
     9.5      var syncDelegate: DeleteFoldersSyncDelegate?
     9.6  
     9.7 -    public init(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
     9.8 +    init(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
     9.9                  imapSyncData: ImapSyncData, account: CdAccount) {
    9.10          self.accountID = account.objectID
    9.11          super.init(parentName: parentName, errorContainer: errorContainer,
    10.1 --- a/pEpForiOS/Background/FetchMessagesOperation.swift	Fri Jul 20 14:07:19 2018 +0200
    10.2 +++ b/pEpForiOS/Background/FetchMessagesOperation.swift	Thu Jul 26 13:41:45 2018 +0200
    10.3 @@ -26,7 +26,7 @@
    10.4      let messageFetchedBlock: MessageFetchedBlock?
    10.5      var syncDelegate: FetchMessagesSyncDelegate?
    10.6  
    10.7 -    public init(
    10.8 +    init(
    10.9          parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
   10.10          imapSyncData: ImapSyncData,
   10.11          folderName: String = ImapSync.defaultImapInboxName,
    11.1 --- a/pEpForiOS/Background/ImapSyncOperation.swift	Fri Jul 20 14:07:19 2018 +0200
    11.2 +++ b/pEpForiOS/Background/ImapSyncOperation.swift	Thu Jul 26 13:41:45 2018 +0200
    11.3 @@ -11,7 +11,7 @@
    11.4  public class ImapSyncOperation: ConcurrentBaseOperation {
    11.5      let imapSyncData: ImapSyncData
    11.6  
    11.7 -    public init(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
    11.8 +    init(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
    11.9                  imapSyncData: ImapSyncData) {
   11.10          self.imapSyncData = imapSyncData
   11.11          super.init(parentName: parentName, errorContainer: errorContainer)
    12.1 --- a/pEpForiOS/Background/SyncFlagsToServerOperation.swift	Fri Jul 20 14:07:19 2018 +0200
    12.2 +++ b/pEpForiOS/Background/SyncFlagsToServerOperation.swift	Thu Jul 26 13:41:45 2018 +0200
    12.3 @@ -27,8 +27,10 @@
    12.4      var changedMessageIDs = [NSManagedObjectID]()
    12.5      weak var delegate: SyncFlagsToServerOperationDelegate?
    12.6  
    12.7 -    public init?(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
    12.8 -                 imapSyncData: ImapSyncData, folder: CdFolder) {
    12.9 +    init?(parentName: String = #function,
   12.10 +          errorContainer: ServiceErrorProtocol = ErrorContainer(),
   12.11 +          imapSyncData: ImapSyncData,
   12.12 +          folder: CdFolder) {
   12.13          guard let moc = folder.managedObjectContext else {
   12.14              Log.shared.errorAndCrash(component: #function, errorString: "MO without moc")
   12.15              return nil
   12.16 @@ -53,9 +55,9 @@
   12.17                     imapSyncData: imapSyncData)
   12.18      }
   12.19  
   12.20 -    public convenience init?(parentName: String,
   12.21 -                             errorContainer: ServiceErrorProtocol = ErrorContainer(),
   12.22 -                             imapSyncData: ImapSyncData, folderID: NSManagedObjectID) {
   12.23 +    convenience init?(parentName: String,
   12.24 +                      errorContainer: ServiceErrorProtocol = ErrorContainer(),
   12.25 +                      imapSyncData: ImapSyncData, folderID: NSManagedObjectID) {
   12.26          let moc = Record.Context.background
   12.27          var folder: CdFolder? = nil;
   12.28          moc.performAndWait {
    13.1 --- a/pEpForiOS/Background/SyncFoldersFromServerOperation.swift	Fri Jul 20 14:07:19 2018 +0200
    13.2 +++ b/pEpForiOS/Background/SyncFoldersFromServerOperation.swift	Thu Jul 26 13:41:45 2018 +0200
    13.3 @@ -41,7 +41,7 @@
    13.4  
    13.5      // MARK: - LIFE CYCLE
    13.6  
    13.7 -    public init(parentName: String = #function,
    13.8 +    init(parentName: String = #function,
    13.9                  errorContainer: ServiceErrorProtocol = ErrorContainer(),
   13.10                  imapSyncData: ImapSyncData, onlyUpdateIfNecessary: Bool = false) {
   13.11          self.onlyUpdateIfNecessary = onlyUpdateIfNecessary
    14.1 --- a/pEpForiOS/Background/SyncMessagesOperation.swift	Fri Jul 20 14:07:19 2018 +0200
    14.2 +++ b/pEpForiOS/Background/SyncMessagesOperation.swift	Thu Jul 26 13:41:45 2018 +0200
    14.3 @@ -21,8 +21,12 @@
    14.4      let firstUID: UInt
    14.5      var syncDelegate: SyncMessagesSyncDelegate?
    14.6  
    14.7 -    public init(parentName: String = #function, errorContainer: ServiceErrorProtocol = ErrorContainer(),
    14.8 -                imapSyncData: ImapSyncData, folderName: String, firstUID: UInt, lastUID: UInt) {
    14.9 +    init(parentName: String = #function,
   14.10 +         errorContainer: ServiceErrorProtocol = ErrorContainer(),
   14.11 +         imapSyncData: ImapSyncData,
   14.12 +         folderName: String,
   14.13 +         firstUID: UInt,
   14.14 +         lastUID: UInt) {
   14.15          self.folderToOpen = folderName
   14.16          self.lastUID = lastUID
   14.17          self.firstUID = firstUID
   14.18 @@ -30,10 +34,10 @@
   14.19                     imapSyncData: imapSyncData)
   14.20      }
   14.21  
   14.22 -    public convenience init?(parentName: String,
   14.23 -                             errorContainer: ServiceErrorProtocol = ErrorContainer(),
   14.24 -                             imapSyncData: ImapSyncData,
   14.25 -                             folder: CdFolder) {
   14.26 +    convenience init?(parentName: String,
   14.27 +                      errorContainer: ServiceErrorProtocol = ErrorContainer(),
   14.28 +                      imapSyncData: ImapSyncData,
   14.29 +                      folder: CdFolder) {
   14.30          guard let folderName = folder.name else {
   14.31              return nil
   14.32          }
    15.1 --- a/pEpForiOS/Base.lproj/AccountCreation.storyboard	Fri Jul 20 14:07:19 2018 +0200
    15.2 +++ b/pEpForiOS/Base.lproj/AccountCreation.storyboard	Thu Jul 26 13:41:45 2018 +0200
    15.3 @@ -1,5 +1,5 @@
    15.4  <?xml version="1.0" encoding="UTF-8"?>
    15.5 -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="n6h-PU-h88">
    15.6 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="n6h-PU-h88">
    15.7      <device id="retina4_7" orientation="portrait">
    15.8          <adaptation id="fullscreen"/>
    15.9      </device>
   15.10 @@ -7,6 +7,7 @@
   15.11          <deployment identifier="iOS"/>
   15.12          <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
   15.13          <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
   15.14 +        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
   15.15          <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   15.16      </dependencies>
   15.17      <scenes>
   15.18 @@ -521,7 +522,7 @@
   15.19                          <outlet property="serverValue" destination="HIi-Wv-jJs" id="yqf-Es-fSK"/>
   15.20                          <outlet property="transportSecurity" destination="Cjb-ue-OdU" id="W8X-Rm-6rK"/>
   15.21                          <segue destination="6yd-9e-jF0" kind="show" identifier="viewLogSegue" id="ohe-5h-dsJ"/>
   15.22 -                        <segue destination="4H2-fK-y3g" kind="unwind" identifier="backToEmailListSegue" unwindAction="unwindToFolderViewWithSegue:" id="KmU-Ae-tvH"/>
   15.23 +                        <segue destination="4H2-fK-y3g" kind="unwind" identifier="backToEmailListSegue" unwindAction="segueUnwindAfterAccountCreationWithSegue:" id="KmU-Ae-tvH"/>
   15.24                      </connections>
   15.25                  </tableViewController>
   15.26                  <placeholder placeholderIdentifier="IBFirstResponder" id="SBU-82-njk" userLabel="First Responder" sceneMemberID="firstResponder"/>
   15.27 @@ -529,10 +530,10 @@
   15.28              </objects>
   15.29              <point key="canvasLocation" x="9512.7999999999993" y="-395.35232383808096"/>
   15.30          </scene>
   15.31 -        <!--UIViewController-01V-rr-Nt1-->
   15.32 +        <!--logNavController-->
   15.33          <scene sceneID="m5u-Nz-i7s">
   15.34              <objects>
   15.35 -                <viewControllerPlaceholder storyboardName="Settings" referencedIdentifier="UIViewController-01V-rr-Nt1" id="kdj-h1-w8d" sceneMemberID="viewController"/>
   15.36 +                <viewControllerPlaceholder storyboardName="Settings" referencedIdentifier="logNavController" id="kdj-h1-w8d" sceneMemberID="viewController"/>
   15.37                  <placeholder placeholderIdentifier="IBFirstResponder" id="4Zu-x4-nOq" userLabel="First Responder" sceneMemberID="firstResponder"/>
   15.38              </objects>
   15.39              <point key="canvasLocation" x="5868" y="-411"/>
   15.40 @@ -717,6 +718,248 @@
   15.41              </objects>
   15.42              <point key="canvasLocation" x="8172" y="348.57571214392806"/>
   15.43          </scene>
   15.44 +        <!--Login View Controller-->
   15.45 +        <scene sceneID="c7J-uR-yAd">
   15.46 +            <objects>
   15.47 +                <viewController id="clh-8B-z2B" customClass="LoginViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
   15.48 +                    <view key="view" contentMode="scaleToFill" id="7n3-u6-UKe">
   15.49 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
   15.50 +                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
   15.51 +                        <subviews>
   15.52 +                            <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mfN-N5-g8Y">
   15.53 +                                <rect key="frame" x="0.0" y="64" width="375" height="603"/>
   15.54 +                                <subviews>
   15.55 +                                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KYm-MK-9MQ" userLabel="ContentView">
   15.56 +                                        <rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
   15.57 +                                        <subviews>
   15.58 +                                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splashscreen" translatesAutoresizingMaskIntoConstraints="NO" id="qYA-qu-vFE">
   15.59 +                                                <rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
   15.60 +                                            </imageView>
   15.61 +                                            <view contentMode="scaleToFill" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="7IS-Mp-8VB">
   15.62 +                                                <rect key="frame" x="37.5" y="223.5" width="300" height="152"/>
   15.63 +                                                <subviews>
   15.64 +                                                    <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="line" placeholder="Username" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="mKi-gF-bu9" customClass="CredentialTextField" customModule="pEpForiOS" customModuleProvider="target">
   15.65 +                                                        <rect key="frame" x="0.0" y="0.0" width="300" height="28"/>
   15.66 +                                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   15.67 +                                                        <accessibility key="accessibilityConfiguration" identifier="username"/>
   15.68 +                                                        <constraints>
   15.69 +                                                            <constraint firstAttribute="width" constant="300" id="3CW-GR-48R">
   15.70 +                                                                <variation key="heightClass=compact" constant="250"/>
   15.71 +                                                            </constraint>
   15.72 +                                                            <constraint firstAttribute="height" constant="28" id="KLj-2n-NCg"/>
   15.73 +                                                        </constraints>
   15.74 +                                                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   15.75 +                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
   15.76 +                                                        <textInputTraits key="textInputTraits" autocapitalizationType="words" autocorrectionType="no" spellCheckingType="no" returnKeyType="next"/>
   15.77 +                                                        <userDefinedRuntimeAttributes>
   15.78 +                                                            <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
   15.79 +                                                                <color key="value" red="0.7843137255" green="0.95294117649999999" blue="0.85882352939999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
   15.80 +                                                            </userDefinedRuntimeAttribute>
   15.81 +                                                            <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
   15.82 +                                                                <real key="value" value="1"/>
   15.83 +                                                            </userDefinedRuntimeAttribute>
   15.84 +                                                            <userDefinedRuntimeAttribute type="color" keyPath="placeholderColor">
   15.85 +                                                                <color key="value" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   15.86 +                                                            </userDefinedRuntimeAttribute>
   15.87 +                                                        </userDefinedRuntimeAttributes>
   15.88 +                                                    </textField>
   15.89 +                                                    <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="line" placeholder="Email Address" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="36s-Iw-b58" customClass="CredentialTextField" customModule="pEpForiOS" customModuleProvider="target">
   15.90 +                                                        <rect key="frame" x="0.0" y="62" width="300" height="28"/>
   15.91 +                                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   15.92 +                                                        <accessibility key="accessibilityConfiguration" identifier="email"/>
   15.93 +                                                        <constraints>
   15.94 +                                                            <constraint firstAttribute="height" constant="28" id="QOR-dt-iTk"/>
   15.95 +                                                        </constraints>
   15.96 +                                                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   15.97 +                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
   15.98 +                                                        <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="emailAddress" returnKeyType="next" smartDashesType="no" smartInsertDeleteType="no" textContentType="email"/>
   15.99 +                                                        <userDefinedRuntimeAttributes>
  15.100 +                                                            <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
  15.101 +                                                                <color key="value" red="0.7843137255" green="0.95294117649999999" blue="0.85882352939999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  15.102 +                                                            </userDefinedRuntimeAttribute>
  15.103 +                                                            <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
  15.104 +                                                                <real key="value" value="1"/>
  15.105 +                                                            </userDefinedRuntimeAttribute>
  15.106 +                                                            <userDefinedRuntimeAttribute type="color" keyPath="placeholderColor">
  15.107 +                                                                <color key="value" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.108 +                                                            </userDefinedRuntimeAttribute>
  15.109 +                                                        </userDefinedRuntimeAttributes>
  15.110 +                                                        <connections>
  15.111 +                                                            <action selector="emailChanged:" destination="clh-8B-z2B" eventType="editingChanged" id="hsV-YG-JFW"/>
  15.112 +                                                        </connections>
  15.113 +                                                    </textField>
  15.114 +                                                    <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="line" placeholder="Password" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="3wB-RC-5fz" customClass="CredentialTextField" customModule="pEpForiOS" customModuleProvider="target">
  15.115 +                                                        <rect key="frame" x="0.0" y="124" width="300" height="28"/>
  15.116 +                                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.117 +                                                        <accessibility key="accessibilityConfiguration" identifier="password"/>
  15.118 +                                                        <constraints>
  15.119 +                                                            <constraint firstAttribute="height" constant="28" id="dOX-HK-3Vs"/>
  15.120 +                                                        </constraints>
  15.121 +                                                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.122 +                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
  15.123 +                                                        <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" secureTextEntry="YES"/>
  15.124 +                                                        <userDefinedRuntimeAttributes>
  15.125 +                                                            <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
  15.126 +                                                                <color key="value" red="0.7843137255" green="0.95294117649999999" blue="0.85882352939999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  15.127 +                                                            </userDefinedRuntimeAttribute>
  15.128 +                                                            <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
  15.129 +                                                                <real key="value" value="1"/>
  15.130 +                                                            </userDefinedRuntimeAttribute>
  15.131 +                                                            <userDefinedRuntimeAttribute type="color" keyPath="placeholderColor">
  15.132 +                                                                <color key="value" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.133 +                                                            </userDefinedRuntimeAttribute>
  15.134 +                                                        </userDefinedRuntimeAttributes>
  15.135 +                                                    </textField>
  15.136 +                                                </subviews>
  15.137 +                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.138 +                                                <constraints>
  15.139 +                                                    <constraint firstItem="mKi-gF-bu9" firstAttribute="centerX" secondItem="7IS-Mp-8VB" secondAttribute="centerX" id="1ms-n9-4as"/>
  15.140 +                                                    <constraint firstItem="3wB-RC-5fz" firstAttribute="centerX" secondItem="7IS-Mp-8VB" secondAttribute="centerX" id="34A-E7-GNN"/>
  15.141 +                                                    <constraint firstItem="36s-Iw-b58" firstAttribute="top" secondItem="mKi-gF-bu9" secondAttribute="bottom" constant="34" id="6Ag-1z-bFo"/>
  15.142 +                                                    <constraint firstItem="36s-Iw-b58" firstAttribute="width" secondItem="mKi-gF-bu9" secondAttribute="width" id="9Oi-kX-hhU"/>
  15.143 +                                                    <constraint firstItem="mKi-gF-bu9" firstAttribute="leading" secondItem="7IS-Mp-8VB" secondAttribute="leading" id="AZM-d1-S7y"/>
  15.144 +                                                    <constraint firstItem="36s-Iw-b58" firstAttribute="centerX" secondItem="7IS-Mp-8VB" secondAttribute="centerX" id="Xfc-yX-uH4"/>
  15.145 +                                                    <constraint firstItem="3wB-RC-5fz" firstAttribute="width" secondItem="36s-Iw-b58" secondAttribute="width" id="Z8I-PG-mQ9"/>
  15.146 +                                                    <constraint firstItem="3wB-RC-5fz" firstAttribute="top" secondItem="36s-Iw-b58" secondAttribute="bottom" constant="34" id="bc2-Nv-gyk"/>
  15.147 +                                                    <constraint firstItem="mKi-gF-bu9" firstAttribute="top" secondItem="7IS-Mp-8VB" secondAttribute="top" id="mcX-3Z-PNw"/>
  15.148 +                                                    <constraint firstAttribute="bottom" secondItem="3wB-RC-5fz" secondAttribute="bottom" id="pg3-uy-lzJ"/>
  15.149 +                                                </constraints>
  15.150 +                                            </view>
  15.151 +                                            <button opaque="NO" contentMode="scaleToFill" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lTY-gw-zK9">
  15.152 +                                                <rect key="frame" x="163" y="425.5" width="49" height="32"/>
  15.153 +                                                <fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
  15.154 +                                                <state key="normal" title="Sign In">
  15.155 +                                                    <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.156 +                                                </state>
  15.157 +                                                <connections>
  15.158 +                                                    <action selector="logIn:" destination="clh-8B-z2B" eventType="touchUpInside" id="Ng7-qd-Lv9"/>
  15.159 +                                                </connections>
  15.160 +                                            </button>
  15.161 +                                            <button opaque="NO" contentMode="scaleToFill" horizontalCompressionResistancePriority="752" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="O4c-eF-dJT">
  15.162 +                                                <rect key="frame" x="156" y="526.5" width="64" height="29"/>
  15.163 +                                                <fontDescription key="fontDescription" type="system" weight="thin" pointSize="14"/>
  15.164 +                                                <state key="normal" title="Advanced">
  15.165 +                                                    <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.166 +                                                </state>
  15.167 +                                                <connections>
  15.168 +                                                    <segue destination="Efv-29-FEv" kind="show" identifier="manualConfigSegue" id="HcB-v7-c76"/>
  15.169 +                                                </connections>
  15.170 +                                            </button>
  15.171 +                                        </subviews>
  15.172 +                                        <constraints>
  15.173 +                                            <constraint firstAttribute="bottom" secondItem="lTY-gw-zK9" secondAttribute="bottom" priority="750" constant="145.5" id="1Jp-wK-FMZ"/>
  15.174 +                                            <constraint firstAttribute="bottom" secondItem="lTY-gw-zK9" secondAttribute="bottom" constant="145.5" id="D5k-Pq-NkU"/>
  15.175 +                                            <constraint firstItem="7IS-Mp-8VB" firstAttribute="centerY" secondItem="8XY-h6-v7E" secondAttribute="centerY" id="Eau-tw-crL"/>
  15.176 +                                            <constraint firstItem="8XY-h6-v7E" firstAttribute="trailing" secondItem="lTY-gw-zK9" secondAttribute="trailing" priority="750" constant="74" id="K0i-st-1Td">
  15.177 +                                                <variation key="heightClass=compact" constant="8"/>
  15.178 +                                            </constraint>
  15.179 +                                            <constraint firstItem="qYA-qu-vFE" firstAttribute="leading" secondItem="8XY-h6-v7E" secondAttribute="leading" id="LbJ-ZA-TEL"/>
  15.180 +                                            <constraint firstItem="7IS-Mp-8VB" firstAttribute="centerY" secondItem="8XY-h6-v7E" secondAttribute="centerY" priority="749" id="Lj5-RZ-eaB"/>
  15.181 +                                            <constraint firstItem="7IS-Mp-8VB" firstAttribute="centerX" secondItem="KYm-MK-9MQ" secondAttribute="centerX" id="R35-5Q-8Ji"/>
  15.182 +                                            <constraint firstItem="O4c-eF-dJT" firstAttribute="centerX" secondItem="lTY-gw-zK9" secondAttribute="centerX" id="Rqe-s9-VcT"/>
  15.183 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="centerY" secondItem="8XY-h6-v7E" secondAttribute="centerY" id="S0B-zV-xqY"/>
  15.184 +                                            <constraint firstItem="8XY-h6-v7E" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="O4c-eF-dJT" secondAttribute="trailing" constant="8" id="VW7-JT-bRE">
  15.185 +                                                <variation key="heightClass=compact" constant="8"/>
  15.186 +                                            </constraint>
  15.187 +                                            <constraint firstItem="7IS-Mp-8VB" firstAttribute="top" relation="greaterThanOrEqual" secondItem="8XY-h6-v7E" secondAttribute="top" constant="8" id="Vw6-Ka-K5S"/>
  15.188 +                                            <constraint firstItem="8XY-h6-v7E" firstAttribute="trailing" secondItem="qYA-qu-vFE" secondAttribute="trailing" id="WCG-Pm-sgF"/>
  15.189 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="7IS-Mp-8VB" secondAttribute="trailing" constant="8" id="XuF-mJ-K95">
  15.190 +                                                <variation key="heightClass=compact" constant="8"/>
  15.191 +                                            </constraint>
  15.192 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="leading" secondItem="36s-Iw-b58" secondAttribute="trailing" priority="750" constant="60" id="dgS-ln-IuB">
  15.193 +                                                <variation key="heightClass=compact" constant="8"/>
  15.194 +                                            </constraint>
  15.195 +                                            <constraint firstItem="O4c-eF-dJT" firstAttribute="top" relation="greaterThanOrEqual" secondItem="lTY-gw-zK9" secondAttribute="bottom" constant="8" id="e4Y-2z-C70"/>
  15.196 +                                            <constraint firstAttribute="bottom" secondItem="qYA-qu-vFE" secondAttribute="bottom" id="eqO-4s-oe2"/>
  15.197 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="centerX" secondItem="7IS-Mp-8VB" secondAttribute="centerX" id="gVR-yZ-GlE"/>
  15.198 +                                            <constraint firstItem="O4c-eF-dJT" firstAttribute="centerY" secondItem="3wB-RC-5fz" secondAttribute="centerY" id="msW-Uz-O7y"/>
  15.199 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="bottom" relation="lessThanOrEqual" secondItem="KYm-MK-9MQ" secondAttribute="bottom" constant="145" id="neM-48-j4c"/>
  15.200 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="trailing" relation="lessThanOrEqual" secondItem="8XY-h6-v7E" secondAttribute="trailing" constant="8" id="o71-cd-lSO">
  15.201 +                                                <variation key="heightClass=compact" constant="-8"/>
  15.202 +                                            </constraint>
  15.203 +                                            <constraint firstItem="qYA-qu-vFE" firstAttribute="top" secondItem="KYm-MK-9MQ" secondAttribute="top" id="oed-9e-ftm"/>
  15.204 +                                            <constraint firstItem="O4c-eF-dJT" firstAttribute="top" secondItem="lTY-gw-zK9" secondAttribute="bottom" priority="750" constant="69" id="qci-hY-6fj"/>
  15.205 +                                            <constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="O4c-eF-dJT" secondAttribute="bottom" constant="46" id="rrf-8k-elt">
  15.206 +                                                <variation key="heightClass=compact" constant="8"/>
  15.207 +                                            </constraint>
  15.208 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="top" relation="greaterThanOrEqual" secondItem="7IS-Mp-8VB" secondAttribute="bottom" constant="50" id="sAa-Hc-jVc"/>
  15.209 +                                            <constraint firstItem="lTY-gw-zK9" firstAttribute="top" secondItem="7IS-Mp-8VB" secondAttribute="bottom" priority="750" constant="50" id="y1H-ee-3d9"/>
  15.210 +                                        </constraints>
  15.211 +                                        <viewLayoutGuide key="safeArea" id="8XY-h6-v7E"/>
  15.212 +                                        <variation key="default">
  15.213 +                                            <mask key="constraints">
  15.214 +                                                <exclude reference="K0i-st-1Td"/>
  15.215 +                                                <exclude reference="VW7-JT-bRE"/>
  15.216 +                                                <exclude reference="Eau-tw-crL"/>
  15.217 +                                                <exclude reference="S0B-zV-xqY"/>
  15.218 +                                                <exclude reference="XuF-mJ-K95"/>
  15.219 +                                                <exclude reference="dgS-ln-IuB"/>
  15.220 +                                                <exclude reference="o71-cd-lSO"/>
  15.221 +                                                <exclude reference="msW-Uz-O7y"/>
  15.222 +                                            </mask>
  15.223 +                                        </variation>
  15.224 +                                        <variation key="heightClass=compact">
  15.225 +                                            <mask key="constraints">
  15.226 +                                                <include reference="K0i-st-1Td"/>
  15.227 +                                                <include reference="VW7-JT-bRE"/>
  15.228 +                                                <include reference="Eau-tw-crL"/>
  15.229 +                                                <exclude reference="Lj5-RZ-eaB"/>
  15.230 +                                                <exclude reference="Vw6-Ka-K5S"/>
  15.231 +                                                <exclude reference="1Jp-wK-FMZ"/>
  15.232 +                                                <exclude reference="D5k-Pq-NkU"/>
  15.233 +                                                <include reference="S0B-zV-xqY"/>
  15.234 +                                                <include reference="XuF-mJ-K95"/>
  15.235 +                                                <include reference="dgS-ln-IuB"/>
  15.236 +                                                <exclude reference="gVR-yZ-GlE"/>
  15.237 +                                                <exclude reference="neM-48-j4c"/>
  15.238 +                                                <include reference="o71-cd-lSO"/>
  15.239 +                                                <exclude reference="sAa-Hc-jVc"/>
  15.240 +                                                <include reference="msW-Uz-O7y"/>
  15.241 +                                                <exclude reference="qci-hY-6fj"/>
  15.242 +                                            </mask>
  15.243 +                                        </variation>
  15.244 +                                    </view>
  15.245 +                                    <activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="dja-Bh-vu3">
  15.246 +                                        <rect key="frame" x="169" y="383.5" width="37" height="37"/>
  15.247 +                                    </activityIndicatorView>
  15.248 +                                </subviews>
  15.249 +                                <constraints>
  15.250 +                                    <constraint firstAttribute="trailing" secondItem="KYm-MK-9MQ" secondAttribute="trailing" id="V6p-Xd-zIP"/>
  15.251 +                                    <constraint firstItem="KYm-MK-9MQ" firstAttribute="top" secondItem="mfN-N5-g8Y" secondAttribute="top" id="WiK-Z3-Smf"/>
  15.252 +                                    <constraint firstItem="KYm-MK-9MQ" firstAttribute="leading" secondItem="mfN-N5-g8Y" secondAttribute="leading" id="YHy-Bc-Jvo"/>
  15.253 +                                    <constraint firstItem="dja-Bh-vu3" firstAttribute="top" secondItem="3wB-RC-5fz" secondAttribute="bottom" constant="8" id="fa6-Pp-07o"/>
  15.254 +                                    <constraint firstItem="KYm-MK-9MQ" firstAttribute="centerX" secondItem="mfN-N5-g8Y" secondAttribute="centerX" id="jMC-uL-WQo"/>
  15.255 +                                    <constraint firstAttribute="bottom" secondItem="KYm-MK-9MQ" secondAttribute="bottom" id="kjz-g4-Xu7"/>
  15.256 +                                    <constraint firstItem="KYm-MK-9MQ" firstAttribute="centerY" secondItem="mfN-N5-g8Y" secondAttribute="centerY" id="pgh-QB-5us"/>
  15.257 +                                    <constraint firstItem="dja-Bh-vu3" firstAttribute="centerX" secondItem="3wB-RC-5fz" secondAttribute="centerX" id="uoo-Oa-ITD"/>
  15.258 +                                </constraints>
  15.259 +                            </scrollView>
  15.260 +                        </subviews>
  15.261 +                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  15.262 +                        <constraints>
  15.263 +                            <constraint firstItem="mfN-N5-g8Y" firstAttribute="trailing" secondItem="jAI-Xy-z2r" secondAttribute="trailing" id="LLP-nz-asU"/>
  15.264 +                            <constraint firstItem="mfN-N5-g8Y" firstAttribute="top" secondItem="jAI-Xy-z2r" secondAttribute="top" id="Td1-FE-HYs"/>
  15.265 +                            <constraint firstItem="jAI-Xy-z2r" firstAttribute="leading" secondItem="mfN-N5-g8Y" secondAttribute="leading" id="l2S-RX-1bM"/>
  15.266 +                            <constraint firstAttribute="bottom" secondItem="mfN-N5-g8Y" secondAttribute="bottom" id="pgz-bC-B7d"/>
  15.267 +                        </constraints>
  15.268 +                        <viewLayoutGuide key="safeArea" id="jAI-Xy-z2r"/>
  15.269 +                    </view>
  15.270 +                    <navigationItem key="navigationItem" id="sZ7-8R-F3P"/>
  15.271 +                    <connections>
  15.272 +                        <outlet property="activityIndicatorView" destination="dja-Bh-vu3" id="2gM-xR-4Fn"/>
  15.273 +                        <outlet property="contentScrollView" destination="mfN-N5-g8Y" id="JuM-x6-79x"/>
  15.274 +                        <outlet property="emailAddress" destination="36s-Iw-b58" id="u6P-Xx-b8J"/>
  15.275 +                        <outlet property="loginButton" destination="lTY-gw-zK9" id="Mfx-D4-xzW"/>
  15.276 +                        <outlet property="manualConfigButton" destination="O4c-eF-dJT" id="vnZ-WA-mrK"/>
  15.277 +                        <outlet property="password" destination="3wB-RC-5fz" id="nje-PL-ldq"/>
  15.278 +                        <outlet property="user" destination="mKi-gF-bu9" id="UKH-Mf-Jwf"/>
  15.279 +                        <segue destination="kdj-h1-w8d" kind="show" identifier="viewLogSegue" id="yg0-Go-ez6"/>
  15.280 +                    </connections>
  15.281 +                </viewController>
  15.282 +                <placeholder placeholderIdentifier="IBFirstResponder" id="bBb-dZ-w49" userLabel="First Responder" sceneMemberID="firstResponder"/>
  15.283 +            </objects>
  15.284 +            <point key="canvasLocation" x="9167.2000000000007" y="335.98200899550227"/>
  15.285 +        </scene>
  15.286          <!--UIViewController-01V-rr-Nt1-->
  15.287          <scene sceneID="Ib2-kl-E5M">
  15.288              <objects>
  15.289 @@ -736,7 +979,7 @@
  15.290                      </navigationBar>
  15.291                      <nil name="viewControllers"/>
  15.292                      <connections>
  15.293 -                        <segue destination="0x8-ea-YBj" kind="relationship" relationship="rootViewController" id="ZPY-i6-k3I"/>
  15.294 +                        <segue destination="clh-8B-z2B" kind="relationship" relationship="rootViewController" id="oJy-Qa-jKN"/>
  15.295                      </connections>
  15.296                  </navigationController>
  15.297                  <placeholder placeholderIdentifier="IBFirstResponder" id="D07-Xf-86Q" userLabel="First Responder" sceneMemberID="firstResponder"/>
  15.298 @@ -744,4 +987,11 @@
  15.299              <point key="canvasLocation" x="7232.8000000000002" y="348.57571214392806"/>
  15.300          </scene>
  15.301      </scenes>
  15.302 +    <resources>
  15.303 +        <image name="splashscreen" width="228" height="404"/>
  15.304 +    </resources>
  15.305 +    <inferredMetricsTieBreakers>
  15.306 +        <segue reference="HcB-v7-c76"/>
  15.307 +        <segue reference="yg0-Go-ez6"/>
  15.308 +    </inferredMetricsTieBreakers>
  15.309  </document>
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/pEpForiOS/Base.lproj/FolderViews.storyboard	Thu Jul 26 13:41:45 2018 +0200
    16.3 @@ -0,0 +1,130 @@
    16.4 +<?xml version="1.0" encoding="UTF-8"?>
    16.5 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="N0y-5z-66z">
    16.6 +    <device id="retina4_7" orientation="portrait">
    16.7 +        <adaptation id="fullscreen"/>
    16.8 +    </device>
    16.9 +    <dependencies>
   16.10 +        <deployment identifier="iOS"/>
   16.11 +        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
   16.12 +        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   16.13 +    </dependencies>
   16.14 +    <scenes>
   16.15 +        <!--Folder Table View Controller-->
   16.16 +        <scene sceneID="sp8-r5-QDF">
   16.17 +            <objects>
   16.18 +                <tableViewController storyboardIdentifier="Folders" id="6ra-tc-Aiv" customClass="FolderTableViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
   16.19 +                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="OAM-Xh-1fA">
   16.20 +                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
   16.21 +                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
   16.22 +                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
   16.23 +                        <color key="sectionIndexBackgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   16.24 +                        <view key="tableFooterView" contentMode="scaleToFill" id="y1Q-G4-Yvh">
   16.25 +                            <rect key="frame" x="0.0" y="72" width="375" height="80"/>
   16.26 +                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
   16.27 +                            <subviews>
   16.28 +                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NEj-lZ-p6O">
   16.29 +                                    <rect key="frame" x="10" y="10" width="250" height="60"/>
   16.30 +                                    <constraints>
   16.31 +                                        <constraint firstAttribute="width" constant="250" id="hN3-sc-EZD"/>
   16.32 +                                    </constraints>
   16.33 +                                    <fontDescription key="fontDescription" type="system" pointSize="18"/>
   16.34 +                                    <inset key="contentEdgeInsets" minX="25" minY="0.0" maxX="0.0" maxY="0.0"/>
   16.35 +                                    <inset key="titleEdgeInsets" minX="25" minY="0.0" maxX="0.0" maxY="0.0"/>
   16.36 +                                    <state key="normal" title="Add Account" image="button-add">
   16.37 +                                        <color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   16.38 +                                    </state>
   16.39 +                                    <connections>
   16.40 +                                        <segue destination="uKb-Ku-Cng" kind="presentation" identifier="newAccount" modalPresentationStyle="formSheet" id="aKb-z0-Qyn"/>
   16.41 +                                    </connections>
   16.42 +                                </button>
   16.43 +                            </subviews>
   16.44 +                            <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
   16.45 +                            <constraints>
   16.46 +                                <constraint firstItem="NEj-lZ-p6O" firstAttribute="centerY" secondItem="y1Q-G4-Yvh" secondAttribute="centerY" id="UiB-SQ-x7F"/>
   16.47 +                                <constraint firstItem="NEj-lZ-p6O" firstAttribute="top" secondItem="y1Q-G4-Yvh" secondAttribute="top" constant="10" id="mKu-BF-aVp"/>
   16.48 +                                <constraint firstItem="NEj-lZ-p6O" firstAttribute="leading" secondItem="y1Q-G4-Yvh" secondAttribute="leading" constant="10" id="sYX-Dy-WeQ"/>
   16.49 +                            </constraints>
   16.50 +                        </view>
   16.51 +                        <prototypes>
   16.52 +                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="Default" id="Gav-RT-MrD">
   16.53 +                                <rect key="frame" x="0.0" y="28" width="375" height="44"/>
   16.54 +                                <autoresizingMask key="autoresizingMask"/>
   16.55 +                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Gav-RT-MrD" id="GDF-rs-ueo">
   16.56 +                                    <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
   16.57 +                                    <autoresizingMask key="autoresizingMask"/>
   16.58 +                                </tableViewCellContentView>
   16.59 +                            </tableViewCell>
   16.60 +                        </prototypes>
   16.61 +                        <connections>
   16.62 +                            <outlet property="dataSource" destination="6ra-tc-Aiv" id="1SN-a9-8B6"/>
   16.63 +                            <outlet property="delegate" destination="6ra-tc-Aiv" id="z48-Ic-eJ4"/>
   16.64 +                        </connections>
   16.65 +                    </tableView>
   16.66 +                    <toolbarItems/>
   16.67 +                    <navigationItem key="navigationItem" id="rcC-dN-oTh"/>
   16.68 +                    <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
   16.69 +                </tableViewController>
   16.70 +                <placeholder placeholderIdentifier="IBFirstResponder" id="o2c-UY-yR4" userLabel="First Responder" sceneMemberID="firstResponder"/>
   16.71 +            </objects>
   16.72 +            <point key="canvasLocation" x="9884" y="-1164.4677661169417"/>
   16.73 +        </scene>
   16.74 +        <!--Settings-->
   16.75 +        <scene sceneID="pIX-qm-rCm">
   16.76 +            <objects>
   16.77 +                <viewControllerPlaceholder storyboardName="Settings" id="tEI-hD-lXp" sceneMemberID="viewController"/>
   16.78 +                <placeholder placeholderIdentifier="IBFirstResponder" id="eR0-nA-UVS" userLabel="First Responder" sceneMemberID="firstResponder"/>
   16.79 +            </objects>
   16.80 +            <point key="canvasLocation" x="10572" y="-1187.4062968515743"/>
   16.81 +        </scene>
   16.82 +        <!--AccountCreation-->
   16.83 +        <scene sceneID="rdR-gU-SsC">
   16.84 +            <objects>
   16.85 +                <viewControllerPlaceholder storyboardName="AccountCreation" id="uKb-Ku-Cng" sceneMemberID="viewController"/>
   16.86 +                <placeholder placeholderIdentifier="IBFirstResponder" id="7bq-Lz-J44" userLabel="First Responder" sceneMemberID="firstResponder"/>
   16.87 +            </objects>
   16.88 +            <point key="canvasLocation" x="10612.799999999999" y="-1142.4287856071965"/>
   16.89 +        </scene>
   16.90 +        <!--Main-->
   16.91 +        <scene sceneID="eeX-Fr-Vs1">
   16.92 +            <objects>
   16.93 +                <viewControllerPlaceholder storyboardName="Main" id="jlA-KV-xmZ" sceneMemberID="viewController">
   16.94 +                    <navigationItem key="navigationItem" id="C0u-m3-NYA"/>
   16.95 +                </viewControllerPlaceholder>
   16.96 +                <placeholder placeholderIdentifier="IBFirstResponder" id="nrT-r1-KyC" userLabel="First Responder" sceneMemberID="firstResponder"/>
   16.97 +            </objects>
   16.98 +            <point key="canvasLocation" x="10091" y="-423"/>
   16.99 +        </scene>
  16.100 +        <!--Navigation Controller-->
  16.101 +        <scene sceneID="7fi-4c-XJX">
  16.102 +            <objects>
  16.103 +                <navigationController id="vQa-F1-CvY" sceneMemberID="viewController">
  16.104 +                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="9sq-1a-bXm">
  16.105 +                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
  16.106 +                        <autoresizingMask key="autoresizingMask"/>
  16.107 +                    </navigationBar>
  16.108 +                    <connections>
  16.109 +                        <segue destination="6ra-tc-Aiv" kind="relationship" relationship="rootViewController" id="DdA-8g-fEw"/>
  16.110 +                    </connections>
  16.111 +                </navigationController>
  16.112 +                <placeholder placeholderIdentifier="IBFirstResponder" id="79P-lr-Jjm" userLabel="First Responder" sceneMemberID="firstResponder"/>
  16.113 +            </objects>
  16.114 +            <point key="canvasLocation" x="9094" y="-1164"/>
  16.115 +        </scene>
  16.116 +        <!--Primary Split View Controller-->
  16.117 +        <scene sceneID="cmc-6v-uzh">
  16.118 +            <objects>
  16.119 +                <splitViewController storyboardIdentifier="main.initial.nvc" maximumPrimaryColumnWidth="320" id="N0y-5z-66z" customClass="PrimarySplitViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
  16.120 +                    <connections>
  16.121 +                        <segue destination="vQa-F1-CvY" kind="relationship" relationship="masterViewController" id="LaJ-Ow-wD4"/>
  16.122 +                        <segue destination="jlA-KV-xmZ" kind="relationship" relationship="detailViewController" id="b81-as-g9K"/>
  16.123 +                    </connections>
  16.124 +                </splitViewController>
  16.125 +                <placeholder placeholderIdentifier="IBFirstResponder" id="d4z-SE-fTT" userLabel="First Responder" sceneMemberID="firstResponder"/>
  16.126 +            </objects>
  16.127 +            <point key="canvasLocation" x="8334" y="-418"/>
  16.128 +        </scene>
  16.129 +    </scenes>
  16.130 +    <resources>
  16.131 +        <image name="button-add" width="22" height="22"/>
  16.132 +    </resources>
  16.133 +</document>
    17.1 --- a/pEpForiOS/Base.lproj/Main.storyboard	Fri Jul 20 14:07:19 2018 +0200
    17.2 +++ b/pEpForiOS/Base.lproj/Main.storyboard	Thu Jul 26 13:41:45 2018 +0200
    17.3 @@ -83,7 +83,7 @@
    17.4                                              </constraints>
    17.5                                          </imageView>
    17.6                                          <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="m0u-Jn-mQU">
    17.7 -                                            <rect key="frame" x="44" y="36" width="20" height="20"/>
    17.8 +                                            <rect key="frame" x="44" y="40" width="20" height="20"/>
    17.9                                              <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
   17.10                                              <constraints>
   17.11                                                  <constraint firstAttribute="height" constant="20" id="4Pu-ac-G9n"/>
   17.12 @@ -133,7 +133,7 @@
   17.13                                          <constraint firstItem="YqR-ga-Tf9" firstAttribute="top" secondItem="jgQ-nZ-h1r" secondAttribute="topMargin" constant="-3" id="j3H-Iv-HG5"/>
   17.14                                          <constraint firstAttribute="trailing" secondItem="8QD-qP-0hS" secondAttribute="trailing" constant="8" id="n5I-Yb-okr"/>
   17.15                                          <constraint firstItem="BvI-Zi-zU6" firstAttribute="trailing" secondItem="8QD-qP-0hS" secondAttribute="trailing" id="tYc-Ao-foD"/>
   17.16 -                                        <constraint firstItem="m0u-Jn-mQU" firstAttribute="bottom" secondItem="YqR-ga-Tf9" secondAttribute="bottom" id="ubw-w6-q4y"/>
   17.17 +                                        <constraint firstItem="m0u-Jn-mQU" firstAttribute="bottom" secondItem="YqR-ga-Tf9" secondAttribute="bottom" constant="4" id="ubw-w6-q4y"/>
   17.18                                      </constraints>
   17.19                                  </tableViewCellContentView>
   17.20                                  <connections>
   17.21 @@ -168,7 +168,7 @@
   17.22                              </connections>
   17.23                          </barButtonItem>
   17.24                          <barButtonItem style="plain" systemItem="flexibleSpace" id="Ypz-yH-KbI"/>
   17.25 -                        <barButtonItem systemItem="compose" id="u8o-KA-6lO">
   17.26 +                        <barButtonItem image="compose" id="u8o-KA-6lO">
   17.27                              <connections>
   17.28                                  <segue destination="NY2-HI-4ou" kind="presentation" identifier="segueCompose" modalPresentationStyle="pageSheet" id="6vv-Jr-8Nm"/>
   17.29                              </connections>
   17.30 @@ -194,7 +194,6 @@
   17.31                          <segue destination="lPr-gi-BrG" kind="showDetail" identifier="segueShowEmail" id="63y-AC-Fyu"/>
   17.32                          <segue destination="wwj-Sj-78N" kind="showDetail" identifier="showNoMessage" id="a9I-b0-iqU"/>
   17.33                          <segue destination="eLD-PA-Nmx" kind="showDetail" identifier="segueShowThreadedEmail" id="rUh-Ai-iWA"/>
   17.34 -                        <segue destination="ahd-JG-zww" kind="showDetail" identifier="segueShowThreadedEmailSingle" id="rVm-oN-S6B"/>
   17.35                      </connections>
   17.36                  </tableViewController>
   17.37                  <placeholder placeholderIdentifier="IBFirstResponder" id="d8T-vB-XpT" userLabel="First Responder" sceneMemberID="firstResponder"/>
   17.38 @@ -804,7 +803,7 @@
   17.39                              </connections>
   17.40                          </barButtonItem>
   17.41                          <barButtonItem style="plain" systemItem="flexibleSpace" id="CmV-4s-3jw"/>
   17.42 -                        <barButtonItem systemItem="reply" id="qxE-Vd-QoS">
   17.43 +                        <barButtonItem image="reply" id="qxE-Vd-QoS">
   17.44                              <connections>
   17.45                                  <action selector="pressReply:" destination="3bx-34-vLD" id="KDm-Or-31Y"/>
   17.46                              </connections>
   17.47 @@ -976,17 +975,19 @@
   17.48          <image name="arrow-lft-active" width="10" height="18"/>
   17.49          <image name="arrow-rgt-active" width="10" height="18"/>
   17.50          <image name="attachment-list-icon" width="14" height="15"/>
   17.51 +        <image name="compose" width="33" height="64"/>
   17.52          <image name="empty-avatar" width="150" height="150"/>
   17.53          <image name="folders-icon-folder" width="25" height="25"/>
   17.54          <image name="folders-icon-trash" width="25" height="25"/>
   17.55          <image name="icon-unflagged" width="33" height="64"/>
   17.56 +        <image name="reply" width="33" height="64"/>
   17.57          <image name="separator_pixel_grey" width="1" height="1"/>
   17.58          <image name="thread-icon" width="13" height="13"/>
   17.59          <image name="unread-icon" width="22" height="22"/>
   17.60      </resources>
   17.61      <inferredMetricsTieBreakers>
   17.62 -        <segue reference="d5O-Wk-gjZ"/>
   17.63 -        <segue reference="oPc-EL-W2c"/>
   17.64 +        <segue reference="RTR-We-Kc1"/>
   17.65 +        <segue reference="8Xh-Bv-MFq"/>
   17.66          <segue reference="ber-OQ-S16"/>
   17.67          <segue reference="6vv-Jr-8Nm"/>
   17.68      </inferredMetricsTieBreakers>
    18.1 --- a/pEpForiOS/Base.lproj/Settings.storyboard	Fri Jul 20 14:07:19 2018 +0200
    18.2 +++ b/pEpForiOS/Base.lproj/Settings.storyboard	Thu Jul 26 13:41:45 2018 +0200
    18.3 @@ -77,6 +77,25 @@
    18.4              </objects>
    18.5              <point key="canvasLocation" x="3385" y="69"/>
    18.6          </scene>
    18.7 +        <!--Navigation Controller-->
    18.8 +        <scene sceneID="P8Y-01-hqj">
    18.9 +            <objects>
   18.10 +                <navigationController storyboardIdentifier="logNavController" id="zMg-PQ-bVQ" sceneMemberID="viewController">
   18.11 +                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="R2m-Kn-Xec">
   18.12 +                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
   18.13 +                        <autoresizingMask key="autoresizingMask"/>
   18.14 +                    </navigationBar>
   18.15 +                    <toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Ygk-fa-G9n">
   18.16 +                        <autoresizingMask key="autoresizingMask"/>
   18.17 +                    </toolbar>
   18.18 +                    <connections>
   18.19 +                        <segue destination="01V-rr-Nt1" kind="relationship" relationship="rootViewController" id="hUX-d3-8R0"/>
   18.20 +                    </connections>
   18.21 +                </navigationController>
   18.22 +                <placeholder placeholderIdentifier="IBFirstResponder" id="5pQ-iQ-idy" userLabel="First Responder" sceneMemberID="firstResponder"/>
   18.23 +            </objects>
   18.24 +            <point key="canvasLocation" x="3368" y="789"/>
   18.25 +        </scene>
   18.26          <!--Credits View Controller-->
   18.27          <scene sceneID="T9v-3i-MfR">
   18.28              <objects>
   18.29 @@ -768,4 +787,7 @@
   18.30              <point key="canvasLocation" x="4401" y="-1430"/>
   18.31          </scene>
   18.32      </scenes>
   18.33 +    <inferredMetricsTieBreakers>
   18.34 +        <segue reference="hUX-d3-8R0"/>
   18.35 +    </inferredMetricsTieBreakers>
   18.36  </document>
    19.1 --- a/pEpForiOS/Base.lproj/Thread.storyboard	Fri Jul 20 14:07:19 2018 +0200
    19.2 +++ b/pEpForiOS/Base.lproj/Thread.storyboard	Thu Jul 26 13:41:45 2018 +0200
    19.3 @@ -94,7 +94,7 @@
    19.4                                                              </constraints>
    19.5                                                          </imageView>
    19.6                                                          <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Lmq-dE-j3O">
    19.7 -                                                            <rect key="frame" x="44" y="36" width="20" height="20"/>
    19.8 +                                                            <rect key="frame" x="44" y="40" width="20" height="20"/>
    19.9                                                              <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
   19.10                                                              <constraints>
   19.11                                                                  <constraint firstAttribute="height" constant="20" id="EZJ-iq-rKe"/>
   19.12 @@ -114,7 +114,7 @@
   19.13                                                          <constraint firstItem="hki-aE-Mre" firstAttribute="leading" secondItem="b1n-Bu-VHQ" secondAttribute="trailing" constant="8" id="avA-w8-BVb"/>
   19.14                                                          <constraint firstItem="LiV-t9-n8p" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="hki-aE-Mre" secondAttribute="trailing" constant="8" id="cL0-g2-O1Z"/>
   19.15                                                          <constraint firstAttribute="trailing" secondItem="LiV-t9-n8p" secondAttribute="trailing" constant="8" id="cyc-aL-xLQ"/>
   19.16 -                                                        <constraint firstItem="Lmq-dE-j3O" firstAttribute="bottom" secondItem="b1n-Bu-VHQ" secondAttribute="bottom" id="dcD-nm-kKD"/>
   19.17 +                                                        <constraint firstItem="Lmq-dE-j3O" firstAttribute="bottom" secondItem="b1n-Bu-VHQ" secondAttribute="bottom" constant="4" id="dcD-nm-kKD"/>
   19.18                                                          <constraint firstItem="Lmq-dE-j3O" firstAttribute="trailing" secondItem="b1n-Bu-VHQ" secondAttribute="trailing" id="fGd-aQ-tYZ"/>
   19.19                                                          <constraint firstItem="nal-dD-vzH" firstAttribute="top" secondItem="LiV-t9-n8p" secondAttribute="bottom" constant="5" id="lDE-PX-tFY"/>
   19.20                                                          <constraint firstItem="b1n-Bu-VHQ" firstAttribute="leading" secondItem="sMr-Gx-h2F" secondAttribute="leadingMargin" constant="8" id="mBb-1s-wGL"/>
   19.21 @@ -176,7 +176,7 @@
   19.22                                                                                      </constraints>
   19.23                                                                                  </imageView>
   19.24                                                                                  <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ivx-PK-RPE">
   19.25 -                                                                                    <rect key="frame" x="44" y="28" width="20" height="20"/>
   19.26 +                                                                                    <rect key="frame" x="44" y="32" width="20" height="20"/>
   19.27                                                                                      <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
   19.28                                                                                      <constraints>
   19.29                                                                                          <constraint firstAttribute="width" constant="20" id="E76-bS-hUN"/>
   19.30 @@ -190,7 +190,7 @@
   19.31                                                                                  <constraint firstItem="ivx-PK-RPE" firstAttribute="trailing" secondItem="Fte-Eh-jpP" secondAttribute="trailing" id="Dxo-VA-uFc"/>
   19.32                                                                                  <constraint firstItem="Fte-Eh-jpP" firstAttribute="leading" secondItem="OdI-WY-AV8" secondAttribute="leadingMargin" constant="8" id="g1Z-cb-EWT"/>
   19.33                                                                                  <constraint firstItem="Fte-Eh-jpP" firstAttribute="top" secondItem="OdI-WY-AV8" secondAttribute="top" id="s5N-G1-a9A"/>
   19.34 -                                                                                <constraint firstItem="ivx-PK-RPE" firstAttribute="bottom" secondItem="Fte-Eh-jpP" secondAttribute="bottom" id="tXI-b0-we4"/>
   19.35 +                                                                                <constraint firstItem="ivx-PK-RPE" firstAttribute="bottom" secondItem="Fte-Eh-jpP" secondAttribute="bottom" constant="4" id="tXI-b0-we4"/>
   19.36                                                                              </constraints>
   19.37                                                                          </view>
   19.38                                                                          <stackView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="249" verticalCompressionResistancePriority="250" axis="vertical" distribution="fillProportionally" alignment="top" translatesAutoresizingMaskIntoConstraints="NO" id="FKO-Bw-vhC">
   19.39 @@ -419,7 +419,7 @@
   19.40                              </connections>
   19.41                          </barButtonItem>
   19.42                          <barButtonItem style="plain" systemItem="flexibleSpace" id="0OE-2V-PxY"/>
   19.43 -                        <barButtonItem systemItem="reply" id="wu8-Rw-KTi">
   19.44 +                        <barButtonItem image="reply" id="wu8-Rw-KTi">
   19.45                              <connections>
   19.46                                  <action selector="replyButtonTapped:" destination="8tS-ie-Ovo" id="6eg-Mm-ndp"/>
   19.47                              </connections>
   19.48 @@ -492,6 +492,7 @@
   19.49          <image name="folders-icon-folder" width="25" height="25"/>
   19.50          <image name="folders-icon-trash" width="25" height="25"/>
   19.51          <image name="icon-unflagged" width="33" height="64"/>
   19.52 +        <image name="reply" width="33" height="64"/>
   19.53      </resources>
   19.54      <inferredMetricsTieBreakers>
   19.55          <segue reference="Dhz-Ep-xy2"/>
    20.1 --- a/pEpForiOS/Info.plist	Fri Jul 20 14:07:19 2018 +0200
    20.2 +++ b/pEpForiOS/Info.plist	Thu Jul 26 13:41:45 2018 +0200
    20.3 @@ -17,7 +17,7 @@
    20.4  	<key>CFBundlePackageType</key>
    20.5  	<string>APPL</string>
    20.6  	<key>CFBundleShortVersionString</key>
    20.7 -	<string>0.0.32</string>
    20.8 +	<string>0.0.33</string>
    20.9  	<key>CFBundleSignature</key>
   20.10  	<string>????</string>
   20.11  	<key>CFBundleURLTypes</key>
    21.1 --- a/pEpForiOS/Models/Account+Extentions.swift	Fri Jul 20 14:07:19 2018 +0200
    21.2 +++ b/pEpForiOS/Models/Account+Extentions.swift	Thu Jul 26 13:41:45 2018 +0200
    21.3 @@ -19,67 +19,68 @@
    21.4          return Account.by(address: addressDefaultAccount)
    21.5      }
    21.6  
    21.7 -    private func emailConnectInfos() -> [(EmailConnectInfo, ServerCredentials)] {
    21.8 -        var result = [(emailConnectInfo: EmailConnectInfo,
    21.9 -                       serverCredentials: ServerCredentials)]()
   21.10 +    func emailConnectInfos() -> [EmailConnectInfo] {
   21.11 +        var result = [EmailConnectInfo]()
   21.12          guard let servers = servers else {
   21.13              return result
   21.14          }
   21.15  
   21.16          for server in servers {
   21.17 -            if server.serverType == Server.ServerType.imap
   21.18 -                || server.serverType == Server.ServerType.smtp  {
   21.19 -                let credentials = server.credentials
   21.20 -                if let emailConnectInfo = emailConnectInfo( account: self,
   21.21 -                                                            server: server,
   21.22 -                                                            credentials: server.credentials) {
   21.23 -                    result.append((emailConnectInfo, credentials))
   21.24 -                }
   21.25 +            guard
   21.26 +                server.serverType == Server.ServerType.imap ||
   21.27 +                    server.serverType == Server.ServerType.smtp
   21.28 +                else {
   21.29 +                    Log.shared.errorAndCrash(component: #function,
   21.30 +                                             errorString: "Unsupported server type")
   21.31 +                    continue
   21.32 +            }
   21.33 +            let credentials = server.credentials
   21.34 +            if let emailConnectInfo = Account.emailConnectInfo(account: self,
   21.35 +                                                               server: server,
   21.36 +                                                               credentials: credentials) {
   21.37 +                result.append(emailConnectInfo)
   21.38              }
   21.39          }
   21.40  
   21.41          return result
   21.42      }
   21.43  
   21.44 -    func emailConnectInfo(account: Account,
   21.45 -                          server: Server,
   21.46 -                          credentials: ServerCredentials) -> EmailConnectInfo? {
   21.47 -        var result: EmailConnectInfo? = nil
   21.48 -        MessageModel.performAndWait {
   21.49 -            guard
   21.50 -                let cdAccount = CdAccount.search(account: self),
   21.51 -                let cdServer = cdAccount.server(type: server.serverType),
   21.52 -                let cdCredentials = cdServer.credentials,
   21.53 -                let transport = server.transport?.rawValue else {
   21.54 -                    Log.shared.errorAndCrash(component: #function, errorString: "Invalid state")
   21.55 -                    return
   21.56 -            }
   21.57 -            let emailProtocol = EmailProtocol(serverType: server.serverType)
   21.58 -            result =  EmailConnectInfo(accountObjectID: cdAccount.objectID,
   21.59 -                                       serverObjectID: cdServer.objectID,
   21.60 -                                       credentialsObjectID: cdCredentials.objectID,
   21.61 -                                       loginName: credentials.loginName,
   21.62 -                                       loginPasswordKeyChainKey: credentials.key,
   21.63 -                                       networkAddress: server.address,
   21.64 -                                       networkPort: server.port,
   21.65 -                                       networkAddressType: nil,
   21.66 -                                       networkTransportType: nil,
   21.67 -                                       emailProtocol: emailProtocol,
   21.68 -                                       connectionTransport:
   21.69 -                ConnectionTransport(fromInt: Int(transport)),
   21.70 -                                       authMethod: AuthMethod(string: server.authMethod),
   21.71 -                                       trusted: server.trusted)
   21.72 -        }
   21.73 -        return result
   21.74 +    /**
   21.75 +     - Returns: The first found IMAP connect info. Used by some tests.
   21.76 +     */
   21.77 +    var imapConnectInfo: EmailConnectInfo? {
   21.78 +        return emailConnectInfos().filter { return $0.emailProtocol == .imap }.first
   21.79      }
   21.80  
   21.81 -     /// - Returns: The first found IMAP connect info.
   21.82 -    var imapConnectInfo: EmailConnectInfo? {
   21.83 -        return emailConnectInfos().filter { return $0.0.emailProtocol == .imap }.first?.0
   21.84 +    /**
   21.85 +     - Returns: The first found SMTP connect info. Used by some tests.
   21.86 +     */
   21.87 +    var smtpConnectInfo: EmailConnectInfo? {
   21.88 +        return emailConnectInfos().filter { return $0.emailProtocol == .smtp }.first
   21.89      }
   21.90  
   21.91 -    /// - Returns: The first found SMTP connect info.
   21.92 -    var smtpConnectInfo: EmailConnectInfo? {
   21.93 -        return emailConnectInfos().filter { return $0.0.emailProtocol == .smtp }.first?.0
   21.94 +    static func emailConnectInfo(account: Account, server: Server,
   21.95 +                          credentials: ServerCredentials) -> EmailConnectInfo? {
   21.96 +        guard
   21.97 +            let emailProtocol = EmailProtocol(serverType: server.serverType),
   21.98 +            let connectionTransport = server.transport
   21.99 +            else {
  21.100 +                Log.shared.errorAndCrash(component: #function, errorString: "Missing emailProtocol")
  21.101 +                return nil
  21.102 +        }
  21.103 +
  21.104 +        return EmailConnectInfo(account: account,
  21.105 +                                server: server,
  21.106 +                                credentials: credentials,
  21.107 +                                loginName: credentials.loginName,
  21.108 +                                loginPasswordKeyChainKey: credentials.key,
  21.109 +                                networkAddress: server.address,
  21.110 +                                networkPort: server.port,
  21.111 +                                networkAddressType: nil,
  21.112 +                                networkTransportType: nil,
  21.113 +                                emailProtocol: emailProtocol,
  21.114 +                                connectionTransport: ConnectionTransport(fromInt: Int(connectionTransport.rawValue)),
  21.115 +                                authMethod: AuthMethod(string: server.authMethod),
  21.116 +                                trusted: server.trusted)
  21.117      }
  21.118  }
    22.1 --- a/pEpForiOS/Models/AccountUserInput.swift	Fri Jul 20 14:07:19 2018 +0200
    22.2 +++ b/pEpForiOS/Models/AccountUserInput.swift	Thu Jul 26 13:41:45 2018 +0200
    22.3 @@ -112,13 +112,11 @@
    22.4          let credentialsImap = ServerCredentials.create(loginName: logIn,
    22.5                                                         key: accessToken?.keyChainID)
    22.6          credentialsImap.password = thePassword
    22.7 -        credentialsImap.needsVerification = true
    22.8  
    22.9          let imapServer = Server.create(serverType: .imap, port: self.portIMAP, address: serverIMAP,
   22.10                                         transport: self.transportIMAP.toServerTransport(),
   22.11                                         authMethod: authMethod?.rawValue,
   22.12                                         credentials: credentialsImap)
   22.13 -        imapServer.needsVerification = true
   22.14  
   22.15          let credentialsSmtp: ServerCredentials
   22.16          if authMethod == .saslXoauth2 {
   22.17 @@ -128,13 +126,13 @@
   22.18              credentialsSmtp = ServerCredentials.create(loginName: logIn, key: accessToken?.keyChainID)
   22.19              credentialsSmtp.password = thePassword
   22.20          }
   22.21 -        credentialsSmtp.needsVerification = true
   22.22  
   22.23 -        let smtpServer = Server.create(serverType: .smtp, port: self.portSMTP, address: serverSMTP,
   22.24 +        let smtpServer = Server.create(serverType: .smtp,
   22.25 +                                       port: self.portSMTP,
   22.26 +                                       address: serverSMTP,
   22.27                                         transport: self.transportSMTP.toServerTransport(),
   22.28                                         authMethod: authMethod?.rawValue,
   22.29                                         credentials: credentialsSmtp)
   22.30 -        smtpServer.needsVerification = true
   22.31  
   22.32          let account = Account(user: identity, servers: [imapServer, smtpServer])
   22.33          return account
    23.1 --- a/pEpForiOS/Models/CdAccount+Extension.swift	Fri Jul 20 14:07:19 2018 +0200
    23.2 +++ b/pEpForiOS/Models/CdAccount+Extension.swift	Thu Jul 26 13:41:45 2018 +0200
    23.3 @@ -9,61 +9,30 @@
    23.4  import MessageModel
    23.5  
    23.6  extension CdAccount {
    23.7 -    private func emailConnectInfos() -> [(EmailConnectInfo, CdServerCredentials)] {
    23.8 -        var result = [(emailConnectInfo: EmailConnectInfo,
    23.9 -                       cdServerCredentials: CdServerCredentials)]()
   23.10 -        guard let cdServers = servers?.allObjects as? [CdServer] else {
   23.11 -            return result
   23.12 -        }
   23.13 -
   23.14 -        for cdServer in cdServers {
   23.15 -            if cdServer.serverType == Server.ServerType.imap
   23.16 -                || cdServer.serverType == Server.ServerType.smtp  {
   23.17 -                guard let cdCredentials = cdServer.credentials else {
   23.18 -                        continue
   23.19 -                }
   23.20 -                if let emailConnectInfo = emailConnectInfo(
   23.21 -                    account: self, server: cdServer, credentials: cdCredentials) {
   23.22 -                    result.append((emailConnectInfo, cdCredentials))
   23.23 -                }
   23.24 -            }
   23.25 -        }
   23.26 -
   23.27 -        return result
   23.28 +    private func emailConnectInfos() -> [EmailConnectInfo] {
   23.29 +        return self.account().emailConnectInfos()
   23.30      }
   23.31  
   23.32      /**
   23.33       - Returns: The first found IMAP connect info.
   23.34       */
   23.35 -    open var imapConnectInfo: EmailConnectInfo? {
   23.36 -        return emailConnectInfos().filter { return $0.0.emailProtocol == .imap }.first?.0
   23.37 +    @available(*, deprecated, message: "use Account - imapConnectInfo() instead")
   23.38 +    var imapConnectInfo: EmailConnectInfo? {
   23.39 +        return emailConnectInfos().filter { return $0.emailProtocol == .imap }.first
   23.40      }
   23.41  
   23.42      /**
   23.43       - Returns: The first found SMTP connect info.
   23.44       */
   23.45 -    open var smtpConnectInfo: EmailConnectInfo? {
   23.46 -        return emailConnectInfos().filter { return $0.0.emailProtocol == .smtp }.first?.0
   23.47 +    @available(*, deprecated, message: "use Account - smtpConnectInfo() instead")
   23.48 +    var smtpConnectInfo: EmailConnectInfo? {
   23.49 +        return emailConnectInfos().filter { return $0.emailProtocol == .smtp }.first
   23.50      }
   23.51  
   23.52 -    func emailConnectInfo(account: CdAccount, server: CdServer,
   23.53 -                          credentials: CdServerCredentials) -> EmailConnectInfo? {
   23.54 -        if let port = server.port?.int16Value,
   23.55 -            let address = server.address,
   23.56 -            let emailProtocol = EmailProtocol(serverType: server.serverType) {
   23.57 -            return EmailConnectInfo(
   23.58 -                accountObjectID: account.objectID, serverObjectID: server.objectID,
   23.59 -                credentialsObjectID: credentials.objectID,
   23.60 -                loginName: credentials.loginName,
   23.61 -                loginPasswordKeyChainKey: credentials.key,
   23.62 -                networkAddress: address, networkPort: UInt16(port),
   23.63 -                networkAddressType: nil,
   23.64 -                networkTransportType: nil, emailProtocol: emailProtocol,
   23.65 -                connectionTransport: ConnectionTransport(fromInt: Int(server.transportRawValue)),
   23.66 -                authMethod: AuthMethod(string: server.authMethod),
   23.67 -                trusted: server.trusted)
   23.68 -        }
   23.69 -        return nil
   23.70 +    @available(*, deprecated, message: "use Account - emailConnectInfos() instead")
   23.71 +    func emailConnectInfo(account: Account, server: Server,
   23.72 +                          credentials: ServerCredentials) -> EmailConnectInfo? {
   23.73 +        return Account.emailConnectInfo(account: account, server: server, credentials: credentials)
   23.74      }
   23.75  
   23.76      /**
   23.77 @@ -72,25 +41,4 @@
   23.78      open func folder(byName name: String) -> CdFolder? {
   23.79          return CdFolder.first(attributes: ["account": self, "name": name])
   23.80      }
   23.81 -
   23.82 -    /**
   23.83 -     Check all credentials for their `needsVerification` status. If none need it anymore,
   23.84 -     the whole account gets updated too.
   23.85 -     */
   23.86 -    open func checkVerificationStatus() {
   23.87 -        guard let cdServers = servers?.allObjects as? [CdServer] else {
   23.88 -            return
   23.89 -        }
   23.90 -        var verificationStillNeeded = false
   23.91 -        for cdServer in cdServers {
   23.92 -            guard let creds = cdServer.credentials else {
   23.93 -                Log.shared.errorAndCrash(component: #function, errorString: "Server \(cdServer) has no credetials.")
   23.94 -                continue
   23.95 -            }
   23.96 -            if creds.needsVerification {
   23.97 -                verificationStillNeeded = true
   23.98 -            }
   23.99 -        }
  23.100 -        needsVerification = verificationStillNeeded
  23.101 -    }
  23.102  }
    24.1 --- a/pEpForiOS/Network/ConnectInfo.swift	Fri Jul 20 14:07:19 2018 +0200
    24.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.3 @@ -1,114 +0,0 @@
    24.4 -//
    24.5 -//  ConnectInfo.swift
    24.6 -//  pEpForiOS
    24.7 -//
    24.8 -//  Created by hernani on 24/10/16.
    24.9 -//  Copyright © 2016 p≡p Security S.A. All rights reserved.
   24.10 -//
   24.11 -
   24.12 -import CoreData
   24.13 -import MessageModel
   24.14 -
   24.15 -public enum NetworkAddressType: String {
   24.16 -    case ipv4 = "IPv4"
   24.17 -    case ipv6 = "IPv6"
   24.18 -    case dns = "DNS"
   24.19 -    case gns = "GNS" // GNU Name System (TBD)
   24.20 -}
   24.21 -
   24.22 -public enum NetworkTransportType: String {
   24.23 -    case udp = "UDP"
   24.24 -    case tcp = "TCP"
   24.25 -}
   24.26 -
   24.27 -/**
   24.28 - Holds basic info to connect to peers (perhaps servers).
   24.29 - */
   24.30 -public class ConnectInfo: Hashable {
   24.31 -    public let accountObjectID: NSManagedObjectID
   24.32 -    public let serverObjectID: NSManagedObjectID
   24.33 -    public let credentialsObjectID: NSManagedObjectID
   24.34 -
   24.35 -    public let loginName: String?
   24.36 -    public let loginPasswordKeyChainKey: String?
   24.37 -    public var loginPassword: String? {
   24.38 -        guard let key = loginPasswordKeyChainKey else {
   24.39 -            return nil
   24.40 -        }
   24.41 -        return KeyChain.serverPassword(forKey: key)
   24.42 -    }
   24.43 -    public let networkAddress: String
   24.44 -    public let networkPort: UInt16
   24.45 -    public let networkAddressType: NetworkAddressType?
   24.46 -    public let networkTransportType: NetworkTransportType?
   24.47 -
   24.48 -    public init(accountObjectID: NSManagedObjectID,
   24.49 -                serverObjectID: NSManagedObjectID,
   24.50 -                credentialsObjectID: NSManagedObjectID,
   24.51 -                loginName: String? = nil,
   24.52 -                loginPasswordKeyChainKey: String? = nil,
   24.53 -                networkAddress: String,
   24.54 -                networkPort: UInt16,
   24.55 -                networkAddressType: NetworkAddressType? = nil,
   24.56 -                networkTransportType: NetworkTransportType? = nil) {
   24.57 -        self.accountObjectID = accountObjectID
   24.58 -        self.serverObjectID = serverObjectID
   24.59 -        self.credentialsObjectID = credentialsObjectID
   24.60 -        self.loginName = loginName
   24.61 -        self.loginPasswordKeyChainKey = loginPasswordKeyChainKey
   24.62 -        self.networkAddress = networkAddress
   24.63 -        self.networkPort = networkPort
   24.64 -        self.networkAddressType = networkAddressType
   24.65 -        self.networkTransportType = networkTransportType
   24.66 -    }
   24.67 -
   24.68 -    // MARK: Hashable
   24.69 -
   24.70 -    /**
   24.71 -     If this was in an extension, the subclasses could not override it. Therefore, it's here.
   24.72 -     */
   24.73 -    public var hashValue: Int {
   24.74 -        return 31 &*
   24.75 -            accountObjectID.hashValue &+
   24.76 -            serverObjectID.hashValue &+
   24.77 -            credentialsObjectID.hashValue &+
   24.78 -            MiscUtil.optionalHashValue(loginName) &+
   24.79 -            MiscUtil.optionalHashValue(networkAddress) &+
   24.80 -            MiscUtil.optionalHashValue(networkPort) &+
   24.81 -            MiscUtil.optionalHashValue(networkAddressType) &+
   24.82 -            MiscUtil.optionalHashValue(networkTransportType)
   24.83 -    }
   24.84 -}
   24.85 -
   24.86 -extension ConnectInfo: Equatable {}
   24.87 -
   24.88 -public func ==(l: ConnectInfo, r: ConnectInfo) -> Bool {
   24.89 -    return l.accountObjectID == r.accountObjectID
   24.90 -        && l.loginName == r.loginName
   24.91 -        && l.networkPort == r.networkPort
   24.92 -        && l.networkAddress == r.networkAddress
   24.93 -        && l.networkAddressType == r.networkAddressType
   24.94 -        && l.networkTransportType == r.networkTransportType
   24.95 -}
   24.96 -
   24.97 -// MARK: Retrieving the account object in an async, safe way
   24.98 -
   24.99 -import MessageModel
  24.100 -
  24.101 -extension ConnectInfo {
  24.102 -    func handleCdAccount(handler: @escaping (CdAccount) -> ()) {
  24.103 -        let context = Record.Context.background
  24.104 -        context.perform { [weak self] in
  24.105 -            if let theSelf = self, let cdAccount = context.object(
  24.106 -                with: theSelf.accountObjectID) as? CdAccount {
  24.107 -                handler(cdAccount)
  24.108 -            }
  24.109 -        }
  24.110 -    }
  24.111 -
  24.112 -    func handleAccount(handler: @escaping (Account) -> ()) {
  24.113 -        handleCdAccount() { cdAccount in
  24.114 -            handler(cdAccount.account())
  24.115 -        }
  24.116 -    }
  24.117 -}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/pEpForiOS/Network/ConnectInfo/ConnectInfo.swift	Thu Jul 26 13:41:45 2018 +0200
    25.3 @@ -0,0 +1,80 @@
    25.4 +//
    25.5 +//  MMConnectInfo.swift
    25.6 +//  pEp
    25.7 +//
    25.8 +//  Created by Andreas Buff on 23.07.18.
    25.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   25.10 +//
   25.11 +
   25.12 +import MessageModel
   25.13 +
   25.14 +enum NetworkAddressType: String {
   25.15 +    case ipv4 = "IPv4"
   25.16 +    case ipv6 = "IPv6"
   25.17 +    case dns = "DNS"
   25.18 +    case gns = "GNS" // GNU Name System (TBD)
   25.19 +}
   25.20 +
   25.21 +enum NetworkTransportType: String {
   25.22 +    case udp = "UDP"
   25.23 +    case tcp = "TCP"
   25.24 +}
   25.25 +
   25.26 +class ConnectInfo: Hashable {
   25.27 +    public let account: Account
   25.28 +    public let server: Server
   25.29 +    public let credentials: ServerCredentials
   25.30 +
   25.31 +    public let loginName: String?
   25.32 +    public let loginPasswordKeyChainKey: String?
   25.33 +    public var loginPassword: String? {
   25.34 +        return credentials.password
   25.35 +    }
   25.36 +    public let networkAddress: String
   25.37 +    public let networkPort: UInt16
   25.38 +    public let networkAddressType: NetworkAddressType?
   25.39 +    public let networkTransportType: NetworkTransportType?
   25.40 +
   25.41 +    public init(account: Account,
   25.42 +                server: Server,
   25.43 +                credentials: ServerCredentials,
   25.44 +                loginName: String? = nil,
   25.45 +                loginPasswordKeyChainKey: String? = nil,
   25.46 +                networkAddress: String,
   25.47 +                networkPort: UInt16,
   25.48 +                networkAddressType: NetworkAddressType? = nil,
   25.49 +                networkTransportType: NetworkTransportType? = nil) {
   25.50 +        self.account = account
   25.51 +        self.server = server
   25.52 +        self.credentials = credentials
   25.53 +        self.loginName = loginName
   25.54 +        self.loginPasswordKeyChainKey = loginPasswordKeyChainKey
   25.55 +        self.networkAddress = networkAddress
   25.56 +        self.networkPort = networkPort
   25.57 +        self.networkAddressType = networkAddressType
   25.58 +        self.networkTransportType = networkTransportType
   25.59 +    }
   25.60 +
   25.61 +    // MARK: Hashable
   25.62 +
   25.63 +    /**
   25.64 +     If this was in an extension, the subclasses could not override it. Therefore, it's here.
   25.65 +     */
   25.66 +    var hashValue: Int {
   25.67 +        return 31 &*
   25.68 +            account.hashValue &+
   25.69 +            server.address.hashValue &+
   25.70 +            credentials.loginName.hashValue &+
   25.71 +            MiscUtil.optionalHashValue(loginName) &+
   25.72 +            MiscUtil.optionalHashValue(networkAddress) &+
   25.73 +            MiscUtil.optionalHashValue(networkPort) &+
   25.74 +            MiscUtil.optionalHashValue(networkAddressType) &+
   25.75 +            MiscUtil.optionalHashValue(networkTransportType)
   25.76 +    }
   25.77 +}
   25.78 +
   25.79 +extension ConnectInfo: Equatable {}
   25.80 +
   25.81 +func ==(l: ConnectInfo, r: ConnectInfo) -> Bool {
   25.82 +    return l.hashValue == r.hashValue
   25.83 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/pEpForiOS/Network/ConnectInfo/EmailConnectInfo+Extension.swift	Thu Jul 26 13:41:45 2018 +0200
    26.3 @@ -0,0 +1,41 @@
    26.4 +//
    26.5 +//  EmailConnectInfo+Extension.swift
    26.6 +//  pEpForiOS
    26.7 +//
    26.8 +//  Created by Dirk Zimmermann on 24.07.17.
    26.9 +//  Copyright © 2017 p≡p Security S.A. All rights reserved.
   26.10 +//
   26.11 +
   26.12 +import Foundation
   26.13 +import CoreData
   26.14 +
   26.15 +import MessageModel
   26.16 +
   26.17 +extension EmailConnectInfo {
   26.18 +
   26.19 +    func folderBy(name: String) throws -> Folder? {
   26.20 +        var cdResult: CdFolder?
   26.21 +        var error: Error?
   26.22 +        MessageModel.performAndWait { [weak self] in
   26.23 +            guard let me = self else {
   26.24 +                Log.shared.errorAndCrash(component: #function, errorString: "Lost myself")
   26.25 +                return
   26.26 +            }
   26.27 +            let context = Record.Context.background
   26.28 +            guard let cdAccount = context.object(with: me.accountObjectID) as? CdAccount else {
   26.29 +                error = BackgroundError.CoreDataError.couldNotFindAccount(info: #function)
   26.30 +                return
   26.31 +            }
   26.32 +            guard let cdFolder = CdFolder.by(name: name, account: cdAccount, context: context) else {
   26.33 +                error = BackgroundError.CoreDataError.couldNotFindFolder(info: #function)
   26.34 +                return
   26.35 +            }
   26.36 +            cdResult = cdFolder
   26.37 +        }
   26.38 +        if let error = error {
   26.39 +            throw error
   26.40 +        }
   26.41 +        return cdResult?.folder()
   26.42 +    }
   26.43 +
   26.44 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/pEpForiOS/Network/ConnectInfo/EmailConnectInfo.swift	Thu Jul 26 13:41:45 2018 +0200
    27.3 @@ -0,0 +1,174 @@
    27.4 +//
    27.5 +//  MMEmailConnectInfo.swift
    27.6 +//  pEp
    27.7 +//
    27.8 +//  Created by Andreas Buff on 23.07.18.
    27.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   27.10 +//
   27.11 +
   27.12 +import MessageModel
   27.13 +
   27.14 +extension ConnectionTransport {
   27.15 +    init?(fromInt: Int?) {
   27.16 +        guard let i = fromInt else {
   27.17 +            return nil
   27.18 +        }
   27.19 +        switch i {
   27.20 +        case ConnectionTransport.plain.rawValue:
   27.21 +            self = ConnectionTransport.plain
   27.22 +        case ConnectionTransport.startTLS.rawValue:
   27.23 +            self = ConnectionTransport.startTLS
   27.24 +        case ConnectionTransport.TLS.rawValue:
   27.25 +            self = ConnectionTransport.TLS
   27.26 +        default:
   27.27 +            return nil
   27.28 +        }
   27.29 +    }
   27.30 +
   27.31 +    static func fromInteger(_ i: Int) -> ConnectionTransport {
   27.32 +        switch i {
   27.33 +        case ConnectionTransport.plain.rawValue:
   27.34 +            return ConnectionTransport.plain
   27.35 +        case ConnectionTransport.startTLS.rawValue:
   27.36 +            return ConnectionTransport.startTLS
   27.37 +        case ConnectionTransport.TLS.rawValue:
   27.38 +            return ConnectionTransport.TLS
   27.39 +        default:
   27.40 +            abort()
   27.41 +        }
   27.42 +    }
   27.43 +
   27.44 +    func localizedString() -> String {
   27.45 +        let transport_security_text = "Transport security (ConnectionTransport)"
   27.46 +        switch self {
   27.47 +        case .plain:
   27.48 +            return NSLocalizedString("None", comment: transport_security_text)
   27.49 +        case .TLS:
   27.50 +            return NSLocalizedString("TLS", comment: transport_security_text)
   27.51 +        case .startTLS:
   27.52 +            return NSLocalizedString("StartTLS", comment: transport_security_text)
   27.53 +        }
   27.54 +    }
   27.55 +
   27.56 +    // XXX: Here material from the Model area is used: to be avoided or code-shared.
   27.57 +    func toServerTransport() -> Server.Transport {
   27.58 +        switch self {
   27.59 +        case .plain: return Server.Transport.plain
   27.60 +        case .TLS: return Server.Transport.tls
   27.61 +        case .startTLS: return Server.Transport.startTls
   27.62 +        }
   27.63 +    }
   27.64 +}
   27.65 +
   27.66 +enum EmailProtocol: String {
   27.67 +    case smtp = "SMTP"
   27.68 +    case imap = "IMAP"
   27.69 +
   27.70 +    init?(emailProtocol: String) {
   27.71 +        if emailProtocol.isEqual(EmailProtocol.smtp.rawValue) {
   27.72 +            self = .smtp
   27.73 +        } else if emailProtocol.isEqual(EmailProtocol.imap.rawValue) {
   27.74 +            self = .imap
   27.75 +        } else {
   27.76 +            return nil
   27.77 +        }
   27.78 +    }
   27.79 +
   27.80 +    init?(serverType: Server.ServerType?) {
   27.81 +        guard let st = serverType else {
   27.82 +            return nil
   27.83 +        }
   27.84 +        switch st {
   27.85 +        case .imap:
   27.86 +            self = .imap
   27.87 +        case .smtp:
   27.88 +            self = .smtp
   27.89 +        }
   27.90 +    }
   27.91 +}
   27.92 +
   27.93 +class EmailConnectInfo: ConnectInfo {
   27.94 +    enum EmailConnectInfoError: Error {
   27.95 +        case cannotFindServerCredentials
   27.96 +    }
   27.97 +
   27.98 +    let emailProtocol: EmailProtocol?
   27.99 +    let connectionTransport: ConnectionTransport?
  27.100 +    let authMethod: AuthMethod?
  27.101 +    let trusted: Bool
  27.102 +
  27.103 +    /**
  27.104 +     There is either the `loginPassword`, or this, but there should never exist both.
  27.105 +     If non-nil, the `authMethod` is expected to be `AuthMethod.saslXoauth2`.
  27.106 +     */
  27.107 +    var accessToken: OAuth2AccessTokenProtocol? {
  27.108 +        guard authMethod == .saslXoauth2,
  27.109 +            let key = loginPasswordKeyChainKey,
  27.110 +            let token = KeyChain.serverPassword(forKey: key) else {
  27.111 +                return nil
  27.112 +        }
  27.113 +        return OAuth2AccessToken.from(base64Encoded: token) as? OAuth2AccessTokenProtocol
  27.114 +    }
  27.115 +
  27.116 +    init(account: Account,
  27.117 +                server: Server,
  27.118 +                credentials: ServerCredentials,
  27.119 +                loginName: String? = nil,
  27.120 +                loginPasswordKeyChainKey: String? = nil,
  27.121 +                networkAddress: String,
  27.122 +                networkPort: UInt16,
  27.123 +                networkAddressType: NetworkAddressType? = nil,
  27.124 +                networkTransportType: NetworkTransportType? = nil,
  27.125 +                emailProtocol: EmailProtocol? = nil,
  27.126 +                connectionTransport: ConnectionTransport? = nil,
  27.127 +                authMethod: AuthMethod? = nil,
  27.128 +                trusted: Bool = false) {
  27.129 +        self.emailProtocol = emailProtocol
  27.130 +        self.connectionTransport = connectionTransport
  27.131 +        self.authMethod = authMethod
  27.132 +        self.trusted = trusted
  27.133 +
  27.134 +        super.init(account: account,
  27.135 +                   server: server,
  27.136 +                   credentials: credentials,
  27.137 +                   loginName: loginName,
  27.138 +                   loginPasswordKeyChainKey: loginPasswordKeyChainKey,
  27.139 +                   networkAddress: networkAddress,
  27.140 +                   networkPort: networkPort,
  27.141 +                   networkAddressType: networkAddressType,
  27.142 +                   networkTransportType: networkTransportType)
  27.143 +    }
  27.144 +
  27.145 +    //    func unsetNeedsVerificationAndFinish(context: NSManagedObjectContext) -> Error? {
  27.146 +    //        guard let creds = context.object(
  27.147 +    //            with: self.credentialsObjectID)
  27.148 +    //            as? CdServerCredentials else {
  27.149 +    //                return EmailConnectInfoError.cannotFindServerCredentials
  27.150 +    //        }
  27.151 +    //
  27.152 +    //        if creds.needsVerification == true {
  27.153 +    //            creds.needsVerification = false
  27.154 +    //            if let cdAccount = creds.account {
  27.155 +    //                cdAccount.checkVerificationStatus()
  27.156 +    //            }
  27.157 +    //            context.saveAndLogErrors()
  27.158 +    //        }
  27.159 +    //        return nil
  27.160 +    //    }
  27.161 +
  27.162 +    override var hashValue: Int {
  27.163 +        return super.hashValue &+ (emailProtocol?.hashValue ?? 0)
  27.164 +            &+ (connectionTransport?.hashValue ?? 0)
  27.165 +            &+ (authMethod?.hashValue ?? 0)
  27.166 +            &+ trusted.hashValue
  27.167 +    }
  27.168 +}
  27.169 +
  27.170 +func ==(l: EmailConnectInfo, r: EmailConnectInfo) -> Bool {
  27.171 +    let sl = l as ConnectInfo
  27.172 +    let sr = r as ConnectInfo
  27.173 +    return sl == sr &&
  27.174 +        l.connectionTransport == r.connectionTransport &&
  27.175 +        l.authMethod == r.authMethod &&
  27.176 +        l.trusted == r.trusted
  27.177 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/pEpForiOS/Network/ConnectInfo/deprecated/LegacyConnectInfoProvider.swift	Thu Jul 26 13:41:45 2018 +0200
    28.3 @@ -0,0 +1,89 @@
    28.4 +//
    28.5 +//  LegacyConnectInfoProvider.swift
    28.6 +//  pEp
    28.7 +//
    28.8 +//  Created by Andreas Buff on 23.07.18.
    28.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   28.10 +//
   28.11 +
   28.12 +import MessageModel
   28.13 +import CoreData
   28.14 +
   28.15 +/// Supports usage of deprecated EmailConnectInfo.
   28.16 +extension ConnectInfo {
   28.17 +    @available(*, deprecated, message: "use account instead")
   28.18 +    var accountObjectID: NSManagedObjectID {
   28.19 +        var result = NSManagedObjectID()
   28.20 +        MessageModel.performAndWait { [weak self] in
   28.21 +            guard let me = self else {
   28.22 +                Log.shared.errorAndCrash(component: #function, errorString: "Lost myself")
   28.23 +                return
   28.24 +            }
   28.25 +            guard let cdAccount = CdAccount.search(account: me.account) else {
   28.26 +                Log.shared.errorAndCrash(component: #function, errorString: "No CdAccount")
   28.27 +                return
   28.28 +
   28.29 +            }
   28.30 +            result = cdAccount.objectID
   28.31 +        }
   28.32 +        return result
   28.33 +    }
   28.34 +
   28.35 +    @available(*, deprecated, message: "use server instead")
   28.36 +    var serverObjectID: NSManagedObjectID {
   28.37 +        var result = NSManagedObjectID()
   28.38 +        MessageModel.performAndWait { [weak self] in
   28.39 +            guard let me = self else {
   28.40 +                Log.shared.errorAndCrash(component: #function, errorString: "Lost myself")
   28.41 +                return
   28.42 +            }
   28.43 +            let serverType = me.server.serverType
   28.44 +            guard
   28.45 +                let cdAccount = CdAccount.search(account: me.account),
   28.46 +                let cdServer = cdAccount.server(type: serverType) else {
   28.47 +                    Log.shared.errorAndCrash(component: #function, errorString: "No CdAccount")
   28.48 +                    return
   28.49 +            }
   28.50 +            result = cdServer.objectID
   28.51 +        }
   28.52 +        return result
   28.53 +    }
   28.54 +
   28.55 +    @available(*, deprecated, message: "use credentials instead")
   28.56 +    var credentialsObjectID: NSManagedObjectID {
   28.57 +        var result = NSManagedObjectID()
   28.58 +        MessageModel.performAndWait { [weak self] in
   28.59 +            guard let me = self else {
   28.60 +                Log.shared.errorAndCrash(component: #function, errorString: "Lost myself")
   28.61 +                return
   28.62 +            }
   28.63 +            let serverType = me.server.serverType
   28.64 +            guard
   28.65 +                let cdAccount = CdAccount.search(account: me.account),
   28.66 +                let cdServer = cdAccount.server(type: serverType),
   28.67 +                let cdCredentials = cdServer.credentials else {
   28.68 +                    Log.shared.errorAndCrash(component: #function, errorString: "No CdAccount")
   28.69 +                    // Return garbage
   28.70 +                    return
   28.71 +            }
   28.72 +
   28.73 +            result = cdCredentials.objectID
   28.74 +        }
   28.75 +        return result
   28.76 +    }
   28.77 +}
   28.78 +
   28.79 +extension EmailConnectInfo {
   28.80 +
   28.81 +    @available(*, deprecated, message: "use folderBy(name:) instead")
   28.82 +    func folderBy(name: String, context: NSManagedObjectContext) throws -> CdFolder {
   28.83 +        guard let cdAccount = context.object(with: accountObjectID) as? CdAccount else {
   28.84 +            throw BackgroundError.CoreDataError.couldNotFindAccount(info: #function)
   28.85 +        }
   28.86 +        guard let cdFolder = CdFolder.by(name: name, account: cdAccount, context: context) else {
   28.87 +            throw BackgroundError.CoreDataError.couldNotFindFolder(info: #function)
   28.88 +        }
   28.89 +        return cdFolder
   28.90 +    }
   28.91 +
   28.92 +}
    29.1 --- a/pEpForiOS/Network/EmailConnectInfo+Extension.swift	Fri Jul 20 14:07:19 2018 +0200
    29.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.3 @@ -1,24 +0,0 @@
    29.4 -//
    29.5 -//  EmailConnectInfo+Extension.swift
    29.6 -//  pEpForiOS
    29.7 -//
    29.8 -//  Created by Dirk Zimmermann on 24.07.17.
    29.9 -//  Copyright © 2017 p≡p Security S.A. All rights reserved.
   29.10 -//
   29.11 -
   29.12 -import Foundation
   29.13 -import CoreData
   29.14 -
   29.15 -import MessageModel
   29.16 -
   29.17 -extension EmailConnectInfo {
   29.18 -    func folderBy(name: String, context: NSManagedObjectContext) throws -> CdFolder {
   29.19 -        guard let cdAccount = context.object(with: accountObjectID) as? CdAccount else {
   29.20 -            throw BackgroundError.CoreDataError.couldNotFindAccount(info: #function)
   29.21 -        }
   29.22 -        guard let cdFolder = CdFolder.by(name: name, account: cdAccount, context: context) else {
   29.23 -            throw BackgroundError.CoreDataError.couldNotFindFolder(info: #function)
   29.24 -        }
   29.25 -        return cdFolder
   29.26 -    }
   29.27 -}
    30.1 --- a/pEpForiOS/Network/EmailConnectInfo.swift	Fri Jul 20 14:07:19 2018 +0200
    30.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.3 @@ -1,181 +0,0 @@
    30.4 -//
    30.5 -//  EmailConnectInfo
    30.6 -//  pEpForiOS
    30.7 -//
    30.8 -//  Created by Dirk Zimmermann on 08/04/16.
    30.9 -//  Copyright © 2016 p≡p Security S.A. All rights reserved.
   30.10 -//
   30.11 -
   30.12 -import CoreData
   30.13 -
   30.14 -import MessageModel
   30.15 -
   30.16 -public extension ConnectionTransport {
   30.17 -    init?(fromInt: Int?) {
   30.18 -        guard let i = fromInt else {
   30.19 -            return nil
   30.20 -        }
   30.21 -        switch i {
   30.22 -        case ConnectionTransport.plain.rawValue:
   30.23 -            self = ConnectionTransport.plain
   30.24 -        case ConnectionTransport.startTLS.rawValue:
   30.25 -            self = ConnectionTransport.startTLS
   30.26 -        case ConnectionTransport.TLS.rawValue:
   30.27 -            self = ConnectionTransport.TLS
   30.28 -        default:
   30.29 -            return nil
   30.30 -        }
   30.31 -    }
   30.32 -
   30.33 -    static public func fromInteger(_ i: Int) -> ConnectionTransport {
   30.34 -        switch i {
   30.35 -        case ConnectionTransport.plain.rawValue:
   30.36 -            return ConnectionTransport.plain
   30.37 -        case ConnectionTransport.startTLS.rawValue:
   30.38 -            return ConnectionTransport.startTLS
   30.39 -        case ConnectionTransport.TLS.rawValue:
   30.40 -            return ConnectionTransport.TLS
   30.41 -        default:
   30.42 -            abort()
   30.43 -        }
   30.44 -    }
   30.45 -    
   30.46 -    public func localizedString() -> String {
   30.47 -        let transport_security_text = "Transport security (ConnectionTransport)"
   30.48 -        switch self {
   30.49 -        case .plain:
   30.50 -            return NSLocalizedString("None", comment: transport_security_text)
   30.51 -        case .TLS:
   30.52 -            return NSLocalizedString("TLS", comment: transport_security_text)
   30.53 -        case .startTLS:
   30.54 -            return NSLocalizedString("StartTLS", comment: transport_security_text)
   30.55 -        }
   30.56 -    }
   30.57 -    
   30.58 -    // XXX: Here material from the Model area is used: to be avoided or code-shared.
   30.59 -    public func toServerTransport() -> Server.Transport {
   30.60 -        switch self {
   30.61 -        case .plain: return Server.Transport.plain
   30.62 -        case .TLS: return Server.Transport.tls
   30.63 -        case .startTLS: return Server.Transport.startTls
   30.64 -        }
   30.65 -    }
   30.66 -
   30.67 -}
   30.68 -
   30.69 -public enum EmailProtocol: String {
   30.70 -    case smtp = "SMTP"
   30.71 -    case imap = "IMAP"
   30.72 -    
   30.73 -    init?(emailProtocol: String) {
   30.74 -        if emailProtocol.isEqual(EmailProtocol.smtp.rawValue) {
   30.75 -            self = .smtp
   30.76 -        } else if emailProtocol.isEqual(EmailProtocol.imap.rawValue) {
   30.77 -            self = .imap
   30.78 -        } else {
   30.79 -            return nil
   30.80 -        }
   30.81 -    }
   30.82 -
   30.83 -    init?(serverType: Server.ServerType?) {
   30.84 -        guard let st = serverType else {
   30.85 -            return nil
   30.86 -        }
   30.87 -        switch st {
   30.88 -        case .imap:
   30.89 -            self = .imap
   30.90 -        case .smtp:
   30.91 -            self = .smtp
   30.92 -        }
   30.93 -    }
   30.94 -}
   30.95 -
   30.96 -/**
   30.97 - Holds additional connection info (like server, port etc.) for IMAP and SMTP.
   30.98 - */
   30.99 -public class EmailConnectInfo: ConnectInfo {
  30.100 -    enum EmailConnectInfoError: Error {
  30.101 -        case cannotFindServerCredentials
  30.102 -    }
  30.103 -    
  30.104 -    public let emailProtocol: EmailProtocol?
  30.105 -    public let connectionTransport: ConnectionTransport?
  30.106 -    public let authMethod: AuthMethod?
  30.107 -    public let trusted: Bool
  30.108 -
  30.109 -    /**
  30.110 -     There is either the `loginPassword`, or this, but there should never exist both.
  30.111 -     If non-nil, the `authMethod` is expected to be `AuthMethod.saslXoauth2`.
  30.112 -     */
  30.113 -    public var accessToken: OAuth2AccessTokenProtocol? {
  30.114 -        guard authMethod == .saslXoauth2,
  30.115 -            let key = loginPasswordKeyChainKey,
  30.116 -            let token = KeyChain.serverPassword(forKey: key) else {
  30.117 -                return nil
  30.118 -        }
  30.119 -        return OAuth2AccessToken.from(base64Encoded: token) as? OAuth2AccessTokenProtocol
  30.120 -    }
  30.121 -
  30.122 -    public init(accountObjectID: NSManagedObjectID,
  30.123 -                serverObjectID: NSManagedObjectID,
  30.124 -                credentialsObjectID: NSManagedObjectID,
  30.125 -                loginName: String? = nil,
  30.126 -                loginPasswordKeyChainKey: String? = nil,
  30.127 -                networkAddress: String,
  30.128 -                networkPort: UInt16,
  30.129 -                networkAddressType: NetworkAddressType? = nil,
  30.130 -                networkTransportType: NetworkTransportType? = nil,
  30.131 -                emailProtocol: EmailProtocol? = nil,
  30.132 -                connectionTransport: ConnectionTransport? = nil,
  30.133 -                authMethod: AuthMethod? = nil,
  30.134 -                trusted: Bool = false) {
  30.135 -        self.emailProtocol = emailProtocol
  30.136 -        self.connectionTransport = connectionTransport
  30.137 -        self.authMethod = authMethod
  30.138 -        self.trusted = trusted
  30.139 -
  30.140 -        super.init(accountObjectID: accountObjectID,
  30.141 -                   serverObjectID: serverObjectID,
  30.142 -                   credentialsObjectID: credentialsObjectID,
  30.143 -                   loginName: loginName,
  30.144 -                   loginPasswordKeyChainKey: loginPasswordKeyChainKey,
  30.145 -                   networkAddress: networkAddress,
  30.146 -                   networkPort: networkPort,
  30.147 -                   networkAddressType: networkAddressType,
  30.148 -                   networkTransportType: networkTransportType)
  30.149 -    }
  30.150 -
  30.151 -    func unsetNeedsVerificationAndFinish(context: NSManagedObjectContext) -> Error? {
  30.152 -        guard let creds = context.object(
  30.153 -            with: self.credentialsObjectID)
  30.154 -            as? CdServerCredentials else {
  30.155 -                return EmailConnectInfoError.cannotFindServerCredentials
  30.156 -        }
  30.157 -
  30.158 -        if creds.needsVerification == true {
  30.159 -            creds.needsVerification = false
  30.160 -            if let cdAccount = creds.account {
  30.161 -                cdAccount.checkVerificationStatus()
  30.162 -            }
  30.163 -            context.saveAndLogErrors()
  30.164 -        }
  30.165 -        return nil
  30.166 -    }
  30.167 -
  30.168 -    override public var hashValue: Int {
  30.169 -        return super.hashValue &+ (emailProtocol?.hashValue ?? 0)
  30.170 -            &+ (connectionTransport?.hashValue ?? 0)
  30.171 -            &+ (authMethod?.hashValue ?? 0)
  30.172 -            &+ trusted.hashValue
  30.173 -    }
  30.174 -}
  30.175 -
  30.176 -public func ==(l: EmailConnectInfo, r: EmailConnectInfo) -> Bool {
  30.177 -    let sl = l as ConnectInfo
  30.178 -    let sr = r as ConnectInfo
  30.179 -    return sl == sr &&
  30.180 -        l.connectionTransport == r.connectionTransport &&
  30.181 -        l.authMethod == r.authMethod &&
  30.182 -        l.trusted == r.trusted
  30.183 -}
  30.184 -
    31.1 --- a/pEpForiOS/Network/EmailService.swift	Fri Jul 20 14:07:19 2018 +0200
    31.2 +++ b/pEpForiOS/Network/EmailService.swift	Thu Jul 26 13:41:45 2018 +0200
    31.3 @@ -26,7 +26,7 @@
    31.4      /// Used if non of the login methods Pantomime currently supports is supported by the server.
    31.5      private let fallBackAuthMethod = AuthMethod.plain
    31.6  
    31.7 -    public init(connectInfo: EmailConnectInfo,
    31.8 +    init(connectInfo: EmailConnectInfo,
    31.9                  fileString: String = #file, functionName: String = #function) {
   31.10          CWLogger.setLogger(Log.shared)
   31.11  
    32.1 --- a/pEpForiOS/Network/Service/AccountVerificationService/AccountVerificationService.swift	Fri Jul 20 14:07:19 2018 +0200
    32.2 +++ b/pEpForiOS/Network/Service/AccountVerificationService/AccountVerificationService.swift	Thu Jul 26 13:41:45 2018 +0200
    32.3 @@ -11,24 +11,24 @@
    32.4  class AccountVerificationService: AccountVerificationServiceProtocol {
    32.5      weak var delegate: AccountVerificationServiceDelegate?
    32.6      var accountVerificationState = AccountVerificationState.idle
    32.7 -    
    32.8 +
    32.9      var runningOperations = [Account:[BaseOperation]]()
   32.10      let verificationQueue = DispatchQueue(
   32.11          label: "AccountVerificationService.verificationQueue", qos: .utility, target: nil)
   32.12      let backgroundQueue = OperationQueue()
   32.13 -    
   32.14 +
   32.15      func verify(account: Account) {
   32.16          verificationQueue.async {
   32.17              self.verifyInternal(account: account)
   32.18          }
   32.19      }
   32.20 -    
   32.21 +
   32.22      func removeFromRunning(account: Account) {
   32.23          verificationQueue.async {
   32.24              self.removeFromRunningInternal(account: account)
   32.25          }
   32.26      }
   32.27 -    
   32.28 +
   32.29      func removeFromRunningInternal(account: Account) {
   32.30          guard let ops = runningOperations[account] else {
   32.31              return
   32.32 @@ -41,19 +41,16 @@
   32.33              let errorOps = ops.filter() { return $0.hasErrors() }
   32.34              if let op = errorOps.first, let err = op.error {
   32.35                  if let imapErr = err as? ImapSyncError {
   32.36 -                    delegate?.verified(account: account, service: self,
   32.37 -                                       result: .imapError(imapErr))
   32.38 +                    delegate?.verified(account: account, service: self, result: .imapError(imapErr))
   32.39                  } else if let smtpErr = err as? SmtpSendError {
   32.40 -                    delegate?.verified(account: account, service: self,
   32.41 -                                       result: .smtpError(smtpErr))
   32.42 +                    delegate?.verified(account: account, service: self, result: .smtpError(smtpErr))
   32.43                  }
   32.44              } else {
   32.45 -                account.needsVerification = false
   32.46                  delegate?.verified(account: account, service: self, result: .ok)
   32.47              }
   32.48          }
   32.49      }
   32.50 -    
   32.51 +
   32.52      func verifyInternal(account: Account) {
   32.53          if runningOperations[account] != nil {
   32.54              return
   32.55 @@ -64,12 +61,11 @@
   32.56                  Log.shared.errorAndCrash(component: #function, errorString: "I am lost")
   32.57                  return
   32.58              }
   32.59 -            let cdAccount = CdAccount.updateOrCreate(account: account)
   32.60 -            guard let imapConnectInfo = cdAccount.imapConnectInfo else {
   32.61 +            guard let imapConnectInfo = account.imapConnectInfo else {
   32.62                  me.delegate?.verified(account: account, service: me, result: .noImapConnectData)
   32.63                  return
   32.64              }
   32.65 -            guard let smtpConnectInfo = cdAccount.smtpConnectInfo else {
   32.66 +            guard let smtpConnectInfo = account.smtpConnectInfo else {
   32.67                  me.delegate?.verified(account: account, service: me, result: .noSmtpConnectData)
   32.68                  return
   32.69              }
   32.70 @@ -81,8 +77,9 @@
   32.71                  imapVerifyOp.completionBlock = nil
   32.72                  self?.removeFromRunning(account: account)
   32.73              }
   32.74 -            let smtpVerifyOp = LoginSmtpOperation(
   32.75 -                parentName: #function, smtpSendData: smtpSendData, errorContainer: ErrorContainer())
   32.76 +            let smtpVerifyOp = LoginSmtpOperation(parentName: #function,
   32.77 +                                                  smtpSendData: smtpSendData,
   32.78 +                                                  errorContainer: ErrorContainer())
   32.79              smtpVerifyOp.completionBlock = {[weak self] in
   32.80                  smtpVerifyOp.completionBlock = nil
   32.81                  self?.removeFromRunning(account: account)
    33.1 --- a/pEpForiOS/Network/Service/FetchNumberOfNewMailsService.swift	Fri Jul 20 14:07:19 2018 +0200
    33.2 +++ b/pEpForiOS/Network/Service/FetchNumberOfNewMailsService.swift	Thu Jul 26 13:41:45 2018 +0200
    33.3 @@ -49,8 +49,7 @@
    33.4      // MARK: - Internal
    33.5  
    33.6      private func fetchAccounts() -> [CdAccount] {
    33.7 -        let p = NSPredicate(format: "needsVerification = false")
    33.8 -        return CdAccount.all(predicate: p, in: context) as? [CdAccount] ?? []
    33.9 +        return CdAccount.all() ?? []
   33.10      }
   33.11  
   33.12      private func gatherConnectInfos() -> [EmailConnectInfo] {
    34.1 --- a/pEpForiOS/Network/Service/LoginImapOperation.swift	Fri Jul 20 14:07:19 2018 +0200
    34.2 +++ b/pEpForiOS/Network/Service/LoginImapOperation.swift	Thu Jul 26 13:41:45 2018 +0200
    34.3 @@ -7,7 +7,6 @@
    34.4  //
    34.5  
    34.6  import UIKit
    34.7 -
    34.8  import MessageModel
    34.9  
   34.10  public class LoginImapOperation: ImapSyncOperation {
   34.11 @@ -15,9 +14,9 @@
   34.12      var capabilities: Set<String>?
   34.13      var service: ImapSync
   34.14  
   34.15 -    override public init(parentName: String = #function,
   34.16 -                         errorContainer: ServiceErrorProtocol = ErrorContainer(),
   34.17 -                         imapSyncData: ImapSyncData) {
   34.18 +    override init(parentName: String = #function,
   34.19 +                  errorContainer: ServiceErrorProtocol = ErrorContainer(),
   34.20 +                  imapSyncData: ImapSyncData) {
   34.21          service = imapSyncData.sync ?? ImapSync(connectInfo: imapSyncData.connectInfo)
   34.22          super.init(parentName: parentName, errorContainer: errorContainer,
   34.23                     imapSyncData: imapSyncData)
   34.24 @@ -61,14 +60,7 @@
   34.25          op.imapSyncData.sync = sync
   34.26  
   34.27          op.capabilities = sync.capabilities
   34.28 -        let context = Record.Context.background
   34.29 -        context.performAndWait {
   34.30 -            if let err = op.imapSyncData.connectInfo.unsetNeedsVerificationAndFinish(
   34.31 -                context: context) {
   34.32 -                op.addError(err)
   34.33 -            }
   34.34 -            op.markAsFinished()
   34.35 -        }
   34.36 +        op.markAsFinished()
   34.37      }
   34.38  
   34.39      override func folderOpenCompleted(_ sync: ImapSync, notification: Notification?) {
    35.1 --- a/pEpForiOS/Network/Service/LoginSmtpOperation.swift	Fri Jul 20 14:07:19 2018 +0200
    35.2 +++ b/pEpForiOS/Network/Service/LoginSmtpOperation.swift	Thu Jul 26 13:41:45 2018 +0200
    35.3 @@ -47,14 +47,7 @@
    35.4  
    35.5      public func authenticationCompleted(_ smtp: SmtpSend, theNotification: Notification?) {
    35.6          smtpSendData.smtp = smtp
    35.7 -        let context = Record.Context.background
    35.8 -        context.perform {
    35.9 -            if let err = self.smtpSendData.connectInfo.unsetNeedsVerificationAndFinish(
   35.10 -                context: context) {
   35.11 -                self.addError(err)
   35.12 -            }
   35.13 -            self.markAsFinished()
   35.14 -        }
   35.15 +        self.markAsFinished()
   35.16      }
   35.17  
   35.18      public func authenticationFailed(_ smtp: SmtpSend, theNotification: Notification?) {
    36.1 --- a/pEpForiOS/Network/Service/NetworkServiceWorker.swift	Fri Jul 20 14:07:19 2018 +0200
    36.2 +++ b/pEpForiOS/Network/Service/NetworkServiceWorker.swift	Thu Jul 26 13:41:45 2018 +0200
    36.3 @@ -195,10 +195,9 @@
    36.4      }
    36.5  
    36.6      func fetchAccounts() -> [CdAccount] {
    36.7 -        let p = NSPredicate(format: "needsVerification = false")
    36.8          var result = [CdAccount]()
    36.9          context.performAndWait {
   36.10 -            result =  CdAccount.all(predicate: p, orderedBy: nil, in: context) as? [CdAccount] ?? []
   36.11 +            result =  CdAccount.all() ?? []
   36.12          }
   36.13          return result
   36.14      }
    37.1 --- a/pEpForiOS/Network/Service/QualifyServerIsLocalService.swift	Fri Jul 20 14:07:19 2018 +0200
    37.2 +++ b/pEpForiOS/Network/Service/QualifyServerIsLocalService.swift	Thu Jul 26 13:41:45 2018 +0200
    37.3 @@ -15,7 +15,7 @@
    37.4  
    37.5      func qualify(serverName: String) {
    37.6          let op = QualifyServerIsLocalOperation(serverName: serverName)
    37.7 -        op.completionBlock = { [weak self] in
    37.8 +        op.completionBlock = { [weak self] in //Looks like leak to me. Tripple check, make op weak.
    37.9              self?.delegate?.didQualify(serverName: serverName,
   37.10                                         isLocal: op.isLocal,
   37.11                                         error: op.error)
    38.1 --- a/pEpForiOS/Network/Service/ServiceUtil.swift	Fri Jul 20 14:07:19 2018 +0200
    38.2 +++ b/pEpForiOS/Network/Service/ServiceUtil.swift	Thu Jul 26 13:41:45 2018 +0200
    38.3 @@ -20,9 +20,9 @@
    38.4                  let smtpCI = acc.smtpConnectInfo
    38.5                  let imapCI = acc.imapConnectInfo
    38.6                  if (smtpCI != nil || imapCI != nil) {
    38.7 -                    connectInfos.append(AccountConnectInfo(
    38.8 -                        needsVerification: acc.needsVerification,
    38.9 -                        accountID: acc.objectID, imapConnectInfo: imapCI, smtpConnectInfo: smtpCI))
   38.10 +                    connectInfos.append(AccountConnectInfo(accountID: acc.objectID,
   38.11 +                                                           imapConnectInfo: imapCI,
   38.12 +                                                           smtpConnectInfo: smtpCI))
   38.13                  }
   38.14              }
   38.15          }
   38.16 @@ -44,8 +44,7 @@
   38.17                      Log.shared.errorAndCrash(component: #function, errorString: "No objId")
   38.18                      accObjID = NSManagedObjectID() // Use nonsense
   38.19                  }
   38.20 -                connectInfos.append(AccountConnectInfo(needsVerification: acc.needsVerification,
   38.21 -                                                       accountID: accObjID,
   38.22 +                connectInfos.append(AccountConnectInfo(accountID: accObjID,
   38.23                                                         imapConnectInfo: imapCI,
   38.24                                                         smtpConnectInfo: smtpCI))
   38.25              }
    39.1 --- a/pEpForiOS/Network/Service/SharedObjects.swift	Fri Jul 20 14:07:19 2018 +0200
    39.2 +++ b/pEpForiOS/Network/Service/SharedObjects.swift	Thu Jul 26 13:41:45 2018 +0200
    39.3 @@ -12,15 +12,13 @@
    39.4   Used for building a line of operations for synching an account.
    39.5   */
    39.6  public struct AccountConnectInfo {
    39.7 -    public let needsVerification: Bool
    39.8 -    public let accountID: NSManagedObjectID
    39.9 -    public let imapConnectInfo: EmailConnectInfo?
   39.10 -    public let smtpConnectInfo: EmailConnectInfo?
   39.11 +    let accountID: NSManagedObjectID
   39.12 +    let imapConnectInfo: EmailConnectInfo?
   39.13 +    let smtpConnectInfo: EmailConnectInfo?
   39.14  }
   39.15  
   39.16  extension AccountConnectInfo {
   39.17      public init(accountID: NSManagedObjectID) {
   39.18 -        self.needsVerification = false
   39.19          self.accountID = accountID
   39.20          self.imapConnectInfo = nil
   39.21          self.smtpConnectInfo = nil
   39.22 @@ -62,8 +60,8 @@
   39.23  /**
   39.24   Used for parameters/state shared between IMAP related operations.
   39.25   */
   39.26 -open class ImapSyncData: ImapConnectionManagerProtocol {
   39.27 -    public let connectInfo: EmailConnectInfo
   39.28 +class ImapSyncData: ImapConnectionManagerProtocol {
   39.29 +    let connectInfo: EmailConnectInfo
   39.30  
   39.31      public var sync: ImapSync?
   39.32  
   39.33 @@ -71,11 +69,11 @@
   39.34          return sync?.supportsIdle ?? false
   39.35      }
   39.36  
   39.37 -    public init(connectInfo: EmailConnectInfo) {
   39.38 +    init(connectInfo: EmailConnectInfo) {
   39.39          self.connectInfo = connectInfo
   39.40      }
   39.41  
   39.42 -    public func imapConnection(connectInfo: EmailConnectInfo) -> ImapSync? {
   39.43 +    func imapConnection(connectInfo: EmailConnectInfo) -> ImapSync? {
   39.44          if self.connectInfo == connectInfo {
   39.45              return sync
   39.46          }
   39.47 @@ -88,10 +86,10 @@
   39.48  }
   39.49  
   39.50  open class SmtpSendData {
   39.51 -    public let connectInfo: EmailConnectInfo
   39.52 +    let connectInfo: EmailConnectInfo
   39.53      public var smtp: SmtpSend?
   39.54  
   39.55 -    public init(connectInfo: EmailConnectInfo) {
   39.56 +    init(connectInfo: EmailConnectInfo) {
   39.57          self.connectInfo = connectInfo
   39.58      }
   39.59  
    40.1 --- a/pEpForiOS/UI/AccountSettings/ViewModel/AccountSettingsViewModel.swift	Fri Jul 20 14:07:19 2018 +0200
    40.2 +++ b/pEpForiOS/UI/AccountSettings/ViewModel/AccountSettingsViewModel.swift	Thu Jul 26 13:41:45 2018 +0200
    40.3 @@ -17,7 +17,6 @@
    40.4      }
    40.5  
    40.6      public struct SecurityViewModel {
    40.7 -
    40.8          var options = Server.Transport.toArray()
    40.9          var size : Int {
   40.10              get {
   40.11 @@ -33,7 +32,6 @@
   40.12      }
   40.13  
   40.14      private var account: Account
   40.15 -    private var clonedAccount: Account?
   40.16      private let headers = [
   40.17          NSLocalizedString("Account", comment: "Account settings"),
   40.18          NSLocalizedString("IMAP Settings", comment: "Account settings title IMAP"),
   40.19 @@ -45,7 +43,9 @@
   40.20      public let isOAuth2: Bool
   40.21  
   40.22      public init(account: Account) {
   40.23 -        self.account = account
   40.24 +        // We are using a copy here. The outside world must not know changed settings until they
   40.25 +        // have been verified.
   40.26 +        self.account = Account(withDataFrom: account)
   40.27          isOAuth2 = account.server(with: .imap)?.authMethod == AuthMethod.saslXoauth2.rawValue
   40.28      }
   40.29  
   40.30 @@ -97,7 +97,6 @@
   40.31      // If we run into problems here modify to updateOrCreate
   40.32      func update(loginName: String, name: String, password: String? = nil, imap: ServerViewModel,
   40.33                  smtp: ServerViewModel) {
   40.34 -        clonedAccount = account.clone()
   40.35          guard let serverImap = account.imapServer,
   40.36              let serverSmtp = account.smtpServer else {
   40.37                  Log.shared.errorAndCrash(component: #function,
   40.38 @@ -123,8 +122,6 @@
   40.39                  Log.shared.errorAndCrash(component: #function, errorString: "Invalid input.")
   40.40                  return
   40.41          }
   40.42 -        serverImap.needsVerification = true
   40.43 -        serverSmtp.needsVerification = true
   40.44  
   40.45          serverImap.updateValues(with: editedServerImap)
   40.46          serverSmtp.updateValues(with: editedServerSmtp)
   40.47 @@ -135,8 +132,6 @@
   40.48              Log.shared.errorAndCrash(component: #function, errorString: "no MessageSyncService")
   40.49              return
   40.50          }
   40.51 -        account.needsVerification = true
   40.52 -        account.save()
   40.53          ms.requestVerification(account: account, delegate: self)
   40.54      }
   40.55  
   40.56 @@ -157,7 +152,6 @@
   40.57          }
   40.58      }
   40.59  
   40.60 -    //MARK: - PRIVATE
   40.61      private func server(from viewModel:ServerViewModel, serverType:Server.ServerType,
   40.62                          loginName: String, password: String?, key: String? = nil) -> Server? {
   40.63          guard let viewModelPort = viewModel.port,
   40.64 @@ -167,7 +161,7 @@
   40.65                                           errorString: "viewModel misses required data.")
   40.66                  return nil
   40.67          }
   40.68 -        let transport = Server.Transport.init(fromString: viewModel.transport)
   40.69 +        let transport = Server.Transport(fromString: viewModel.transport)
   40.70  
   40.71          let credentials = ServerCredentials.create(loginName: loginName, key: key)
   40.72          if password != nil && password != "" {
   40.73 @@ -180,10 +174,6 @@
   40.74          return server
   40.75      }
   40.76  
   40.77 -    func cleanClonedAccount() {
   40.78 -        //account.update(to: clonedAccount)
   40.79 -    }
   40.80 -
   40.81      func updateToken(accessToken: OAuth2AccessTokenProtocol) {
   40.82          guard let imapServer = account.imapServer,
   40.83              let smtpServer = account.smtpServer else {
   40.84 @@ -192,17 +182,26 @@
   40.85          let password = accessToken.persistBase64Encoded()
   40.86          imapServer.credentials.password = password
   40.87          smtpServer.credentials.password = password
   40.88 -        imapServer.credentials.save()
   40.89      }
   40.90  }
   40.91  
   40.92 +// MARK: - AccountVerificationServiceDelegate
   40.93 +
   40.94  extension AccountSettingsViewModel: AccountVerificationServiceDelegate {
   40.95 -    func verified(account: Account, service: AccountVerificationServiceProtocol,
   40.96 +    func verified(account: Account,
   40.97 +                  service: AccountVerificationServiceProtocol,
   40.98                    result: AccountVerificationResult) {
   40.99 -        cleanClonedAccount()
  40.100 -        DispatchQueue.main.sync {
  40.101 -            delegate?.didVerify(result: result, accountInput: nil)
  40.102 +        if result == .ok {
  40.103 +            MessageModel.performAndWait {
  40.104 +                account.save()
  40.105 +            }
  40.106 +        }
  40.107 +        GCD.onMainWait { [weak self] in
  40.108 +            guard let me = self else {
  40.109 +                Log.shared.errorAndCrash(component: #function, errorString: "Lost myself")
  40.110 +                return
  40.111 +            }
  40.112 +            me.delegate?.didVerify(result: result, accountInput: nil)
  40.113          }
  40.114      }
  40.115  }
  40.116 -
    41.1 --- a/pEpForiOS/UI/Base.lproj/FolderViews.storyboard	Fri Jul 20 14:07:19 2018 +0200
    41.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.3 @@ -1,130 +0,0 @@
    41.4 -<?xml version="1.0" encoding="UTF-8"?>
    41.5 -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="N0y-5z-66z">
    41.6 -    <device id="retina4_7" orientation="portrait">
    41.7 -        <adaptation id="fullscreen"/>
    41.8 -    </device>
    41.9 -    <dependencies>
   41.10 -        <deployment identifier="iOS"/>
   41.11 -        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
   41.12 -        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
   41.13 -    </dependencies>
   41.14 -    <scenes>
   41.15 -        <!--Folder Table View Controller-->
   41.16 -        <scene sceneID="sp8-r5-QDF">
   41.17 -            <objects>
   41.18 -                <tableViewController storyboardIdentifier="Folders" id="6ra-tc-Aiv" customClass="FolderTableViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
   41.19 -                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="OAM-Xh-1fA">
   41.20 -                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
   41.21 -                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
   41.22 -                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
   41.23 -                        <color key="sectionIndexBackgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   41.24 -                        <view key="tableFooterView" contentMode="scaleToFill" id="y1Q-G4-Yvh">
   41.25 -                            <rect key="frame" x="0.0" y="72" width="375" height="80"/>
   41.26 -                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
   41.27 -                            <subviews>
   41.28 -                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NEj-lZ-p6O">
   41.29 -                                    <rect key="frame" x="10" y="10" width="250" height="60"/>
   41.30 -                                    <constraints>
   41.31 -                                        <constraint firstAttribute="width" constant="250" id="hN3-sc-EZD"/>
   41.32 -                                    </constraints>
   41.33 -                                    <fontDescription key="fontDescription" type="system" pointSize="18"/>
   41.34 -                                    <inset key="contentEdgeInsets" minX="25" minY="0.0" maxX="0.0" maxY="0.0"/>
   41.35 -                                    <inset key="titleEdgeInsets" minX="25" minY="0.0" maxX="0.0" maxY="0.0"/>
   41.36 -                                    <state key="normal" title="add account" image="button-add">
   41.37 -                                        <color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
   41.38 -                                    </state>
   41.39 -                                    <connections>
   41.40 -                                        <segue destination="uKb-Ku-Cng" kind="presentation" identifier="newAccount" modalPresentationStyle="formSheet" id="aKb-z0-Qyn"/>
   41.41 -                                    </connections>
   41.42 -                                </button>
   41.43 -                            </subviews>
   41.44 -                            <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
   41.45 -                            <constraints>
   41.46 -                                <constraint firstItem="NEj-lZ-p6O" firstAttribute="centerY" secondItem="y1Q-G4-Yvh" secondAttribute="centerY" id="UiB-SQ-x7F"/>
   41.47 -                                <constraint firstItem="NEj-lZ-p6O" firstAttribute="top" secondItem="y1Q-G4-Yvh" secondAttribute="top" constant="10" id="mKu-BF-aVp"/>
   41.48 -                                <constraint firstItem="NEj-lZ-p6O" firstAttribute="leading" secondItem="y1Q-G4-Yvh" secondAttribute="leading" constant="10" id="sYX-Dy-WeQ"/>
   41.49 -                            </constraints>
   41.50 -                        </view>
   41.51 -                        <prototypes>
   41.52 -                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="Default" id="Gav-RT-MrD">
   41.53 -                                <rect key="frame" x="0.0" y="28" width="375" height="44"/>
   41.54 -                                <autoresizingMask key="autoresizingMask"/>
   41.55 -                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Gav-RT-MrD" id="GDF-rs-ueo">
   41.56 -                                    <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
   41.57 -                                    <autoresizingMask key="autoresizingMask"/>
   41.58 -                                </tableViewCellContentView>
   41.59 -                            </tableViewCell>
   41.60 -                        </prototypes>
   41.61 -                        <connections>
   41.62 -                            <outlet property="dataSource" destination="6ra-tc-Aiv" id="1SN-a9-8B6"/>
   41.63 -                            <outlet property="delegate" destination="6ra-tc-Aiv" id="z48-Ic-eJ4"/>
   41.64 -                        </connections>
   41.65 -                    </tableView>
   41.66 -                    <toolbarItems/>
   41.67 -                    <navigationItem key="navigationItem" id="rcC-dN-oTh"/>
   41.68 -                    <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
   41.69 -                </tableViewController>
   41.70 -                <placeholder placeholderIdentifier="IBFirstResponder" id="o2c-UY-yR4" userLabel="First Responder" sceneMemberID="firstResponder"/>
   41.71 -            </objects>
   41.72 -            <point key="canvasLocation" x="9884" y="-1164.4677661169417"/>
   41.73 -        </scene>
   41.74 -        <!--Settings-->
   41.75 -        <scene sceneID="pIX-qm-rCm">
   41.76 -            <objects>
   41.77 -                <viewControllerPlaceholder storyboardName="Settings" id="tEI-hD-lXp" sceneMemberID="viewController"/>
   41.78 -                <placeholder placeholderIdentifier="IBFirstResponder" id="eR0-nA-UVS" userLabel="First Responder" sceneMemberID="firstResponder"/>
   41.79 -            </objects>
   41.80 -            <point key="canvasLocation" x="10572" y="-1187.4062968515743"/>
   41.81 -        </scene>
   41.82 -        <!--AccountCreation-->
   41.83 -        <scene sceneID="rdR-gU-SsC">
   41.84 -            <objects>
   41.85 -                <viewControllerPlaceholder storyboardName="AccountCreation" id="uKb-Ku-Cng" sceneMemberID="viewController"/>
   41.86 -                <placeholder placeholderIdentifier="IBFirstResponder" id="7bq-Lz-J44" userLabel="First Responder" sceneMemberID="firstResponder"/>
   41.87 -            </objects>
   41.88 -            <point key="canvasLocation" x="10612.799999999999" y="-1142.4287856071965"/>
   41.89 -        </scene>
   41.90 -        <!--Main-->
   41.91 -        <scene sceneID="eeX-Fr-Vs1">
   41.92 -            <objects>
   41.93 -                <viewControllerPlaceholder storyboardName="Main" id="jlA-KV-xmZ" sceneMemberID="viewController">
   41.94 -                    <navigationItem key="navigationItem" id="C0u-m3-NYA"/>
   41.95 -                </viewControllerPlaceholder>
   41.96 -                <placeholder placeholderIdentifier="IBFirstResponder" id="nrT-r1-KyC" userLabel="First Responder" sceneMemberID="firstResponder"/>
   41.97 -            </objects>
   41.98 -            <point key="canvasLocation" x="10091" y="-423"/>
   41.99 -        </scene>
  41.100 -        <!--Navigation Controller-->
  41.101 -        <scene sceneID="7fi-4c-XJX">
  41.102 -            <objects>
  41.103 -                <navigationController id="vQa-F1-CvY" sceneMemberID="viewController">
  41.104 -                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="9sq-1a-bXm">
  41.105 -                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
  41.106 -                        <autoresizingMask key="autoresizingMask"/>
  41.107 -                    </navigationBar>
  41.108 -                    <connections>
  41.109 -                        <segue destination="6ra-tc-Aiv" kind="relationship" relationship="rootViewController" id="DdA-8g-fEw"/>
  41.110 -                    </connections>
  41.111 -                </navigationController>
  41.112 -                <placeholder placeholderIdentifier="IBFirstResponder" id="79P-lr-Jjm" userLabel="First Responder" sceneMemberID="firstResponder"/>
  41.113 -            </objects>
  41.114 -            <point key="canvasLocation" x="9094" y="-1164"/>
  41.115 -        </scene>
  41.116 -        <!--Primary Split View Controller-->
  41.117 -        <scene sceneID="cmc-6v-uzh">
  41.118 -            <objects>
  41.119 -                <splitViewController storyboardIdentifier="main.initial.nvc" maximumPrimaryColumnWidth="320" id="N0y-5z-66z" customClass="PrimarySplitViewController" customModule="pEpForiOS" customModuleProvider="target" sceneMemberID="viewController">
  41.120 -                    <connections>
  41.121 -                        <segue destination="vQa-F1-CvY" kind="relationship" relationship="masterViewController" id="LaJ-Ow-wD4"/>
  41.122 -                        <segue destination="jlA-KV-xmZ" kind="relationship" relationship="detailViewController" id="b81-as-g9K"/>
  41.123 -                    </connections>
  41.124 -                </splitViewController>
  41.125 -                <placeholder placeholderIdentifier="IBFirstResponder" id="d4z-SE-fTT" userLabel="First Responder" sceneMemberID="firstResponder"/>
  41.126 -            </objects>
  41.127 -            <point key="canvasLocation" x="8334" y="-418"/>
  41.128 -        </scene>
  41.129 -    </scenes>
  41.130 -    <resources>
  41.131 -        <image name="button-add" width="22" height="22"/>
  41.132 -    </resources>
  41.133 -</document>
    42.1 --- a/pEpForiOS/UI/EmailDisplay/EmailViewController+MoveToFolderDelegate.swift	Fri Jul 20 14:07:19 2018 +0200
    42.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailViewController+MoveToFolderDelegate.swift	Thu Jul 26 13:41:45 2018 +0200
    42.3 @@ -10,6 +10,10 @@
    42.4  import MessageModel
    42.5  
    42.6  extension EmailViewController: MoveToFolderDelegate {
    42.7 +    func didmove(messages: [Message]) {
    42.8 +        self.didMove()
    42.9 +    }
   42.10 +
   42.11      func didMove() {
   42.12          if let msg = self.message {
   42.13              delegate?.emailDisplayDidDelete(message: msg)
    43.1 --- a/pEpForiOS/UI/EmailDisplayList/EmailListViewCell.swift	Fri Jul 20 14:07:19 2018 +0200
    43.2 +++ b/pEpForiOS/UI/EmailDisplayList/EmailListViewCell.swift	Thu Jul 26 13:41:45 2018 +0200
    43.3 @@ -81,7 +81,8 @@
    43.4          isSeen = viewModel.isSeen
    43.5          hasAttachment = viewModel.showAttchmentIcon
    43.6          dateLabel.text = viewModel.dateText
    43.7 -        messageCount = viewModel.messageCount
    43.8 +        
    43.9 +        configureThreadIndicator(for: viewModel)
   43.10          if viewModel.senderContactImage != nil {
   43.11              setContactImage(image: viewModel.senderContactImage)
   43.12          } else {
   43.13 @@ -96,6 +97,18 @@
   43.14          }
   43.15      }
   43.16  
   43.17 +    func configureThreadIndicator(for viewModel: MessageViewModel) {
   43.18 +        guard let _ = messageCountLabel,
   43.19 +            let _ = threadIndicator else {
   43.20 +                messageCount = 0
   43.21 +                return
   43.22 +        }
   43.23 +        viewModel.messageCount { (messageCount) in
   43.24 +            self.messageCount = messageCount
   43.25 +        }
   43.26 +
   43.27 +    }
   43.28 +
   43.29      func setPepRatingImage(image: UIImage?) {
   43.30          guard image != nil else {
   43.31              return
    44.1 --- a/pEpForiOS/UI/EmailDisplayList/EmailListViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    44.2 +++ b/pEpForiOS/UI/EmailDisplayList/EmailListViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    44.3 @@ -52,7 +52,7 @@
    44.4      
    44.5      override func viewDidLoad() {
    44.6          super.viewDidLoad()
    44.7 -        
    44.8 +
    44.9          UIHelper.emailListTableHeight(self.tableView)
   44.10          self.textFilterButton.isEnabled = false
   44.11  
   44.12 @@ -134,6 +134,11 @@
   44.13              model = EmailListViewModel(emailListViewModelDelegate: self,
   44.14                                         messageSyncService: appConfig.messageSyncService,
   44.15                                         folderToShow: theFolder)
   44.16 +
   44.17 +            guard let screenComposer = splitViewController as? ScreenComposerProtocol else {
   44.18 +                return
   44.19 +            }
   44.20 +            model?.screenComposer =  screenComposer
   44.21          }
   44.22      }
   44.23      
   44.24 @@ -168,6 +173,7 @@
   44.25              action: nil)
   44.26          self.toolbarItems?.append(contentsOf: [flexibleSpace,item])
   44.27          self.navigationController?.title = title
   44.28 +
   44.29      }
   44.30  
   44.31      private func weCameBackFromAPushedView() -> Bool {
   44.32 @@ -497,11 +503,17 @@
   44.33          // Flag
   44.34          if folderIsDraft(parentFolder) {
   44.35              // Do not add "Flag" action to drafted mails.
   44.36 +
   44.37              let flagAction = SwipeAction(style: .default, title: "Flag") { action, indexPath in
   44.38                  self.flagAction(forCellAt: indexPath)
   44.39              }
   44.40 +
   44.41              flagAction.hidesWhenSelected = true
   44.42 -            configure(action: flagAction, with: .flag)
   44.43 +            
   44.44 +            let flagged = model?.message(representedByRowAt: indexPath)?.imapFlags?.flagged ?? false
   44.45 +            let actionDescriptor: SwipeActionDescriptor = flagged == true ? .unflag : .flag
   44.46 +
   44.47 +            configure(action: flagAction, with: actionDescriptor)
   44.48              swipeActions.append(flagAction)
   44.49          }
   44.50  
   44.51 @@ -881,7 +893,7 @@
   44.52      /**
   44.53       Enables manual account setup to unwind to the unified inbox.
   44.54       */
   44.55 -    @IBAction func unwindToFolderView(segue:UIStoryboardSegue) {
   44.56 +    @IBAction func segueUnwindAfterAccountCreation(segue:UIStoryboardSegue) {
   44.57          folderToShow = UnifiedInbox()
   44.58          resetModel()
   44.59      }
   44.60 @@ -960,7 +972,7 @@
   44.61          case .segueAddNewAccount:
   44.62              guard
   44.63                  let nav = segue.destination as? UINavigationController,
   44.64 -                let vc = nav.rootViewController as? LoginTableViewController else {
   44.65 +                let vc = nav.rootViewController as? LoginViewController else {
   44.66                      Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
   44.67                      return
   44.68              }
   44.69 @@ -1056,11 +1068,11 @@
   44.70      }
   44.71  }
   44.72  
   44.73 -// MARK: - LoginTableViewControllerDelegate
   44.74 +// MARK: - LoginViewControllerDelegate
   44.75  
   44.76 -extension EmailListViewController: LoginTableViewControllerDelegate {
   44.77 -    func loginTableViewControllerDidCreateNewAccount(
   44.78 -        _ loginTableViewController: LoginTableViewController) {
   44.79 +extension EmailListViewController: LoginViewControllerDelegate {
   44.80 +    func loginViewControllerDidCreateNewAccount(
   44.81 +        _ loginViewController: LoginViewController) {
   44.82          // Setup model after initial account setup
   44.83          setup()
   44.84      }
   44.85 @@ -1106,7 +1118,7 @@
   44.86          case .reply: name = "reply"
   44.87          case .more: name = "more"
   44.88          case .flag: name = "flag"
   44.89 -        case .unflag: name = "unflag"
   44.90 +        case .unflag: name = "flag"
   44.91          case .trash: name = "trash"
   44.92          case .archive: name = "archive"
   44.93          }
    45.1 --- a/pEpForiOS/UI/EmailDisplayList/EmailListViewModel+MessageFolderDelegate.swift	Fri Jul 20 14:07:19 2018 +0200
    45.2 +++ b/pEpForiOS/UI/EmailDisplayList/EmailListViewModel+MessageFolderDelegate.swift	Thu Jul 26 13:41:45 2018 +0200
    45.3 @@ -75,8 +75,7 @@
    45.4                              viewModel: theSelf, didUpdateDataAt: [IndexPath(row: index, section: 0)])
    45.5                          if theSelf.isCurrentlyDisplayingDetailsOf(oneOf: referencedMessages) {
    45.6                              if theSelf.shouldShowThreadVC() {
    45.7 -                                theSelf.emailListViewModelDelegate?.showThreadView(
    45.8 -                                    for: IndexPath(row: index, section: 0))
    45.9 +                              theSelf.screenComposer?.emailListViewModel(theSelf, requestsShowThreadViewFor: message)
   45.10                              } else {
   45.11                                  theSelf.updateThreadListDelegate?.added(message: message)
   45.12                              }
    46.1 --- a/pEpForiOS/UI/EmailDisplayList/EmailListViewModel+MoveToFolderDelegate.swift	Fri Jul 20 14:07:19 2018 +0200
    46.2 +++ b/pEpForiOS/UI/EmailDisplayList/EmailListViewModel+MoveToFolderDelegate.swift	Thu Jul 26 13:41:45 2018 +0200
    46.3 @@ -10,6 +10,26 @@
    46.4  import MessageModel
    46.5  
    46.6  extension EmailListViewModel: MoveToFolderDelegate {
    46.7 +    func didmove(messages: [Message]) {
    46.8 +        var ips = [IndexPath]()
    46.9 +        var pms = [PreviewMessage]()
   46.10 +        messages.forEach { (msg) in
   46.11 +            let ind = index(of: msg)!
   46.12 +            let pm = self.messages.object(at: ind)!
   46.13 +            pms.append(pm)
   46.14 +            let ip = IndexPath(row: ind, section: 0)
   46.15 +            ips.append(ip)
   46.16 +        }
   46.17 +        deletePreviewMessagesHelper(previewMEssages: pms)
   46.18 +        emailListViewModelDelegate?.emailListViewModel(viewModel: self, didRemoveDataAt: ips)
   46.19 +    }
   46.20 +
   46.21 +    func deletePreviewMessagesHelper(previewMEssages: [PreviewMessage]) {
   46.22 +        previewMEssages.forEach { (pm) in
   46.23 +            self.messages.remove(object: pm)
   46.24 +        }
   46.25 +    }
   46.26 +
   46.27      func didMove() {
   46.28          reloadData()
   46.29      }
    47.1 --- a/pEpForiOS/UI/EmailDisplayList/EmailListViewModel.swift	Fri Jul 20 14:07:19 2018 +0200
    47.2 +++ b/pEpForiOS/UI/EmailDisplayList/EmailListViewModel.swift	Thu Jul 26 13:41:45 2018 +0200
    47.3 @@ -19,7 +19,6 @@
    47.4      func toolbarIs(enabled: Bool)
    47.5      func showUnflagButton(enabled: Bool)
    47.6      func showUnreadButton(enabled: Bool)
    47.7 -    func showThreadView(for indexPath: IndexPath)
    47.8  }
    47.9  
   47.10  // MARK: - FilterUpdateProtocol
   47.11 @@ -37,7 +36,6 @@
   47.12          "net.pep-security-EmailListViewModel-MessageFolderDelegateHandling")
   47.13      let contactImageTool = IdentityImageTool()
   47.14      let messageSyncService: MessageSyncServiceProtocol
   47.15 -    
   47.16      internal var messages: SortedSet<PreviewMessage>
   47.17      private let queue: OperationQueue = {
   47.18          let createe = OperationQueue()
   47.19 @@ -51,6 +49,7 @@
   47.20      internal let threadedMessageFolder: ThreadedMessageFolderProtocol
   47.21  
   47.22      public var currentDisplayedMessage: DisplayedMessage?
   47.23 +    public var screenComposer: ScreenComposerProtocol?
   47.24  
   47.25      let sortByDateSentAscending: SortedSet<PreviewMessage>.SortBlock =
   47.26      { (pvMsg1: PreviewMessage, pvMsg2: PreviewMessage) -> ComparisonResult in
   47.27 @@ -70,6 +69,7 @@
   47.28      private var selectedItems: Set<IndexPath>?
   47.29  
   47.30      weak var updateThreadListDelegate: UpdateThreadListDelegate?
   47.31 +    var defaultFilter: CompositeFilter<FilterBase>?
   47.32      
   47.33      // MARK: - Life Cycle
   47.34      
   47.35 @@ -82,6 +82,7 @@
   47.36  
   47.37          self.folderToShow = folderToShow
   47.38          self.threadedMessageFolder = FolderThreading.makeThreadAware(folder: folderToShow)
   47.39 +        self.defaultFilter = folderToShow.filter?.clone()
   47.40          resetViewModel()
   47.41      }
   47.42  
   47.43 @@ -399,7 +400,7 @@
   47.44          if isFilterEnabled {
   47.45              folderFilter.with(filters: filterViewFilter)
   47.46          } else {
   47.47 -            folderFilter.without(filters: filterViewFilter)
   47.48 +            self.folderToShow.filter = defaultFilter
   47.49          }
   47.50          resetViewModel()
   47.51      }
    48.1 --- a/pEpForiOS/UI/EmailDisplayList/MessageViewModel.swift	Fri Jul 20 14:07:19 2018 +0200
    48.2 +++ b/pEpForiOS/UI/EmailDisplayList/MessageViewModel.swift	Thu Jul 26 13:41:45 2018 +0200
    48.3 @@ -24,7 +24,6 @@
    48.4      var isFlagged: Bool = false
    48.5      var isSeen: Bool = false
    48.6      var dateText: String
    48.7 -    var messageCount: Int
    48.8      var profilePictureComposer: ProfilePictureComposer
    48.9      var body: NSAttributedString {
   48.10              return getBodyMessage()
   48.11 @@ -39,12 +38,24 @@
   48.12          isFlagged = message.imapFlags?.flagged ?? false
   48.13          isSeen = message.imapFlags?.seen ?? false
   48.14          dateText =  (message.sent ?? Date()).smartString()
   48.15 -        messageCount = message.numberOfMessagesInThread()
   48.16          profilePictureComposer = PepProfilePictureComposer()
   48.17          bodyPeek = MessageViewModel.getSummary(fromMessage: message)
   48.18          self.message = message
   48.19      }
   48.20  
   48.21 +    func messageCount(completion: @escaping (Int)->()) {
   48.22 +        DispatchQueue.global(qos: .userInitiated).async {
   48.23 +
   48.24 +            MessageModel.performAndWait {
   48.25 +                let messageCount = self.message.numberOfMessagesInThread()
   48.26 +
   48.27 +                DispatchQueue.main.async {
   48.28 +                    completion(messageCount)
   48.29 +                }
   48.30 +            }
   48.31 +        }
   48.32 +    }
   48.33 +
   48.34      private class func address(at folder: Folder?, from message: Message) -> String {
   48.35          guard let folder = folder else {
   48.36              return ""
   48.37 @@ -94,7 +105,8 @@
   48.38      }
   48.39  
   48.40      func getProfilePicture(completion: @escaping (UIImage?)->()){
   48.41 -        profilePictureComposer.getProfilePicture(for: from, completion: completion)
   48.42 +        let identity = message.from ?? Identity(address: from)
   48.43 +        profilePictureComposer.getProfilePicture(for: identity, completion: completion)
   48.44      }
   48.45  
   48.46      func getSecurityBadge(completion: @escaping (UIImage?) ->()) {
    49.1 --- a/pEpForiOS/UI/EmailDisplayList/PepPictureComposer.swift	Fri Jul 20 14:07:19 2018 +0200
    49.2 +++ b/pEpForiOS/UI/EmailDisplayList/PepPictureComposer.swift	Thu Jul 26 13:41:45 2018 +0200
    49.3 @@ -13,13 +13,15 @@
    49.4  
    49.5      let contactImageTool = IdentityImageTool()
    49.6  
    49.7 -    func getProfilePicture(for address: String, completion: @escaping (UIImage?) -> ()) {
    49.8 -        let identity = Identity(address: address)
    49.9 +    func getProfilePicture(for identity: Identity, completion: @escaping (UIImage?) -> ()) {
   49.10  
   49.11          if let image = self.contactImageTool.cachedIdentityImage(forIdentity: identity){
   49.12              completion(image)
   49.13 +
   49.14 +
   49.15          } else {
   49.16 -            MessageModel.performAndWait {
   49.17 +            DispatchQueue.global().async {
   49.18 +
   49.19                  let senderImage = self.contactImageTool.identityImage(for: identity)
   49.20                  DispatchQueue.main.async {
   49.21                      completion(senderImage)
    50.1 --- a/pEpForiOS/UI/EmailDisplayList/ProfilePictureComposer.swift	Fri Jul 20 14:07:19 2018 +0200
    50.2 +++ b/pEpForiOS/UI/EmailDisplayList/ProfilePictureComposer.swift	Thu Jul 26 13:41:45 2018 +0200
    50.3 @@ -11,7 +11,7 @@
    50.4  
    50.5  protocol ProfilePictureComposer {
    50.6  
    50.7 -    func getProfilePicture(for address: String, completion: @escaping (UIImage?)->())
    50.8 +    func getProfilePicture(for identity: Identity, completion: @escaping (UIImage?)->())
    50.9  
   50.10      func getSecurityBadge(for message: Message, completion: @escaping (UIImage?) ->())
   50.11  
    51.1 --- a/pEpForiOS/UI/Folder/FolderTableViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    51.2 +++ b/pEpForiOS/UI/Folder/FolderTableViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    51.3 @@ -160,11 +160,11 @@
    51.4      private func showFolder(indexPath: IndexPath?) {
    51.5          let sb = UIStoryboard(name: "Main", bundle: nil)
    51.6          guard
    51.7 -            let vc = sb.instantiateViewController(withIdentifier: EmailListViewController.storyboardId)
    51.8 -                as? EmailListViewController
    51.9 -            else {
   51.10 -                Log.shared.errorAndCrash(component: #function, errorString: "Problem!")
   51.11 -                return
   51.12 +            let vc = sb.instantiateViewController(
   51.13 +                withIdentifier: EmailListViewController.storyboardId)
   51.14 +                as? EmailListViewController else {
   51.15 +                    Log.shared.errorAndCrash(component: #function, errorString: "Problem!")
   51.16 +                    return
   51.17          }
   51.18          vc.appConfig = appConfig
   51.19          if let vm = folderVM, let ip = indexPath {
   51.20 @@ -183,7 +183,7 @@
   51.21          if segue.identifier == "newAccount" {
   51.22              guard
   51.23                  let nav = segue.destination as? UINavigationController,
   51.24 -                let vc = nav.rootViewController as? LoginTableViewController else {
   51.25 +                let vc = nav.rootViewController as? LoginViewController else {
   51.26                      Log.shared.errorAndCrash(component: #function, errorString: "Missing VCs")
   51.27                      return
   51.28              }
   51.29 @@ -200,13 +200,20 @@
   51.30              dvc.hidesBottomBarWhenPushed = true
   51.31          }
   51.32      }
   51.33 +
   51.34 +    /**
   51.35 +     Unwind segue for the case of adding an account that requires manual setup
   51.36 +     */
   51.37 +    @IBAction func segueUnwindAfterAccountCreation(segue:UIStoryboardSegue) {
   51.38 +        showNext = true
   51.39 +    }
   51.40  }
   51.41  
   51.42  // MARK: - LoginTableViewControllerDelegate
   51.43  
   51.44 -extension FolderTableViewController: LoginTableViewControllerDelegate {
   51.45 -    func loginTableViewControllerDidCreateNewAccount(
   51.46 -        _ loginTableViewController: LoginTableViewController) {
   51.47 +extension FolderTableViewController: LoginViewControllerDelegate {
   51.48 +    func loginViewControllerDidCreateNewAccount(
   51.49 +        _ loginViewController: LoginViewController) {
   51.50          showNext = true
   51.51      }
   51.52  }
    52.1 --- a/pEpForiOS/UI/Login/LoginTableViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    52.2 +++ b/pEpForiOS/UI/Login/LoginTableViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    52.3 @@ -30,7 +30,8 @@
    52.4              return NSLocalizedString("Username must not be empty.",
    52.5                                       comment: "Empty username message")
    52.6          case .minimumLengthUsername:
    52.7 -            return NSLocalizedString("Username must have more than 5 characters.",
    52.8 +            return NSLocalizedString("Username must have more than " +
    52.9 +                "\(LoginTableViewController.minCharUserName) characters.",
   52.10                                       comment: "minimum username length")
   52.11          case .noConnectData:
   52.12              return NSLocalizedString("Internal error",
   52.13 @@ -46,6 +47,7 @@
   52.14   }
   52.15  
   52.16   class LoginTableViewController: BaseTableViewController {
   52.17 +    static let minCharUserName = 1
   52.18      var loginViewModel = LoginViewModel()
   52.19      var offerManualSetup = false
   52.20      var delegate: LoginTableViewControllerDelegate?
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/pEpForiOS/UI/Login/LoginViewController+Keyboard.swift	Thu Jul 26 13:41:45 2018 +0200
    53.3 @@ -0,0 +1,39 @@
    53.4 +//
    53.5 +//  LoginViewController+Keyboard.swift
    53.6 +//  pEp
    53.7 +//
    53.8 +//  Created by Miguel Berrocal Gómez on 20/07/2018.
    53.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   53.10 +//
   53.11 +
   53.12 +import Foundation
   53.13 +
   53.14 +
   53.15 +extension LoginViewController {
   53.16 +
   53.17 +    func configureKeyboardAwareness() {
   53.18 +        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil)
   53.19 +        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil)
   53.20 +    }
   53.21 +
   53.22 +    @objc func keyboardWillShow(notification:NSNotification){
   53.23 +
   53.24 +        guard let keyboardFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?
   53.25 +            .cgRectValue else {
   53.26 +            return
   53.27 +        }
   53.28 +
   53.29 +        var contentInset:UIEdgeInsets = contentScrollView.contentInset
   53.30 +        contentInset.bottom = keyboardFrame.size.height
   53.31 +        contentScrollView.contentInset = contentInset
   53.32 +        contentScrollView.scrollIndicatorInsets = contentInset
   53.33 +        contentScrollView.scrollRectToVisible(loginButton.frame, animated: true)
   53.34 +    }
   53.35 +
   53.36 +    @objc func keyboardWillHide(notification:NSNotification){
   53.37 +
   53.38 +        let contentInset:UIEdgeInsets = UIEdgeInsets.zero
   53.39 +        self.contentScrollView.contentInset = contentInset
   53.40 +    }
   53.41 +
   53.42 +}
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/pEpForiOS/UI/Login/LoginViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    54.3 @@ -0,0 +1,352 @@
    54.4 +//
    54.5 +//  LoginViewController.swift
    54.6 +//  pEp
    54.7 +//
    54.8 +//  Created by Miguel Berrocal Gómez on 13/07/2018.
    54.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   54.10 +//
   54.11 +
   54.12 +import UIKit
   54.13 +
   54.14 +enum LoginViewControllerError: Error {
   54.15 +    case missingEmail
   54.16 +    case missingPassword
   54.17 +    case noConnectData
   54.18 +    case missingUsername
   54.19 +    case minimumLengthUsername
   54.20 +    case accountExistence
   54.21 +}
   54.22 +
   54.23 +extension LoginViewControllerError: LocalizedError {
   54.24 +    var errorDescription: String? {
   54.25 +        switch self {
   54.26 +        case .missingEmail:
   54.27 +            return NSLocalizedString("Email needed",
   54.28 +                                     comment: "Automated account setup error description")
   54.29 +        case .missingPassword:
   54.30 +            return NSLocalizedString("Password needed",
   54.31 +                                     comment: "Automated account setup error description")
   54.32 +        case .missingUsername:
   54.33 +            return NSLocalizedString("Username must not be empty.",
   54.34 +                                     comment: "Empty username message")
   54.35 +        case .minimumLengthUsername:
   54.36 +            return NSLocalizedString("Username must have more than 5 characters.",
   54.37 +                                     comment: "minimum username length")
   54.38 +        case .noConnectData:
   54.39 +            return NSLocalizedString("Internal error",
   54.40 +                                     comment: "Automated account setup error description")
   54.41 +        case .accountExistence:
   54.42 +            return NSLocalizedString("Account already exist", comment: "account exist error message")
   54.43 +        }
   54.44 +    }
   54.45 +}
   54.46 +
   54.47 +
   54.48 +protocol LoginViewControllerDelegate: class  {
   54.49 +    func loginViewControllerDidCreateNewAccount(_ loginViewController: LoginViewController)
   54.50 +}
   54.51 +
   54.52 +
   54.53 +class LoginViewController: BaseViewController {
   54.54 +    var loginViewModel = LoginViewModel()
   54.55 +    var offerManualSetup = false
   54.56 +    weak var delegate: LoginViewControllerDelegate?
   54.57 +
   54.58 +    @IBOutlet var emailAddress: UITextField!
   54.59 +    @IBOutlet var password: UITextField!
   54.60 +    @IBOutlet var manualConfigButton: UIButton!
   54.61 +    @IBOutlet var loginButton: UIButton!
   54.62 +    @IBOutlet var user: UITextField!
   54.63 +    @IBOutlet var activityIndicatorView: UIActivityIndicatorView!
   54.64 +
   54.65 +    @IBOutlet var contentScrollView: UIScrollView!
   54.66 +
   54.67 +
   54.68 +    var isCurrentlyVerifying = false {
   54.69 +        didSet {
   54.70 +            updateView()
   54.71 +        }
   54.72 +    }
   54.73 +
   54.74 +    /**
   54.75 +     The last account input as determined by LAS, and delivered via didVerify.
   54.76 +     */
   54.77 +    var lastAccountInput: AccountUserInput?
   54.78 +
   54.79 +    override var prefersStatusBarHidden: Bool {
   54.80 +        return true
   54.81 +    }
   54.82 +
   54.83 +    override func didSetAppConfig() {
   54.84 +        super.didSetAppConfig()
   54.85 +        loginViewModel.messageSyncService = appConfig.messageSyncService
   54.86 +    }
   54.87 +
   54.88 +    override func viewDidLoad() {
   54.89 +        super.viewDidLoad()
   54.90 +        loginViewModel.loginViewModelLoginErrorDelegate = self
   54.91 +        loginViewModel.loginViewModelOAuth2ErrorDelegate = self
   54.92 +        configureView()
   54.93 +        configureKeyboardAwareness()
   54.94 +    }
   54.95 +
   54.96 +    override func viewWillAppear(_ animated: Bool) {
   54.97 +        updateView()
   54.98 +    }
   54.99 +
  54.100 +    func configureView(){
  54.101 +
  54.102 +        password.isEnabled = true
  54.103 +        activityIndicatorView.hidesWhenStopped = true
  54.104 +
  54.105 +        self.emailAddress.convertToLoginField(
  54.106 +            placeholder: NSLocalizedString("Email", comment: "Email"), delegate: self)
  54.107 +        self.password.convertToLoginField(
  54.108 +            placeholder: NSLocalizedString("Password", comment: "password"), delegate: self)
  54.109 +        self.loginButton.convertToLoginButton(
  54.110 +            placeholder: NSLocalizedString("Sign In", comment: "Login"))
  54.111 +        self.manualConfigButton.convertToLoginButton(
  54.112 +            placeholder: NSLocalizedString("Manual configuration", comment: "manual"))
  54.113 +        self.user.convertToLoginField(
  54.114 +            placeholder: NSLocalizedString("Name", comment: "username"), delegate: self)
  54.115 +
  54.116 +        self.navigationController?.navigationBar.isHidden = !loginViewModel.isThereAnAccount()
  54.117 +
  54.118 +        // hide extended login fields
  54.119 +        manualConfigButton.isHidden = true
  54.120 +        let tap: UITapGestureRecognizer = UITapGestureRecognizer(
  54.121 +            target: self, action: #selector(LoginTableViewController.dismissKeyboard))
  54.122 +        view.addGestureRecognizer(tap)
  54.123 +
  54.124 +        self.navigationItem.hidesBackButton = true
  54.125 +        self.navigationItem.leftBarButtonItem = UIBarButtonItem(
  54.126 +            title:NSLocalizedString("Cancel", comment: "Login NavigationBar canel button title"),
  54.127 +            style:.plain, target:self,
  54.128 +            action:#selector(self.backButton))
  54.129 +
  54.130 +        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: self, queue: nil) { (notification) in
  54.131 +            print("hola")
  54.132 +        }
  54.133 +    }
  54.134 +
  54.135 +    @objc func backButton() {
  54.136 +        self.dismiss(animated: true, completion: nil)
  54.137 +    }
  54.138 +
  54.139 +    override func didReceiveMemoryWarning() {
  54.140 +        super.didReceiveMemoryWarning()
  54.141 +    }
  54.142 +
  54.143 +    func updateView() {
  54.144 +        if isCurrentlyVerifying {
  54.145 +            activityIndicatorView.startAnimating()
  54.146 +        } else {
  54.147 +            activityIndicatorView.stopAnimating()
  54.148 +        }
  54.149 +        navigationItem.rightBarButtonItem?.isEnabled = !isCurrentlyVerifying
  54.150 +        loginButton.isEnabled = !isCurrentlyVerifying
  54.151 +        manualConfigButton.isEnabled = !isCurrentlyVerifying
  54.152 +    }
  54.153 +
  54.154 +    private func handleLoginError(error: Error, offerManualSetup: Bool) {
  54.155 +        Log.shared.error(component: #function, error: error)
  54.156 +        self.isCurrentlyVerifying = false
  54.157 +        guard let error = DisplayUserError(withError: error) else {
  54.158 +            // Do nothing. The error type is not suitable to bother the user with.
  54.159 +            return
  54.160 +        }
  54.161 +        let alertView = UIAlertController.pEpAlertController(title: error.title,
  54.162 +                                                             message:error.localizedDescription,
  54.163 +                                                             preferredStyle: .alert)
  54.164 +        alertView.addAction(UIAlertAction(
  54.165 +            title: NSLocalizedString( "View log",
  54.166 +                                      comment: "Button for viewing the log on error"),
  54.167 +            style: .default, handler: { action in
  54.168 +                self.viewLog()
  54.169 +        }))
  54.170 +        alertView.addAction(UIAlertAction(
  54.171 +            title: NSLocalizedString(
  54.172 +                "Ok",
  54.173 +                comment: "UIAlertAction ok after error"),
  54.174 +            style: .default, handler: {action in
  54.175 +                if offerManualSetup {
  54.176 +                    self.manualConfigButton.isHidden = false
  54.177 +                    self.offerManualSetup = true
  54.178 +                }
  54.179 +        }))
  54.180 +        present(alertView, animated: true, completion: nil)
  54.181 +    }
  54.182 +
  54.183 +    @objc func dismissKeyboard() {
  54.184 +        view.endEditing(true)
  54.185 +    }
  54.186 +
  54.187 +    func viewLog() {
  54.188 +        performSegue(withIdentifier: .viewLogSegue, sender: self)
  54.189 +    }
  54.190 +
  54.191 +    // MARK: - IBAction
  54.192 +
  54.193 +    @IBAction func logIn(_ sender: Any) {
  54.194 +        dismissKeyboard()
  54.195 +        isCurrentlyVerifying = true
  54.196 +
  54.197 +        guard let email = emailAddress.text?.trimmedWhiteSpace(), email != "" else {
  54.198 +            handleLoginError(error: LoginTableViewControllerError.missingEmail,
  54.199 +                             offerManualSetup: false)
  54.200 +            return
  54.201 +        }
  54.202 +        guard !loginViewModel.exist(address: email) else {
  54.203 +            isCurrentlyVerifying = false
  54.204 +            handleLoginError(error: LoginTableViewControllerError.accountExistence,
  54.205 +                             offerManualSetup: false)
  54.206 +            return
  54.207 +        }
  54.208 +        guard let username = user.text, username != ""  else {
  54.209 +            handleLoginError(error: LoginTableViewControllerError.missingUsername,
  54.210 +                             offerManualSetup: false)
  54.211 +            return
  54.212 +        }
  54.213 +
  54.214 +        guard username.count >= LoginTableViewController.minCharUserName else {
  54.215 +            handleLoginError(error: LoginTableViewControllerError.minimumLengthUsername,
  54.216 +                             offerManualSetup: false)
  54.217 +            return
  54.218 +        }
  54.219 +
  54.220 +        loginViewModel.accountVerificationResultDelegate = self
  54.221 +
  54.222 +        if loginViewModel.isOAuth2Possible(email: email) {
  54.223 +            let oauth = appConfig.oauth2AuthorizationFactory.createOAuth2Authorizer()
  54.224 +            loginViewModel.loginWithOAuth2(
  54.225 +                viewController: self, emailAddress: email, userName: username,
  54.226 +                mySelfer: appConfig.mySelfer, oauth2Authorizer: oauth)
  54.227 +        } else {
  54.228 +            guard let pass = password.text, pass != "" else {
  54.229 +                handleLoginError(error: LoginTableViewControllerError.missingPassword,
  54.230 +                                 offerManualSetup: false)
  54.231 +                return
  54.232 +            }
  54.233 +
  54.234 +            loginViewModel.login(
  54.235 +                accountName: email, userName: username, password: pass,
  54.236 +                mySelfer: appConfig.mySelfer)
  54.237 +        }
  54.238 +    }
  54.239 +
  54.240 +    @IBAction func emailChanged(_ sender: UITextField) {
  54.241 +        updatePasswordField(email: sender.text)
  54.242 +    }
  54.243 +
  54.244 +    // MARK: - Util
  54.245 +
  54.246 +    func updatePasswordField(email: String?) {
  54.247 +        let oauth2Possible = loginViewModel.isOAuth2Possible(email: email)
  54.248 +        password.isEnabled = !oauth2Possible
  54.249 +        if password.isEnabled {
  54.250 +            password.enableLoginField()
  54.251 +        } else {
  54.252 +            password.disableLoginField()
  54.253 +        }
  54.254 +    }
  54.255 +}
  54.256 +
  54.257 +// MARK: - UITextFieldDelegate
  54.258 +
  54.259 +extension LoginViewController: UITextFieldDelegate {
  54.260 +    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  54.261 +        if textField == self.user {
  54.262 +            self.emailAddress.becomeFirstResponder()
  54.263 +        } else if textField == self.emailAddress {
  54.264 +            self.password.becomeFirstResponder()
  54.265 +        } else if textField == self.password {
  54.266 +            textField.resignFirstResponder()
  54.267 +            self.logIn(self.password)
  54.268 +        }
  54.269 +        return true
  54.270 +    }
  54.271 +}
  54.272 +
  54.273 +// MARK: - SegueHandlerType
  54.274 +
  54.275 +extension LoginViewController: SegueHandlerType {
  54.276 +    public enum SegueIdentifier: String {
  54.277 +        case noSegue
  54.278 +        case viewLogSegue
  54.279 +        case manualConfigSegue
  54.280 +    }
  54.281 +
  54.282 +    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  54.283 +        switch segueIdentifier(for: segue) {
  54.284 +        case .manualConfigSegue:
  54.285 +            if
  54.286 +                let navVC = segue.destination as? UINavigationController,
  54.287 +                let vc = navVC.topViewController as? UserInfoTableViewController {
  54.288 +                vc.appConfig = appConfig
  54.289 +
  54.290 +                if let accountInput = lastAccountInput {
  54.291 +                    vc.model = accountInput // give the user some prefilled data in manual mode
  54.292 +                }
  54.293 +
  54.294 +                // Overwrite with more recent data that we might have (in case it was changed)
  54.295 +                vc.model.address = emailAddress.text
  54.296 +                vc.model.password = password.text
  54.297 +                vc.model.userName = user.text
  54.298 +            }
  54.299 +        case .viewLogSegue:
  54.300 +            if let navVC = segue.destination as? UINavigationController,
  54.301 +                let vc = navVC.topViewController as? LogViewController {
  54.302 +                vc.appConfig = appConfig
  54.303 +                vc.navigationController?.navigationBar.isHidden = false
  54.304 +                vc.configureDismissButton(with: .done)
  54.305 +            }
  54.306 +        default:
  54.307 +            break
  54.308 +        }
  54.309 +    }
  54.310 +}
  54.311 +
  54.312 +// MARK: - AccountVerificationResultDelegate
  54.313 +
  54.314 +extension LoginViewController: AccountVerificationResultDelegate {
  54.315 +    func didVerify(result: AccountVerificationResult, accountInput: AccountUserInput?) {
  54.316 +        GCD.onMain() { [weak self] in
  54.317 +            guard let me = self else {
  54.318 +                Log.shared.errorAndCrash(component: #function, errorString: "Lost myself")
  54.319 +                return
  54.320 +            }
  54.321 +            me.lastAccountInput = nil
  54.322 +            switch result {
  54.323 +            case .ok:
  54.324 +                me.delegate?.loginViewControllerDidCreateNewAccount(me)
  54.325 +                me.navigationController?.dismiss(animated: true)
  54.326 +            case .imapError(let err):
  54.327 +                me.lastAccountInput = accountInput
  54.328 +                me.handleLoginError(error: err, offerManualSetup: true)
  54.329 +            case .smtpError(let err):
  54.330 +                me.lastAccountInput = accountInput
  54.331 +                me.handleLoginError(error: err, offerManualSetup: true)
  54.332 +            case .noImapConnectData, .noSmtpConnectData:
  54.333 +                me.lastAccountInput = accountInput
  54.334 +                me.handleLoginError(error: LoginTableViewControllerError.noConnectData,
  54.335 +                                    offerManualSetup: true)
  54.336 +            }
  54.337 +        }
  54.338 +    }
  54.339 +}
  54.340 +
  54.341 +// MARK: - LoginViewModelLoginErrorDelegate
  54.342 +
  54.343 +extension LoginViewController: LoginViewModelLoginErrorDelegate {
  54.344 +    func handle(loginError: Error) {
  54.345 +        self.handleLoginError(error: loginError, offerManualSetup: true)
  54.346 +    }
  54.347 +}
  54.348 +
  54.349 +// MARK: - LoginViewModelOAuth2ErrorDelegate
  54.350 +
  54.351 +extension LoginViewController: LoginViewModelOAuth2ErrorDelegate {
  54.352 +    func handle(oauth2Error: Error) {
  54.353 +        self.handleLoginError(error: oauth2Error, offerManualSetup: false)
  54.354 +    }
  54.355 +}
    55.1 --- a/pEpForiOS/UI/Login/ViewModel/LoginViewModel.swift	Fri Jul 20 14:07:19 2018 +0200
    55.2 +++ b/pEpForiOS/UI/Login/ViewModel/LoginViewModel.swift	Thu Jul 26 13:41:45 2018 +0200
    55.3 @@ -167,16 +167,11 @@
    55.4              Log.shared.errorAndCrash(component: #function, errorString: "no MessageSyncService")
    55.5              return
    55.6          }
    55.7 -
    55.8          guard let account = loginAccount else {
    55.9              Log.shared.errorAndCrash(component: #function, errorString: "have lost loginAccount")
   55.10              return
   55.11          }
   55.12 -
   55.13          account.imapServer?.trusted = trusted
   55.14 -
   55.15 -        account.needsVerification = true
   55.16 -        account.save()
   55.17          ms.requestVerification(account: account, delegate: self)
   55.18      }
   55.19  
   55.20 @@ -193,16 +188,15 @@
   55.21  // MARK: - AccountVerificationServiceDelegate
   55.22  
   55.23  extension LoginViewModel: AccountVerificationServiceDelegate {
   55.24 -    func verified(account: Account, service: AccountVerificationServiceProtocol,
   55.25 +    func verified(account: Account,
   55.26 +                  service: AccountVerificationServiceProtocol,
   55.27                    result: AccountVerificationResult) {
   55.28          if result == .ok {
   55.29 +            MessageModel.performAndWait {
   55.30 +                account.save()
   55.31 +            }
   55.32              mySelfer?.startMySelf()
   55.33 -        } else {
   55.34 -            MessageModel.performAndWait {
   55.35 -                account.delete()
   55.36 -            }
   55.37          }
   55.38 -
   55.39          accountVerificationResultDelegate?.didVerify(result: result,
   55.40                                                       accountInput: accountInVerification)
   55.41      }
   55.42 @@ -234,6 +228,8 @@
   55.43      }
   55.44  }
   55.45  
   55.46 +// MARK: - QualifyServerIsLocalServiceDelegate
   55.47 +
   55.48  extension LoginViewModel: QualifyServerIsLocalServiceDelegate {
   55.49      func didQualify(serverName: String, isLocal: Bool?, error: Error?) {
   55.50          GCD.onMain { [weak self] in
    56.1 --- a/pEpForiOS/UI/ManualLogin/ImapSetup/IMAPSettingsTableViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    56.2 +++ b/pEpForiOS/UI/ManualLogin/ImapSetup/IMAPSettingsTableViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    56.3 @@ -28,7 +28,7 @@
    56.4  
    56.5      let viewWidthAligner = ViewWidthsAligner()
    56.6  
    56.7 -    var model: AccountUserInput! //FIXME: remove !
    56.8 +    var model: AccountUserInput!
    56.9      var fields = [UITextField]()
   56.10      var responder = 0
   56.11  
    57.1 --- a/pEpForiOS/UI/ManualLogin/InfoUserSettup/UserInfoTableViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    57.2 +++ b/pEpForiOS/UI/ManualLogin/InfoUserSettup/UserInfoTableViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    57.3 @@ -34,7 +34,7 @@
    57.4  
    57.5      public override func viewDidLoad() {
    57.6          super.viewDidLoad()
    57.7 -        
    57.8 +
    57.9          self.title = NSLocalizedString("Account", comment: "Title for manual account setup")
   57.10          handleCancelButtonVisibility()
   57.11          passwordValue.delegate = self
   57.12 @@ -44,7 +44,7 @@
   57.13  
   57.14      public override func viewDidLayoutSubviews() {
   57.15          super.viewDidLayoutSubviews()
   57.16 -        
   57.17 +
   57.18          viewWidthAligner.alignViews([
   57.19              emailTitle,
   57.20              usernameTitle,
   57.21 @@ -52,7 +52,7 @@
   57.22              nameTitle
   57.23              ], parentView: view)
   57.24      }
   57.25 -    
   57.26 +
   57.27      func handleCancelButtonVisibility() {
   57.28          accounts = Account.all()
   57.29          if accounts.isEmpty {
   57.30 @@ -66,7 +66,7 @@
   57.31          updateViewFromInitialModel()
   57.32          updateView()
   57.33      }
   57.34 -    
   57.35 +
   57.36      public override func viewDidAppear(_ animated: Bool) {
   57.37          super.viewDidAppear(animated)
   57.38          firstResponder(!model.isValidName)
   57.39 @@ -93,7 +93,7 @@
   57.40          }
   57.41          return true
   57.42      }
   57.43 -    
   57.44 +
   57.45      public func textFieldDidEndEditing(_ textField: UITextField) {
   57.46          changedResponder(textField)
   57.47      }
   57.48 @@ -117,7 +117,7 @@
   57.49          model.userName = sender.text
   57.50          updateView()
   57.51      }
   57.52 -    
   57.53 +
   57.54      @IBAction func cancelButtonTapped(_ sender: UIButton) {
   57.55          navigationController?.dismiss(animated: true, completion: nil)
   57.56      }
   57.57 @@ -130,7 +130,7 @@
   57.58          case IMAPSettings
   57.59          case noSegue
   57.60      }
   57.61 -    
   57.62 +
   57.63      public override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
   57.64          switch segueIdentifier(for: segue) {
   57.65          case .IMAPSettings:
    58.1 --- a/pEpForiOS/UI/ManualLogin/SMTPSetup/SMTPSettingsTableViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    58.2 +++ b/pEpForiOS/UI/ManualLogin/SMTPSetup/SMTPSettingsTableViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    58.3 @@ -10,10 +10,7 @@
    58.4  
    58.5  import MessageModel
    58.6  
    58.7 -class SMTPSettingsTableViewController: BaseTableViewController, TextfieldResponder,
    58.8 -UITextFieldDelegate {
    58.9 -    let comp = "SMTPSettingsTableView"
   58.10 -
   58.11 +class SMTPSettingsTableViewController: BaseTableViewController, TextfieldResponder {
   58.12      @IBOutlet var activityIndicatorView: UIActivityIndicatorView!
   58.13      @IBOutlet weak var serverValue: UITextField!
   58.14      @IBOutlet weak var portValue: UITextField!
   58.15 @@ -23,6 +20,7 @@
   58.16      @IBOutlet weak var portTitle: UILabel!
   58.17  
   58.18      var model: AccountUserInput!
   58.19 +    private var currentlyVerifiedAccount: Account?
   58.20      var fields = [UITextField]()
   58.21      var responder = 0
   58.22  
   58.23 @@ -33,23 +31,15 @@
   58.24          }
   58.25      }
   58.26  
   58.27 +    // MARK: - Life Cylcle
   58.28 +
   58.29      public override func viewDidLoad() {
   58.30          super.viewDidLoad()
   58.31 -
   58.32          self.title = NSLocalizedString("SMTP", comment: "Manual account setup")
   58.33          UIHelper.variableCellHeightsTableView(tableView)
   58.34          fields = [serverValue, portValue]
   58.35      }
   58.36  
   58.37 -    public override func viewDidLayoutSubviews() {
   58.38 -        super.viewDidLayoutSubviews()
   58.39 -
   58.40 -        viewWidthAligner.alignViews([
   58.41 -            serverTitle,
   58.42 -            portTitle
   58.43 -            ], parentView: view)
   58.44 -    }
   58.45 -
   58.46      public override func viewWillAppear(_ animated: Bool) {
   58.47          super.viewWillAppear(animated)
   58.48          updateView()
   58.49 @@ -57,14 +47,16 @@
   58.50  
   58.51      public override func viewDidAppear(_ animated: Bool) {
   58.52          super.viewDidAppear(animated)
   58.53 -
   58.54          firstResponder(model.serverSMTP == nil)
   58.55      }
   58.56  
   58.57 -    public override func didReceiveMemoryWarning() {
   58.58 -        super.didReceiveMemoryWarning()
   58.59 +    public override func viewDidLayoutSubviews() {
   58.60 +        super.viewDidLayoutSubviews()
   58.61 +        viewWidthAligner.alignViews([serverTitle, portTitle], parentView: view)
   58.62      }
   58.63  
   58.64 +    // MARK: - Working Bees
   58.65 +
   58.66      private func updateView() {
   58.67          serverValue.text = model.serverSMTP
   58.68          portValue.text = String(model.portSMTP)
   58.69 @@ -81,7 +73,8 @@
   58.70      private func showErrorMessage (_ message: String) {
   58.71          let alertView = UIAlertController.pEpAlertController(
   58.72              title: NSLocalizedString("Error",
   58.73 -                                     comment: "the text in the title for the error message AlerView in account settings"),
   58.74 +                                     comment:
   58.75 +                "the text in the title for the error message AlerView in account settings"),
   58.76              message:message, preferredStyle: .alert)
   58.77          alertView.addAction(UIAlertAction(
   58.78              title: NSLocalizedString(
   58.79 @@ -93,7 +86,8 @@
   58.80          alertView.addAction(UIAlertAction(
   58.81              title: NSLocalizedString(
   58.82                  "Ok",
   58.83 -                comment: "confirmation button text for error message AlertView in account settings"),
   58.84 +                comment:
   58.85 +                "confirmation button text for error message AlertView in account settings"),
   58.86              style: .default, handler: nil))
   58.87          present(alertView, animated: true, completion: nil)
   58.88      }
   58.89 @@ -102,6 +96,35 @@
   58.90          performSegue(withIdentifier: .viewLogSegue, sender: self)
   58.91      }
   58.92  
   58.93 +    /// Triggers verification for given data.
   58.94 +    ///
   58.95 +    /// - Throws: AccountVerificationError
   58.96 +    private func verifyAccount() throws {
   58.97 +        isCurrentlyVerifying =  true
   58.98 +        let account = try model.account()
   58.99 +        currentlyVerifiedAccount = account
  58.100 +        appConfig.messageSyncService.requestVerification(account: account, delegate: self)
  58.101 +    }
  58.102 +
  58.103 +    private func informUser(about error: Error, title: String) {
  58.104 +        let alert = UIAlertController.pEpAlertController(
  58.105 +            title: title,
  58.106 +            message: error.localizedDescription,
  58.107 +            preferredStyle: UIAlertControllerStyle.alert)
  58.108 +        let cancelAction = UIAlertAction(title:
  58.109 +            NSLocalizedString("OK", comment: "OK button for invalid accout settings user input alert"),
  58.110 +                                         style: .cancel, handler: nil)
  58.111 +        alert.addAction(cancelAction)
  58.112 +        present(alert, animated: true)
  58.113 +    }
  58.114 +
  58.115 +    private func hideKeybord() {
  58.116 +        serverValue.resignFirstResponder()
  58.117 +        portValue.resignFirstResponder()
  58.118 +    }
  58.119 +
  58.120 +    // MARK: - Actions
  58.121 +
  58.122      @IBAction func alertWithSecurityValues(_ sender: UIButton) {
  58.123          let alertController = UIAlertController.pEpAlertController(
  58.124              title: NSLocalizedString("Transport protocol",
  58.125 @@ -141,22 +164,6 @@
  58.126          }
  58.127      }
  58.128  
  58.129 -    /// Creates and persits an account with given data and triggers a verification request.
  58.130 -    ///
  58.131 -    /// - Parameter model: account data
  58.132 -    /// - Throws: AccountVerificationError
  58.133 -    private func verifyAccount() throws {
  58.134 -        isCurrentlyVerifying =  true
  58.135 -        do {
  58.136 -            let account = try model.account()
  58.137 -            account.needsVerification = true
  58.138 -            account.save()
  58.139 -            appConfig.messageSyncService.requestVerification(account: account, delegate: self)
  58.140 -        } catch {
  58.141 -            throw error
  58.142 -        }
  58.143 -    }
  58.144 -
  58.145      @IBAction func nextButtonTapped(_ sender: UIBarButtonItem) {
  58.146          do {
  58.147              try verifyAccount()
  58.148 @@ -168,61 +175,33 @@
  58.149              informUser(about: error, title: errorTopic)
  58.150          }
  58.151      }
  58.152 +}
  58.153  
  58.154 -    private func informUser(about error: Error, title: String) {
  58.155 -        let alert = UIAlertController.pEpAlertController(
  58.156 -            title: title,
  58.157 -            message: error.localizedDescription,
  58.158 -            preferredStyle: UIAlertControllerStyle.alert)
  58.159 -        let cancelAction = UIAlertAction(title:
  58.160 -            NSLocalizedString("OK", comment: "OK button for invalid accout settings user input alert"),
  58.161 -                                         style: .cancel, handler: nil)
  58.162 -        alert.addAction(cancelAction)
  58.163 -        present(alert, animated: true)
  58.164 -    }
  58.165 -
  58.166 -    private func hideKeybord() {
  58.167 -        serverValue.resignFirstResponder()
  58.168 -        portValue.resignFirstResponder()
  58.169 -    }
  58.170 -
  58.171 -    public func textFieldShouldReturn(_ textfield: UITextField) -> Bool {
  58.172 -        nextResponder(textfield)
  58.173 -        return true
  58.174 -    }
  58.175 -
  58.176 -    public func textFieldDidEndEditing(_ textField: UITextField) {
  58.177 -        changedResponder(textField)
  58.178 -    }
  58.179 -
  58.180 -    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  58.181 -        switch segueIdentifier(for: segue) {
  58.182 -        case .backToEmailListSegue:
  58.183 -            guard
  58.184 -                let destination = segue.destination as? EmailListViewController
  58.185 -                else {
  58.186 -                    Log.shared.errorAndCrash(component: #function, errorString: "Problem casting DVC")
  58.187 -                    return
  58.188 -            }
  58.189 -            destination.appConfig = self.appConfig
  58.190 -        case .viewLogSegue:
  58.191 -            if let dnc = segue.destination as? UINavigationController,
  58.192 -                let dvc = dnc.rootViewController as? LogViewController {
  58.193 -                dvc.appConfig = appConfig
  58.194 -            }
  58.195 -        default:()
  58.196 -        }
  58.197 -    }
  58.198 -}
  58.199 +// MARK: - AccountVerificationServiceDelegate
  58.200  
  58.201  extension SMTPSettingsTableViewController: AccountVerificationServiceDelegate {
  58.202      func verified(account: Account, service: AccountVerificationServiceProtocol,
  58.203                    result: AccountVerificationResult) {
  58.204 +        if result == .ok {
  58.205 +            MessageModel.performAndWait { [weak self] in
  58.206 +                guard let me = self else {
  58.207 +                    Log.shared.errorAndCrash(component: #function, errorString: "Lost myself")
  58.208 +                    return
  58.209 +                }
  58.210 +                guard let account = me.currentlyVerifiedAccount else {
  58.211 +                    Log.shared.errorAndCrash(component: #function,
  58.212 +                                             errorString: "We verified an non-existing account? " +
  58.213 +                        "Now what?")
  58.214 +                    return
  58.215 +                }
  58.216 +                account.save()
  58.217 +            }
  58.218 +        }
  58.219          GCD.onMain() {
  58.220              self.isCurrentlyVerifying =  false
  58.221              switch result {
  58.222              case .ok:
  58.223 -                // unwind back to INBOX on success
  58.224 +                // unwind back to INBOX or folder list on success
  58.225                  self.performSegue(withIdentifier: .backToEmailListSegue, sender: self)
  58.226              case .imapError(let err):
  58.227                  self.showErrorMessage(err.localizedDescription)
  58.228 @@ -236,10 +215,40 @@
  58.229      }
  58.230  }
  58.231  
  58.232 +// MARK: - SegueHandlerType
  58.233 +
  58.234  extension SMTPSettingsTableViewController: SegueHandlerType {
  58.235      public enum SegueIdentifier: String {
  58.236          case noSegue
  58.237          case viewLogSegue
  58.238          case backToEmailListSegue
  58.239      }
  58.240 +
  58.241 +    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  58.242 +        switch segueIdentifier(for: segue) {
  58.243 +        case .backToEmailListSegue:
  58.244 +            // nothing to do, since it's an unwind segue the targets already are configured
  58.245 +            break
  58.246 +        case .viewLogSegue:
  58.247 +            if let dnc = segue.destination as? UINavigationController,
  58.248 +                let dvc = dnc.rootViewController as? LogViewController {
  58.249 +                dvc.appConfig = appConfig
  58.250 +            }
  58.251 +        default:()
  58.252 +        }
  58.253 +    }
  58.254  }
  58.255 +
  58.256 +// MARK: - UITextFieldDelegate
  58.257 +
  58.258 +extension SMTPSettingsTableViewController: UITextFieldDelegate {
  58.259 +
  58.260 +    public func textFieldShouldReturn(_ textfield: UITextField) -> Bool {
  58.261 +        nextResponder(textfield)
  58.262 +        return true
  58.263 +    }
  58.264 +
  58.265 +    public func textFieldDidEndEditing(_ textField: UITextField) {
  58.266 +        changedResponder(textField)
  58.267 +    }
  58.268 +}
    59.1 --- a/pEpForiOS/UI/MessageThreading/ThreadedFolder.swift	Fri Jul 20 14:07:19 2018 +0200
    59.2 +++ b/pEpForiOS/UI/MessageThreading/ThreadedFolder.swift	Thu Jul 26 13:41:45 2018 +0200
    59.3 @@ -31,11 +31,13 @@
    59.4  
    59.5          MessageModel.performAndWait {
    59.6              for msg in originalMessages {
    59.7 -                let threadMessageIds = msg.threadMessageIdSet()
    59.8 -                if messageIdSet.intersection(threadMessageIds).isEmpty {
    59.9 -                    topMessages.append(msg)
   59.10 +                if !messageIdSet.contains(msg.uuid) {
   59.11 +                    let threadMessageIds = msg.threadMessageIdSet()
   59.12 +                    if messageIdSet.intersection(threadMessageIds).isEmpty {
   59.13 +                        topMessages.append(msg)
   59.14 +                    }
   59.15 +                    messageIdSet.formUnion(threadMessageIds)
   59.16                  }
   59.17 -                messageIdSet.formUnion(threadMessageIds)
   59.18              }
   59.19          }
   59.20  
    60.1 --- a/pEpForiOS/UI/MoveToFolder/MoveToAccountViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    60.2 +++ b/pEpForiOS/UI/MoveToFolder/MoveToAccountViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    60.3 @@ -92,8 +92,8 @@
    60.4          if segue.identifier == "showAccount" {
    60.5              if let vc = segue.destination as? MoveToFolderTableViewController, let appCfg = self.appConfig, let vm = selectedViewModel {
    60.6                  vc.appConfig = appCfg
    60.7 +                vm.delegate = self.delegate
    60.8                  vc.viewModel = vm
    60.9 -                vc.delegate = self.delegate
   60.10              }
   60.11          }
   60.12      }
    61.1 --- a/pEpForiOS/UI/MoveToFolder/MoveToFolderTableViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    61.2 +++ b/pEpForiOS/UI/MoveToFolder/MoveToFolderTableViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    61.3 @@ -13,10 +13,10 @@
    61.4      var viewModel : moveToFolderViewModel?
    61.5      let storyboardId = "MoveToFolderViewController"
    61.6      private let cellId = "FolderCell"
    61.7 -    weak var delegate : MoveToFolderDelegate?
    61.8  
    61.9      override func viewWillAppear(_ animated: Bool) {
   61.10          super.viewWillAppear(animated)
   61.11 +
   61.12      }
   61.13  
   61.14      // MARK: - Table view data source
   61.15 @@ -33,11 +33,12 @@
   61.16          let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
   61.17          if let vm = viewModel?[indexPath.row] {
   61.18              cell.textLabel?.text = vm.title
   61.19 -            cell.accessoryType = .disclosureIndicator
   61.20              if !vm.isSelectable {
   61.21                  cell.isUserInteractionEnabled = false
   61.22                  cell.selectionStyle = .none
   61.23                  cell.textLabel?.isEnabled = false
   61.24 +            } else {
   61.25 +                cell.accessoryType = .disclosureIndicator
   61.26              }
   61.27          }
   61.28          return cell
   61.29 @@ -52,9 +53,7 @@
   61.30  
   61.31      override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
   61.32          if let vm = viewModel {
   61.33 -            if vm.moveMessagesTo(index: indexPath.row) {
   61.34 -                delegate?.didMove()
   61.35 -            }
   61.36 +            vm.moveMessagesTo(index: indexPath.row)
   61.37              dismiss(animated: true)
   61.38          }
   61.39      }
    62.1 --- a/pEpForiOS/UI/MoveToFolder/ViewMdeol/MoveToFolderDelegate.swift	Fri Jul 20 14:07:19 2018 +0200
    62.2 +++ b/pEpForiOS/UI/MoveToFolder/ViewMdeol/MoveToFolderDelegate.swift	Thu Jul 26 13:41:45 2018 +0200
    62.3 @@ -12,4 +12,6 @@
    62.4  protocol MoveToFolderDelegate: class {
    62.5      func didMove()
    62.6  
    62.7 +    func didmove(messages: [Message])
    62.8 +
    62.9  }
    63.1 --- a/pEpForiOS/UI/MoveToFolder/ViewMdeol/MoveToFolderViewModel.swift	Fri Jul 20 14:07:19 2018 +0200
    63.2 +++ b/pEpForiOS/UI/MoveToFolder/ViewMdeol/MoveToFolderViewModel.swift	Thu Jul 26 13:41:45 2018 +0200
    63.3 @@ -61,6 +61,8 @@
    63.4      var items : [moveToFolderCellViewModel]
    63.5      var acc : Account
    63.6      var messages: [Message]
    63.7 +    var delegate : MoveToFolderDelegate?
    63.8 +
    63.9      init(account: Account, messages: [Message]) {
   63.10          items = []
   63.11          self.acc = account
   63.12 @@ -91,6 +93,9 @@
   63.13                  result = true
   63.14              }
   63.15          }
   63.16 +        if result {
   63.17 +            delegate?.didmove(messages: messages)
   63.18 +        }
   63.19          return result
   63.20      }
   63.21  
    64.1 --- a/pEpForiOS/UI/Settings/OptionsViewController/LogViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    64.2 +++ b/pEpForiOS/UI/Settings/OptionsViewController/LogViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    64.3 @@ -15,6 +15,9 @@
    64.4      @IBOutlet weak var switchLabel: UILabel!
    64.5      @IBOutlet weak var enableLogSwitch: UISwitch!
    64.6  
    64.7 +    override func viewDidAppear(_ animated: Bool) {
    64.8 +        print("MAO")
    64.9 +    }
   64.10  
   64.11      override func viewWillAppear(_ animated: Bool) {
   64.12          super.viewWillAppear(animated)
   64.13 @@ -53,3 +56,9 @@
   64.14          }
   64.15      }
   64.16  }
   64.17 +
   64.18 +extension LogViewController: Dismissable, SelfDismissable {
   64.19 +    func requestDismiss() {
   64.20 +        self.dismiss(animated: true, completion: nil)
   64.21 +    }
   64.22 +}
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/pEpForiOS/UI/SplitView/PrimarySplitViewcontroller+ScreenComposerProtocol.swift	Thu Jul 26 13:41:45 2018 +0200
    65.3 @@ -0,0 +1,83 @@
    65.4 +//
    65.5 +//  PrimarySplitViewcontroller+ScreenComposerProtocol.swift
    65.6 +//  pEp
    65.7 +//
    65.8 +//  Created by Borja González de Pablo on 20/07/2018.
    65.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   65.10 +//
   65.11 +
   65.12 +import Foundation
   65.13 +import MessageModel
   65.14 +
   65.15 +extension PrimarySplitViewController: ScreenComposerProtocol{
   65.16 +    func emailListViewModel(_ emailListViewModel: EmailListViewModel,
   65.17 +                            requestsShowThreadViewFor message: Message) {
   65.18 +        let storyboard = UIStoryboard(name: "Thread", bundle: nil)
   65.19 +
   65.20 +        guard let singleViewController = getDetailViewController() as? EmailViewController,
   65.21 +            let nav = singleViewController.navigationController,
   65.22 +            let folder = singleViewController.folderShow,
   65.23 +            let vc: ThreadViewController =
   65.24 +            storyboard.instantiateViewController(withIdentifier: "threadViewController")
   65.25 +                as? ThreadViewController
   65.26 +            else {
   65.27 +                Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
   65.28 +                return
   65.29 +        }
   65.30 +        vc.appConfig = singleViewController.appConfig
   65.31 +        let viewModel = ThreadedEmailViewModel(tip:message, folder: folder)
   65.32 +        viewModel.emailDisplayDelegate = emailListViewModel
   65.33 +        vc.model = viewModel
   65.34 +        nav.viewControllers[nav.viewControllers.count - 1] = vc
   65.35 +        emailListViewModel.currentDisplayedMessage = viewModel
   65.36 +        emailListViewModel.updateThreadListDelegate = viewModel
   65.37 +    }
   65.38 +
   65.39 +    func emailListViewModel(_ emailListViewModel: EmailListViewModel,
   65.40 +                            requestsShowEmailViewFor message: Message) {
   65.41 +
   65.42 +        let storyboard = UIStoryboard(name: "Main", bundle: nil)
   65.43 +
   65.44 +        guard let threadViewController = getDetailViewController() as? EmailViewController,
   65.45 +            let nav = threadViewController.navigationController,
   65.46 +            let vc: EmailViewController =
   65.47 +            storyboard.instantiateViewController(withIdentifier: "emailDetail")
   65.48 +                as? EmailViewController
   65.49 +            else {
   65.50 +                Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
   65.51 +                return
   65.52 +        }
   65.53 +
   65.54 +        vc.appConfig = threadViewController.appConfig
   65.55 +        nav.viewControllers[nav.viewControllers.count - 1 ] = vc
   65.56 +        emailListViewModel.currentDisplayedMessage = vc
   65.57 +
   65.58 +    }
   65.59 +
   65.60 +    private func getDetailViewController() -> UIViewController? {
   65.61 +        let viewControllers = self.viewControllers
   65.62 +        let last = viewControllers.last
   65.63 +
   65.64 +        if isCollapsed {
   65.65 +            guard let nav = last as? UINavigationController,
   65.66 +                let emailNav = nav.topViewController as? UINavigationController,
   65.67 +                let singleViewController = emailNav.rootViewController as? EmailViewController
   65.68 +                else {
   65.69 +                    Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
   65.70 +                    return nil
   65.71 +            }
   65.72 +            return singleViewController
   65.73 +
   65.74 +        } else {
   65.75 +            guard let nav = last as? UINavigationController,
   65.76 +                let singleViewController = nav.rootViewController as? EmailViewController
   65.77 +                else {
   65.78 +                    Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
   65.79 +                    return nil
   65.80 +            }
   65.81 +            return singleViewController
   65.82 +        }
   65.83 +    }
   65.84 +
   65.85 +
   65.86 +}
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/pEpForiOS/UI/SplitView/ScreenComposerProtocol.swift	Thu Jul 26 13:41:45 2018 +0200
    66.3 @@ -0,0 +1,18 @@
    66.4 +//
    66.5 +//  ScreenComposerProtocol.swift
    66.6 +//  pEp
    66.7 +//
    66.8 +//  Created by Borja González de Pablo on 20/07/2018.
    66.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   66.10 +//
   66.11 +
   66.12 +import Foundation
   66.13 +import MessageModel
   66.14 +
   66.15 +protocol ScreenComposerProtocol {
   66.16 +    func emailListViewModel(_ emailListViewModel: EmailListViewModel,
   66.17 +                            requestsShowThreadViewFor message: Message)
   66.18 +    
   66.19 +    func emailListViewModel(_ emailListViewModel: EmailListViewModel,
   66.20 +                            requestsShowEmailViewFor message: Message)
   66.21 +}
    67.1 --- a/pEpForiOS/UI/Thread/Cells/FullMessageCell.swift	Fri Jul 20 14:07:19 2018 +0200
    67.2 +++ b/pEpForiOS/UI/Thread/Cells/FullMessageCell.swift	Thu Jul 26 13:41:45 2018 +0200
    67.3 @@ -44,7 +44,6 @@
    67.4          }
    67.5      }
    67.6  
    67.7 -
    67.8      @IBOutlet weak var view: UIView!
    67.9      func configure(for viewModel:MessageViewModel) {
   67.10          isFlagged = viewModel.isFlagged
   67.11 @@ -88,7 +87,9 @@
   67.12  
   67.13      override func awakeFromNib() {
   67.14          super.awakeFromNib()
   67.15 -        // Initialization code
   67.16 +        self.profilePicture.layer.cornerRadius = round(profilePicture.bounds.size.width / 2)
   67.17 +        self.profilePicture.layer.masksToBounds = true
   67.18 +        
   67.19      }
   67.20  
   67.21      override func setSelected(_ selected: Bool, animated: Bool) {
    68.1 --- a/pEpForiOS/UI/Thread/ThreadViewController+ViewModelDelegate.swift	Fri Jul 20 14:07:19 2018 +0200
    68.2 +++ b/pEpForiOS/UI/Thread/ThreadViewController+ViewModelDelegate.swift	Thu Jul 26 13:41:45 2018 +0200
    68.3 @@ -13,6 +13,7 @@
    68.4          updateTableView {
    68.5              tableView.insertSections(IndexSet([index]), with: .automatic)
    68.6          }
    68.7 +        numberOfMessages += 1
    68.8      }
    68.9  
   68.10      func emailViewModel(viewModel: ThreadedEmailViewModel, didUpdateDataAt index: Int) {
   68.11 @@ -27,6 +28,7 @@
   68.12          updateTableView {
   68.13              tableView.deleteSections(IndexSet([index]), with: .none)
   68.14          }
   68.15 +        numberOfMessages -= 1
   68.16      }
   68.17  
   68.18      func emailViewModeldidChangeFlag(viewModel: ThreadedEmailViewModel){
    69.1 --- a/pEpForiOS/UI/Thread/ThreadViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    69.2 +++ b/pEpForiOS/UI/Thread/ThreadViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    69.3 @@ -15,6 +15,11 @@
    69.4      @IBOutlet weak var tableView: UITableView!
    69.5      var model: ThreadedEmailViewModel!
    69.6  
    69.7 +    var numberOfMessages = 0 {
    69.8 +        didSet {
    69.9 +            self.navigationItem.title = String(numberOfMessages)  + " messages"
   69.10 +        }
   69.11 +    }
   69.12      override func viewDidLoad() {
   69.13          super.viewDidLoad()
   69.14          configureSplitViewBackButton()
   69.15 @@ -22,7 +27,7 @@
   69.16              return
   69.17          }
   69.18          model.delegate = self
   69.19 -        self.navigationItem.title = String(model.rowCount())  + " messages"
   69.20 +        numberOfMessages = model.rowCount()
   69.21          setUpFlaggedStatus()
   69.22      }
   69.23  
    70.1 --- a/pEpForiOS/UI/Thread/Util/ThreadNavigationDelegate.swift	Fri Jul 20 14:07:19 2018 +0200
    70.2 +++ b/pEpForiOS/UI/Thread/Util/ThreadNavigationDelegate.swift	Thu Jul 26 13:41:45 2018 +0200
    70.3 @@ -19,6 +19,7 @@
    70.4  
    70.5          guard let splitView = navigationController.splitViewController,
    70.6          !splitView.isCollapsed else {
    70.7 +            navigationController.interactivePopGestureRecognizer?.delegate = nil
    70.8              return nil
    70.9          }
   70.10          if toVC is EmailViewController {
    71.1 --- a/pEpForiOS/UI/Thread/ViewModel/ThreadedEmailViewModel+MoveToFolderDelegate.swift	Fri Jul 20 14:07:19 2018 +0200
    71.2 +++ b/pEpForiOS/UI/Thread/ViewModel/ThreadedEmailViewModel+MoveToFolderDelegate.swift	Thu Jul 26 13:41:45 2018 +0200
    71.3 @@ -7,8 +7,13 @@
    71.4  //
    71.5  
    71.6  import Foundation
    71.7 +import MessageModel
    71.8  
    71.9  extension ThreadedEmailViewModel: MoveToFolderDelegate{
   71.10 +    func didmove(messages: [Message]) {
   71.11 +        didMove()
   71.12 +    }
   71.13 +
   71.14      func didMove() {
   71.15          guard let lastMessage = messages.last else {
   71.16              return
    72.1 --- a/pEpForiOS/UI/Util/BaseViewController.swift	Fri Jul 20 14:07:19 2018 +0200
    72.2 +++ b/pEpForiOS/UI/Util/BaseViewController.swift	Thu Jul 26 13:41:45 2018 +0200
    72.3 @@ -10,7 +10,7 @@
    72.4  
    72.5  class BaseViewController: UIViewController, ErrorPropagatorSubscriber {
    72.6      private var _appConfig: AppConfig?
    72.7 -    var appConfig: AppConfig? {
    72.8 +    var appConfig: AppConfig! {
    72.9          get {
   72.10              guard _appConfig != nil else {
   72.11                  Log.shared.errorAndCrash(component: #function, errorString: "No appConfig?")
   72.12 @@ -20,9 +20,14 @@
   72.13          }
   72.14          set {
   72.15              _appConfig = newValue
   72.16 +            didSetAppConfig()
   72.17          }
   72.18      }
   72.19  
   72.20 +    func didSetAppConfig() {
   72.21 +        // Do nothing. Meant to override in subclasses.
   72.22 +    }
   72.23 +
   72.24      override func viewWillAppear(_ animated: Bool) {
   72.25          super.viewWillAppear(animated)
   72.26          appConfig?.errorPropagator.subscriber = self
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/pEpForiOS/UI/Util/CredentialTextField.swift	Thu Jul 26 13:41:45 2018 +0200
    73.3 @@ -0,0 +1,35 @@
    73.4 +//
    73.5 +//  CredentialTextField.swift
    73.6 +//
    73.7 +//
    73.8 +//  Created by Miguel Berrocal Gómez on 09/07/2018.
    73.9 +//
   73.10 +
   73.11 +import UIKit
   73.12 +
   73.13 +@IBDesignable
   73.14 +class CredentialTextField: UITextField {
   73.15 +
   73.16 +    @IBInspectable var borderColor: UIColor? {
   73.17 +        didSet {
   73.18 +            layer.borderColor = borderColor?.cgColor
   73.19 +        }
   73.20 +    }
   73.21 +
   73.22 +    @IBInspectable var borderWidth: CGFloat = 0 {
   73.23 +        didSet {
   73.24 +            layer.borderWidth = borderWidth
   73.25 +        }
   73.26 +    }
   73.27 +
   73.28 +    @IBInspectable var placeholderColor: UIColor {
   73.29 +        get {
   73.30 +            return attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .clear
   73.31 +        }
   73.32 +        set {
   73.33 +            guard let attributedPlaceholder = attributedPlaceholder else { return }
   73.34 +            let attributes: [NSAttributedStringKey: UIColor] = [.foregroundColor: newValue]
   73.35 +            self.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string, attributes: attributes)
   73.36 +        }
   73.37 +    }
   73.38 +}
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/pEpForiOS/UI/Util/SelfDismissable.swift	Thu Jul 26 13:41:45 2018 +0200
    74.3 @@ -0,0 +1,35 @@
    74.4 +//
    74.5 +//  SelfDismissable.swift
    74.6 +//  pEp
    74.7 +//
    74.8 +//  Created by Miguel Berrocal Gómez on 19/07/2018.
    74.9 +//  Copyright © 2018 p≡p Security S.A. All rights reserved.
   74.10 +//
   74.11 +
   74.12 +import Foundation
   74.13 +
   74.14 +protocol SelfDismissable {
   74.15 +    func configureDismissButton(with item:UIBarButtonSystemItem)
   74.16 +}
   74.17 +
   74.18 +@objc protocol Dismissable {
   74.19 +    func requestDismiss()
   74.20 +}
   74.21 +
   74.22 +extension SelfDismissable where Self: UIViewController & Dismissable {
   74.23 +
   74.24 +    func configureDismissButton(with item:UIBarButtonSystemItem) {
   74.25 +
   74.26 +        let barButtonItem = UIBarButtonItem(barButtonSystemItem: item, target: self, action: #selector(requestDismiss))
   74.27 +
   74.28 +
   74.29 +        var items:[UIBarButtonItem] = [barButtonItem]
   74.30 +
   74.31 +        if let leftItems = navigationItem.leftBarButtonItems {
   74.32 +            items.append(contentsOf: leftItems)
   74.33 +        }
   74.34 +
   74.35 +        navigationItem.leftBarButtonItems = items
   74.36 +
   74.37 +    }
   74.38 +}
    75.1 --- a/pEpForiOS/UI/Util/UIButton+Extension.swift	Fri Jul 20 14:07:19 2018 +0200
    75.2 +++ b/pEpForiOS/UI/Util/UIButton+Extension.swift	Thu Jul 26 13:41:45 2018 +0200
    75.3 @@ -28,8 +28,6 @@
    75.4      func convertToLoginButton(placeholder: String) {
    75.5          self.backgroundColor = UIColor.clear
    75.6          self.tintColor = UIColor.pEpGreen
    75.7 -        self.layer.borderColor = UIColor.pEpGreen.cgColor
    75.8 -        self.layer.borderWidth = 1.0
    75.9          self.setTitle(placeholder, for: .normal)
   75.10      }
   75.11  
    76.1 --- a/pEpForiOS/UI/Util/UITextField+Extension.swift	Fri Jul 20 14:07:19 2018 +0200
    76.2 +++ b/pEpForiOS/UI/Util/UITextField+Extension.swift	Thu Jul 26 13:41:45 2018 +0200
    76.3 @@ -12,9 +12,6 @@
    76.4      func convertToLoginField(placeholder: String, delegate: UITextFieldDelegate) {
    76.5          // common properties
    76.6          self.delegate = delegate
    76.7 -        self.backgroundColor = UIColor.clear
    76.8 -        self.tintColor = UIColor.pEpGreen
    76.9 -        self.layer.borderWidth = 1.0
   76.10          self.placeholder = placeholder
   76.11  
   76.12          // properties divided between enabled/disabled
   76.13 @@ -34,9 +31,9 @@
   76.14      }
   76.15  
   76.16      func enableOrDisableLoginField(enable: Bool) {
   76.17 -        let theColor = enable ? UIColor.pEpGreen : UIColor.gray
   76.18 +        let theColor = enable ? UIColor.white : UIColor.gray
   76.19          self.textColor = theColor
   76.20 -        self.layer.borderColor = theColor.cgColor
   76.21 +//        self.layer.borderColor = theColor.cgColor
   76.22          if let ph = placeholder {
   76.23              self.attributedPlaceholder = NSAttributedString(
   76.24                  string: ph, attributes: [NSAttributedStringKey.foregroundColor: theColor])
    77.1 --- a/pEpForiOS/Util/ConnectionManager.swift	Fri Jul 20 14:07:19 2018 +0200
    77.2 +++ b/pEpForiOS/Util/ConnectionManager.swift	Thu Jul 26 13:41:45 2018 +0200
    77.3 @@ -6,13 +6,12 @@
    77.4  //  Copyright © 2016 p≡p Security S.A. All rights reserved.
    77.5  //
    77.6  
    77.7 -public protocol ImapConnectionManagerProtocol {
    77.8 +protocol ImapConnectionManagerProtocol {
    77.9      func imapConnection(connectInfo: EmailConnectInfo) -> ImapSync?
   77.10  }
   77.11  
   77.12 -public protocol SmtpConnectionManagerProtocol {
   77.13 +protocol SmtpConnectionManagerProtocol {
   77.14      func smtpConnection(connectInfo: EmailConnectInfo) -> SmtpSend?
   77.15  }
   77.16  
   77.17 -public protocol ConnectionManagerProtocol: ImapConnectionManagerProtocol,
   77.18 -SmtpConnectionManagerProtocol {}
   77.19 +protocol ConnectionManagerProtocol: ImapConnectionManagerProtocol, SmtpConnectionManagerProtocol {}
    78.1 --- a/pEpForiOSTests/Background/FetchMessagesOperationTest.swift	Fri Jul 20 14:07:19 2018 +0200
    78.2 +++ b/pEpForiOSTests/Background/FetchMessagesOperationTest.swift	Thu Jul 26 13:41:45 2018 +0200
    78.3 @@ -22,7 +22,6 @@
    78.4          Record.saveAndWait()
    78.5          
    78.6          let cdAccount2 = SecretTestData().createWorkingCdAccount(number: 1)
    78.7 -        TestUtil.skipValidation()
    78.8          Record.saveAndWait()
    78.9          cdAccount2.createRequiredFoldersAndWait()
   78.10          Record.saveAndWait()
    79.1 --- a/pEpForiOSTests/Background/LoginImapOperationTest.swift	Fri Jul 20 14:07:19 2018 +0200
    79.2 +++ b/pEpForiOSTests/Background/LoginImapOperationTest.swift	Thu Jul 26 13:41:45 2018 +0200
    79.3 @@ -9,7 +9,7 @@
    79.4  import XCTest
    79.5  
    79.6  import CoreData
    79.7 -import pEpForiOS
    79.8 +@testable import pEpForiOS
    79.9  import MessageModel
   79.10  
   79.11  class LoginImapOperationTest: CoreDataDrivenTestBase {
    80.1 --- a/pEpForiOSTests/Background/MoveToFolderOperationTest.swift	Fri Jul 20 14:07:19 2018 +0200
    80.2 +++ b/pEpForiOSTests/Background/MoveToFolderOperationTest.swift	Thu Jul 26 13:41:45 2018 +0200
    80.3 @@ -20,7 +20,6 @@
    80.4          Record.saveAndWait()
    80.5          // the sender
    80.6          let cdAccount2 = SecretTestData().createWorkingCdAccount(number: 1)
    80.7 -        TestUtil.skipValidation()
    80.8          Record.saveAndWait()
    80.9          cdAccount2.createRequiredFoldersAndWait()
   80.10          Record.saveAndWait()
   80.11 @@ -61,7 +60,6 @@
   80.12          Record.saveAndWait()
   80.13          // the sender
   80.14          let cdAccount2 = SecretTestData().createWorkingCdAccount(number: 1)
   80.15 -        TestUtil.skipValidation()
   80.16          Record.saveAndWait()
   80.17          cdAccount2.createRequiredFoldersAndWait()
   80.18          Record.saveAndWait()
    81.1 --- a/pEpForiOSTests/Background/SyncFlagsToServerOperationTest.swift	Fri Jul 20 14:07:19 2018 +0200
    81.2 +++ b/pEpForiOSTests/Background/SyncFlagsToServerOperationTest.swift	Thu Jul 26 13:41:45 2018 +0200
    81.3 @@ -7,11 +7,9 @@
    81.4  //
    81.5  
    81.6  import XCTest
    81.7 -
    81.8  import CoreData
    81.9 -
   81.10 -import pEpForiOS
   81.11  import MessageModel
   81.12 +@testable import pEpForiOS
   81.13  
   81.14  class SyncFlagsToServerOperationTest: CoreDataDrivenTestBase {
   81.15  
    82.1 --- a/pEpForiOSTests/ContentDispositionTest.swift	Fri Jul 20 14:07:19 2018 +0200
    82.2 +++ b/pEpForiOSTests/ContentDispositionTest.swift	Thu Jul 26 13:41:45 2018 +0200
    82.3 @@ -30,7 +30,6 @@
    82.4          Record.saveAndWait()
    82.5  
    82.6          let cdAccount2 = SecretTestData().createWorkingCdAccount(number: 1)
    82.7 -        TestUtil.skipValidation()
    82.8          Record.saveAndWait()
    82.9          cdAccount2.createRequiredFoldersAndWait()
   82.10          Record.saveAndWait()
    83.1 --- a/pEpForiOSTests/DecryptImportedMessagesTests.swift	Fri Jul 20 14:07:19 2018 +0200
    83.2 +++ b/pEpForiOSTests/DecryptImportedMessagesTests.swift	Thu Jul 26 13:41:45 2018 +0200
    83.3 @@ -47,8 +47,6 @@
    83.4          cdInbox.name = ImapSync.defaultImapInboxName
    83.5          cdInbox.uuid = MessageID.generate()
    83.6          cdInbox.account = cdOwnAccount
    83.7 -
    83.8 -        TestUtil.skipValidation()
    83.9          Record.saveAndWait()
   83.10  
   83.11          return cdOwnAccount
    84.1 --- a/pEpForiOSTests/DecryptionTestsInternal.swift	Fri Jul 20 14:07:19 2018 +0200
    84.2 +++ b/pEpForiOSTests/DecryptionTestsInternal.swift	Thu Jul 26 13:41:45 2018 +0200
    84.3 @@ -55,8 +55,6 @@
    84.4          cdInbox.name = ImapSync.defaultImapInboxName
    84.5          cdInbox.uuid = MessageID.generate()
    84.6          cdInbox.account = cdMyAccount
    84.7 -
    84.8 -        TestUtil.skipValidation()
    84.9          Record.saveAndWait()
   84.10  
   84.11          self.backgroundQueue = OperationQueue()
    85.1 --- a/pEpForiOSTests/Features/ReUploadTest.swift	Fri Jul 20 14:07:19 2018 +0200
    85.2 +++ b/pEpForiOSTests/Features/ReUploadTest.swift	Thu Jul 26 13:41:45 2018 +0200
    85.3 @@ -331,7 +331,6 @@
    85.4              "unittest_ios_3_peptest_ch_550A_9E62_6822_040E_57CB_151A_651C_4A5D_B15B_77A3_pub.asc")
    85.5          try! session.setOwnKey(cdAccount.identity!.pEpIdentity(),
    85.6                                 fingerprint: "550A9E626822040E57CB151A651C4A5DB15B77A3")
    85.7 -        TestUtil.skipValidation()
    85.8          Record.saveAndWait()
    85.9          cdAccount.createRequiredFoldersAndWait()
   85.10      }
   85.11 @@ -401,7 +400,6 @@
   85.12          Record.saveAndWait()
   85.13          // Save new acount
   85.14          createe.save()
   85.15 -        TestUtil.skipValidation()
   85.16          guard let cdAccount = createe.cdAccount() else {
   85.17              XCTFail("No Accoount")
   85.18              return createe
    86.1 --- a/pEpForiOSTests/HandshakeTests.swift	Fri Jul 20 14:07:19 2018 +0200
    86.2 +++ b/pEpForiOSTests/HandshakeTests.swift	Thu Jul 26 13:41:45 2018 +0200
    86.3 @@ -31,8 +31,6 @@
    86.4          cdInbox.name = ImapSync.defaultImapInboxName
    86.5          cdInbox.uuid = MessageID.generate()
    86.6          cdInbox.account = cdMyAccount
    86.7 -
    86.8 -        TestUtil.skipValidation()
    86.9          Record.saveAndWait()
   86.10  
   86.11          cdOwnAccount = cdMyAccount
    87.1 --- a/pEpForiOSTests/MessageReevalutionTests.swift	Fri Jul 20 14:07:19 2018 +0200
    87.2 +++ b/pEpForiOSTests/MessageReevalutionTests.swift	Thu Jul 26 13:41:45 2018 +0200
    87.3 @@ -49,7 +49,6 @@
    87.4          cdInbox.name = ImapSync.defaultImapInboxName
    87.5          cdInbox.uuid = MessageID.generate()
    87.6          cdInbox.account = cdMyAccount
    87.7 -        TestUtil.skipValidation()
    87.8          self.cdOwnAccount = cdMyAccount
    87.9  
   87.10          // Sender
    88.1 --- a/pEpForiOSTests/Models/EmailListViewModeTests+Threading.swift	Fri Jul 20 14:07:19 2018 +0200
    88.2 +++ b/pEpForiOSTests/Models/EmailListViewModeTests+Threading.swift	Thu Jul 26 13:41:45 2018 +0200
    88.3 @@ -16,6 +16,7 @@
    88.4      var inbox: Folder!
    88.5      var topMessages = [Message]()
    88.6      let emailListViewModelDelegate = MyEmailListViewModelDelegate()
    88.7 +    let screenComposerProtocol = MyScreenComposerProtocol()
    88.8      let messageSyncServiceProtocol = MyMessageSyncServiceProtocol()
    88.9      var emailListViewModel: EmailListViewModel!
   88.10      var displayedMessage = MyDisplayedMessage()
   88.11 @@ -341,7 +342,7 @@
   88.12              emailListViewModelDelegate: emailListViewModelDelegate,
   88.13              messageSyncService: messageSyncServiceProtocol,
   88.14              folderToShow: inbox)
   88.15 -
   88.16 +        emailListViewModel.screenComposer = self.screenComposerProtocol
   88.17          emailListViewModel.updateThreadListDelegate = updateThreadListDelegate
   88.18  
   88.19          waitForExpectations(timeout: TestUtil.waitTimeLocal) { err in
   88.20 @@ -394,8 +395,8 @@
   88.21                  expectation: expectation(description: "expectationUpdated"))
   88.22          } else {
   88.23              if openThread {
   88.24 -                // expect transforming from single to thread
   88.25 -                emailListViewModelDelegate.expectationShowThreadView = ExpectationShowThreadView(
   88.26 +                //expect transforming from single to thread
   88.27 +                screenComposerProtocol.expectationShowThreadView = ExpectationShowThreadView(
   88.28                      expectation: expectation(description: "expectationShowThreadView"))
   88.29              } else {
   88.30                  // expect child message to existing thread
   88.31 @@ -587,7 +588,6 @@
   88.32          var expectationInserted: ExpectationTopMessageInserted?
   88.33          var expectationUndiplayedMessageUpdated: ExpectationUndiplayedMessageUpdated?
   88.34          var expectationTopMessageDeleted: ExpectationViewModelDelegateTopMessageDeleted?
   88.35 -        var expectationShowThreadView: ExpectationShowThreadView?
   88.36  
   88.37          func emailListViewModel(viewModel: EmailListViewModel,
   88.38                                  didInsertDataAt indexPaths: [IndexPath]) {
   88.39 @@ -651,12 +651,23 @@
   88.40          func updateView() {
   88.41              expectationViewUpdated?.fulfill()
   88.42          }
   88.43 +    }
   88.44  
   88.45 -        func showThreadView(for indexPath: IndexPath) {
   88.46 -            if let exp = expectationShowThreadView {
   88.47 -                exp.expectation.fulfill()
   88.48 +    class MyScreenComposerProtocol: ScreenComposerProtocol {
   88.49 +        var expectationShowThreadView: ExpectationShowThreadView?
   88.50 +
   88.51 +        func emailListViewModel(_ emailListViewModel: EmailListViewModel,
   88.52 +                                requestsShowEmailViewFor message: Message) {
   88.53 +            
   88.54 +        }
   88.55 +
   88.56 +
   88.57 +        func emailListViewModel(_ emailListViewModel: EmailListViewModel,
   88.58 +                                requestsShowThreadViewFor message: Message) {
   88.59 +                if let exp = expectationShowThreadView {
   88.60 +                    exp.expectation.fulfill()
   88.61 +                }
   88.62              }
   88.63 -        }
   88.64      }
   88.65  
   88.66      class MyUpdateThreadListDelegate: UpdateThreadListDelegate {
    89.1 --- a/pEpForiOSTests/Models/LoginViewModelTests.swift	Fri Jul 20 14:07:19 2018 +0200
    89.2 +++ b/pEpForiOSTests/Models/LoginViewModelTests.swift	Thu Jul 26 13:41:45 2018 +0200
    89.3 @@ -57,30 +57,6 @@
    89.4          func requestFetchOlderMessages(inFolder folder: Folder) {
    89.5              XCTFail("unexpected call to \(#function)")
    89.6          }
    89.7 -
    89.8 -        func requestDraft(message: Message) {
    89.9 -            XCTFail("unexpected call to \(#function)")
   89.10 -        }
   89.11 -
   89.12 -        func requestSend(message: Message) {
   89.13 -            XCTFail("unexpected call to \(#function)")
   89.14 -        }
   89.15 -
   89.16 -        func requestFlagChange(message: Message) {
   89.17 -            XCTFail("unexpected call to \(#function)")
   89.18 -        }
   89.19 -
   89.20 -        func requestMessageSync(folder: Folder) {
   89.21 -            XCTFail("unexpected call to \(#function)")
   89.22 -        }
   89.23 -
   89.24 -        func start(account: Account) {
   89.25 -            XCTFail("unexpected call to \(#function)")
   89.26 -        }
   89.27 -
   89.28 -        func cancel(account: Account) {
   89.29 -            XCTFail("unexpected call to \(#function)")
   89.30 -        }
   89.31      }
   89.32  
   89.33      /// This tests makes sense only if the server settings 
    90.1 --- a/pEpForiOSTests/NetworkServiceTests.swift	Fri Jul 20 14:07:19 2018 +0200
    90.2 +++ b/pEpForiOSTests/NetworkServiceTests.swift	Thu Jul 26 13:41:45 2018 +0200
    90.3 @@ -116,7 +116,6 @@
    90.4          networkService.sendLayerDelegate = sendLayerDelegate
    90.5  
    90.6          _ = SecretTestData().createWorkingCdAccount()
    90.7 -        TestUtil.skipValidation()
    90.8          Record.saveAndWait()
    90.9  
   90.10          networkService.start()
   90.11 @@ -190,7 +189,6 @@
   90.12          let networkService = NetworkService(keyImportListener: KeyImportService())
   90.13  
   90.14          _ = SecretTestData().createWorkingCdAccount()
   90.15 -        TestUtil.skipValidation()
   90.16          Record.saveAndWait()
   90.17  
   90.18          for _ in 0...10 {
   90.19 @@ -236,7 +234,6 @@
   90.20  
   90.21          let cdAccount = useCorrectSmtpAccount ? SecretTestData().createWorkingCdAccount() :
   90.22              SecretTestData().createSmtpTimeOutCdAccount()
   90.23 -        TestUtil.skipValidation()
   90.24          Record.saveAndWait()
   90.25  
   90.26          TestUtil.syncAndWait()
    91.1 --- a/pEpForiOSTests/SpecialUseMailboxesTest.swift	Fri Jul 20 14:07:19 2018 +0200
    91.2 +++ b/pEpForiOSTests/SpecialUseMailboxesTest.swift	Thu Jul 26 13:41:45 2018 +0200
    91.3 @@ -7,10 +7,9 @@
    91.4  //
    91.5  
    91.6  import XCTest
    91.7 -
    91.8  import CoreData
    91.9 -import pEpForiOS
   91.10  import MessageModel
   91.11 +@testable import pEpForiOS
   91.12  
   91.13  class SpecialUseMailboxesTest: CoreDataDrivenTestBase {
   91.14      /// This test makes sense only for a Yahoo account as special-use
    92.1 --- a/pEpForiOSTests/TestUtils/CdAccount+TestUtils.swift	Fri Jul 20 14:07:19 2018 +0200
    92.2 +++ b/pEpForiOSTests/TestUtils/CdAccount+TestUtils.swift	Thu Jul 26 13:41:45 2018 +0200
    92.3 @@ -8,7 +8,7 @@
    92.4  
    92.5  import XCTest
    92.6  import MessageModel
    92.7 -import pEpForiOS
    92.8 +@testable import pEpForiOS
    92.9  
   92.10  extension CdAccount {
   92.11      public func allMessages(inFolderOfType type: FolderType,
    93.1 --- a/pEpForiOSTests/TestUtils/CoreDataDrivenTestBase.swift	Fri Jul 20 14:07:19 2018 +0200
    93.2 +++ b/pEpForiOSTests/TestUtils/CoreDataDrivenTestBase.swift	Thu Jul 26 13:41:45 2018 +0200
    93.3 @@ -42,7 +42,6 @@
    93.4          persistentSetup = PersistentSetup()
    93.5  
    93.6          let cdAccount = SecretTestData().createWorkingCdAccount()
    93.7 -        TestUtil.skipValidation()
    93.8          Record.saveAndWait()
    93.9          self.cdAccount = cdAccount
   93.10  
    94.1 --- a/pEpForiOSTests/TestUtils/NetworkServiceObserver.swift	Fri Jul 20 14:07:19 2018 +0200
    94.2 +++ b/pEpForiOSTests/TestUtils/NetworkServiceObserver.swift	Thu Jul 26 13:41:45 2018 +0200
    94.3 @@ -7,10 +7,9 @@
    94.4  //
    94.5  
    94.6  import XCTest
    94.7 -import pEpForiOS
    94.8  import MessageModel
    94.9 -
   94.10  import CoreData
   94.11 +@testable import pEpForiOS
   94.12  
   94.13  class NetworkServiceObserver: NetworkServiceUnitTestDelegate, CustomDebugStringConvertible {
   94.14      let expAllSynced: XCTestExpectation?
    95.1 --- a/pEpForiOSTests/TestUtils/TestUtil.swift	Fri Jul 20 14:07:19 2018 +0200
    95.2 +++ b/pEpForiOSTests/TestUtils/TestUtil.swift	Thu Jul 26 13:41:45 2018 +0200
    95.3 @@ -188,31 +188,6 @@
    95.4          }
    95.5      }
    95.6  
    95.7 -    /**
    95.8 -     Validates all servers and their credentials without actually validating them.
    95.9 -     */
   95.10 -    static func skipValidation() {
   95.11 -        guard let accs = CdAccount.all() as? [CdAccount] else {
   95.12 -            XCTAssertTrue(false)
   95.13 -            return
   95.14 -        }
   95.15 -        for acc in accs {
   95.16 -            acc.needsVerification = false
   95.17 -        }
   95.18 -
   95.19 -        guard let servers = CdServer.all() as? [CdServer] else {
   95.20 -            XCTAssertTrue(false)
   95.21 -            return
   95.22 -        }
   95.23 -        for server in servers {
   95.24 -            guard let creds = server.credentials else {
   95.25 -                XCTAssertTrue(false)
   95.26 -                return
   95.27 -            }
   95.28 -            creds.needsVerification = false
   95.29 -        }
   95.30 -    }
   95.31 -
   95.32      static func checkForExistanceAndUniqueness(uuids: [MessageID]) {
   95.33          for uuid in uuids {
   95.34              if let ms = CdMessage.all(attributes: ["uuid": uuid]) as? [CdMessage] {
   95.35 @@ -266,9 +241,7 @@
   95.36  
   95.37      // MARK: - Sync Loop
   95.38  
   95.39 -    static public func syncAndWait(numAccountsToSync: Int = 1,
   95.40 -                                   skipValidation: Bool = true,
   95.41 -                                   networkService: NetworkService? = nil) {
   95.42 +    static public func syncAndWait(numAccountsToSync: Int = 1, networkService: NetworkService? = nil) {
   95.43          let testCase = XCTestCase()
   95.44          let networkService: NetworkService! = networkService != nil ? networkService :
   95.45              NetworkService(keyImportListener: KeyImportService())
   95.46 @@ -281,10 +254,6 @@
   95.47                                           failOnError: true)
   95.48  
   95.49          networkService.unitTestDelegate = del
   95.50 -
   95.51 -        if skipValidation {
   95.52 -            TestUtil.skipValidation()
   95.53 -        }
   95.54          Record.saveAndWait()
   95.55  
   95.56          networkService.start()
    96.1 --- a/pEpForiOSTests/Util/ComposeUtilTest.swift	Fri Jul 20 14:07:19 2018 +0200
    96.2 +++ b/pEpForiOSTests/Util/ComposeUtilTest.swift	Thu Jul 26 13:41:45 2018 +0200
    96.3 @@ -38,7 +38,7 @@
    96.4  
    96.5      override func setUp() {
    96.6          super.setUp()
    96.7 -        cdAccount.createRequiredFoldersAndWait(testCase: self)
    96.8 +        cdAccount.createRequiredFoldersAndWait()
    96.9          meSomeUnusedAccount = SecretTestData().createWorkingAccount(number: 1).user
   96.10      }
   96.11  
   96.12 @@ -478,7 +478,6 @@
   96.13      }
   96.14  
   96.15      private func createOriginalMessage(inFolderOfType type: FolderType,
   96.16 -                                       /*of account: Account? = nil,*/
   96.17                                         from: Identity,
   96.18                                         tos: [Identity],
   96.19                                         ccs: [Identity],
    97.1 --- a/pEpForiOSTests/Util/KeyImport/KeyImportServiceTest.swift	Fri Jul 20 14:07:19 2018 +0200
    97.2 +++ b/pEpForiOSTests/Util/KeyImport/KeyImportServiceTest.swift	Thu Jul 26 13:41:45 2018 +0200
    97.3 @@ -551,7 +551,6 @@
    97.4          }
    97.5          imapCredentials.loginName = "unittest.ios.3@peptest.ch"
    97.6          smtpCredentials.loginName = "unittest.ios.3@peptest.ch"
    97.7 -        TestUtil.skipValidation()
    97.8          Record.saveAndWait()
    97.9          cdAccount.createRequiredFoldersAndWait()
   97.10  
   97.11 @@ -572,7 +571,6 @@
   97.12      }
   97.13  
   97.14      private func switchTo(device: Device) {
   97.15 -//        XCTAssertTrue(PEPUtil.pEpClean())
   97.16          super.tearEverythingDown()
   97.17          super.setupEverythingUp()
   97.18          setupAccount(device: device)
    98.1 --- a/pEpForiOSUITests/NewAccountSetupUITest.swift	Fri Jul 20 14:07:19 2018 +0200
    98.2 +++ b/pEpForiOSUITests/NewAccountSetupUITest.swift	Thu Jul 26 13:41:45 2018 +0200
    98.3 @@ -42,15 +42,28 @@
    98.4  
    98.5      func testAdditionalAccount() {
    98.6          app().launch()
    98.7 -        let theApp = app()
    98.8 -        theApp.navigationBars["Inbox"].buttons["Folders"].tap()
    98.9 -        theApp.tables.buttons["add account"].tap()
   98.10 -
   98.11 +        addAccount()
   98.12          let account = SecretUITestData.workingAccount2
   98.13          newAccountSetup(account: account)
   98.14          waitForever()
   98.15      }
   98.16  
   98.17 +    func testAdditionalManualAccount() {
   98.18 +        app().launch()
   98.19 +        addAdditionalManual(account: SecretUITestData.manualAccount)
   98.20 +    }
   98.21 +
   98.22 +    func testAutoAccountPlusManual() {
   98.23 +        app().launch()
   98.24 +
   98.25 +        dismissInitialSystemAlerts()
   98.26 +
   98.27 +        let account1 = SecretUITestData.workingAccount1
   98.28 +        newAccountSetup(account: account1)
   98.29 +
   98.30 +        addAdditionalManual(account: SecretUITestData.manualAccount)
   98.31 +    }
   98.32 +
   98.33      func testTwoInitialAccounts() {
   98.34          app().launch()
   98.35  
   98.36 @@ -59,9 +72,7 @@
   98.37          let account1 = SecretUITestData.workingAccount1
   98.38          newAccountSetup(account: account1)
   98.39  
   98.40 -        let theApp = app()
   98.41 -        theApp.navigationBars["Inbox"].buttons["Folders"].tap()
   98.42 -        theApp.tables.buttons["add account"].tap()
   98.43 +        addAccount()
   98.44  
   98.45          let account2 = SecretUITestData.workingAccount2
   98.46          newAccountSetup(account: account2)
   98.47 @@ -78,13 +89,7 @@
   98.48          let account = SecretUITestData.manualAccount
   98.49          newAccountSetup(account: account)
   98.50  
   98.51 -        let alertOkButton = theApp.buttons["Ok"]
   98.52 -        let exists = NSPredicate(format: "enabled == true")
   98.53 -        expectation(for: exists, evaluatedWith: alertOkButton, handler: nil)
   98.54 -        waitForExpectations(timeout: 5, handler: nil)
   98.55 -
   98.56 -        alertOkButton.tap()
   98.57 -        theApp.buttons["Manual configuration"].tap()
   98.58 +        switchToManualConfig()
   98.59  
   98.60          manualNewAccountSetup(account)
   98.61  
   98.62 @@ -137,7 +142,7 @@
   98.63          waitForExpectations(timeout: 3000, handler: nil)
   98.64      }
   98.65  
   98.66 -    func typeTextIfEmpty(textField: XCUIElement,  text: String) {
   98.67 +    func typeTextIfEmpty(textField: XCUIElement, text: String) {
   98.68          if (textField.value as? String ?? "") == "" {
   98.69              textField.typeText(text)
   98.70          }
   98.71 @@ -147,7 +152,7 @@
   98.72          let theApp = app()
   98.73          let tablesQuery = theApp.tables
   98.74  
   98.75 -        var tf = tablesQuery.cells.textFields["nameOfTheUser"]
   98.76 +        var tf = tablesQuery.cells.textFields["username"]
   98.77          typeTextIfEmpty(textField: tf, text: account.nameOfTheUser)
   98.78  
   98.79          tf = tablesQuery.cells.textFields["email"]
   98.80 @@ -170,7 +175,6 @@
   98.81          let sheet = theApp.sheets["Transport protocol"]
   98.82          sheet.buttons[account.imapTransportSecurityString].tap()
   98.83  
   98.84 -        // TODO: Support alert for choosing transport
   98.85          theApp.navigationBars.buttons["Next"].tap()
   98.86  
   98.87          tf = tablesQuery.textFields["smtpServer"]
   98.88 @@ -187,24 +191,7 @@
   98.89      }
   98.90  
   98.91      func newAccountSetup(account: UIAccount, enterPassword: Bool = true) {
   98.92 -        let theApp = app()
   98.93 -        let tablesQuery = theApp.tables
   98.94 -
   98.95 -        var tf = tablesQuery.cells.textFields["userName"]
   98.96 -        tf.tap()
   98.97 -        tf.typeText(account.nameOfTheUser)
   98.98 -
   98.99 -        tf = tablesQuery.cells.textFields["email"]
  98.100 -        tf.tap()
  98.101 -        tf.typeText(account.email)
  98.102 -
  98.103 -        if enterPassword {
  98.104 -            tf = tablesQuery.cells.secureTextFields["password"]
  98.105 -            tf.tap()
  98.106 -            tf.typeText(account.password)
  98.107 -        }
  98.108 -
  98.109 -        theApp.tables.cells.buttons["Sign In"].tap()
  98.110 +        signIn(account: account, enterPassword: enterPassword)
  98.111      }
  98.112  
  98.113      // Opens the "add account" setting in manual configuration mode.
  98.114 @@ -245,4 +232,53 @@
  98.115              button.tap()
  98.116          }
  98.117      }
  98.118 +
  98.119 +    func addAdditionalManual(account: UIAccount) {
  98.120 +        addAccount()
  98.121 +
  98.122 +        signIn(account: account, enterPassword: true)
  98.123 +        switchToManualConfig()
  98.124 +        manualNewAccountSetup(account)
  98.125 +
  98.126 +        waitForever()
  98.127 +    }
  98.128 +
  98.129 +    func signIn(account: UIAccount, enterPassword: Bool = true) {
  98.130 +        let theApp = app()
  98.131 +        let textFieldsQuery = theApp.textFields
  98.132 +
  98.133 +        var tf = textFieldsQuery["username"]
  98.134 +        tf.tap()
  98.135 +        tf.typeText(account.nameOfTheUser)
  98.136 +
  98.137 +        tf = textFieldsQuery["email"]
  98.138 +        tf.tap()
  98.139 +        tf.typeText(account.email)
  98.140 +
  98.141 +        if enterPassword {
  98.142 +            tf = theApp.secureTextFields["password"]
  98.143 +            tf.tap()
  98.144 +            tf.typeText(account.password)
  98.145 +        }
  98.146 +
  98.147 +        theApp.buttons["Sign In"].tap()
  98.148 +    }
  98.149 +
  98.150 +    func switchToManualConfig() {
  98.151 +        let theApp = app()
  98.152 +
  98.153 +        let alertOkButton = theApp.buttons["Ok"]
  98.154 +        let exists = NSPredicate(format: "enabled == true")
  98.155 +        expectation(for: exists, evaluatedWith: alertOkButton, handler: nil)
  98.156 +        waitForExpectations(timeout: 5, handler: nil)
  98.157 +
  98.158 +        alertOkButton.tap()
  98.159 +        theApp.buttons["Manual configuration"].tap()
  98.160 +    }
  98.161 +
  98.162 +    func addAccount() {
  98.163 +        let theApp = app()
  98.164 +        theApp.navigationBars["All"].buttons["Folders"].tap()
  98.165 +        theApp.tables.buttons["Add Account"].tap()
  98.166 +    }
  98.167  }