Browse Source

Merge pull request #604 from deltachat/remove_mailbox_pointer

Remove mailbox pointer
cyBerta 5 years ago
parent
commit
bda3d0e6bb
29 changed files with 378 additions and 346 deletions
  1. 42 76
      deltachat-ios/AppDelegate.swift
  2. 5 3
      deltachat-ios/Controller/AccountSetup/CertificateCheckController.swift
  3. 7 5
      deltachat-ios/Controller/AccountSetup/SecuritySettingsController.swift
  4. 32 34
      deltachat-ios/Controller/AccountSetupController.swift
  5. 6 4
      deltachat-ios/Controller/ChatListController.swift
  6. 16 31
      deltachat-ios/Controller/ChatViewController.swift
  7. 1 1
      deltachat-ios/Controller/EditContactController.swift
  8. 1 1
      deltachat-ios/Controller/EditGroupViewController.swift
  9. 7 7
      deltachat-ios/Controller/EditSettingsController.swift
  10. 7 7
      deltachat-ios/Controller/GroupChatDetailViewController.swift
  11. 8 8
      deltachat-ios/Controller/GroupMembersViewController.swift
  12. 1 1
      deltachat-ios/Controller/MailboxViewController.swift
  13. 1 1
      deltachat-ios/Controller/NewChatViewController.swift
  14. 1 1
      deltachat-ios/Controller/NewContactController.swift
  15. 3 3
      deltachat-ios/Controller/NewGroupController.swift
  16. 1 1
      deltachat-ios/Controller/QrInviteViewController.swift
  17. 1 1
      deltachat-ios/Controller/QrViewController.swift
  18. 3 3
      deltachat-ios/Controller/SettingsClassicViewController.swift
  19. 17 16
      deltachat-ios/Controller/SettingsController.swift
  20. 14 13
      deltachat-ios/Coordinator/AppCoordinator.swift
  21. 186 99
      deltachat-ios/DC/Wrapper.swift
  22. 1 1
      deltachat-ios/DC/events.swift
  23. 2 4
      deltachat-ios/Helper/AvatarHelper.swift
  24. 0 11
      deltachat-ios/Helper/Utils.swift
  25. 4 5
      deltachat-ios/View/Cell/ProfileCell.swift
  26. 1 1
      deltachat-ios/View/ContactCell.swift
  27. 4 2
      deltachat-ios/ViewModel/ChatListViewModel.swift
  28. 4 4
      deltachat-ios/ViewModel/ContactCellViewModel.swift
  29. 2 2
      deltachat-ios/ViewModel/ContactDetailViewModel.swift

+ 42 - 76
deltachat-ios/AppDelegate.swift

@@ -5,7 +5,6 @@ import SwiftyBeaver
 import UIKit
 import UserNotifications
 
