Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Privitty.framework/Privitty
Binary file not shown.
Binary file modified Privitty.framework/_CodeSignature/CodeDirectory
Binary file not shown.
Binary file modified Privitty.framework/_CodeSignature/CodeRequirements-1
Binary file not shown.
Binary file modified Privitty.framework/_CodeSignature/CodeSignature
Binary file not shown.
19 changes: 8 additions & 11 deletions deltachat-ios/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@
self.launchOptions = launchOptions
continueDidFinishLaunchingWithOptions()

if !PrvContext.shared.initialize() {
logger.error("APP DELEGATE: Failed to initialize Privitty Core")
}

// Verify Poppins fonts are loaded
#if DEBUG
logger.info("🔤 Verifying custom fonts...")
Expand Down Expand Up @@ -145,7 +141,7 @@
relayHelper = RelayHelper.setup(dcAccounts.getSelected())
appCoordinator = AppCoordinator(window: window, dcAccounts: dcAccounts)
locationManager = LocationManager(dcAccounts: dcAccounts)
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)

Check warning on line 144 in deltachat-ios/AppDelegate.swift

View workflow job for this annotation

GitHub Actions / build

'setMinimumBackgroundFetchInterval' was deprecated in iOS 13.0: Use a BGAppRefreshTask in the BackgroundTasks framework instead
notificationManager = NotificationManager(dcAccounts: dcAccounts)
setStockTranslations()
dcAccounts.startIo()
Expand Down Expand Up @@ -189,13 +185,9 @@
registerForNotifications()
prepopulateWidget()

// Ensure Privitty user is selected after account is configured
// Initialize Privitty for existing accounts (e.g., after backup restore)
let dcContext = dcAccounts.getSelected()
if PrvContext.shared.switchProfile(for: dcContext) {
logger.info("Privitty profile aligned with selected account on app launch")
} else {
logger.error("Failed to align Privitty profile on app launch")
}
PrvContext.shared.initializePrivittyForSelectedAccount(dcContext: dcContext)
}

