diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 2e50a323b..45a8cde16 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -7778,7 +7778,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 496; + CURRENT_PROJECT_VERSION = 505; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -7816,7 +7816,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 2.8.2; + MARKETING_VERSION = 2.8.3; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -7849,7 +7849,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 496; + CURRENT_PROJECT_VERSION = 505; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -7887,7 +7887,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 2.8.2; + MARKETING_VERSION = 2.8.3; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; diff --git a/Session/Calls/Call Management/SessionCallManager.swift b/Session/Calls/Call Management/SessionCallManager.swift index 7235ec02a..1d240f45b 100644 --- a/Session/Calls/Call Management/SessionCallManager.swift +++ b/Session/Calls/Call Management/SessionCallManager.swift @@ -113,7 +113,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol { // Construct a CXCallUpdate describing the incoming call, including the caller. let update = CXCallUpdate() update.localizedCallerName = callerName - update.remoteHandle = CXHandle(type: .generic, value: call.callId.uuidString) + update.remoteHandle = CXHandle(type: .generic, value: call.sessionId) update.hasVideo = false disableUnsupportedFeatures(callUpdate: update) @@ -140,11 +140,12 @@ public final class SessionCallManager: NSObject, CallManagerProtocol { } func handleCallEnded() { + SNLog("[Calls] Call ended.") WebRTCSession.current = nil UserDefaults.sharedLokiProject?[.isCallOngoing] = false UserDefaults.sharedLokiProject?[.lastCallPreOffer] = nil - if Singleton.hasAppContext && Singleton.appContext.isInBackground { + if Singleton.hasAppContext && Singleton.appContext.isNotInForeground { (UIApplication.shared.delegate as? AppDelegate)?.stopPollers() Log.flush() } @@ -198,6 +199,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol { } public static func suspendDatabaseIfCallEndedInBackground() { + SNLog("[Calls] suspendDatabaseIfCallEndedInBackground.") if Singleton.hasAppContext && Singleton.appContext.isInBackground { // FIXME: Initialise the `SessionCallManager` with a dependencies instance let dependencies: Dependencies = Dependencies() @@ -238,8 +240,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol { { let callVC = CallVC(for: call) callVC.conversationVC = conversationVC - conversationVC.inputAccessoryView?.isHidden = true - conversationVC.inputAccessoryView?.alpha = 0 + conversationVC.hideInputAccessoryView() presentingVC.present(callVC, animated: true, completion: nil) } else if !Preferences.isCallKitSupported { diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index b6b352767..7ebcafae0 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -600,8 +600,11 @@ final class CallVC: UIViewController, VideoPreviewDelegate { } Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { [weak self] _ in - self?.conversationVC?.showInputAccessoryView() - self?.presentingViewController?.dismiss(animated: true, completion: nil) + DispatchQueue.main.async { + self?.dismiss(animated: true, completion: { + self?.conversationVC?.showInputAccessoryView() + }) + } } } @@ -623,9 +626,13 @@ final class CallVC: UIViewController, VideoPreviewDelegate { AppEnvironment.shared.callManager.reportCurrentCallEnded(reason: nil) } - DispatchQueue.main.async { - self?.conversationVC?.showInputAccessoryView() - self?.presentingViewController?.dismiss(animated: true, completion: nil) + Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [weak self] _ in + DispatchQueue.main.async { + self?.dismiss(animated: true, completion: { + self?.conversationVC?.becomeFirstResponder() + self?.conversationVC?.showInputAccessoryView() + }) + } } } } diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index ba1669fcb..248c51934 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -791,13 +791,23 @@ extension ConversationVC: } func hideInputAccessoryView() { - DispatchQueue.main.async { - self.inputAccessoryView?.isHidden = true - self.inputAccessoryView?.alpha = 0 + guard Thread.isMainThread else { + DispatchQueue.main.async { + self.hideInputAccessoryView() + } + return } + self.inputAccessoryView?.isHidden = true + self.inputAccessoryView?.alpha = 0 } func showInputAccessoryView() { + guard Thread.isMainThread else { + DispatchQueue.main.async { + self.showInputAccessoryView() + } + return + } UIView.animate(withDuration: 0.25, animations: { self.inputAccessoryView?.isHidden = false self.inputAccessoryView?.alpha = 1 diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index f9e5e732e..5b609d185 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -353,7 +353,7 @@ final class HomeVC: BaseVC, LibSessionRespondingViewController, UITableViewDataS ) // Start polling if needed (i.e. if the user just created or restored their Session ID) - if Identity.userExists(), let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate { + if Identity.userExists(), let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate, !Singleton.appContext.isNotInForeground { appDelegate.startPollersIfNeeded() } diff --git a/Session/Meta/Settings.bundle/ThirdPartyLicenses.plist b/Session/Meta/Settings.bundle/ThirdPartyLicenses.plist index 1e94962d9..6ca29b954 100644 --- a/Session/Meta/Settings.bundle/ThirdPartyLicenses.plist +++ b/Session/Meta/Settings.bundle/ThirdPartyLicenses.plist @@ -985,6 +985,88 @@ SOFTWARE. License The MIT License (MIT) +Copyright (c) 2016 swiftlyfalling (https://github.com/swiftlyfalling) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + Title + session-grdb-swift + + + License + The author disclaims copyright to this source code. In place of +a legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + Title + session-grdb-swift + + + License + /* +** LICENSE for the sqlite3 WebAssembly/JavaScript APIs. +** +** This bundle (typically released as sqlite3.js or sqlite3.mjs) +** is an amalgamation of JavaScript source code from two projects: +** +** 1) https://emscripten.org: the Emscripten "glue code" is covered by +** the terms of the MIT license and University of Illinois/NCSA +** Open Source License, as described at: +** +** https://emscripten.org/docs/introducing_emscripten/emscripten_license.html +** +** 2) https://sqlite.org: all code and documentation labeled as being +** from this source are released under the same terms as the sqlite3 +** C library: +** +** 2022-10-16 +** +** The author disclaims copyright to this source code. In place of a +** legal notice, here is a blessing: +** +** * May you do good and not evil. +** * May you find forgiveness for yourself and forgive others. +** * May you share freely, never taking more than you give. +*/ + + Title + session-grdb-swift + + + License + The author disclaims copyright to this source code. In place of +a legal notice, here is a blessing: + + May you do good and not evil. + May you find forgiveness for yourself and forgive others. + May you share freely, never taking more than you give. + + Title + session-grdb-swift + + + License + The MIT License (MIT) + Copyright (c) 2015 ibireme <ibireme@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/Session/Notifications/PushRegistrationManager.swift b/Session/Notifications/PushRegistrationManager.swift index 3987ed35c..752bdfeec 100644 --- a/Session/Notifications/PushRegistrationManager.swift +++ b/Session/Notifications/PushRegistrationManager.swift @@ -284,7 +284,8 @@ public enum PushRegistrationError: Error { guard let uuid: String = payload["uuid"] as? String, let caller: String = payload["caller"] as? String, - let timestampMs: Int64 = payload["timestamp"] as? Int64 + let timestampMs: UInt64 = payload["timestamp"] as? UInt64, + TimestampUtils.isWithinOneMinute(timestampMs: timestampMs) else { SessionCallManager.reportFakeCall(info: "Missing payload data") // stringlint:ignore return @@ -297,40 +298,33 @@ public enum PushRegistrationError: Error { LibSession.resumeNetworkAccess() let maybeCall: SessionCall? = Storage.shared.write { db in - let messageInfo: CallMessage.MessageInfo = CallMessage.MessageInfo( - state: (caller == getUserHexEncodedPublicKey(db) ? - .outgoing : - .incoming - ) - ) - - let messageInfoString: String? = { - if let messageInfoData: Data = try? JSONEncoder().encode(messageInfo) { - return String(data: messageInfoData, encoding: .utf8) - } else { - return "callsIncoming" - .put(key: "name", value: caller) - .localized() - } - }() - - let call: SessionCall = SessionCall(db, for: caller, uuid: uuid, mode: .answer) - let thread: SessionThread = try SessionThread - .fetchOrCreate(db, id: caller, variant: .contact, shouldBeVisible: nil) - - let interaction: Interaction = try Interaction( - messageUuid: uuid, - threadId: thread.id, - threadVariant: thread.variant, - authorId: caller, - variant: .infoCall, - body: messageInfoString, - timestampMs: timestampMs - ) - .withDisappearingMessagesConfiguration(db, threadVariant: thread.variant) - .inserted(db) + var call: SessionCall? = nil - call.callInteractionId = interaction.id + do { + call = SessionCall( + db, + for: caller, + uuid: uuid, + mode: .answer + ) + + let thread: SessionThread = try SessionThread + .fetchOrCreate( + db, + id: caller, + variant: .contact, + shouldBeVisible: nil + ) + + let interaction: Interaction? = try Interaction + .filter(Interaction.Columns.threadId == thread.id) + .filter(Interaction.Columns.messageUuid == uuid) + .fetchOne(db) + + call?.callInteractionId = interaction?.id + } catch { + SNLog("[Calls] Failed to create call due to error: \(error)") + } return call } @@ -340,12 +334,16 @@ public enum PushRegistrationError: Error { return } + JobRunner.appDidBecomeActive() + // NOTE: Just start 1-1 poller so that it won't wait for polling group messages (UIApplication.shared.delegate as? AppDelegate)?.startPollersIfNeeded(shouldStartGroupPollers: false) call.reportIncomingCallIfNeeded { error in if let error = error { SNLog("[Calls] Failed to report incoming call to CallKit due to error: \(error)") + } else { + SNLog("[Calls] Succeeded to report incoming call to CallKit") } } } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift index 127ea94ac..7249ce74f 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift @@ -109,6 +109,7 @@ extension MessageReceiver { // Ignore pre offer message after the same call instance has been generated if let currentCall: CurrentCallProtocol = callManager.currentCall, currentCall.uuid == message.uuid { + SNLog("[MessageReceiver+Calls] Ignoring pre-offer message for call[\(currentCall.uuid)] instance because it is already active.") return } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift index c9d240fbf..20819912f 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift @@ -117,7 +117,7 @@ extension MessageReceiver { } // Update the `didApproveMe` state of the sender - try updateContactApprovalStatusIfNeeded( + let shouldInsertControlMessage: Bool = try updateContactApprovalStatusIfNeeded( db, senderSessionId: senderId, threadId: nil @@ -138,6 +138,7 @@ extension MessageReceiver { ) } + guard shouldInsertControlMessage else { return } // Notify the user of their approval (Note: This will always appear in the un-blinded thread) // // Note: We want to do this last as it'll mean the un-blinded thread gets updated and the @@ -156,11 +157,11 @@ extension MessageReceiver { ).inserted(db) } - internal static func updateContactApprovalStatusIfNeeded( + @discardableResult internal static func updateContactApprovalStatusIfNeeded( _ db: Database, senderSessionId: String, threadId: String? - ) throws { + ) throws -> Bool { let userPublicKey: String = getUserHexEncodedPublicKey(db) // If the sender of the message was the current user @@ -171,13 +172,13 @@ extension MessageReceiver { let threadId: String = threadId, let thread: SessionThread = try? SessionThread.fetchOne(db, id: threadId), !thread.isNoteToSelf(db) - else { return } + else { return true } // Sending a message to someone flags them as approved so create the contact record if // it doesn't exist let contact: Contact = Contact.fetchOrCreate(db, id: threadId) - guard !contact.isApproved else { return } + guard !contact.isApproved else { return false } try? contact.save(db) _ = try? Contact @@ -189,12 +190,14 @@ extension MessageReceiver { // someone without approving them) let contact: Contact = Contact.fetchOrCreate(db, id: senderSessionId) - guard !contact.didApproveMe else { return } + guard !contact.didApproveMe else { return false } try? contact.save(db) _ = try? Contact .filter(id: senderSessionId) .updateAllAndConfig(db, Contact.Columns.didApproveMe.set(to: true)) } + + return true } } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift index 1f11a1457..dd6ef8a7b 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift @@ -413,7 +413,9 @@ public class Poller { job: job, canStartJob: ( !forceSynchronousProcessing && - (Singleton.hasAppContext && !Singleton.appContext.isInBackground) + (Singleton.hasAppContext && !Singleton.appContext.isInBackground) || + // FIXME: Better seperate the call messages handling, since we need to handle them all the time + SessionEnvironment.shared?.callManager.wrappedValue?.currentCall != nil ), using: dependencies ) diff --git a/SessionUtilitiesKit/General/AppContext.swift b/SessionUtilitiesKit/General/AppContext.swift index 423e8f5de..35dcb7e29 100644 --- a/SessionUtilitiesKit/General/AppContext.swift +++ b/SessionUtilitiesKit/General/AppContext.swift @@ -46,7 +46,9 @@ public extension AppContext { var frontmostViewController: UIViewController? { nil } var backgroundTimeRemaining: TimeInterval { 0 } + // Note: CallKit will make the app state as .inactive var isInBackground: Bool { reportedApplicationState == .background } + var isNotInForeground: Bool { reportedApplicationState != .active } var isAppForegroundAndActive: Bool { reportedApplicationState == .active } // MARK: - Paths