diff --git a/Privitty.framework.zip b/Privitty.framework.zip new file mode 100644 index 000000000..cf74b719b Binary files /dev/null and b/Privitty.framework.zip differ diff --git a/Privitty.framework/Privitty b/Privitty.framework/Privitty index e73904752..c96320030 100644 Binary files a/Privitty.framework/Privitty and b/Privitty.framework/Privitty differ diff --git a/Privitty.framework/_CodeSignature/CodeDirectory b/Privitty.framework/_CodeSignature/CodeDirectory index ee1433bfd..136c429bc 100644 Binary files a/Privitty.framework/_CodeSignature/CodeDirectory and b/Privitty.framework/_CodeSignature/CodeDirectory differ diff --git a/Privitty.framework/_CodeSignature/CodeRequirements-1 b/Privitty.framework/_CodeSignature/CodeRequirements-1 index dec6abb8a..c23cfb830 100644 Binary files a/Privitty.framework/_CodeSignature/CodeRequirements-1 and b/Privitty.framework/_CodeSignature/CodeRequirements-1 differ diff --git a/Privitty.framework/_CodeSignature/CodeSignature b/Privitty.framework/_CodeSignature/CodeSignature index 1907fcfe2..9a241270a 100644 Binary files a/Privitty.framework/_CodeSignature/CodeSignature and b/Privitty.framework/_CodeSignature/CodeSignature differ diff --git a/deltachat-ios.xcodeproj/project.pbxproj b/deltachat-ios.xcodeproj/project.pbxproj index f9a3207c3..b09c6c8dc 100644 --- a/deltachat-ios.xcodeproj/project.pbxproj +++ b/deltachat-ios.xcodeproj/project.pbxproj @@ -183,6 +183,7 @@ AE6EC5242497663200A400E4 /* UIImageView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6EC5232497663200A400E4 /* UIImageView+Extensions.swift */; }; AE728F15229D5C390047565B /* PhotoPickerAlertAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE728F14229D5C390047565B /* PhotoPickerAlertAction.swift */; }; AE76E5EE242BF2EA003CF461 /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE76E5ED242BF2EA003CF461 /* WelcomeViewController.swift */; }; + F4FA10E83EA041329C24AAF6 /* ServerSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D436D0085A422CB2AA0795 /* ServerSelectionViewController.swift */; }; AE77838F23E4276D0093EABD /* ContactCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE77838E23E4276D0093EABD /* ContactCellViewModel.swift */; }; AE8519EA2272FDCA00ED86F0 /* DeviceContactsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE8519E92272FDCA00ED86F0 /* DeviceContactsHandler.swift */; }; AE851AC5227C755A00ED86F0 /* Protocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC4227C755A00ED86F0 /* Protocols.swift */; }; @@ -541,6 +542,7 @@ AE6EC5232497663200A400E4 /* UIImageView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+Extensions.swift"; sourceTree = ""; }; AE728F14229D5C390047565B /* PhotoPickerAlertAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerAlertAction.swift; sourceTree = ""; }; AE76E5ED242BF2EA003CF461 /* WelcomeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeViewController.swift; sourceTree = ""; }; + 37D436D0085A422CB2AA0795 /* ServerSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewController.swift; sourceTree = ""; }; AE77838E23E4276D0093EABD /* ContactCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactCellViewModel.swift; sourceTree = ""; }; AE8519E92272FDCA00ED86F0 /* DeviceContactsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceContactsHandler.swift; sourceTree = ""; }; AE851AC4227C755A00ED86F0 /* Protocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Protocols.swift; sourceTree = ""; }; @@ -1077,6 +1079,7 @@ children = ( D8A0729E2BED0FC8001A4C7C /* Instand Onboarding */, AE76E5ED242BF2EA003CF461 /* WelcomeViewController.swift */, + 37D436D0085A422CB2AA0795 /* ServerSelectionViewController.swift */, AEE56D752253431E007DC082 /* AccountSetupController.swift */, 30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */, AE18F293228C602A0007B1BE /* SecuritySettingsController.swift */, @@ -1880,6 +1883,7 @@ 5F785F6E2CB9344F003FFFB9 /* ReusableCellProtocol.swift in Sources */, D8C1B0DD2CE7421C00C233A7 /* ShareProxyViewController.swift in Sources */, AE76E5EE242BF2EA003CF461 /* WelcomeViewController.swift in Sources */, + F4FA10E83EA041329C24AAF6 /* ServerSelectionViewController.swift in Sources */, 3052C60A253F082E007D13EA /* MessageLabelDelegate.swift in Sources */, 2FB219D92EF167CB00A7E8A8 /* FileAccessControlViewController.swift in Sources */, AE0AA9562478191900D42A7F /* GridCollectionViewFlowLayout.swift in Sources */, @@ -2353,7 +2357,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 142; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 8Y86453UA8; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -2374,7 +2378,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 2.11.0; + MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -2420,7 +2424,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 142; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 8Y86453UA8; ENABLE_NS_ASSERTIONS = NO; @@ -2435,7 +2439,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 2.11.0; + MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/deltachat-ios/AppDelegate.swift b/deltachat-ios/AppDelegate.swift index b5ae80891..1c23a0e24 100644 --- a/deltachat-ios/AppDelegate.swift +++ b/deltachat-ios/AppDelegate.swift @@ -76,10 +76,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD 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...") @@ -145,7 +141,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD relayHelper = RelayHelper.setup(dcAccounts.getSelected()) appCoordinator = AppCoordinator(window: window, dcAccounts: dcAccounts) locationManager = LocationManager(dcAccounts: dcAccounts) - UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum) + // Note: setMinimumBackgroundFetchInterval is deprecated in iOS 13.0+ + // Background fetch is handled by BackgroundTasks framework in modern iOS + if #available(iOS 13.0, *) { + // Background fetch is managed by BackgroundTasks framework + } else { + UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum) + } notificationManager = NotificationManager(dcAccounts: dcAccounts) setStockTranslations() dcAccounts.startIo() @@ -189,13 +191,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD 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 @@ -603,8 +601,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD 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 { @@ -641,29 +644,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD let chatContext = dcContext.getChat(chatId: chatId) // Check if message is encrypted and not a contact request - logger.debug("Privitty: Message received") + logger.info("Privitty: Message received") if chatContext.isProtected && !chatContext.isContactRequest { - logger.debug("Privitty: Protected message received") + logger.info("Privitty: Protected message received") if let messageText = dcMsg.text, PrvContext.shared.isPrivittyMessage(messageText) { - logger.debug("Privitty: Message detected for chatId: \(chatId)") + logger.info("Privitty: Message detected for chatId: \(chatId)") // Process the Privitty message let result = PrvContext.shared.processIncomingMessage(chatId: chatId, pdu: messageText, direction: "incoming") - logger.debug("Privitty: Result: \(result)") + logger.info("Privitty: Result: \(result)") if result.success { logger.info("Privitty: Message processed successfully") // Parse response structure: data.data.pdu and data.data.chat_id (matches Android line 206) if let data = result.data { - logger.debug("Privitty: Response data exists, keys: \(Array(data.keys))") + logger.info("Privitty: Response data exists, keys: \(Array(data.keys))") // Check if response has "data" key (matches Android: responseJson.has("data")) if let dataDataJson = data["data"] as? [String: Any] { - logger.debug("Privitty: Found data.data, keys: \(Array(dataDataJson.keys))") + logger.info("Privitty: Found data.data, keys: \(Array(dataDataJson.keys))") // Check if dataDataJson has "data" key (matches Android: dataDataJson.has("data")) // Try data.data.data first (Android structure), then fall back to data.data (iOS structure) @@ -672,19 +675,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if let nestedData = dataDataJson["data"] as? [String: Any] { // Triple nested: data.data.data (Android structure) dataJson = nestedData - logger.debug("Privitty: Found data.data.data (triple nested - Android structure)") + logger.info("Privitty: Found data.data.data (triple nested - Android structure)") } else if dataDataJson["pdu"] != nil { // Double nested: data.data (iOS structure - pdu and chat_id are directly here) dataJson = dataDataJson - logger.debug("Privitty: Using data.data directly (double nested - iOS structure)") + logger.info("Privitty: Using data.data directly (double nested - iOS structure)") } if let dataJson = dataJson { - logger.debug("Privitty: Processing dataJson, keys: \(Array(dataJson.keys))") + logger.info("Privitty: Processing dataJson, keys: \(Array(dataJson.keys))") // Check if dataJson has "pdu" key (matches Android: dataJson.has("pdu")) if let pdu = dataJson["pdu"] as? String { - logger.debug("Privitty: Found PDU, size: \(pdu.count)") + logger.info("Privitty: Found PDU, size: \(pdu.count)") // Extract chat_id from response (matches Android: dataJson.has("chat_id")) // Note: chat_id might be Int or String, handle both cases @@ -701,7 +704,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD let msg = dcContext.newMessage(viewType: DC_MSG_TEXT) msg.text = pdu dcContext.sendMessage(chatId: puntChatId, message: msg) - logger.debug("Privitty: Privitty PDU sent - chatId: \(chatId), puntChatId: \(puntChatId)") + logger.info("Privitty: Privitty PDU sent - chatId: \(chatId), puntChatId: \(puntChatId)") } else { logger.error("Privitty: chat ID is missing or invalid for the requested PDU") logger.error("Privitty: chat_id value: \(String(describing: dataJson["chat_id"])), type: \(type(of: dataJson["chat_id"]))") @@ -725,7 +728,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD logger.error("Privitty: Failed to process message: \(result.error ?? "Unknown error")") } } else { - logger.debug("Privitty: Not a Privitty message") + logger.info("Privitty: Not a Privitty message") } } } diff --git a/deltachat-ios/Chat/ChatViewController.swift b/deltachat-ios/Chat/ChatViewController.swift index d993feb4b..a108dc324 100644 --- a/deltachat-ios/Chat/ChatViewController.swift +++ b/deltachat-ios/Chat/ChatViewController.swift @@ -1473,12 +1473,18 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { } 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)) @@ -1546,7 +1552,7 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { } private func sendPrivittyHandshake() { - let chat = dcContext.getChat(chatId: chatId) + _ = dcContext.getChat(chatId: chatId) logger.info("Initiating Privitty handshake for chat: \(chatId)") @@ -1677,7 +1683,7 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { self?.present(errorAlert, animated: true) } } else { - logger.debug("Waiting for handshake... attempt \(attemptCount)/\(maxAttempts)") + logger.info("Waiting for handshake... attempt \(attemptCount)/\(maxAttempts)") } } } @@ -1989,8 +1995,8 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { } logger.info("Privitty: Encrypting file before sending") - logger.debug("Privitty: File: \(filePath)") - logger.debug("Privitty: Original filename: \(originalFileName)") + logger.info("Privitty: File: \(filePath)") + logger.info("Privitty: Original filename: \(originalFileName)") let encryptionResult = PrvContext.shared.requestFileEncryption( filePath: filePath, @@ -2009,8 +2015,8 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { let displayFileName = originalFileName + ".prv" logger.info("Privitty: File encrypted successfully!") - logger.debug("Privitty: Encrypted file: \(prvFileName)") - logger.debug("Privitty: Display name: \(displayFileName)") + logger.info("Privitty: Encrypted file: \(prvFileName)") + logger.info("Privitty: Display name: \(displayFileName)") // Store one-time key to send after message is sent self.pendingOneTimeKey = oneTimeKey @@ -2069,7 +2075,7 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { private func sendPendingOneTimeKey() { guard let oneTimeKey = pendingOneTimeKey else { - logger.debug("Privitty: No pending one-time key to send") + logger.info("Privitty: No pending one-time key to send") return } @@ -2902,22 +2908,22 @@ extension ChatViewController: BaseMessageCellDelegate { /// Matches Android's hasPendingForwardedRequests() method private func hasPendingForwardedRequests(for message: DcMsg) -> Bool { guard let filePath = message.file, filePath.lowercased().hasSuffix(".prv") else { - logger.debug("File Access: hasPendingForwardedRequests - not a .prv file") + logger.info("File Access: hasPendingForwardedRequests - not a .prv file") return false } guard message.isFromCurrentSender else { - logger.debug("File Access: hasPendingForwardedRequests - not outgoing message") + logger.info("File Access: hasPendingForwardedRequests - not outgoing message") return false } let chatIdString = String(message.chatId) - logger.debug("File Access: ========================================") - logger.debug("File Access: Checking for pending forwarded requests") - logger.debug("File Access: ChatId: \(chatIdString)") - logger.debug("File Access: FilePath: \(filePath)") - logger.debug("File Access: ========================================") + logger.info("File Access: ========================================") + logger.info("File Access: Checking for pending forwarded requests") + logger.info("File Access: ChatId: \(chatIdString)") + logger.info("File Access: FilePath: \(filePath)") + logger.info("File Access: ========================================") let result = PrvContext.shared.getFileAccessStatusList(chatId: chatIdString, filePath: filePath) @@ -2934,7 +2940,7 @@ extension ChatViewController: BaseMessageCellDelegate { return false } - logger.debug("File Access: Response received - checking for pending requests") + logger.info("File Access: Response received - checking for pending requests") var pendingCount = 0 @@ -2944,7 +2950,7 @@ extension ChatViewController: BaseMessageCellDelegate { let contactName = sharedInfo["contact_name"] as? String ?? "unknown" let contactId = sharedInfo["contact_id"] as? String ?? "unknown" - logger.debug("File Access: Shared_info - User: \(contactName) (ID: \(contactId)), Status: \(status)") + logger.info("File Access: Shared_info - User: \(contactName) (ID: \(contactId)), Status: \(status)") // Only check for WAITING_OWNER_ACTION (matches Android) if status == "waiting_owner_action" { @@ -2952,19 +2958,19 @@ extension ChatViewController: BaseMessageCellDelegate { pendingCount += 1 } } else { - logger.debug("File Access: No shared_info in response") + logger.info("File Access: No shared_info in response") } // Check forwarded_list for pending requests (only WAITING_OWNER_ACTION) if let forwardedList = fileData["forwarded_list"] as? [[String: Any]], !forwardedList.isEmpty { - logger.debug("File Access: Checking forwarded_list with \(forwardedList.count) users") + logger.info("File Access: Checking forwarded_list with \(forwardedList.count) users") for (index, forwardedInfo) in forwardedList.enumerated() { let status = (forwardedInfo["status"] as? String ?? "").lowercased() let contactName = forwardedInfo["contact_name"] as? String ?? "unknown" let contactId = forwardedInfo["contact_id"] as? String ?? "unknown" - logger.debug("File Access: Forwarded[\(index)] - User: \(contactName) (ID: \(contactId)), Status: \(status)") + logger.info("File Access: Forwarded[\(index)] - User: \(contactName) (ID: \(contactId)), Status: \(status)") // Only check for WAITING_OWNER_ACTION (matches Android) if status == "waiting_owner_action" { @@ -2973,12 +2979,12 @@ extension ChatViewController: BaseMessageCellDelegate { } } } else { - logger.debug("File Access: No forwarded_list or empty forwarded_list") + logger.info("File Access: No forwarded_list or empty forwarded_list") } - logger.debug("File Access: ========================================") - logger.debug("File Access: Total pending requests found: \(pendingCount)") - logger.debug("File Access: ========================================") + logger.info("File Access: ========================================") + logger.info("File Access: Total pending requests found: \(pendingCount)") + logger.info("File Access: ========================================") return pendingCount > 0 } @@ -3062,9 +3068,9 @@ extension ChatViewController: BaseMessageCellDelegate { let absoluteFilePath = fileURL.path logger.info("Calling prvInitForwardAccessRequest - chatId: \(chatIdString)") - logger.debug("File path: \(absoluteFilePath)") - logger.debug("Message ID: \(message.id), Chat ID: \(message.chatId)") - logger.debug("Is forwarded: \(message.isForwarded)") + logger.info("File path: \(absoluteFilePath)") + logger.info("Message ID: \(message.id), Chat ID: \(message.chatId)") + logger.info("Is forwarded: \(message.isForwarded)") // Call processInitForwardAccessRequest (matches Android prvInitForwardAccessRequest) let result = PrvContext.shared.processInitForwardAccessRequest(chatId: chatIdString, filePath: absoluteFilePath) @@ -3102,7 +3108,7 @@ extension ChatViewController: BaseMessageCellDelegate { // Try with original file path if absolute path failed (matches Android retry logic) if absoluteFilePath != encryptedFilePath { - logger.debug("Retrying with original file path format") + logger.info("Retrying with original file path format") let retryResult = PrvContext.shared.processInitForwardAccessRequest(chatId: chatIdString, filePath: encryptedFilePath) if retryResult.success, let pdu = retryResult.pdu { @@ -3173,7 +3179,7 @@ extension ChatViewController: BaseMessageCellDelegate { // Check if message is forwarded and call appropriate decryption method (matches Android line 1730-1734) let isForwarded = message.isForwarded - logger.debug("Privitty: Decrypting file - isForwarded: \(isForwarded)") + logger.info("Privitty: Decrypting file - isForwarded: \(isForwarded)") let result: (success: Bool, data: [String: Any]?, error: String?) if isForwarded { @@ -3229,7 +3235,7 @@ extension ChatViewController: BaseMessageCellDelegate { // Check if message is forwarded and call appropriate method (matches Android line 1475-1480) let isForwarded = message.isForwarded - logger.debug("Privitty: Requesting file access for chatId: \(chatIdString), file: \(filePath), isForwarded: \(isForwarded)") + logger.info("Privitty: Requesting file access for chatId: \(chatIdString), file: \(filePath), isForwarded: \(isForwarded)") let result: (success: Bool, data: [String: Any]?, message: String?, error: String?) if isForwarded { diff --git a/deltachat-ios/Controller/AccountSetup/Instand Onboarding/InstantOnboardingViewController.swift b/deltachat-ios/Controller/AccountSetup/Instand Onboarding/InstantOnboardingViewController.swift index ba6f978af..9d0ed46c0 100644 --- a/deltachat-ios/Controller/AccountSetup/Instand Onboarding/InstantOnboardingViewController.swift +++ b/deltachat-ios/Controller/AccountSetup/Instand Onboarding/InstantOnboardingViewController.swift @@ -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)") - } - } } } diff --git a/deltachat-ios/Controller/AccountSetup/ServerSelectionViewController.swift b/deltachat-ios/Controller/AccountSetup/ServerSelectionViewController.swift new file mode 100644 index 000000000..93e30e1d8 --- /dev/null +++ b/deltachat-ios/Controller/AccountSetup/ServerSelectionViewController.swift @@ -0,0 +1,199 @@ +import UIKit +import DcCore + +class ServerSelectionViewController: UIViewController { + + private let dcAccounts: DcAccounts + private var dcContext: DcContext + private var qrCodeReader: QrCodeReaderController? + + // MARK: - UI Components + + private lazy var containerView: UIView = { + let view = UIView() + view.backgroundColor = .white + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.text = "Get Started" + label.font = AppFont.semiBold(size: 28) + label.textColor = UIColor(hexString: "020202") + label.textAlignment = .center + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private lazy var subtitleLabel: UILabel = { + let label = UILabel() + label.text = "Choose how you want to connect" + label.font = AppFont.regular(size: 16) + label.textColor = UIColor(hexString: "4F4F4F") + label.textAlignment = .center + label.numberOfLines = 0 + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private lazy var scanQRButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("Scan Invitation Code", for: .normal) + button.titleLabel?.font = AppFont.medium(size: 16) + button.setTitleColor(.white, for: .normal) + button.backgroundColor = UIColor(hexString: "6750A4") + button.layer.cornerRadius = 30 + button.clipsToBounds = true + button.addTarget(self, action: #selector(scanQRCodeTapped), for: .touchUpInside) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + #if DEBUG + private lazy var connectToPrivittyButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("Connect to Privitty", for: .normal) + button.titleLabel?.font = AppFont.medium(size: 16) + button.setTitleColor(UIColor(hexString: "6750A4"), for: .normal) + button.backgroundColor = .white + button.layer.cornerRadius = 30 + button.layer.borderWidth = 1.5 + button.layer.borderColor = UIColor(hexString: "6750A4").cgColor + button.clipsToBounds = true + button.addTarget(self, action: #selector(connectToPrivittyTapped), for: .touchUpInside) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + #endif + + // MARK: - Initialization + + init(dcAccounts: DcAccounts) { + self.dcAccounts = dcAccounts + self.dcContext = dcAccounts.getSelected() + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Lifecycle + + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + setupConstraints() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + navigationController?.setNavigationBarHidden(false, animated: animated) + } + + // MARK: - Setup + + private func setupUI() { + view.backgroundColor = .white + title = "Get Started" + + view.addSubview(containerView) + containerView.addSubview(titleLabel) + containerView.addSubview(subtitleLabel) + containerView.addSubview(scanQRButton) + + #if DEBUG + containerView.addSubview(connectToPrivittyButton) + #endif + } + + private func setupConstraints() { + NSLayoutConstraint.activate([ + // Container + containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -40), + containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24), + containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24), + + // Title + titleLabel.topAnchor.constraint(equalTo: containerView.topAnchor), + titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + titleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + + // Subtitle + subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 12), + subtitleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + subtitleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + + // Scan QR Button + scanQRButton.topAnchor.constraint(equalTo: subtitleLabel.bottomAnchor, constant: 48), + scanQRButton.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + scanQRButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + scanQRButton.heightAnchor.constraint(equalToConstant: 60), + ]) + + #if DEBUG + // Connect to Privitty Button (only in DEBUG) + NSLayoutConstraint.activate([ + connectToPrivittyButton.topAnchor.constraint(equalTo: scanQRButton.bottomAnchor, constant: 16), + connectToPrivittyButton.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + connectToPrivittyButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + connectToPrivittyButton.heightAnchor.constraint(equalToConstant: 60), + connectToPrivittyButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) + ]) + #else + // If not DEBUG, scan button is the last element + NSLayoutConstraint.activate([ + scanQRButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) + ]) + #endif + } + + // MARK: - Actions + + @objc private func scanQRCodeTapped() { + let qrReader = QrCodeReaderController(title: "Scan Invitation Code") + qrReader.delegate = self + qrCodeReader = qrReader + navigationController?.pushViewController(qrReader, animated: true) + } + + #if DEBUG + @objc private func connectToPrivittyTapped() { + // Navigate to InstantOnboardingViewController with default server (chat.privittytech.com) + let controller = InstantOnboardingViewController(dcAccounts: dcAccounts) + navigationController?.pushViewController(controller, animated: true) + } + #endif +} + +// MARK: - QrCodeReaderDelegate + +extension ServerSelectionViewController: QrCodeReaderDelegate { + func handleQrCode(_ qrCode: String) { + let lot = dcContext.checkQR(qrCode: qrCode) + + // Check if this is a valid invitation code (LOGIN or ACCOUNT QR) + if lot.state == DC_QR_LOGIN || lot.state == DC_QR_ACCOUNT { + // Navigate to InstantOnboardingViewController with the scanned server + qrCodeReader?.stopSession() + navigationController?.popViewController(animated: false) + + let controller = InstantOnboardingViewController(dcAccounts: dcAccounts, qrCodeData: qrCode) + navigationController?.pushViewController(controller, animated: true) + } else { + // Show error for invalid QR codes + let alert = UIAlertController( + title: "Invalid Invitation Code", + message: "This QR code is not a valid server invitation. Please scan a valid invitation code from your server.", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] _ in + self?.qrCodeReader?.startSession() + }) + qrCodeReader?.present(alert, animated: true) + } + } +} + diff --git a/deltachat-ios/Controller/AccountSetup/WelcomeViewController.swift b/deltachat-ios/Controller/AccountSetup/WelcomeViewController.swift index 661855068..29e459c27 100644 --- a/deltachat-ios/Controller/AccountSetup/WelcomeViewController.swift +++ b/deltachat-ios/Controller/AccountSetup/WelcomeViewController.swift @@ -14,7 +14,7 @@ class WelcomeViewController: UIViewController { let view = WelcomeContentView() view.onSignUp = { [weak self] in guard let self else { return } - let controller = InstantOnboardingViewController(dcAccounts: dcAccounts) + let controller = ServerSelectionViewController(dcAccounts: dcAccounts) navigationController?.pushViewController(controller, animated: true) } view.onLogIn = { [weak self] in @@ -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() diff --git a/deltachat-ios/Controller/BackupTransferViewController.swift b/deltachat-ios/Controller/BackupTransferViewController.swift index 07e6455b2..a06c3ccde 100644 --- a/deltachat-ios/Controller/BackupTransferViewController.swift +++ b/deltachat-ios/Controller/BackupTransferViewController.swift @@ -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 { diff --git a/deltachat-ios/Controller/FileAccessControlViewController.swift b/deltachat-ios/Controller/FileAccessControlViewController.swift index 94c47dfeb..c5dbc9c75 100644 --- a/deltachat-ios/Controller/FileAccessControlViewController.swift +++ b/deltachat-ios/Controller/FileAccessControlViewController.swift @@ -137,7 +137,7 @@ public class FileAccessControlViewController: UIViewController { // MARK: - Data Loading private func loadAccessData() { - logger.debug("FileAccessControl: Loading access data for chatId=\(chatId), filePath=\(filePath)") + logger.info("FileAccessControl: Loading access data for chatId=\(chatId), filePath=\(filePath)") DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } @@ -147,7 +147,7 @@ public class FileAccessControlViewController: UIViewController { DispatchQueue.main.async { if result.success, let data = result.data { - logger.debug("FileAccessControl: Successfully loaded access data") + logger.info("FileAccessControl: Successfully loaded access data") self.processFileAccessData(data) } else { logger.error("FileAccessControl: Failed to load access data: \(result.error ?? "Unknown error")") @@ -230,7 +230,7 @@ public class FileAccessControlViewController: UIViewController { // MARK: - Actions private func showFileAccessBottomSheet(for requestee: FileAccessRequestee) { - logger.debug("FileAccessControl: Showing bottom sheet for \(requestee.name)") + logger.info("FileAccessControl: Showing bottom sheet for \(requestee.name)") let bottomSheet = FileAccessRequestBottomSheet( requestee: requestee, @@ -330,7 +330,7 @@ extension FileAccessControlViewController: UITableViewDelegate { if status == "waiting_owner_action" { showFileAccessBottomSheet(for: requestee) } else { - logger.debug("FileAccessControl: Status is \(requestee.status), not showing access control form") + logger.info("FileAccessControl: Status is \(requestee.status), not showing access control form") // Could optionally show an alert here explaining why they can't take action } } diff --git a/deltachat-ios/Controller/FileAccessRequestBottomSheet.swift b/deltachat-ios/Controller/FileAccessRequestBottomSheet.swift index 2eb2830b6..1236bb8f3 100644 --- a/deltachat-ios/Controller/FileAccessRequestBottomSheet.swift +++ b/deltachat-ios/Controller/FileAccessRequestBottomSheet.swift @@ -291,12 +291,12 @@ public class FileAccessRequestBottomSheet: UIViewController { let isRelayForwardRequest = self.requestee.isForwarded let relayForwardContactId = self.requestee.contactId - logger.debug("FileAccessBottomSheet: Calling prvInitRevertRelayForwardAccessAccept") - logger.debug(" chatId: \(self.chatId)") - logger.debug(" filePath: \(self.filePath)") - logger.debug(" contactId: \(relayForwardContactId)") - logger.debug(" seconds: \(self.selectedSeconds)") - logger.debug(" allowDownload: \(self.allowDownload)") + logger.info("FileAccessBottomSheet: Calling prvInitRevertRelayForwardAccessAccept") + logger.info(" chatId: \(self.chatId)") + logger.info(" filePath: \(self.filePath)") + logger.info(" contactId: \(relayForwardContactId)") + logger.info(" seconds: \(self.selectedSeconds)") + logger.info(" allowDownload: \(self.allowDownload)") // Call Privitty API let result: (success: Bool, pdu: String?, message: String?, error: String?) @@ -361,10 +361,10 @@ public class FileAccessRequestBottomSheet: UIViewController { let relayForwardContactId = self.requestee.contactId let defaultReason = "Access denied by user" - logger.debug("FileAccessBottomSheet: Calling prvInitRevertRelayForwardAccessDenied") - logger.debug(" chatId: \(self.chatId)") - logger.debug(" filePath: \(self.filePath)") - logger.debug(" contactId: \(relayForwardContactId)") + logger.info("FileAccessBottomSheet: Calling prvInitRevertRelayForwardAccessDenied") + logger.info(" chatId: \(self.chatId)") + logger.info(" filePath: \(self.filePath)") + logger.info(" contactId: \(relayForwardContactId)") // Call Privitty API let result: (success: Bool, pdu: String?, message: String?, error: String?) diff --git a/deltachat-ios/DC/DcContext.swift b/deltachat-ios/DC/DcContext.swift index f78e271d4..343eb6c3d 100644 --- a/deltachat-ios/DC/DcContext.swift +++ b/deltachat-ios/DC/DcContext.swift @@ -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 + } } diff --git a/deltachat-ios/DC/PrvContext.swift b/deltachat-ios/DC/PrvContext.swift index 124bc3f74..1e4131281 100644 --- a/deltachat-ios/DC/PrvContext.swift +++ b/deltachat-ios/DC/PrvContext.swift @@ -22,11 +22,11 @@ public class PrvContext { public func initialize() -> Bool { // Check if already initialized if let existingCore = core { - logger.debug("Core object exists, checking if initialized...") + logger.info("Core object exists, checking if initialized...") // Safely check initialization let isInit = existingCore.isInitialized() - logger.debug("Core isInitialized: \(isInit)") + logger.info("Core isInitialized: \(isInit)") if isInit { logger.info("Privitty Core already initialized") @@ -35,7 +35,7 @@ public class PrvContext { } logger.info("Creating new Privitty Core instance...") - logger.debug("Base directory: \(documentsPath)") + logger.info("Base directory: \(documentsPath)") guard let newCore = PrivittyCore(baseDirectory: documentsPath) else { logger.error("Failed to create PrivittyCore object") @@ -44,7 +44,7 @@ public class PrvContext { // Verify it initialized properly let isInit = newCore.isInitialized() - logger.debug("New core isInitialized: \(isInit)") + logger.info("New core isInitialized: \(isInit)") if isInit { // Store the core only if it's initialized @@ -55,7 +55,7 @@ public class PrvContext { let success = versionResponse["success"] as? Int, success == 1, let data = versionResponse["data"] as? [String: Any] { - logger.debug("Raw version response: \(versionResponse)") + logger.info("Raw version response: \(versionResponse)") if let coreVersion = data["core_version"] as? String { logger.info("Privitty Core Version: \(coreVersion)") @@ -96,12 +96,12 @@ public class PrvContext { /// Check if core is initialized public func isInitialized() -> Bool { guard let existingCore = core else { - logger.debug("isInitialized: core is nil") + logger.info("isInitialized: core is nil") return false } let isInit = existingCore.isInitialized() - logger.debug("isInitialized: \(isInit)") + logger.info("isInitialized: \(isInit)") return isInit } @@ -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.info("No selected account available for Privitty initialization") + return + } + + // Check if account is configured + guard dcContext.isConfigured() else { + logger.info("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?) { @@ -125,7 +225,7 @@ public class PrvContext { } logger.info("Deleting chat room for user: \(currentUser)") - logger.debug("Chat ID: \(chatId)") + logger.info("Chat ID: \(chatId)") guard let result = core.deleteChatRoom(withChatId: chatId) else { logger.error("Failed to get delete chat room response") @@ -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 } @@ -180,13 +280,13 @@ public class PrvContext { // Check if user is already selected if let currentUser = core.getCurrentUser(), currentUser == username { - logger.debug("User '\(username)' already selected") + logger.info("User '\(username)' already selected") return true } logger.info("Switching to user profile: \(username)") - logger.debug("User email: \(useremail.isEmpty ? "(none)" : useremail)") - logger.debug("User ID: \(userid.isEmpty ? "(none)" : userid)") + logger.info("User email: \(useremail.isEmpty ? "(none)" : useremail)") + logger.info("User ID: \(userid.isEmpty ? "(none)" : userid)") if core.switchProfile(withUsername: username, useremail: useremail, userid: userid) { logger.info("Successfully switched to user: \(username)") @@ -344,7 +444,7 @@ public class PrvContext { let selfEmail = dcContext.getConfig("configured_addr") ?? "" logger.info("Creating/switching Privitty user: \(userName)") - logger.debug("Email: \(selfEmail)") + logger.info("Email: \(selfEmail)") // Call switchProfile with all three parameters (userid is empty string) if ensureUserSetup(username: userName, useremail: selfEmail, userid: "") { @@ -375,9 +475,9 @@ public class PrvContext { } logger.info("Creating peer add request...") - logger.debug("Current user: \(currentUser)") - logger.debug("Chat ID: \(chatId)") - logger.debug("Peer: \(peerName)") + logger.info("Current user: \(currentUser)") + logger.info("Chat ID: \(chatId)") + logger.info("Peer: \(peerName)") let result = core.createPeerAddRequest( withChatId: chatId, @@ -396,7 +496,7 @@ public class PrvContext { let data = resultDict["data"] as? [String: Any], let pdu = data["pdu"] as? String { logger.info("Peer add request created successfully") - logger.debug("PDU length: \(pdu.count) characters") + logger.info("PDU length: \(pdu.count) characters") return (true, pdu, nil) } else if let error = resultDict["error"] as? String { logger.error("Failed to create peer add request: \(error)") @@ -420,7 +520,7 @@ public class PrvContext { } logger.info("Processing incoming message for user: \(currentUser)") - logger.debug("Chat ID: \(chatId), Direction: \(direction), PDU length: \(pdu.count) characters") + logger.info("Chat ID: \(chatId), Direction: \(direction), PDU length: \(pdu.count) characters") let eventDataJson = """ { @@ -459,7 +559,7 @@ public class PrvContext { } let isProtected = core.isChatProtected(chatId) - logger.debug("Chat \(chatId) protection status: \(isProtected)") + logger.info("Chat \(chatId) protection status: \(isProtected)") return isProtected } @@ -479,11 +579,11 @@ public class PrvContext { // MARK: - File Operations /// Request file encryption - public func requestFileEncryption(filePath: String, - chatId: String, - allowDownload: Bool, - allowForward: Bool, - accessTime: Int) -> (success: Bool, data: [String: Any]?, error: String?) { + public func requestFileEncryption(filePath: String, + chatId: String, + allowDownload: Bool, + allowForward: Bool, + accessTime: Int) -> (success: Bool, data: [String: Any]?, error: String?) { guard let core = getCore() else { logger.error("Cannot encrypt file: Core not initialized") return (false, nil, "Core not initialized") @@ -495,11 +595,11 @@ public class PrvContext { } logger.info("Requesting file encryption for user: \(currentUser)") - logger.debug("File: \(filePath)") - logger.debug("Chat ID: \(chatId)") - logger.debug("Access Time: \(accessTime) seconds") - logger.debug("Allow Download: \(allowDownload)") - logger.debug("Allow Forward: \(allowForward)") + logger.info("File: \(filePath)") + logger.info("Chat ID: \(chatId)") + logger.info("Access Time: \(accessTime) seconds") + logger.info("Allow Download: \(allowDownload)") + logger.info("Allow Forward: \(allowForward)") let result = core.processFileEncryptRequest( withFilePath: filePath, @@ -543,8 +643,8 @@ public class PrvContext { } logger.info("Requesting file decryption for user: \(currentUser)") - logger.debug("PRV file: \(prvFile)") - logger.debug("Chat ID: \(chatId)") + logger.info("PRV file: \(prvFile)") + logger.info("Chat ID: \(chatId)") let result = core.processFileDecryptRequest(withPrvFile: prvFile, chatId: chatId) @@ -588,8 +688,8 @@ public class PrvContext { } logger.info("Requesting forwarded file decryption for user: \(currentUser)") - logger.debug("File ID: \(fileId)") - logger.debug("Forwarder Peer (Chat ID): \(forwarderPeer)") + logger.info("File ID: \(fileId)") + logger.info("Forwarder Peer (Chat ID): \(forwarderPeer)") let result = core.processForwardedFileDecryptRequest(withFileId: fileId, forwarderPeer: forwarderPeer) @@ -628,9 +728,9 @@ public class PrvContext { return (false, nil, "No user selected") } - logger.debug("Requesting file access status for user: \(currentUser)") - logger.debug("File path: \(filePath)") - logger.debug("Chat ID: \(chatId)") + logger.info("Requesting file access status for user: \(currentUser)") + logger.info("File path: \(filePath)") + logger.info("Chat ID: \(chatId)") guard let result = core.getFileAccessStatus(withChatId: chatId, filePath: filePath) else { logger.error("Failed to get file access status response") @@ -675,8 +775,8 @@ public class PrvContext { } logger.info("Requesting file access grant for user: \(currentUser)") - logger.debug("File path: \(filePath)") - logger.debug("Chat ID: \(chatId)") + logger.info("File path: \(filePath)") + logger.info("Chat ID: \(chatId)") guard let result = core.processInitAccessGrantRequest(withChatId: chatId, filePath: filePath) else { logger.error("Failed to get access grant request response") @@ -721,9 +821,9 @@ public class PrvContext { } logger.info("Revoking file access for user: \(currentUser)") - logger.debug("File path: \(filePath)") - logger.debug("Chat ID: \(chatId)") - logger.debug("Reason: \(reason)") + logger.info("File path: \(filePath)") + logger.info("Chat ID: \(chatId)") + logger.info("Reason: \(reason)") guard let result = core.processInitAccessRevokeRequest(withChatId: chatId, filePath: filePath, reason: reason) else { logger.error("Failed to get access revoke response") @@ -770,9 +870,9 @@ public class PrvContext { } logger.info("Accepting access request for user: \(currentUser)") - logger.debug("File path: \(filePath)") - logger.debug("Chat ID: \(chatId)") - logger.debug("Allow download: \(allowDownload), Allow forward: \(allowForward), Duration: \(accessDuration)s") + logger.info("File path: \(filePath)") + logger.info("Chat ID: \(chatId)") + logger.info("Allow download: \(allowDownload), Allow forward: \(allowForward), Duration: \(accessDuration)s") guard let result = core.processInitAccessGrantAccept( withChatId: chatId, @@ -823,8 +923,8 @@ public class PrvContext { } logger.info("Denying access request for user: \(currentUser)") - logger.debug("File path: \(filePath)") - logger.debug("Chat ID: \(chatId)") + logger.info("File path: \(filePath)") + logger.info("Chat ID: \(chatId)") guard let result = core.processInitAccessDenied( withChatId: chatId, @@ -880,8 +980,8 @@ public class PrvContext { } logger.info("Creating forward peer add request for user: \(currentUser)") - logger.debug("Source Chat ID: \(chatId), Target Chat ID: \(forwardeeChatId)") - logger.debug("File: \(prvFile)") + logger.info("Source Chat ID: \(chatId), Target Chat ID: \(forwardeeChatId)") + logger.info("File: \(prvFile)") guard let result = core.processInitForwardPeerAddRequest(withChatId: chatId, forwardeeChatId: forwardeeChatId, @@ -934,7 +1034,7 @@ public class PrvContext { } logger.info("Creating forward access request for user: \(currentUser)") - logger.debug("Chat ID: \(chatId), File: \(filePath)") + logger.info("Chat ID: \(chatId), File: \(filePath)") guard let result = core.processInitForwardAccessRequest(withChatId: chatId, filePath: filePath) else { @@ -991,8 +1091,8 @@ public class PrvContext { } logger.info("Accepting relay forward access for user: \(currentUser)") - logger.debug("Chat ID: \(chatId), File: \(filePath)") - logger.debug("Contact ID: \(contactId), Duration: \(accessDuration)s, Allow Download: \(allowDownload)") + logger.info("Chat ID: \(chatId), File: \(filePath)") + logger.info("Contact ID: \(contactId), Duration: \(accessDuration)s, Allow Download: \(allowDownload)") guard let result = core.processInitRevertRelayForwardAccessAccept(withChatId: chatId, filePath: filePath, @@ -1050,8 +1150,8 @@ public class PrvContext { } logger.info("Denying relay forward access for user: \(currentUser)") - logger.debug("Chat ID: \(chatId), File: \(filePath)") - logger.debug("Contact ID: \(contactId), Reason: \(denialReason)") + logger.info("Chat ID: \(chatId), File: \(filePath)") + logger.info("Contact ID: \(contactId), Reason: \(denialReason)") guard let result = core.processInitRevertRelayForwardAccessDenied(withChatId: chatId, filePath: filePath, @@ -1104,7 +1204,7 @@ public class PrvContext { } logger.info("Decrypting forwarded file for user: \(currentUser)") - logger.debug("File ID: \(fileId), Forwarder Peer: \(forwarderPeer)") + logger.info("File ID: \(fileId), Forwarder Peer: \(forwarderPeer)") guard let result = core.processForwardedFileDecryptRequest(withFileId: fileId, forwarderPeer: forwarderPeer) else { @@ -1154,8 +1254,8 @@ public class PrvContext { return (false, nil, "No user selected") } - logger.debug("Getting file access status list for user: \(currentUser)") - logger.debug("Chat ID: \(chatId), File: \(filePath)") + logger.info("Getting file access status list for user: \(currentUser)") + logger.info("Chat ID: \(chatId), File: \(filePath)") guard let result = core.getFileAccessStatusList(withChatId: chatId, filePath: filePath) else { logger.error("Failed to get file access status list response") diff --git a/deltachat-ios/Helper/RelayHelper.swift b/deltachat-ios/Helper/RelayHelper.swift index a8fbd73b1..3ba638c0c 100644 --- a/deltachat-ios/Helper/RelayHelper.swift +++ b/deltachat-ios/Helper/RelayHelper.swift @@ -229,14 +229,14 @@ class RelayHelper { // Get file path from first message guard let filePath = firstMsg.file, !filePath.isEmpty else { - logger.debug("No file to forward") + logger.info("No file to forward") dcContext.forwardMessages(with: messageIds, to: targetChatId) return } logger.info("Processing Privitty forward") - logger.debug("Source Chat: \(sourceChatId), Target Chat: \(targetChatId)") - logger.debug("File: \(filePath)") + logger.info("Source Chat: \(sourceChatId), Target Chat: \(targetChatId)") + logger.info("File: \(filePath)") let sourceChatIdString = String(sourceChatId) let targetChatIdString = String(targetChatId) diff --git a/deltachat-ios/Info.plist b/deltachat-ios/Info.plist index 4274b44c1..0ab1667e8 100644 --- a/deltachat-ios/Info.plist +++ b/deltachat-ios/Info.plist @@ -63,21 +63,21 @@ LSSupportsOpeningDocumentsInPlace NSCameraUsageDescription - Delta Chat uses your camera to take and send photos and videos and to scan QR codes. + Privitty Chat uses your camera to take and send photos and videos and to scan QR codes. NSContactsUsageDescription - Delta Chat uses your contacts to show a list of email addresses you can write to. Delta Chat has no server, your contacts are not sent anywhere. + Privitty Chat uses your contacts to show a list of email addresses you can write to. Privitty Chat has no server, your contacts are not sent anywhere. NSFaceIDUsageDescription - Delta Chat uses Face ID to protect your local profile, backup creation and second device setup. + Privitty Chat uses Face ID to protect your local profile, backup creation and second device setup. NSLocationAlwaysAndWhenInUseUsageDescription - Delta Chat needs the location permission in order to share your location for the timespan you have enabled location sharing. + Privitty Chat needs the location permission in order to share your location for the timespan you have enabled location sharing. NSLocationWhenInUseUsageDescription - Delta Chat needs the location permission in order to share your location for the timespan you have enabled location sharing. + Privitty Chat needs the location permission in order to share your location for the timespan you have enabled location sharing. NSMicrophoneUsageDescription - Delta Chat uses your microphone to record and send voice messages and videos with sound. + Privitty Chat uses your microphone to record and send voice messages and videos with sound. NSPhotoLibraryAddUsageDescription - Delta Chat wants to save images to your photo library. + Privitty Chat wants to save images to your photo library. NSPhotoLibraryUsageDescription - Delta Chat will let you choose which photos from your library to send. + Privitty Chat will let you choose which photos from your library to send. NSUserActivityTypes INSendMessageIntent