launchOptions = nil
Expand Down Expand Up @@ -603,8 +595,13 @@
if dcAccounts.getSelected().isConfigured() {
appCoordinator.resetTabBarRootViewControllers()

// Ensure Privitty user is selected after account reload
// Initialize Privitty if not already initialized (e.g., after backup restore)
let dcContext = dcAccounts.getSelected()
if !PrvContext.shared.isInitialized() {
PrvContext.shared.initializePrivittyForSelectedAccount(dcContext: dcContext)
}

// Ensure Privitty user is selected after account reload
if PrvContext.shared.switchProfile(for: dcContext) {
logger.info("Privitty profile aligned with selected account on context reload")
} else {
Expand Down
12 changes: 9 additions & 3 deletions deltachat-ios/Chat/ChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1473,12 +1473,18 @@
}

private func handleAddAttachment() {
// Check if Privitty is initialized
// Try to initialize Privitty if not already initialized
if !PrvContext.shared.isInitialized() {
logger.info("Privitty not initialized, attempting to initialize for current account")
PrvContext.shared.initializePrivittyForSelectedAccount(dcContext: dcContext)
}

// Check if Privitty is initialized after attempting initialization
guard PrvContext.shared.isInitialized() else {
logger.error("Privitty not initialized")
logger.error("Privitty not initialized and initialization failed")
let alert = UIAlertController(
title: "Error",
message: "Privitty is not initialized",
message: "Privitty is not initialized. Please restart the app.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
Expand Down Expand Up @@ -1546,7 +1552,7 @@
}

private func sendPrivittyHandshake() {
let chat = dcContext.getChat(chatId: chatId)

Check warning on line 1555 in deltachat-ios/Chat/ChatViewController.swift

View workflow job for this annotation

GitHub Actions / build

initialization of immutable value 'chat' was never used; consider replacing with assignment to '_' or removing it

logger.info("Initiating Privitty handshake for chat: \(chatId)")

Expand Down Expand Up @@ -3840,4 +3846,4 @@
focusInputTextView()
FileHelper.deleteFileAsync(atPath: url.relativePath)
}
}

Check warning on line 3849 in deltachat-ios/Chat/ChatViewController.swift

View workflow job for this annotation

GitHub Actions / build

File Length Violation: File should contain 2000 lines or less excluding comments and whitespaces: currently contains 2467 (file_length)
Original file line number Diff line number Diff line change
Expand Up @@ -301,27 +301,15 @@ class InstantOnboardingViewController: UIViewController {
appDelegate.registerForNotifications()
appDelegate.reloadDcContext()
appDelegate.prepopulateWidget()

// Initialize Privitty for the newly created account
let dcContext = self.dcAccounts.getSelected()
PrvContext.shared.initializePrivittyForSelectedAccount(dcContext: dcContext)
}
}

private func storeImageAndName() {
dcContext.displayname = contentView?.nameTextField.text

// Create/switch Privitty user profile.
if let username = contentView?.nameTextField.text, !username.isEmpty {
// Get user email from Delta Chat config (like Android Java code)
let selfEmail = dcContext.getConfig("configured_addr") ?? ""

logger.info("Creating Privitty user: \(username)")
logger.debug("Email: \(selfEmail)")

let success = PrvContext.shared.createOrSwitchUser(username: username, useremail: selfEmail, userid: "")
if success {
logger.info("Privitty user created/switched successfully: \(username)")
} else {
logger.error("Failed to create/switch Privitty user: \(username)")
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ class WelcomeViewController: UIViewController {

private func handleBackupRestoreSuccess() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }

// Initialize Privitty for the restored account FIRST (before reloadDcContext)
// This ensures Privitty is initialized before any code tries to use it
let dcContext = dcAccounts.getSelected()
PrvContext.shared.initializePrivittyForSelectedAccount(dcContext: dcContext)

appDelegate.registerForNotifications()
appDelegate.reloadDcContext()
appDelegate.prepopulateWidget()
Expand Down
5 changes: 5 additions & 0 deletions deltachat-ios/Controller/BackupTransferViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ class BackupTransferViewController: UIViewController {
self.navigationItem.leftBarButtonItem = nil // "Cancel" no longer fits as things are done
statusLineText = String.localized("done") + " 😀"
hideQrCode = true

// Initialize Privitty for the restored account (no app restart needed)
// This handles the case when BackupTransferViewController is used for receiving
let dcContext = self.dcAccounts.getSelected()
PrvContext.shared.initializePrivittyForSelectedAccount(dcContext: dcContext)
}

if let statusLineText = statusLineText {
Expand Down
8 changes: 8 additions & 0 deletions deltachat-ios/DC/DcContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -791,4 +791,12 @@ public class DcContext {

setConfig("proxy_url", allProxies)
}

/// Get the blob directory path for this account
public func getBlobdir() -> String? {
guard let cString = dc_get_blobdir(contextPointer) else { return nil }
let swiftString = String(cString: cString)
dc_str_unref(cString)
return swiftString.isEmpty ? nil : swiftString
}
}
102 changes: 101 additions & 1 deletion deltachat-ios/DC/PrvContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,106 @@ public class PrvContext {
core = nil
}

/// Initialize Privitty for the selected account if a Privitty database exists.
/// This is called during app startup to initialize Privitty for existing accounts
/// (e.g., after backup restore).
/// Can also be called after backup restore to initialize Privitty without app restart.
public func initializePrivittyForSelectedAccount(dcContext: DcContext) {
guard dcContext.isOpen() else {
logger.debug("No selected account available for Privitty initialization")
return
}

// Check if account is configured
guard dcContext.isConfigured() else {
logger.debug("Selected account is not configured, skipping Privitty initialization")
return
}

// Get account directory path (parent of blobdir)
guard let blobdirPath = dcContext.getBlobdir(), !blobdirPath.isEmpty else {
logger.warning("Blobdir path is null or empty, cannot initialize Privitty")
return
}

let blobdirURL = URL(fileURLWithPath: blobdirPath)
guard let accountDir = blobdirURL.deletingLastPathComponent().pathComponents.isEmpty ? nil : blobdirURL.deletingLastPathComponent() else {
logger.warning("Account directory does not exist: \(blobdirPath)")
return
}

let accountDirPath = accountDir.path
let fileManager = FileManager.default

guard fileManager.fileExists(atPath: accountDirPath) else {
logger.warning("Account directory does not exist: \(accountDirPath)")
return
}

// Check if .privitty/dbase/ directory exists and has database files
let privittyDbaseDir = accountDir.appendingPathComponent(".privitty").appendingPathComponent("dbase")
let privittyDbasePath = privittyDbaseDir.path

var hasExistingDatabase = false
if fileManager.fileExists(atPath: privittyDbasePath),
let contents = try? fileManager.contentsOfDirectory(atPath: privittyDbasePath) {
// Look for any prv*.db file
let dbFiles = contents.filter { $0.hasPrefix("prv") && $0.hasSuffix(".db") }
hasExistingDatabase = !dbFiles.isEmpty
}

if hasExistingDatabase {
logger.info("Found Privitty database, initializing with account path: \(accountDirPath)")
} else {
logger.info("No existing Privitty database found, initializing Privitty for new account at: \(accountDirPath)")
}

// Shutdown existing core if initialized
if isInitialized() {
shutdown()
}

guard let newCore = PrivittyCore(baseDirectory: accountDirPath) else {
logger.error("Failed to create PrivittyCore object")
return
}

let isInit = newCore.isInitialized()
guard isInit else {
logger.error("Core object created but not initialized")
return
}

core = newCore

if let versionResponse = newCore.getVersion(),
let success = versionResponse["success"] as? Int, success == 1,
let data = versionResponse["data"] as? [String: Any] {
if let coreVersion = data["core_version"] as? String {
logger.info("Privitty initialized successfully - Version: \(coreVersion)")
}
} else {
logger.warning("Failed to get or parse version response")
}

// Switch to the account's profile
let userName = dcContext.displayname ?? dcContext.getConfig("configured_addr") ?? ""
let selfEmail = dcContext.getConfig("configured_addr") ?? ""
let selfContact = dcContext.getContact(id: Int(DC_CONTACT_ID_SELF))
let userId = String(selfContact.id)

if !userName.isEmpty {
let switched = createOrSwitchUser(username: userName, useremail: selfEmail, userid: userId)
if switched {
logger.info("Privitty profile switched to: \(userName) (email: \(selfEmail))")
} else {
logger.warning("Privitty profile switch failed for: \(userName)")
}
} else {
logger.warning("Username is null or empty, cannot switch Privitty profile")
}
}

// MARK: - Chat Room Management
/// Delete a chat room from Privitty database
public func deleteChatRoom(chatId: String) -> (success: Bool, message: String?, error: String?) {
Expand Down Expand Up @@ -166,7 +266,7 @@ public class PrvContext {
/// Get all available users
public func getAvailableUsers() -> [String] {
guard let core = getCore() else { return [] }
guard let users = core.getAvailableUsers() as? [String] else { return [] }
guard let users = core.getAvailableUsers() else { return [] }
return users
}

Expand Down
Loading