-var mailboxPointer: OpaquePointer!
 let logger = SwiftyBeaver.self
 
 enum ApplicationState {
@@ -17,7 +16,7 @@ enum ApplicationState {
 
 @UIApplicationMain
 class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
-    private let dcContext = DcContext()
+    private let dcContext = DcContext.shared
     var appCoordinator: AppCoordinator!
     var relayHelper: RelayHelper!
     var locationManager: LocationManager!
@@ -31,19 +30,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
     var state = ApplicationState.stopped
 
-    private func getCoreInfo() -> [[String]] {
-        if let cString = dc_get_info(mailboxPointer) {
-            let info = String(cString: cString)
-            dc_str_unref(cString)
-            logger.info(info)
-            return info.components(separatedBy: "\n").map { val in
-                val.components(separatedBy: "=")
-            }
-        }
-
-        return []
-    }
-
     func application(_: UIApplication, open url: URL, options _: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
         // gets here when app returns from oAuth2-Setup process - the url contains the provided token
         if let params = url.queryParameters, let token = params["code"] {
@@ -148,64 +134,52 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
     func open() {
         logger.info("open: \(dbfile())")
-
-        if mailboxPointer == nil {
-            mailboxPointer = dcContext.contextPointer
-            guard mailboxPointer != nil else {
-                fatalError("Error: dc_context_new returned nil")
-            }
-        }
-        _ = dc_open(mailboxPointer, dbfile(), nil)
+        dcContext.openDatabase(dbFile: dbfile())
     }
 
     func setStockTranslations() {
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_NOMESSAGES), String.localized("chat_no_messages"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_SELF), String.localized("self"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_DRAFT), String.localized("draft"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_VOICEMESSAGE), String.localized("voice_message"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_DEADDROP), String.localized("chat_contact_request"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_IMAGE), String.localized("image"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_VIDEO), String.localized("video"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_AUDIO), String.localized("audio"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_FILE), String.localized("file"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_STATUSLINE), String.localized("pref_default_status_text"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_NEWGROUPDRAFT), String.localized("group_hello_draft"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGGRPNAME), String.localized("systemmsg_group_name_changed"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGGRPIMGCHANGED), String.localized("systemmsg_group_image_changed"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGADDMEMBER), String.localized("systemmsg_member_added"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGDELMEMBER), String.localized("systemmsg_member_removed"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGGROUPLEFT), String.localized("systemmsg_group_left"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_GIF), String.localized("gif"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_CANTDECRYPT_MSG_BODY), String.localized("systemmsg_cannot_decrypt"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_READRCPT), String.localized("systemmsg_read_receipt_subject"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_READRCPT_MAILBODY), String.localized("systemmsg_read_receipt_body"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGGRPIMGDELETED), String.localized("systemmsg_group_image_deleted"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_CONTACT_VERIFIED), String.localized("contact_verified"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_CONTACT_NOT_VERIFIED), String.localized("contact_not_verified"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_CONTACT_SETUP_CHANGED), String.localized("contact_setup_changed"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_ARCHIVEDCHATS), String.localized("chat_archived_chats_title"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_AC_SETUP_MSG_SUBJECT), String.localized("autocrypt_asm_subject"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_AC_SETUP_MSG_BODY), String.localized("autocrypt_asm_general_body"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_CANNOT_LOGIN), String.localized("login_error_cannot_login"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_SERVER_RESPONSE), String.localized("login_error_server_response"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGACTIONBYUSER), String.localized("systemmsg_action_by_user"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_MSGACTIONBYME), String.localized("systemmsg_action_by_me"))
-        dc_set_stock_translation(mailboxPointer, UInt32(DC_STR_DEVICE_MESSAGES), String.localized("device_talk"))
+        dcContext.setStockTranslation(id: DC_STR_NOMESSAGES, localizationKey: "chat_no_messages")
+        dcContext.setStockTranslation(id: DC_STR_SELF, localizationKey: "self")
+        dcContext.setStockTranslation(id: DC_STR_DRAFT, localizationKey: "draft")
+        dcContext.setStockTranslation(id: DC_STR_VOICEMESSAGE, localizationKey: "voice_message")
+        dcContext.setStockTranslation(id: DC_STR_DEADDROP, localizationKey: "chat_contact_request")
+        dcContext.setStockTranslation(id: DC_STR_IMAGE, localizationKey: "image")
+        dcContext.setStockTranslation(id: DC_STR_VIDEO, localizationKey: "video")
+        dcContext.setStockTranslation(id: DC_STR_AUDIO, localizationKey: "audio")
+        dcContext.setStockTranslation(id: DC_STR_FILE, localizationKey: "file")
+        dcContext.setStockTranslation(id: DC_STR_STATUSLINE, localizationKey: "pref_default_status_text")
+        dcContext.setStockTranslation(id: DC_STR_NEWGROUPDRAFT, localizationKey: "group_hello_draft")
+        dcContext.setStockTranslation(id: DC_STR_MSGGRPNAME, localizationKey: "systemmsg_group_name_changed")
+        dcContext.setStockTranslation(id: DC_STR_MSGGRPIMGCHANGED, localizationKey: "systemmsg_group_image_changed")
+        dcContext.setStockTranslation(id: DC_STR_MSGADDMEMBER, localizationKey: "systemmsg_member_added")
+        dcContext.setStockTranslation(id: DC_STR_MSGDELMEMBER, localizationKey: "systemmsg_member_removed")
+        dcContext.setStockTranslation(id: DC_STR_MSGGROUPLEFT, localizationKey: "systemmsg_group_left")
+        dcContext.setStockTranslation(id: DC_STR_GIF, localizationKey: "gif")
+        dcContext.setStockTranslation(id: DC_STR_CANTDECRYPT_MSG_BODY, localizationKey: "systemmsg_cannot_decrypt")
+        dcContext.setStockTranslation(id: DC_STR_READRCPT, localizationKey: "systemmsg_read_receipt_subject")
+        dcContext.setStockTranslation(id: DC_STR_READRCPT_MAILBODY, localizationKey: "systemmsg_read_receipt_body")
+        dcContext.setStockTranslation(id: DC_STR_MSGGRPIMGDELETED, localizationKey: "systemmsg_group_image_deleted")
+        dcContext.setStockTranslation(id: DC_STR_CONTACT_VERIFIED, localizationKey: "contact_verified")
+        dcContext.setStockTranslation(id: DC_STR_CONTACT_NOT_VERIFIED, localizationKey: "contact_not_verified")
+        dcContext.setStockTranslation(id: DC_STR_CONTACT_SETUP_CHANGED, localizationKey: "contact_setup_changed")
+        dcContext.setStockTranslation(id: DC_STR_ARCHIVEDCHATS, localizationKey: "chat_archived_chats_title")
+        dcContext.setStockTranslation(id: DC_STR_AC_SETUP_MSG_SUBJECT, localizationKey: "autocrypt_asm_subject")
+        dcContext.setStockTranslation(id: DC_STR_AC_SETUP_MSG_BODY, localizationKey: "autocrypt_asm_general_body")
+        dcContext.setStockTranslation(id: DC_STR_CANNOT_LOGIN, localizationKey: "login_error_cannot_login")
+        dcContext.setStockTranslation(id: DC_STR_SERVER_RESPONSE, localizationKey: "login_error_server_response")
+        dcContext.setStockTranslation(id: DC_STR_MSGACTIONBYUSER, localizationKey: "systemmsg_action_by_user")
+        dcContext.setStockTranslation(id: DC_STR_MSGACTIONBYME, localizationKey: "systemmsg_action_by_me")
+        dcContext.setStockTranslation(id: DC_STR_DEVICE_MESSAGES, localizationKey: "device_talk")
     }
 
     func stop() {
         state = .background
-
-        dc_interrupt_imap_idle(mailboxPointer)
-        dc_interrupt_smtp_idle(mailboxPointer)
-        dc_interrupt_mvbox_idle(mailboxPointer)
-        dc_interrupt_sentbox_idle(mailboxPointer)
+        dcContext.interruptIdle()
     }
 
     func close() {
         state = .stopped
-        dc_close(mailboxPointer)
-        mailboxPointer = nil
+        dcContext.closeDatabase()
     }
 
     func start(_ completion: (() -> Void)? = nil) {
@@ -214,15 +188,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         if state == .running {
             return
         }
-
         state = .running
 
         DispatchQueue.global(qos: .background).async {
             self.registerBackgroundTask()
             while self.state == .running {
-                dc_perform_imap_jobs(mailboxPointer)
-                dc_perform_imap_fetch(mailboxPointer)
-                dc_perform_imap_idle(mailboxPointer)
+                self.dcContext.performImap()
             }
             if self.backgroundTask != .invalid {
                 completion?()
@@ -233,8 +204,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         DispatchQueue.global(qos: .utility).async {
             self.registerBackgroundTask()
             while self.state == .running {
-                dc_perform_smtp_jobs(mailboxPointer)
-                dc_perform_smtp_idle(mailboxPointer)
+                self.dcContext.performSmtp()
             }
             if self.backgroundTask != .invalid {
                 self.endBackgroundTask()
@@ -243,17 +213,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
         DispatchQueue.global(qos: .background).async {
             while self.state == .running {
-                dc_perform_sentbox_jobs(mailboxPointer)
-                dc_perform_sentbox_fetch(mailboxPointer)
-                dc_perform_sentbox_idle(mailboxPointer)
+                self.dcContext.performSentbox()
             }
         }
 
         DispatchQueue.global(qos: .background).async {
             while self.state == .running {
-                dc_perform_mvbox_jobs(mailboxPointer)
-                dc_perform_mvbox_fetch(mailboxPointer)
-                dc_perform_mvbox_idle(mailboxPointer)
+                self.dcContext.performMoveBox()
             }
         }
 
@@ -265,7 +231,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             logger.info("could not start reachability notifier")
         }
 
-        let info: [DBCustomVariable] = getCoreInfo().map { kv in
+        let info: [DBCustomVariable] = dcContext.getInfo().map { kv in
             let value = kv.count > 1 ? kv[1] : ""
             return DBCustomVariable(name: kv[0], value: value)
         }
@@ -288,7 +254,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             // however, in fact, it may halt things for some seconds.
             // this pr is a workaround that make things usable for now.
             DispatchQueue.global(qos: .background).async {
-                dc_maybe_network(mailboxPointer)
+                self.dcContext.maybeNetwork()
             }
         case .none:
             logger.info("network: not reachable")

+ 5 - 3
deltachat-ios/Controller/AccountSetup/CertificateCheckController.swift

@@ -8,6 +8,7 @@ class CertificateCheckController: UITableViewController {
 
     var currentValue: Int
     var selectedIndex: Int?
+    let dcContext: DcContext
 
     var okButton: UIBarButtonItem {
         let button =  UIBarButtonItem(title: String.localized("ok"), style: .done, target: self, action: #selector(okButtonPressed))
@@ -28,8 +29,9 @@ class CertificateCheckController: UITableViewController {
         })
     }
 
-    init(sectionTitle: String?) {
-        self.currentValue = DcConfig.certificateChecks
+    init(dcContext: DcContext, sectionTitle: String?) {
+        self.dcContext = dcContext
+        self.currentValue = dcContext.certificateChecks
         for (index, value) in options.enumerated() where currentValue == value {
             selectedIndex = index
         }
@@ -94,7 +96,7 @@ class CertificateCheckController: UITableViewController {
     }
 
     @objc private func okButtonPressed() {
-        DcConfig.certificateChecks = currentValue
+        dcContext.certificateChecks = currentValue
         navigationController?.popViewController(animated: true)
     }
 

+ 7 - 5
deltachat-ios/Controller/AccountSetup/SecuritySettingsController.swift

@@ -7,6 +7,7 @@ class SecuritySettingsController: UITableViewController {
     private var selectedIndex: Int
 
     private var securityType: SecurityType
+    private let dcContext: DcContext
 
     private var okButton: UIBarButtonItem {
         let button =  UIBarButtonItem(title: String.localized("ok"), style: .done, target: self, action: #selector(okButtonPressed))
@@ -27,15 +28,16 @@ class SecuritySettingsController: UITableViewController {
         }
     }
 
-    init(title: String, type: SecurityType) {
+    init(dcContext: DcContext, title: String, type: SecurityType) {
         self.securityType = type
+        self.dcContext = dcContext
         switch securityType {
         case .IMAPSecurity:
             options = [0x00, 0x100, 0x200, 0x400]
-            selectedIndex = options.index(of: DcConfig.getImapSecurity()) ?? 0
+            selectedIndex = options.index(of: dcContext.getImapSecurity()) ?? 0
         case .SMTPSecurity:
             options = [0x00, 0x10000, 0x20000, 0x40000]
-            selectedIndex = options.index(of: DcConfig.getSmtpSecurity()) ?? 0
+            selectedIndex = options.index(of: dcContext.getSmtpSecurity()) ?? 0
         }
         super.init(style: .grouped)
         self.title = title
@@ -86,9 +88,9 @@ class SecuritySettingsController: UITableViewController {
     @objc func okButtonPressed() {
         switch securityType {
         case .IMAPSecurity:
-            DcConfig.setImapSecurity(imapFlags: options[selectedIndex])
+            dcContext.setImapSecurity(imapFlags: options[selectedIndex])
         case .SMTPSecurity:
-            DcConfig.setSmtpSecurity(smptpFlags: options[selectedIndex])
+            dcContext.setSmtpSecurity(smptpFlags: options[selectedIndex])
         }
         navigationController?.popViewController(animated: true)
     }

+ 32 - 34
deltachat-ios/Controller/AccountSetupController.swift

@@ -119,7 +119,7 @@ class AccountSetupController: UITableViewController {
         cell.tag = tagEmailCell
         cell.textField.addTarget(self, action: #selector(emailCellEdited), for: .editingChanged)
         cell.textField.tag = tagTextFieldEmail // will be used to eventually show oAuth-Dialogue when pressing return key
-        cell.setText(text: DcConfig.addr ?? nil)
+        cell.setText(text: dcContext.addr ?? nil)
         cell.textField.delegate = self
         cell.textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
         return cell
@@ -130,7 +130,7 @@ class AccountSetupController: UITableViewController {
         cell.tag = tagPasswordCell
         cell.textField.tag = tagTextFieldPassword  // will be used to eventually show oAuth-Dialogue when selecting
         cell.textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
-        cell.setText(text: DcConfig.mailPw ?? nil)
+        cell.setText(text: dcContext.mailPw ?? nil)
         cell.textField.delegate = self
         return cell
     }()
@@ -182,7 +182,7 @@ class AccountSetupController: UITableViewController {
             placeholder: String.localized("automatic"),
             delegate: self)
         cell.tag = tagImapServerCell
-        cell.setText(text: DcConfig.mailServer ?? nil)
+        cell.setText(text: dcContext.mailServer ?? nil)
         cell.textField.tag = tagTextFieldImapServer
         cell.textField.autocorrectionType = .no
         cell.textField.spellCheckingType = .no
@@ -195,7 +195,7 @@ class AccountSetupController: UITableViewController {
             descriptionID: "login_imap_login",
             placeholder: String.localized("automatic"),
             delegate: self)
-        cell.setText(text: DcConfig.mailUser ?? nil)
+        cell.setText(text: dcContext.mailUser ?? nil)
         cell.textField.tag = tagTextFieldImapLogin
         cell.tag = tagImapUserCell
         return cell
@@ -218,18 +218,18 @@ class AccountSetupController: UITableViewController {
             placeholder: String.localized("automatic"),
             delegate: self)
         cell.tag = tagImapPortCell
-        cell.setText(text: editablePort(port: DcConfig.mailPort))
+        cell.setText(text: editablePort(port: dcContext.mailPort))
         cell.textField.tag = tagImapPortCell
         cell.textField.keyboardType = .numberPad
         return cell
     }()
 
     lazy var imapSecurityCell: UITableViewCell = {
-        let text = "\(DcConfig.getImapSecurity())"
+        let text = "\(dcContext.getImapSecurity())"
         let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("login_imap_security")
         cell.accessoryType = .disclosureIndicator
-        cell.detailTextLabel?.text = "\(DcConfig.getImapSecurity())"
+        cell.detailTextLabel?.text = "\(dcContext.getImapSecurity())"
         cell.selectionStyle = .none
         cell.tag = tagImapSecurityCell
         return cell
@@ -241,7 +241,7 @@ class AccountSetupController: UITableViewController {
             placeholder: String.localized("automatic"),
             delegate: self)
         cell.textField.tag = tagTextFieldSmtpServer
-        cell.setText(text: DcConfig.sendServer ?? nil)
+        cell.setText(text: dcContext.sendServer ?? nil)
         cell.tag = tagSmtpServerCell
         cell.textField.autocorrectionType = .no
         cell.textField.spellCheckingType = .no
@@ -255,7 +255,7 @@ class AccountSetupController: UITableViewController {
             placeholder: String.localized("automatic"),
             delegate: self)
         cell.textField.tag = tagTextFieldSmtpUser
-        cell.setText(text: DcConfig.sendUser ?? nil)
+        cell.setText(text: dcContext.sendUser ?? nil)
         cell.tag = tagSmtpUserCell
         return cell
     }()
@@ -266,7 +266,7 @@ class AccountSetupController: UITableViewController {
             placeholder: String.localized("automatic"),
             delegate: self)
         cell.tag = tagSmtpPortCell
-        cell.setText(text: editablePort(port: DcConfig.sendPort))
+        cell.setText(text: editablePort(port: dcContext.sendPort))
         cell.textField.tag = tagSmtpPortCell
         cell.textField.keyboardType = .numberPad
         return cell
@@ -278,7 +278,7 @@ class AccountSetupController: UITableViewController {
             placeholder: String.localized("automatic"),
             delegate: self)
         cell.textField.textContentType = UITextContentType.password
-        cell.setText(text: DcConfig.sendPw ?? nil)
+        cell.setText(text: dcContext.sendPw ?? nil)
         cell.textField.isSecureTextEntry = true
         cell.textField.tag = tagTextFieldSmtpPassword
         cell.tag = tagSmtpPasswordCell
@@ -286,7 +286,7 @@ class AccountSetupController: UITableViewController {
     }()
 
     lazy var smtpSecurityCell: UITableViewCell = {
-        let security = "\(DcConfig.getSmtpSecurity())"
+        let security = "\(dcContext.getSmtpSecurity())"
         let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("login_smtp_security")
         cell.detailTextLabel?.text = security
@@ -297,7 +297,7 @@ class AccountSetupController: UITableViewController {
     }()
 
     lazy var certCheckCell: UITableViewCell = {
-        let certCheckType = CertificateCheckController.ValueConverter.convertHexToString(value: DcConfig.certificateChecks)
+        let certCheckType = CertificateCheckController.ValueConverter.convertHexToString(value: dcContext.certificateChecks)
         let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("login_certificate_checks")
         cell.detailTextLabel?.text = certCheckType
@@ -358,7 +358,7 @@ class AccountSetupController: UITableViewController {
             style: .done,
             target: self,
             action: #selector(loginButtonPressed))
-        button.isEnabled = dc_is_configured(mailboxPointer) == 0
+        button.isEnabled = !dcContext.isConfigured()
         return button
     }()
 
@@ -603,15 +603,15 @@ class AccountSetupController: UITableViewController {
     private func login(emailAddress: String, password: String, skipAdvanceSetup: Bool = false) {
         addProgressHudLoginListener()
         resignFirstResponderOnAllCells()	// this will resign focus from all textFieldCells so the keyboard wont pop up anymore
-        DcConfig.addr = emailAddress
-        DcConfig.mailPw = password
+        dcContext.addr = emailAddress
+        dcContext.mailPw = password
 
         if !skipAdvanceSetup {
             evaluateAdvancedSetup() // this will set MRConfig related to advanced fields
         }
 
-        print("oAuth-Flag when loggin in: \(DcConfig.getAuthFlags())")
-        dc_configure(mailboxPointer)
+        print("oAuth-Flag when loggin in: \(dcContext.getAuthFlags())")
+        dcContext.configure()
         showProgressHud(title: String.localized("login_header"))
     }
 
@@ -672,7 +672,7 @@ class AccountSetupController: UITableViewController {
             return
         }
         passwordCell.setText(text: token)
-        DcConfig.setAuthFlags(flags: Int(DC_LP_AUTH_OAUTH2))
+        dcContext.setAuthFlags(flags: Int(DC_LP_AUTH_OAUTH2))
         login(emailAddress: emailAddress, password: token, skipAdvanceSetup: true)
     }
 
@@ -725,19 +725,19 @@ class AccountSetupController: UITableViewController {
             if let textFieldCell = cell as? TextFieldCell {
                 switch  textFieldCell.tag {
                 case tagImapServerCell:
-                    DcConfig.mailServer = textFieldCell.getText() ?? nil
+                    dcContext.mailServer = textFieldCell.getText() ?? nil
                 case tagImapPortCell:
-                    DcConfig.mailPort = textFieldCell.getText() ?? nil
+                    dcContext.mailPort = textFieldCell.getText() ?? nil
                 case tagImapUserCell:
-                    DcConfig.mailUser = textFieldCell.getText() ?? nil
+                    dcContext.mailUser = textFieldCell.getText() ?? nil
                 case tagSmtpServerCell:
-                    DcConfig.sendServer = textFieldCell.getText() ?? nil
+                    dcContext.sendServer = textFieldCell.getText() ?? nil
                 case tagSmtpPortCell:
-                    DcConfig.sendPort = textFieldCell.getText() ?? nil
+                    dcContext.sendPort = textFieldCell.getText() ?? nil
                 case tagSmtpUserCell:
-                    DcConfig.sendUser = textFieldCell.getText() ?? nil
+                    dcContext.sendUser = textFieldCell.getText() ?? nil
                 case tagSmtpPasswordCell:
-                    DcConfig.sendPw = textFieldCell.getText() ?? nil
+                    dcContext.sendPw = textFieldCell.getText() ?? nil
                 default:
                     logger.info("unknown identifier \(cell.tag)")
                 }
@@ -747,7 +747,7 @@ class AccountSetupController: UITableViewController {
 
     private func restoreBackup() {
         logger.info("restoring backup")
-        if DcConfig.configured {
+        if dcContext.configured {
             return
         }
         addProgressHudBackupListener()
@@ -755,12 +755,10 @@ class AccountSetupController: UITableViewController {
         if !documents.isEmpty {
             logger.info("looking for backup in: \(documents[0])")
 
-            if let cString = dc_imex_has_backup(mailboxPointer, documents[0]) {
-                let file = String(cString: cString)
-                dc_str_unref(cString)
+            if let file = dcContext.imexHasBackup(filePath: documents[0]) {
                 logger.info("restoring backup: \(file)")
                 showProgressHud(title: String.localized("import_backup_title"))
-                dc_imex(mailboxPointer, DC_IMEX_IMPORT_BACKUP, file, nil)
+                dcContext.imex(what: DC_IMEX_IMPORT_BACKUP, directory: file)
             }
             else {
                 let alert = UIAlertController(
@@ -844,9 +842,9 @@ class AccountSetupController: UITableViewController {
     }
 
     private func initSelectionCells() {
-        smtpSecurityCell.detailTextLabel?.text = SecurityConverter.convertHexToString(type: .SMTPSecurity, hex: DcConfig.getSmtpSecurity())
-        imapSecurityCell.detailTextLabel?.text = SecurityConverter.convertHexToString(type: .IMAPSecurity, hex: DcConfig.getImapSecurity())
-        certCheckCell.detailTextLabel?.text = CertificateCheckController.ValueConverter.convertHexToString(value: DcConfig.certificateChecks)
+        smtpSecurityCell.detailTextLabel?.text = SecurityConverter.convertHexToString(type: .SMTPSecurity, hex: dcContext.getSmtpSecurity())
+        imapSecurityCell.detailTextLabel?.text = SecurityConverter.convertHexToString(type: .IMAPSecurity, hex: dcContext.getImapSecurity())
+        certCheckCell.detailTextLabel?.text = CertificateCheckController.ValueConverter.convertHexToString(value: dcContext.certificateChecks)
     }
 
     private func resignFirstResponderOnAllCells() {

+ 6 - 4
deltachat-ios/Controller/ChatListController.swift

@@ -3,6 +3,7 @@ import UIKit
 class ChatListController: UITableViewController {
     weak var coordinator: ChatListCoordinator?
     let viewModel: ChatListViewModelProtocol
+    let dcContext: DcContext
 
     private let chatCellReuseIdentifier = "chat_cell"
     private let deadDropCellReuseIdentifier = "deaddrop_cell"
@@ -41,8 +42,9 @@ class ChatListController: UITableViewController {
         return cell
     }
 
-    init(viewModel: ChatListViewModelProtocol) {
+    init(dcContext: DcContext, viewModel: ChatListViewModelProtocol) {
         self.viewModel = viewModel
+        self.dcContext = dcContext
         if viewModel.isArchive {
             super.init(nibName: nil, bundle: nil)
         } else {
@@ -180,7 +182,7 @@ class ChatListController: UITableViewController {
         case .chat(let chatData):
             let chatId = chatData.chatId
             if chatId == DC_CHAT_ID_ARCHIVED_LINK {
-                return getArchiveCell(title: DcChat(id: chatId).name)
+                return getArchiveCell(title: dcContext.getChat(chatId: chatId).name)
             } else if let chatCell = tableView.dequeueReusableCell(withIdentifier: chatCellReuseIdentifier, for: indexPath) as? ContactCell {
                 // default chatCell
                 chatCell.updateCell(cellViewModel: cellData)
@@ -247,7 +249,7 @@ class ChatListController: UITableViewController {
         }
         archiveAction.backgroundColor = UIColor.lightGray
 
-        let chat = DcChat(id: chatId)
+        let chat = dcContext.getChat(chatId: chatId)
         let pinned = chat.visibility==DC_CHAT_VISIBILITY_PINNED
         let pinAction = UITableViewRowAction(style: .destructive, title: String.localized(pinned ? "unpin" : "pin")) { [unowned self] _, _ in
             self.viewModel.pinChatToggle(chatId: chat.id)
@@ -313,7 +315,7 @@ class ChatListController: UITableViewController {
         let title = String.localizedStringWithFormat(String.localized("ask_start_chat_with"), dcContact.nameNAddr)
         let alert = UIAlertController(title: title, message: nil, preferredStyle: .safeActionSheet)
         alert.addAction(UIAlertAction(title: String.localized("start_chat"), style: .default, handler: { _ in
-            let chat = dcMsg.createChat()
+            let chat = self.dcContext.createChatByMessageId(msgId)
             self.coordinator?.showChat(chatId: chat.id)
         }))
         alert.addAction(UIAlertAction(title: String.localized("not_now"), style: .default, handler: { _ in

+ 16 - 31
deltachat-ios/Controller/ChatViewController.swift

@@ -81,7 +81,7 @@ class ChatViewController: MessagesViewController {
     }
 
     init(dcContext: DcContext, chatId: Int) {
-        let dcChat = DcChat(id: chatId)
+        let dcChat = dcContext.getChat(chatId: chatId)
         self.dcContext = dcContext
         self.chatId = chatId
         self.disableWriting = !dcChat.canSend
@@ -97,7 +97,7 @@ class ChatViewController: MessagesViewController {
     override func viewDidLoad() {
         messagesCollectionView.register(InfoMessageCell.self)
         super.viewDidLoad()
-        if !DcConfig.configured {
+        if !dcContext.isConfigured() {
             // TODO: display message about nothing being configured
             return
         }
@@ -148,7 +148,7 @@ class ChatViewController: MessagesViewController {
         navigationController?.navigationBar.addGestureRecognizer(navBarTap)
 
         if showCustomNavBar {
-            updateTitle(chat: DcChat(id: chatId))
+            updateTitle(chat: dcContext.getChat(chatId: chatId))
         }
 
         configureMessageMenu()
@@ -172,7 +172,7 @@ class ChatViewController: MessagesViewController {
                     }
                 }
                 if self.showCustomNavBar {
-                    self.updateTitle(chat: DcChat(id: self.chatId))
+                    self.updateTitle(chat: self.dcContext.getChat(chatId: self.chatId))
                 }
             }
         }
@@ -205,7 +205,7 @@ class ChatViewController: MessagesViewController {
         // things that do not affect the chatview
         // and are delayed after the view is displayed
         dcContext.marknoticedChat(chatId: chatId)
-        let array = DcArray(arrayPointer: dc_get_fresh_msgs(mailboxPointer))
+        let array = dcContext.getFreshMessages()
         UIApplication.shared.applicationIconBadgeNumber = array.count
         startTimer()
     }
@@ -241,7 +241,7 @@ class ChatViewController: MessagesViewController {
                 }
             },
             completion: { _ in
-                self.updateTitle(chat: DcChat(id: self.chatId))
+                self.updateTitle(chat: self.dcContext.getChat(chatId: self.chatId))
                 self.messagesCollectionView.reloadDataAndKeepOffset()
                 if lastSectionVisibleBeforeTransition {
                     self.messagesCollectionView.scrollToBottom(animated: false)
@@ -323,9 +323,9 @@ class ChatViewController: MessagesViewController {
 
     private func showEmptyStateView(_ show: Bool) {
         if show {
-            let dcChat = DcChat(id: chatId)
+            let dcChat = dcContext.getChat(chatId: chatId)
             if chatId == DC_CHAT_ID_DEADDROP {
-                if DcConfig.showEmails != DC_SHOW_EMAILS_ALL {
+                if dcContext.showEmails != DC_SHOW_EMAILS_ALL {
                     emptyStateView.text = String.localized("chat_no_contact_requests")
                 } else {
                     emptyStateView.text = String.localized("chat_no_messages")
@@ -350,21 +350,11 @@ class ChatViewController: MessagesViewController {
     }
 
     private var textDraft: String? {
-        if let draft = dc_get_draft(mailboxPointer, UInt32(chatId)) {
-            if let cString = dc_msg_get_text(draft) {
-                let swiftString = String(cString: cString)
-                dc_str_unref(cString)
-                dc_msg_unref(draft)
-                return swiftString
-            }
-            dc_msg_unref(draft)
-            return nil
-        }
-        return nil
+        return dcContext.getDraft(chatId: chatId)
     }
 
     private func getMessageIds(_ count: Int, from: Int? = nil) -> [DcMsg] {
-        let cMessageIds = dc_get_chat_msgs(mailboxPointer, UInt32(chatId), 0, 0)
+        let cMessageIds = dcContext.getChatMessages(chatId: chatId)
 
         let ids: [Int]
         if let from = from {
@@ -374,7 +364,7 @@ class ChatViewController: MessagesViewController {
         }
 
         let markIds: [UInt32] = ids.map { UInt32($0) }
-        dc_markseen_msgs(mailboxPointer, UnsafePointer(markIds), Int32(ids.count))
+        dcContext.markSeenMessages(messageIds: markIds, count: ids.count)
 
         return ids.map {
             DcMsg(id: $0)
@@ -383,12 +373,7 @@ class ChatViewController: MessagesViewController {
 
     @objc private func setTextDraft() {
         if let text = self.messageInputBar.inputTextView.text {
-            let draft = dc_msg_new(mailboxPointer, DC_MSG_TEXT)
-            dc_msg_set_text(draft, text.cString(using: .utf8))
-            dc_set_draft(mailboxPointer, UInt32(chatId), draft)
-
-            // cleanup
-            dc_msg_unref(draft)
+            dcContext.setDraft(chatId: chatId, draftText: text)
         }
     }
 
@@ -640,7 +625,7 @@ class ChatViewController: MessagesViewController {
     }
 
     private func askToForwardMessage() {
-        let chat = DcChat(id: self.chatId)
+        let chat = dcContext.getChat(chatId: self.chatId)
         if chat.isSelfTalk {
             RelayHelper.sharedInstance.forward(to: self.chatId)
         } else {
@@ -889,7 +874,7 @@ extension ChatViewController: MessagesDataSource {
 
     func updateMessage(_ messageId: Int) {
         if let index = messageList.firstIndex(where: { $0.id == messageId }) {
-            dc_markseen_msgs(mailboxPointer, UnsafePointer([UInt32(messageId)]), 1)
+            dcContext.markSeenMessages(messageIds: [UInt32(messageId)])
 
             messageList[index] = DcMsg(id: messageId)
             // Reload section to update header/footer labels
@@ -915,7 +900,7 @@ extension ChatViewController: MessagesDataSource {
     }
 
     func insertMessage(_ message: DcMsg) {
-        dc_markseen_msgs(mailboxPointer, UnsafePointer([UInt32(message.id)]), 1)
+        dcContext.markSeenMessages(messageIds: [UInt32(message.id)])
         messageList.append(message)
         emptyStateView.isHidden = true
         // Reload last section to update header/footer labels and insert a new one
@@ -1242,7 +1227,7 @@ extension ChatViewController: MessageCellDelegate {
     @objc func didTapAvatar(in cell: MessageCollectionViewCell) {
         if let indexPath = messagesCollectionView.indexPath(for: cell) {
             let message = messageList[indexPath.section]
-            let chat = DcChat(id: chatId)
+            let chat = dcContext.getChat(chatId: chatId)
             coordinator?.showContactDetail(of: message.fromContact.id, in: chat.chatType, chatId: chatId)
         }
     }

+ 1 - 1
deltachat-ios/Controller/EditContactController.swift

@@ -28,7 +28,7 @@ class EditContactController: NewContactController {
     }
 
     @objc override func saveContactButtonPressed() {
-        dc_create_contact(mailboxPointer, model.name, model.email)
+        _ = dcContext.createContact(name: model.name, email: model.email)
         coordinator?.navigateBack()
     }
 

+ 1 - 1
deltachat-ios/Controller/EditGroupViewController.swift

@@ -77,7 +77,7 @@ class EditGroupViewController: UITableViewController, MediaPickerDelegate {
         if let groupImage = groupImage, let dcContext = coordinator?.dcContext {
             AvatarHelper.saveChatAvatar(dcContext: dcContext, image: groupImage, for: Int(chat.id))
         }
-        dc_set_chat_name(mailboxPointer, UInt32(chat.id), newName)
+        _ = DcContext.shared.setChatName(chatId: chat.id, name: newName ?? "")
         coordinator?.navigateBack()
     }
 

+ 7 - 7
deltachat-ios/Controller/EditSettingsController.swift

@@ -27,7 +27,7 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
 
     private lazy var statusCell: MultilineTextFieldCell = {
         let cell = MultilineTextFieldCell(description: String.localized("pref_default_status_label"),
-                                          multilineText: DcConfig.selfstatus,
+                                          multilineText: dcContext.selfstatus,
                                           placeholder: String.localized("pref_default_status_label"))
         return cell
     }()
@@ -47,7 +47,7 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
 
     private lazy var nameCell: TextFieldCell = {
         let cell = TextFieldCell(description: String.localized("pref_your_name"), placeholder: String.localized("pref_your_name"))
-        cell.setText(text: DcConfig.displayname)
+        cell.setText(text: dcContext.displayname)
         return cell
     }()
 
@@ -68,9 +68,9 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
     }
 
     override func viewWillDisappear(_ animated: Bool) {
-        DcConfig.selfstatus = statusCell.getText()
-        DcConfig.displayname = nameCell.getText()
-        dc_configure(mailboxPointer)
+        dcContext.selfstatus = statusCell.getText()
+        dcContext.displayname = nameCell.getText()
+        dcContext.configure()
     }
 
     // MARK: - Table view data source
@@ -149,7 +149,7 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
     }
 
     private func deleteProfileIconPressed(_ action: UIAlertAction) {
-        DcConfig.selfavatar = nil
+        dcContext.selfavatar = nil
         updateAvatarAndNameCell()
     }
 
@@ -170,7 +170,7 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
     }
 
     func onImageSelected(image: UIImage) {
-        AvatarHelper.saveSelfAvatarImage(image: image)
+        AvatarHelper.saveSelfAvatarImage(dcContext: dcContext, image: image)
         updateAvatarAndNameCell()
     }
 

+ 7 - 7
deltachat-ios/Controller/GroupChatDetailViewController.swift

@@ -23,7 +23,7 @@ class GroupChatDetailViewController: UIViewController {
     private let sections: [ProfileSections] = [.attachments, .members, .chatActions]
 
     private var currentUser: DcContact? {
-        let myId = groupMemberIds.filter { DcContact(id: $0).email == DcConfig.addr }.first
+        let myId = groupMemberIds.filter { DcContact(id: $0).email == context.addr }.first
         guard let currentUserId = myId else {
             return nil
         }
@@ -107,7 +107,7 @@ class GroupChatDetailViewController: UIViewController {
 
     init(chatId: Int, context: DcContext) {
         self.context = context
-        chat = DcChat(id: chatId)
+        chat = context.getChat(chatId: chatId)
         super.init(nibName: nil, bundle: nil)
         setupSubviews()
     }
@@ -137,7 +137,7 @@ class GroupChatDetailViewController: UIViewController {
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         //update chat object, maybe chat name was edited
-        chat = DcChat(id: chat.id)
+        chat = context.getChat(chatId: chat.id)
         updateGroupMembers()
         tableView.reloadData() // to display updates
         editBarButtonItem.isEnabled = currentUser != nil
@@ -176,7 +176,7 @@ class GroupChatDetailViewController: UIViewController {
         } else {
             self.navigationController?.popToRootViewController(animated: false)
         }
-        self.chat = DcChat(id: chat.id)
+        self.chat = context.getChat(chatId: chat.id)
      }
 
     private func getGroupMemberIdFor(_ row: Int) -> Int {
@@ -346,8 +346,8 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
                 let title = String.localizedStringWithFormat(String.localized("ask_remove_members"), contact.nameNAddr)
                 let alert = UIAlertController(title: title, message: nil, preferredStyle: .safeActionSheet)
                 alert.addAction(UIAlertAction(title: String.localized("remove_desktop"), style: .destructive, handler: { _ in
-                    let success = dc_remove_contact_from_chat(mailboxPointer, UInt32(self.chat.id), UInt32(contact.id))
-                    if success == 1 {
+                    let success = self.context.removeContactFromChat(chatId: self.chat.id, contactId: contact.id)
+                    if success {
                         self.removeGroupMemberFromTableAt(indexPath)
                     }
                 }))
@@ -391,7 +391,7 @@ extension GroupChatDetailViewController {
         if let userId = currentUser?.id {
             let alert = UIAlertController(title: String.localized("ask_leave_group"), message: nil, preferredStyle: .safeActionSheet)
             alert.addAction(UIAlertAction(title: String.localized("menu_leave_group"), style: .destructive, handler: { _ in
-                dc_remove_contact_from_chat(mailboxPointer, UInt32(self.chat.id), UInt32(userId))
+                _ = self.context.removeContactFromChat(chatId: self.chat.id, contactId: userId)
                 self.editBarButtonItem.isEnabled = false
                 self.updateGroupMembers()
             }))

+ 8 - 8
deltachat-ios/Controller/GroupMembersViewController.swift

@@ -2,7 +2,6 @@ import UIKit
 
 class NewGroupAddMembersViewController: GroupMembersViewController {
     weak var coordinator: NewGroupAddMembersCoordinator?
-    let dcContext: DcContext
 
     var onMembersSelected: ((Set<Int>) -> Void)?
     let isVerifiedGroup: Bool
@@ -17,8 +16,7 @@ class NewGroupAddMembersViewController: GroupMembersViewController {
        return button
    }()
 
-    init(dcContext: DcContext, preselected: Set<Int>, isVerified: Bool) {
-        self.dcContext = dcContext
+    init(preselected: Set<Int>, isVerified: Bool) {
         isVerifiedGroup = isVerified
         super.init()
         selectedContactIds = preselected
@@ -81,7 +79,7 @@ class AddGroupMembersViewController: GroupMembersViewController {
 
     private lazy var chat: DcChat? = {
         if let chatId = chatId {
-            return DcChat(id: chatId)
+            return coordinator?.dcContext.getChat(chatId: chatId)
         }
         return nil
     }()
@@ -192,7 +190,7 @@ class AddGroupMembersViewController: GroupMembersViewController {
     }
 
     func loadMemberCandidates() -> [Int] {
-        var contactIds = Utils.getContactIds()
+        var contactIds = dcContext.getContacts(flags: 0)
         let memberSet = Set(chatMemberIds)
         contactIds.removeAll(where: { memberSet.contains($0)})
         return Array(contactIds)
@@ -207,7 +205,7 @@ class AddGroupMembersViewController: GroupMembersViewController {
             return
         }
         for contactId in selectedContactIds {
-            dc_add_contact_to_chat(mailboxPointer, UInt32(chatId), UInt32(contactId))
+           _ = dcContext.addContactToChat(chatId: chatId, contactId: contactId)
         }
         navigationController?.popViewController(animated: true)
     }
@@ -241,7 +239,7 @@ class BlockedContactsViewController: GroupMembersViewController, GroupMemberSele
     override func viewDidLoad() {
         super.viewDidLoad()
         title = String.localized("pref_blocked_contacts")
-        contactIds = Utils.getBlockedContactIds()
+        contactIds = dcContext.getBlockedContacts()
         selectedContactIds = Set(contactIds)
         navigationItem.searchController = nil
         groupMemberSelectionDelegate = self
@@ -259,7 +257,7 @@ class BlockedContactsViewController: GroupMembersViewController, GroupMemberSele
             alert.addAction(UIAlertAction(title: String.localized("menu_unblock_contact"), style: .default, handler: { _ in
                 let contact = DcContact(id: contactId)
                 contact.unblock()
-                self.contactIds = Utils.getBlockedContactIds()
+                self.contactIds = self.dcContext.getBlockedContacts()
                 self.selectedContactIds = Set(self.contactIds)
                 self.tableView.reloadData()
             }))
@@ -281,6 +279,7 @@ class GroupMembersViewController: UITableViewController, UISearchResultsUpdating
     weak var groupMemberSelectionDelegate: GroupMemberSelectionDelegate?
     var enableCheckmarks = true
     var numberOfSections = 1
+    let dcContext: DcContext
 
     var contactIds: [Int] = [] {
         didSet {
@@ -325,6 +324,7 @@ class GroupMembersViewController: UITableViewController, UISearchResultsUpdating
     var selectedContactIds: Set<Int> = []
 
     init() {
+        self.dcContext = DcContext.shared
         super.init(style: .grouped)
         hidesBottomBarWhenPushed = true
     }

+ 1 - 1
deltachat-ios/Controller/MailboxViewController.swift

@@ -47,7 +47,7 @@ class MailboxViewController: ChatViewController {
             let title = String.localizedStringWithFormat(String.localized("ask_start_chat_with"), dcContact.nameNAddr)
             let alert = UIAlertController(title: title, message: nil, preferredStyle: .safeActionSheet)
             alert.addAction(UIAlertAction(title: String.localized("start_chat"), style: .default, handler: { _ in
-                let chat = message.createChat()
+                let chat = self.dcContext.createChatByMessageId(message.id)
                 self.coordinator?.showChat(chatId: chat.id)
             }))
             alert.addAction(UIAlertAction(title: String.localized("menu_block_contact"), style: .destructive, handler: { _ in

+ 1 - 1
deltachat-ios/Controller/NewChatViewController.swift

@@ -47,7 +47,7 @@ class NewChatViewController: UITableViewController {
     var hud: ProgressHud?
 
     lazy var deviceContactHandler: DeviceContactsHandler = {
-        let handler = DeviceContactsHandler(dcContext: DcContext())
+        let handler = DeviceContactsHandler(dcContext: DcContext.shared)
         handler.contactListDelegate = self
         return handler
     }()

+ 1 - 1
deltachat-ios/Controller/NewContactController.swift

@@ -2,7 +2,7 @@ import UIKit
 
 class NewContactController: UITableViewController {
 
-    private let dcContext: DcContext
+    let dcContext: DcContext
     weak var coordinator: EditContactCoordinatorProtocol?
     var openChatOnSave = true
 

+ 3 - 3
deltachat-ios/Controller/NewGroupController.swift

@@ -258,7 +258,7 @@ class NewGroupController: UITableViewController, MediaPickerDelegate {
         //swipe by delete
         if section == sectionGroupMembers, groupContactIds[row] != DC_CONTACT_ID_SELF {
             let delete = UITableViewRowAction(style: .destructive, title: String.localized("remove_desktop")) { [unowned self] _, indexPath in
-                if self.groupChatId != 0, DcChat(id: self.groupChatId).contactIds.contains(self.groupContactIds[row]) {
+                if self.groupChatId != 0, self.dcContext.getChat(chatId: self.groupChatId).contactIds.contains(self.groupContactIds[row]) {
                     let success = self.dcContext.removeContactFromChat(chatId: self.groupChatId, contactId: self.groupContactIds[row])
                     if success {
                         self.removeGroupContactFromList(at: indexPath)
@@ -315,7 +315,7 @@ class NewGroupController: UITableViewController, MediaPickerDelegate {
     }
 
     func updateGroupContactIdsOnQRCodeInvite() {
-        for contactId in DcChat(id: groupChatId).contactIds {
+        for contactId in dcContext.getChat(chatId: groupChatId).contactIds {
             contactIdsForGroup.insert(contactId)
         }
         groupContactIds = Array(contactIdsForGroup)
@@ -325,7 +325,7 @@ class NewGroupController: UITableViewController, MediaPickerDelegate {
     func updateGroupContactIdsOnListSelection(_ members: Set<Int>) {
         if groupChatId != 0 {
             var members = members
-            for contactId in DcChat(id: groupChatId).contactIds {
+            for contactId in dcContext.getChat(chatId: groupChatId).contactIds {
                 members.insert(contactId)
             }
         }

+ 1 - 1
deltachat-ios/Controller/QrInviteViewController.swift

@@ -106,7 +106,7 @@ class QrInviteViewController: UITableViewController {
     private func createDescriptionView() -> UIView {
         let label = UILabel.init()
         label.translatesAutoresizingMaskIntoConstraints = false
-        let dcChat = DcChat(id: chatId)
+        let dcChat = dcContext.getChat(chatId: chatId)
         if !dcChat.name.isEmpty {
             label.text = String.localizedStringWithFormat(String.localized("qrshow_join_group_hint"), dcChat.name)
         }

+ 1 - 1
deltachat-ios/Controller/QrViewController.swift

@@ -11,7 +11,7 @@ class QrViewController: UITableViewController, QrCodeReaderDelegate {
     var dcContext: DcContext
     var contact: DcContact? {
         // This is nil if we do not have an account setup yet
-        if !DcConfig.configured {
+        if !dcContext.isConfigured() {
             return nil
         }
         return DcContact(id: Int(DC_CONTACT_ID_SELF))

+ 3 - 3
deltachat-ios/Controller/SettingsClassicViewController.swift

@@ -55,18 +55,18 @@ class SettingsClassicViewController: UITableViewController {
     }
 
     override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-        let oldSelectedCell = tableView.cellForRow(at: IndexPath.init(row: DcConfig.showEmails, section: 0))
+        let oldSelectedCell = tableView.cellForRow(at: IndexPath.init(row: dcContext.showEmails, section: 0))
         oldSelectedCell?.accessoryType = .none
 
         let newSelectedCell = tableView.cellForRow(at: IndexPath.init(row: indexPath.row, section: 0))
         newSelectedCell?.accessoryType = .checkmark
 
-        DcConfig.showEmails = indexPath.row
+        dcContext.showEmails = indexPath.row
     }
 
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = staticCells[indexPath.row]
-        if options[indexPath.row] == DcConfig.showEmails {
+        if options[indexPath.row] == dcContext.showEmails {
             cell.accessoryType = .checkmark
         }
         return cell

+ 17 - 16
deltachat-ios/Controller/SettingsController.swift

@@ -42,11 +42,11 @@ internal final class SettingsViewController: UITableViewController {
 
     private let profileHeader = ContactDetailHeader()
 
-    private var profileCell: ProfileCell = {
-        let displayName = DcConfig.displayname ?? String.localized("pref_your_name")
-        let email = (DcConfig.addr ?? "")
+    private lazy var profileCell: ProfileCell = {
+        let displayName = dcContext.displayname ?? String.localized("pref_your_name")
+        let email = dcContext.addr ?? ""
         let selfContact = DcContact(id: Int(DC_CONTACT_ID_SELF))
-        let cell = ProfileCell(contact: selfContact)
+        let cell = ProfileCell(contact: selfContact, displayName: displayName, address: email)
         cell.tag = CellTags.profile.rawValue
         return cell
     }()
@@ -59,12 +59,12 @@ internal final class SettingsViewController: UITableViewController {
         return cell
     }()
 
-    private var chatPreferenceCell: UITableViewCell = {
+    private lazy var chatPreferenceCell: UITableViewCell = {
         let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
         cell.tag = CellTags.preferences.rawValue
         cell.textLabel?.text = String.localized("pref_show_emails")
         cell.accessoryType = .disclosureIndicator
-        cell.detailTextLabel?.text = SettingsClassicViewController.getValString(val: DcConfig.showEmails)
+        cell.detailTextLabel?.text = SettingsClassicViewController.getValString(val: dcContext.showEmails)
         return cell
     }()
 
@@ -94,7 +94,7 @@ internal final class SettingsViewController: UITableViewController {
     private lazy var receiptConfirmationSwitch: UISwitch = {
         let switchControl = UISwitch()
         switchControl.isUserInteractionEnabled = false // toggled by cell tap
-        switchControl.isOn = DcConfig.mdnsEnabled
+        switchControl.isOn = dcContext.mdnsEnabled
         return switchControl
     }()
 
@@ -106,10 +106,10 @@ internal final class SettingsViewController: UITableViewController {
         return cell
     }()
 
-    private var autocryptSwitch: UISwitch = {
+    private lazy var autocryptSwitch: UISwitch = {
         let switchControl = UISwitch()
         switchControl.isUserInteractionEnabled = false // toggled by cell tap
-        switchControl.isOn = DcConfig.e2eeEnabled
+        switchControl.isOn = dcContext.e2eeEnabled
         return switchControl
     }()
 
@@ -320,14 +320,14 @@ internal final class SettingsViewController: UITableViewController {
 
     private func handleReceiptConfirmationToggle() {
         receiptConfirmationSwitch.isOn = !receiptConfirmationSwitch.isOn
-        DcConfig.mdnsEnabled = receiptConfirmationSwitch.isOn
-        dc_configure(mailboxPointer)
+        dcContext.mdnsEnabled = receiptConfirmationSwitch.isOn
+        dcContext.configure()
     }
 
     private func handleAutocryptPreferencesToggle() {
         autocryptSwitch.isOn = !autocryptSwitch.isOn
-        DcConfig.e2eeEnabled = autocryptSwitch.isOn
-        dc_configure(mailboxPointer)
+        dcContext.e2eeEnabled = autocryptSwitch.isOn
+        dcContext.configure()
     }
 
     private func sendAutocryptSetupMessage() {
@@ -409,10 +409,11 @@ internal final class SettingsViewController: UITableViewController {
 
     // MARK: - updates
     private func updateCells() {
+        let displayName = dcContext.displayname ?? String.localized("pref_your_name")
+        let email = dcContext.addr ?? ""
         let selfContact = DcContact(id: Int(DC_CONTACT_ID_SELF))
-        profileCell.update(contact: selfContact)
-
-        chatPreferenceCell.detailTextLabel?.text = SettingsClassicViewController.getValString(val: DcConfig.showEmails)
+        profileCell.update(contact: selfContact, displayName: displayName, address: email)
 
+        chatPreferenceCell.detailTextLabel?.text = SettingsClassicViewController.getValString(val: dcContext.showEmails)
     }
 }

+ 14 - 13
deltachat-ios/Coordinator/AppCoordinator.swift

@@ -59,7 +59,7 @@ class AppCoordinator: NSObject, Coordinator {
 
     private lazy var chatListController: UIViewController = {
         let viewModel = ChatListViewModel(dcContext: dcContext, isArchive: false)
-        let controller = ChatListController(viewModel: viewModel)
+        let controller = ChatListController(dcContext: dcContext, viewModel: viewModel)
         let nav = UINavigationController(rootViewController: controller)
         let settingsImage = UIImage(named: "ic_chat")
         nav.tabBarItem = UITabBarItem(title: String.localized("pref_chats"), image: settingsImage, tag: chatsTab)
@@ -253,7 +253,7 @@ class ChatListCoordinator: Coordinator {
 
     func showArchive() {
         let viewModel = ChatListViewModel(dcContext: dcContext, isArchive: true)
-        let controller = ChatListController(viewModel: viewModel)
+        let controller = ChatListController(dcContext: dcContext, viewModel: viewModel)
         let coordinator = ChatListCoordinator(dcContext: dcContext, navigationController: navigationController)
         childCoordinators.append(coordinator)
         controller.coordinator = coordinator
@@ -261,7 +261,7 @@ class ChatListCoordinator: Coordinator {
     }
 
     func showNewChat(contactId: Int) {
-        let chatId = dc_create_chat_by_contact_id(mailboxPointer, UInt32(contactId))
+        let chatId = dcContext.createChatByContactId(contactId: contactId)
         showChat(chatId: Int(chatId))
     }
 }
@@ -341,18 +341,20 @@ class AccountSetupCoordinator: Coordinator {
     }
 
     func showCertCheckOptions() {
-        let certificateCheckController = CertificateCheckController(sectionTitle: String.localized("login_certificate_checks"))
+        let certificateCheckController = CertificateCheckController(dcContext: dcContext, sectionTitle: String.localized("login_certificate_checks"))
         navigationController.pushViewController(certificateCheckController, animated: true)
     }
 
     func showImapSecurityOptions() {
-        let securitySettingsController = SecuritySettingsController(title: String.localized("login_imap_security"),
+        let securitySettingsController = SecuritySettingsController(dcContext: dcContext, title: String.localized("login_imap_security"),
                                                                       type: SecurityType.IMAPSecurity)
         navigationController.pushViewController(securitySettingsController, animated: true)
     }
 
     func showSmptpSecurityOptions() {
-        let securitySettingsController = SecuritySettingsController(title: String.localized("login_imap_security"), type: SecurityType.SMTPSecurity)
+        let securitySettingsController = SecuritySettingsController(dcContext: dcContext,
+                                                                    title: String.localized("login_imap_security"),
+                                                                    type: SecurityType.SMTPSecurity)
         navigationController.pushViewController(securitySettingsController, animated: true)
     }
 
@@ -506,7 +508,7 @@ class GroupChatDetailCoordinator: Coordinator {
         func showArchive() {
             self.navigationController.popToRootViewController(animated: false) // in main ChatList now
             let viewModel = ChatListViewModel(dcContext: dcContext, isArchive: true)
-            let controller = ChatListController(viewModel: viewModel)
+            let controller = ChatListController(dcContext: dcContext, viewModel: viewModel)
             let coordinator = ChatListCoordinator(dcContext: dcContext, navigationController: navigationController)
             childCoordinators.append(coordinator)
             controller.coordinator = coordinator
@@ -516,7 +518,7 @@ class GroupChatDetailCoordinator: Coordinator {
         CATransaction.begin()
         CATransaction.setCompletionBlock(notifyToDeleteChat)
 
-        let chat = DcChat(id: chatId)
+        let chat = dcContext.getChat(chatId: chatId)
         if chat.isArchived {
             showArchive()
         } else {
@@ -547,7 +549,7 @@ class ChatViewCoordinator: NSObject, Coordinator {
     }
 
     func showChatDetail(chatId: Int) {
-        let chat = DcChat(id: chatId)
+        let chat = dcContext.getChat(chatId: chatId)
         switch chat.chatType {
         case .SINGLE:
             if let contactId = chat.contactIds.first {
@@ -679,8 +681,7 @@ class NewGroupCoordinator: Coordinator {
     }
 
     func showAddMembers(preselectedMembers: Set<Int>, isVerified: Bool) {
-        let newGroupController = NewGroupAddMembersViewController(dcContext: dcContext,
-                                                                  preselected: preselectedMembers,
+        let newGroupController = NewGroupAddMembersViewController(preselected: preselectedMembers,
                                                                   isVerified: isVerified)
         let coordinator = NewGroupAddMembersCoordinator(dcContext: dcContext, navigationController: navigationController)
         childCoordinators.append(coordinator)
@@ -775,7 +776,7 @@ class ContactDetailCoordinator: Coordinator, ContactDetailCoordinatorProtocol {
         func showArchive() {
             self.navigationController.popToRootViewController(animated: false) // in main ChatList now
             let viewModel = ChatListViewModel(dcContext: dcContext, isArchive: true)
-            let controller = ChatListController(viewModel: viewModel)
+            let controller = ChatListController(dcContext: dcContext, viewModel: viewModel)
             let coordinator = ChatListCoordinator(dcContext: dcContext, navigationController: navigationController)
             childCoordinators.append(coordinator)
             controller.coordinator = coordinator
@@ -785,7 +786,7 @@ class ContactDetailCoordinator: Coordinator, ContactDetailCoordinatorProtocol {
         CATransaction.begin()
         CATransaction.setCompletionBlock(notifyToDeleteChat)
 
-        let chat = DcChat(id: chatId)
+        let chat = dcContext.getChat(chatId: chatId)
         if chat.isArchived {
             showArchive()
         } else {

+ 186 - 99
deltachat-ios/DC/Wrapper.swift

@@ -3,9 +3,12 @@ import UIKit
 import AVFoundation
 
 class DcContext {
-    let contextPointer: OpaquePointer?
+    /// TODO: THIS global instance should be replaced in the future, for example for a multi-account scenario,
+    /// where we want to have more than one DcContext.
+    static let dcContext: DcContext = DcContext()
+    let contextPointer: OpaquePointer
 
-    init() {
+    private init() {
         var version = ""
         if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
             version += " " + appVersion
@@ -18,6 +21,11 @@ class DcContext {
         dc_context_unref(contextPointer)
     }
 
+    /// Injection of DcContext is preferred over the usage of the shared variable
+    static var shared: DcContext {
+        return .dcContext
+    }
+
     func createContact(name: String, email: String) -> Int {
         return Int(dc_create_contact(contextPointer, name, email))
     }
@@ -27,12 +35,17 @@ class DcContext {
     }
 
     func getContacts(flags: Int32, queryString: String? = nil) -> [Int] {
-        let cContacts = dc_get_contacts(self.contextPointer, UInt32(flags), queryString)
+        let cContacts = dc_get_contacts(contextPointer, UInt32(flags), queryString)
         return Utils.copyAndFreeArray(inputArray: cContacts)
     }
 
+    func getBlockedContacts() -> [Int] {
+        let cBlockedContacts = dc_get_blocked_contacts(contextPointer)
+        return Utils.copyAndFreeArray(inputArray: cBlockedContacts)
+    }
+
     func addContacts(contactString: String) {
-        dc_add_address_book(mailboxPointer, contactString)
+        dc_add_address_book(contextPointer, contactString)
     }
 
     func getChat(chatId: Int) -> DcChat {
@@ -40,7 +53,7 @@ class DcContext {
     }
 
     func getChatIdByContactId(_ contactId: Int) -> Int? {
-        let chatId = dc_get_chat_id_by_contact_id(self.contextPointer, UInt32(contactId))
+        let chatId = dc_get_chat_id_by_contact_id(contextPointer, UInt32(contactId))
         if chatId == 0 {
             return nil
         } else {
@@ -48,6 +61,11 @@ class DcContext {
         }
     }
 
+    func createChatByMessageId(_ messageId: Int) -> DcChat {
+        let chatId = dc_create_chat_by_msg_id(contextPointer, UInt32(messageId))
+        return DcChat(id: Int(chatId))
+    }
+
     func getChatlist(flags: Int32, queryString: String?, queryId: Int) -> DcChatlist {
         let chatlistPointer = dc_get_chatlist(contextPointer, flags, queryString, UInt32(queryId))
         let chatlist = DcChatlist(chatListPointer: chatlistPointer)
@@ -125,6 +143,96 @@ class DcContext {
         dc_stop_ongoing_process(contextPointer)
     }
 
+    func getInfo() -> [[String]] {
+        if let cString = dc_get_info(contextPointer) {
+            let info = String(cString: cString)
+            dc_str_unref(cString)
+            logger.info(info)
+            return info.components(separatedBy: "\n").map { val in
+                val.components(separatedBy: "=")
+            }
+        }
+        return []
+    }
+
+    func interruptIdle() {
+        dc_interrupt_imap_idle(contextPointer)
+        dc_interrupt_smtp_idle((contextPointer))
+        dc_interrupt_mvbox_idle((contextPointer))
+        dc_interrupt_sentbox_idle((contextPointer))
+    }
+
+    func openDatabase(dbFile: String) {
+        _ = dc_open(contextPointer, dbFile, nil)
+    }
+
+    func closeDatabase() {
+        dc_close(contextPointer)
+    }
+
+    func performImap() {
+        dc_perform_imap_jobs(contextPointer)
+        dc_perform_imap_fetch(contextPointer)
+        dc_perform_imap_idle(contextPointer)
+    }
+
+    func performMoveBox() {
+        dc_perform_mvbox_jobs(contextPointer)
+        dc_perform_mvbox_fetch(contextPointer)
+        dc_perform_mvbox_idle(contextPointer)
+    }
+
+    func performSmtp() {
+        dc_perform_smtp_jobs(contextPointer)
+        dc_perform_smtp_idle(contextPointer)
+    }
+
+    func performSentbox() {
+        dc_perform_sentbox_jobs(contextPointer)
+        dc_perform_sentbox_fetch(contextPointer)
+        dc_perform_sentbox_idle(contextPointer)
+    }
+
+    func setStockTranslation(id: Int32, localizationKey: String) {
+        dc_set_stock_translation(contextPointer, UInt32(id), String.localized(localizationKey))
+    }
+
+    func getDraft(chatId: Int) -> String? {
+        if let draft = dc_get_draft(contextPointer, UInt32(chatId)) {
+            if let cString = dc_msg_get_text(draft) {
+                let swiftString = String(cString: cString)
+                dc_str_unref(cString)
+                dc_msg_unref(draft)
+                return swiftString
+            }
+            dc_msg_unref(draft)
+            return nil
+        }
+        return nil
+    }
+
+    func setDraft(chatId: Int, draftText: String) {
+        let draft = dc_msg_new(contextPointer, DC_MSG_TEXT)
+        dc_msg_set_text(draft, draftText.cString(using: .utf8))
+        dc_set_draft(contextPointer, UInt32(chatId), draft)
+
+        // cleanup
+        dc_msg_unref(draft)
+    }
+
+    func getFreshMessages() -> DcArray {
+        return DcArray(arrayPointer: dc_get_fresh_msgs(contextPointer))
+    }
+
+    func markSeenMessages(messageIds: [UInt32], count: Int = 1) {
+        let ptr = UnsafePointer(messageIds)
+        dc_markseen_msgs(contextPointer, ptr, Int32(count))
+    }
+
+    func getChatMessages(chatId: Int) -> OpaquePointer {
+        return dc_get_chat_msgs(contextPointer, UInt32(chatId), 0, 0)
+    }
+    
     func getMsgInfo(msgId: Int) -> String {
         if let cString = dc_get_msg_info(self.contextPointer, UInt32(msgId)) {
             let swiftString = String(cString: cString)
@@ -159,6 +267,10 @@ class DcContext {
         return dc_continue_key_transfer(self.contextPointer, UInt32(msgId), setupCode) != 0
     }
 
+    func configure() {
+        dc_configure(contextPointer)
+    }
+
     func getConfig(_ key: String) -> String? {
         guard let cString = dc_get_config(self.contextPointer, key) else { return nil }
         let value = String(cString: cString)
@@ -186,6 +298,22 @@ class DcContext {
         setConfig(key, vStr)
     }
 
+    func getConfigInt(_ key: String) -> Int {
+        let vStr = getConfig(key)
+        if vStr == nil {
+            return 0
+        }
+        let vInt = Int(vStr!)
+        if vInt == nil {
+            return 0
+        }
+        return vInt!
+    }
+
+    private func setConfigInt(_ key: String, _ value: Int) {
+        setConfig(key, String(value))
+    }
+
     func getUnreadMessages(chatId: Int) -> Int {
         return Int(dc_get_fresh_msg_cnt(contextPointer, UInt32(chatId)))
     }
@@ -199,7 +327,7 @@ class DcContext {
     }
 
     func getSelfAvatarImage() -> UIImage? {
-       guard let fileName = DcConfig.selfavatar else { return nil }
+       guard let fileName = selfavatar else { return nil }
        let path: URL = URL(fileURLWithPath: fileName, isDirectory: false)
        if path.isFileURL {
            do {
@@ -235,6 +363,15 @@ class DcContext {
         dc_imex(contextPointer, what, directory, nil)
     }
 
+    func imexHasBackup(filePath: String) -> String? {
+        var file: String?
+        if let cString = dc_imex_has_backup(contextPointer, filePath) {
+            file = String(cString: cString)
+            dc_str_unref(cString)
+        }
+        return file
+    }
+
     func isSendingLocationsToChat(chatId: Int) -> Bool {
         return dc_is_sending_locations_to_chat(contextPointer, UInt32(chatId)) == 1
     }
@@ -254,13 +391,11 @@ class DcContext {
         let messageIds = Utils.copyAndFreeArray(inputArray: arrayPointer)
         return messageIds
     }
-}
-
-class DcConfig {
 
-    // it is fine to use existing functionality of DcConfig,
-    // however, as DcConfig uses a global pointer,
-    // new functionality should be added to DcContext.
+    // call dc_maybe_network() from a worker thread.
+    func maybeNetwork() {
+        dc_maybe_network(contextPointer)
+    }
 
     // also, there is no much worth in adding a separate function or so
     // for each config option - esp. if they are just forwarded to the core
@@ -268,110 +403,67 @@ class DcConfig {
     // this adds a complexity that can be avoided -
     // and makes grep harder as these names are typically named following different guidelines.
 
-    private class func getConfig(_ key: String) -> String? {
-        guard let cString = dc_get_config(mailboxPointer, key) else { return nil }
-        let value = String(cString: cString)
-        dc_str_unref(cString)
-        if value.isEmpty {
-            return nil
-        }
-        return value
-    }
-
-    private class func setConfig(_ key: String, _ value: String?) {
-        if let v = value {
-            dc_set_config(mailboxPointer, key, v)
-        } else {
-            dc_set_config(mailboxPointer, key, nil)
-        }
-    }
-
-    private class func getConfigBool(_ key: String) -> Bool {
-        return strToBool(getConfig(key))
-    }
-
-    private class func setConfigBool(_ key: String, _ value: Bool) {
-        let vStr = value ? "1" : "0"
-        setConfig(key, vStr)
-    }
-
-    private class func getConfigInt(_ key: String) -> Int {
-        let vStr = getConfig(key)
-        if vStr == nil {
-            return 0
-        }
-        let vInt = Int(vStr!)
-        if vInt == nil {
-            return 0
-        }
-        return vInt!
-    }
-
-    private class func setConfigInt(_ key: String, _ value: Int) {
-        setConfig(key, String(value))
-    }
-
-    class var displayname: String? {
+    var displayname: String? {
         set { setConfig("displayname", newValue) }
         get { return getConfig("displayname") }
     }
 
-    class var selfstatus: String? {
+    var selfstatus: String? {
         set { setConfig("selfstatus", newValue) }
         get { return getConfig("selfstatus") }
     }
 
-    class var selfavatar: String? {
+    var selfavatar: String? {
         set { setConfig("selfavatar", newValue) }
         get { return getConfig("selfavatar") }
     }
 
-    class var addr: String? {
+    var addr: String? {
         set { setConfig("addr", newValue) }
         get { return getConfig("addr") }
     }
 
-    class var mailServer: String? {
+    var mailServer: String? {
         set { setConfig("mail_server", newValue) }
         get { return getConfig("mail_server") }
     }
 
-    class var mailUser: String? {
+    var mailUser: String? {
         set { setConfig("mail_user", newValue) }
         get { return getConfig("mail_user") }
     }
 
-    class var mailPw: String? {
+    var mailPw: String? {
         set { setConfig("mail_pw", newValue) }
         get { return getConfig("mail_pw") }
     }
 
-    class var mailPort: String? {
+    var mailPort: String? {
         set { setConfig("mail_port", newValue) }
         get { return getConfig("mail_port") }
     }
 
-    class var sendServer: String? {
+    var sendServer: String? {
         set { setConfig("send_server", newValue) }
         get { return getConfig("send_server") }
     }
 
-    class var sendUser: String? {
+    var sendUser: String? {
         set { setConfig("send_user", newValue) }
         get { return getConfig("send_user") }
     }
 
-    class var sendPw: String? {
+    var sendPw: String? {
         set { setConfig("send_pw", newValue) }
         get { return getConfig("send_pw") }
     }
 
-    class var sendPort: String? {
+    var sendPort: String? {
         set { setConfig("send_port", newValue) }
         get { return getConfig("send_port") }
     }
 
-    class var certificateChecks: Int {
+    var certificateChecks: Int {
         set {
             setConfig("smtp_certificate_checks", "\(newValue)")
             setConfig("imap_certificate_checks", "\(newValue)")
@@ -385,7 +477,7 @@ class DcConfig {
         }
     }
 
-    private class var serverFlags: Int {
+    private var serverFlags: Int {
         // IMAP-/SMTP-flags as a combination of DC_LP flags
         set {
             setConfig("server_flags", "\(newValue)")
@@ -399,63 +491,63 @@ class DcConfig {
         }
     }
 
-    class func setImapSecurity(imapFlags flags: Int) {
+    func setImapSecurity(imapFlags flags: Int) {
         var sf = serverFlags
         sf = sf & ~0x700 // DC_LP_IMAP_SOCKET_FLAGS
         sf = sf | flags
         serverFlags = sf
     }
 
-    class func setSmtpSecurity(smptpFlags flags: Int) {
+    func setSmtpSecurity(smptpFlags flags: Int) {
         var sf = serverFlags
         sf = sf & ~0x70000 // DC_LP_SMTP_SOCKET_FLAGS
         sf = sf | flags
         serverFlags = sf
     }
 
-    class func setAuthFlags(flags: Int) {
+    func setAuthFlags(flags: Int) {
         var sf = serverFlags
         sf = sf & ~0x6 // DC_LP_AUTH_FLAGS
         sf = sf | flags
         serverFlags = sf
     }
 
-    class func getImapSecurity() -> Int {
+    func getImapSecurity() -> Int {
         var sf = serverFlags
         sf = sf & 0x700 // DC_LP_IMAP_SOCKET_FLAGS
         return sf
     }
 
-    class func getSmtpSecurity() -> Int {
+    func getSmtpSecurity() -> Int {
         var sf = serverFlags
         sf = sf & 0x70000  // DC_LP_SMTP_SOCKET_FLAGS
         return sf
     }
 
-    class func getAuthFlags() -> Int {
+    func getAuthFlags() -> Int {
         var sf = serverFlags
         sf = sf & 0x6 // DC_LP_AUTH_FLAGS
         return sf
     }
 
-    class var e2eeEnabled: Bool {
+    var e2eeEnabled: Bool {
         set { setConfigBool("e2ee_enabled", newValue) }
         get { return getConfigBool("e2ee_enabled") }
     }
 
-    class var mdnsEnabled: Bool {
+    var mdnsEnabled: Bool {
         set { setConfigBool("mdns_enabled", newValue) }
         get { return getConfigBool("mdns_enabled") }
     }
-    
-    class var showEmails: Int {
+
+    var showEmails: Int {
         // one of DC_SHOW_EMAILS_*
         set { setConfigInt("show_emails", newValue) }
         get { return getConfigInt("show_emails") }
     }
 
     // do not use. use DcContext::isConfigured() instead
-    class var configured: Bool {
+    var configured: Bool {
         return getConfigBool("configured")
     }
 }
@@ -497,7 +589,7 @@ class DcChat {
 
     // use DcContext.getChat() instead of calling the constructor directly
     init(id: Int) {
-        if let p = dc_get_chat(mailboxPointer, UInt32(id)) {
+        if let p = dc_get_chat(DcContext.shared.contextPointer, UInt32(id)) {
             chatPointer = p
         } else {
             fatalError("Invalid chatID opened \(id)")
@@ -565,7 +657,7 @@ class DcChat {
     }
 
     var contactIds: [Int] {
-        return Utils.copyAndFreeArray(inputArray: dc_get_chat_contacts(mailboxPointer, UInt32(id)))
+        return Utils.copyAndFreeArray(inputArray: dc_get_chat_contacts(DcContext.shared.contextPointer, UInt32(id)))
     }
 
     lazy var profileImage: UIImage? = { [unowned self] in
@@ -624,15 +716,15 @@ class DcMsg: MessageType {
             DC_MSG_FILE
      */
     init(viewType: Int32) {
-        messagePointer = dc_msg_new(mailboxPointer, viewType)
+        messagePointer = dc_msg_new(DcContext.shared.contextPointer, viewType)
     }
 
     init(id: Int) {
-        messagePointer = dc_get_msg(mailboxPointer, UInt32(id))
+        messagePointer = dc_get_msg(DcContext.shared.contextPointer, UInt32(id))
     }
 
     init(type: Int32) {
-        messagePointer = dc_msg_new(mailboxPointer, type)
+        messagePointer = dc_msg_new(DcContext.shared.contextPointer, type)
     }
 
     deinit {
@@ -919,37 +1011,32 @@ class DcMsg: MessageType {
         return dc_msg_get_showpadlock(messagePointer) == 1
     }
 
-    func createChat() -> DcChat {
-        let chatId = dc_create_chat_by_msg_id(mailboxPointer, UInt32(id))
-        return DcChat(id: Int(chatId))
-    }
-
     func sendInChat(id: Int) {
-        dc_send_msg(mailboxPointer, UInt32(id), messagePointer)
+        dc_send_msg(DcContext.shared.contextPointer, UInt32(id), messagePointer)
     }
 
     func previousMediaURLs() -> [URL] {
         var urls: [URL] = []
-        var prev: Int = Int(dc_get_next_media(mailboxPointer, UInt32(id), -1, Int32(type), 0, 0))
+        var prev: Int = Int(dc_get_next_media(DcContext.shared.contextPointer, UInt32(id), -1, Int32(type), 0, 0))
         while prev != 0 {
             let prevMessage = DcMsg(id: prev)
             if let url = prevMessage.fileURL {
                 urls.insert(url, at: 0)
             }
-            prev = Int(dc_get_next_media(mailboxPointer, UInt32(prevMessage.id), -1, Int32(prevMessage.type), 0, 0))
+            prev = Int(dc_get_next_media(DcContext.shared.contextPointer, UInt32(prevMessage.id), -1, Int32(prevMessage.type), 0, 0))
         }
         return urls
     }
 
     func nextMediaURLs() -> [URL] {
         var urls: [URL] = []
-        var next: Int = Int(dc_get_next_media(mailboxPointer, UInt32(id), 1, Int32(type), 0, 0))
+        var next: Int = Int(dc_get_next_media(DcContext.shared.contextPointer, UInt32(id), 1, Int32(type), 0, 0))
         while next != 0 {
             let nextMessage = DcMsg(id: next)
             if let url = nextMessage.fileURL {
                 urls.append(url)
             }
-            next = Int(dc_get_next_media(mailboxPointer, UInt32(nextMessage.id), 1, Int32(nextMessage.type), 0, 0))
+            next = Int(dc_get_next_media(DcContext.shared.contextPointer, UInt32(nextMessage.id), 1, Int32(nextMessage.type), 0, 0))
         }
         return urls
     }
@@ -959,7 +1046,7 @@ class DcContact {
     private var contactPointer: OpaquePointer?
 
     init(id: Int) {
-        contactPointer = dc_get_contact(mailboxPointer, UInt32(id))
+        contactPointer = dc_get_contact(DcContext.shared.contextPointer, UInt32(id))
     }
 
     deinit {
@@ -1028,15 +1115,15 @@ class DcContact {
     }
 
     func block() {
-        dc_block_contact(mailboxPointer, UInt32(id), 1)
+        dc_block_contact(DcContext.shared.contextPointer, UInt32(id), 1)
     }
 
     func unblock() {
-        dc_block_contact(mailboxPointer, UInt32(id), 0)
+        dc_block_contact(DcContext.shared.contextPointer, UInt32(id), 0)
     }
 
     func marknoticed() {
-        dc_marknoticed_contact(mailboxPointer, UInt32(id))
+        dc_marknoticed_contact(DcContext.shared.contextPointer, UInt32(id))
     }
 }
 

+ 1 - 1
deltachat-ios/DC/events.swift

@@ -131,7 +131,7 @@ public func callbackSwift(event: CInt, data1: CUnsignedLong, data2: CUnsignedLon
                 logger.info("notifications: added \(content)")
             }
 
-            let array = DcArray(arrayPointer: dc_get_fresh_msgs(mailboxPointer))
+            let array = DcContext.shared.getFreshMessages()
             UIApplication.shared.applicationIconBadgeNumber = array.count
         }
 

+ 2 - 4
deltachat-ios/Helper/AvatarHelper.swift

@@ -9,10 +9,10 @@ class AvatarHelper {
         case runtimeError(String)
     }
 
-    static func saveSelfAvatarImage(image: UIImage) {
+    static func saveSelfAvatarImage(dcContext: DcContext, image: UIImage) {
         do {
             let avatarFile = try saveAvatarImageToFile(image: image)
-            DcConfig.selfavatar = avatarFile.path
+            dcContext.selfavatar = avatarFile.path
             deleteAvatarFile(avatarFile)
         } catch let error {
             logger.error("Error saving Image: \(error.localizedDescription)")
@@ -29,7 +29,6 @@ class AvatarHelper {
         }
     }
 
-
     private static func saveAvatarImageToFile(image: UIImage) throws -> URL {
         if let data = image.jpegData(compressionQuality: 1.0) {
             let filemanager = FileManager.default
@@ -63,5 +62,4 @@ class AvatarHelper {
         }
     }
 
-
 }

+ 0 - 11
deltachat-ios/Helper/Utils.swift

@@ -4,17 +4,6 @@ import AVFoundation
 
 struct Utils {
 
-    // do not use, use DcContext::getContacts() instead
-    static func getContactIds() -> [Int] {
-        let cContacts = dc_get_contacts(mailboxPointer, 0, nil)
-        return Utils.copyAndFreeArray(inputArray: cContacts)
-    }
-
-    static func getBlockedContactIds() -> [Int] {
-        let cBlockedContacts = dc_get_blocked_contacts(mailboxPointer)
-        return Utils.copyAndFreeArray(inputArray: cBlockedContacts)
-    }
-
     static func getInitials(inputName: String) -> String {
         if let firstLetter = inputName.first {
             return firstLetter.uppercased()

+ 4 - 5
deltachat-ios/View/Cell/ProfileCell.swift

@@ -4,11 +4,11 @@ class ProfileCell: UITableViewCell {
 
     private let detailView = ContactDetailHeader()
 
-    init(contact: DcContact) {
+    init(contact: DcContact, displayName: String?, address: String?) {
         super.init(style: .default, reuseIdentifier: nil)
         accessoryType = .disclosureIndicator
         setupSubviews()
-        update(contact: contact)
+        update(contact: contact, displayName: displayName, address: address)
         detailView.backgroundColor = .clear
     }
 
@@ -26,9 +26,8 @@ class ProfileCell: UITableViewCell {
         detailView.heightAnchor.constraint(equalToConstant: ContactDetailHeader.headerHeight).isActive = true
     }
 
-    func update(contact: DcContact) {
-        let displayName = DcConfig.displayname
-        let email = DcConfig.addr ?? contact.email
+    func update(contact: DcContact, displayName: String?, address: String?) {
+        let email = address ?? contact.email
         detailView.updateDetails(title: displayName ?? contact.displayName, subtitle: email)
         if let image = contact.profileImage {
             detailView.setImage(image)

+ 1 - 1
deltachat-ios/View/ContactCell.swift

@@ -252,7 +252,7 @@ class ContactCell: UITableViewCell {
             titleLabel.attributedText = cellViewModel.title.boldAt(indexes: cellViewModel.titleHighlightIndexes, fontSize: titleLabel.font.pointSize)
 
         case .chat(let chatData):
-            let chat = DcChat(id: chatData.chatId)
+            let chat = DcContext.shared.getChat(chatId: chatData.chatId)
 
             // text bold if chat contains unread messages - otherwise hightlight search results if needed
             if chatData.unreadMessages > 0 {

+ 4 - 2
deltachat-ios/ViewModel/ChatListViewModel.swift

@@ -200,7 +200,7 @@ private extension ChatListViewModel {
 
 
         if let msgId = msgIdFor(row: index), chatId == DC_CHAT_ID_DEADDROP {
-            return ChatCellViewModel(dearddropCellData: DeaddropCellData(chatId: chatId, msgId: msgId, summary: summary))
+            return ChatCellViewModel(dcContext: dcContext, deaddropCellData: DeaddropCellData(chatId: chatId, msgId: msgId, summary: summary))
         }
 
         let chat = dcContext.getChat(chatId: chatId)
@@ -213,6 +213,7 @@ private extension ChatListViewModel {
         }
 
         let viewModel = ChatCellViewModel(
+            dcContext: dcContext,
             chatData: ChatCellData(
                 chatId: chatId,
                 summary: summary,
@@ -226,11 +227,12 @@ private extension ChatListViewModel {
     func makeMessageCellViewModel(msgId: Int) -> AvatarCellViewModel {
         let msg: DcMsg = DcMsg(id: msgId)
         let chatId: Int = msg.chatId
-        let chat: DcChat = DcChat(id: chatId)
+        let chat: DcChat = dcContext.getChat(chatId: chatId)
         let summary: DcLot = msg.summary(chat: chat)
         let unreadMessages = dcContext.getUnreadMessages(chatId: chatId)
 
         let viewModel = ChatCellViewModel(
+            dcContext: dcContext,
             chatData: ChatCellData(
                 chatId: chatId,
                 summary: summary,

+ 4 - 4
deltachat-ios/ViewModel/ContactCellViewModel.swift

@@ -84,19 +84,19 @@ class ChatCellViewModel: AvatarCellViewModel {
     var titleHighlightIndexes: [Int]
     var subtitleHighlightIndexes: [Int]
 
-    init(chatData: ChatCellData, titleHighlightIndexes: [Int] = [], subtitleHighlightIndexes: [Int] = []) {
+    init(dcContext: DcContext, chatData: ChatCellData, titleHighlightIndexes: [Int] = [], subtitleHighlightIndexes: [Int] = []) {
         self.type = CellModel.chat(chatData)
         self.titleHighlightIndexes = titleHighlightIndexes
         self.subtitleHighlightIndexes = subtitleHighlightIndexes
         self.summary = chatData.summary
-        self.chat = DcChat(id: chatData.chatId)
+        self.chat = dcContext.getChat(chatId: chatData.chatId)
     }
 
-    init(dearddropCellData cellData: DeaddropCellData) {
+    init(dcContext: DcContext, deaddropCellData cellData: DeaddropCellData) {
         self.type = CellModel.deaddrop(cellData)
         self.titleHighlightIndexes = []
         self.subtitleHighlightIndexes = []
-        self.chat = DcChat(id: cellData.chatId)
+        self.chat = dcContext.getChat(chatId: cellData.chatId)
         self.summary = cellData.summary
     }
 }

+ 2 - 2
deltachat-ios/ViewModel/ContactDetailViewModel.swift

@@ -88,7 +88,7 @@ class ContactDetailViewModel: ContactDetailViewModelProtocol {
            // safe_fatalError("This is a ContactDetail view with no chat id")
             return false
         }
-        return DcChat(id: chatId).isArchived
+        return context.getChat(chatId: chatId).isArchived
     }
 
     var numberOfSections: Int {
@@ -116,7 +116,7 @@ class ContactDetailViewModel: ContactDetailViewModelProtocol {
         let unreadMessages = context.getUnreadMessages(chatId: chatId)
 
         let cellData = ChatCellData(chatId: chatId, summary: summary, unreadMessages: unreadMessages)
-        let cellViewModel = ChatCellViewModel(chatData: cellData)
+        let cellViewModel = ChatCellViewModel(dcContext: context, chatData: cellData)
         cell.updateCell(cellViewModel: cellViewModel)
     }