Merge branch 'master'

Conflicts:
	Linphone/Contacts/ContactsManager.swift
	Linphone/LinphoneApp.swift
	Linphone/UI/Main/ContentView.swift
This commit is contained in:
Benoit Martins 2023-11-09 11:47:41 +01:00
commit 19da1739f0
8 changed files with 254 additions and 261 deletions

View file

@ -7,7 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
886500223A8E518D3EE5FCB7 /* Pods_Linphone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A334B8FDAD2893691A734BE /* Pods_Linphone.framework */; };
D706BA822ADD72D100278F45 /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */; };
D70C93DE2AC2D0F60063CA3B /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D70C93DD2AC2D0F60063CA3B /* Localizable.xcstrings */; };
D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; };
@ -71,8 +70,6 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
1A334B8FDAD2893691A734BE /* Pods_Linphone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Linphone.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1DE4CD5FD6E1F01639F27E3B /* Pods-Linphone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Linphone.release.xcconfig"; path = "Target Support Files/Pods-Linphone/Pods-Linphone.release.xcconfig"; sourceTree = "<group>"; };
D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
D70C93DD2AC2D0F60063CA3B /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
D717071D2AC5922E0037746F /* ColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtension.swift; sourceTree = "<group>"; };
@ -136,7 +133,6 @@
D7E6D0542AEBFCCE00A57AAF /* ContactsInnerFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsInnerFragment.swift; sourceTree = "<group>"; };
D7EAACCE2AD6ED8000AA6A8A /* PermissionsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsFragment.swift; sourceTree = "<group>"; };
D7FB55102AD447FD00A5AB15 /* RegisterFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterFragment.swift; sourceTree = "<group>"; };
FB718F405DAF7B9993AEB878 /* Pods-Linphone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Linphone.debug.xcconfig"; path = "Target Support Files/Pods-Linphone/Pods-Linphone.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -144,26 +140,15 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
886500223A8E518D3EE5FCB7 /* Pods_Linphone.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1CD95087B17CAD149119B7C2 /* Frameworks */ = {
isa = PBXGroup;
children = (
1A334B8FDAD2893691A734BE /* Pods_Linphone.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
A31AF2AB8C6A3D7B7EA3B424 /* Pods */ = {
isa = PBXGroup;
children = (
FB718F405DAF7B9993AEB878 /* Pods-Linphone.debug.xcconfig */,
1DE4CD5FD6E1F01639F27E3B /* Pods-Linphone.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -187,7 +172,6 @@
D719ABB52ABC67BF00B41C10 /* Linphone */,
D719ABB42ABC67BF00B41C10 /* Products */,
A31AF2AB8C6A3D7B7EA3B424 /* Pods */,
1CD95087B17CAD149119B7C2 /* Frameworks */,
);
sourceTree = "<group>";
};
@ -422,12 +406,10 @@
isa = PBXNativeTarget;
buildConfigurationList = D719ABC22ABC67BF00B41C10 /* Build configuration list for PBXNativeTarget "Linphone" */;
buildPhases = (
BE9432280D0A11AA770A50FD /* [CP] Check Pods Manifest.lock */,
D719ABAF2ABC67BF00B41C10 /* Sources */,
D719ABB02ABC67BF00B41C10 /* Frameworks */,
D719ABB12ABC67BF00B41C10 /* Resources */,
D7FB55122AD53FE200A5AB15 /* Run Script */,
D5CA1ECD620857DB91E334A5 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -491,45 +473,6 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
BE9432280D0A11AA770A50FD /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Linphone-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
D5CA1ECD620857DB91E334A5 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Linphone/Pods-Linphone-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Linphone/Pods-Linphone-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Linphone/Pods-Linphone-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
D7FB55122AD53FE200A5AB15 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@ -617,6 +560,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@ -677,6 +621,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@ -728,7 +673,6 @@
};
D719ABC32ABC67BF00B41C10 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = FB718F405DAF7B9993AEB878 /* Pods-Linphone.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
@ -773,7 +717,6 @@
};
D719ABC42ABC67BF00B41C10 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1DE4CD5FD6E1F01639F27E3B /* Pods-Linphone.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;

View file

@ -40,16 +40,16 @@ final class ContactsManager: ObservableObject {
}
func fetchContacts() {
DispatchQueue.global().async {
if self.coreContext.mCore.globalState == GlobalState.Shutdown || self.coreContext.mCore.globalState == GlobalState.Off {
coreContext.doOnCoreQueue { core in
if core.globalState == GlobalState.Shutdown || core.globalState == GlobalState.Off {
print("$TAG Core is being stopped or already destroyed, abort")
} else {
print("$TAG ${friends.size} friends created")
self.friendList = self.coreContext.mCore.getFriendListByName(name: self.nativeAddressBookFriendList)
self.friendList = core.getFriendListByName(name: self.nativeAddressBookFriendList)
if self.friendList == nil {
do {
self.friendList = try self.coreContext.mCore.createFriendList()
self.friendList = try core.createFriendList()
} catch let error {
print("Failed to enumerate contact", error)
}
@ -63,7 +63,7 @@ final class ContactsManager: ObservableObject {
self.friendList!.databaseStorageEnabled = false // We don't want to store local address-book in DB
self.friendList!.displayName = self.nativeAddressBookFriendList
self.coreContext.mCore.addFriendList(list: self.friendList!)
core.addFriendList(list: self.friendList!)
} else {
print(
"$TAG Friend list [$LINPHONE_ADDRESS_BOOK_FRIEND_LIST] found, removing existing friends if any"
@ -73,10 +73,10 @@ final class ContactsManager: ObservableObject {
}
}
self.linphoneFriendList = self.coreContext.mCore.getFriendListByName(name: self.linphoneAddressBookFirendList)
self.linphoneFriendList = core.getFriendListByName(name: self.linphoneAddressBookFirendList)
if self.linphoneFriendList == nil {
do {
self.linphoneFriendList = try self.coreContext.mCore.createFriendList()
self.linphoneFriendList = try core.createFriendList()
} catch let error {
print("Failed to enumerate contact", error)
}
@ -90,7 +90,7 @@ final class ContactsManager: ObservableObject {
self.linphoneFriendList!.databaseStorageEnabled = true
self.linphoneFriendList!.displayName = self.linphoneAddressBookFirendList
self.coreContext.mCore.addFriendList(list: self.linphoneFriendList!)
core.addFriendList(list: self.linphoneFriendList!)
}
}
@ -200,66 +200,69 @@ final class ContactsManager: ObservableObject {
}
func saveFriend(result: String, contact: Contact, existingFriend: Friend?) -> Friend? {
do {
let friend = (existingFriend != nil) ? existingFriend : try self.coreContext.mCore.createFriend()
if friend != nil {
friend!.edit()
self.coreContext.doOnCoreQueue() { core in
do {
let friend = (existingFriend != nil) ? existingFriend : try core.createFriend()
friend!.nativeUri = contact.identifier
try friend!.setName(newValue: contact.firstName + " " + contact.lastName)
let friendvCard = friend!.vcard
if friendvCard != nil {
friendvCard!.givenName = contact.firstName
friendvCard!.familyName = contact.lastName
}
friend!.organization = contact.organizationName
var friendAddresses: [Address] = []
friend?.addresses.forEach({ address in
friend?.removeAddress(address: address)
})
contact.sipAddresses.forEach { sipAddress in
let address = self.coreContext.mCore.interpretUrl(url: sipAddress, applyInternationalPrefix: true)
if friend != nil {
friend!.edit()
if address != nil && ((friendAddresses.firstIndex(where: {$0.asString() == address?.asString()})) == nil) {
friend!.addAddress(address: address!)
friendAddresses.append(address!)
friend!.nativeUri = contact.identifier
try friend!.setName(newValue: contact.firstName + " " + contact.lastName)
let friendvCard = friend!.vcard
if friendvCard != nil {
friendvCard!.givenName = contact.firstName
friendvCard!.familyName = contact.lastName
}
}
var friendPhoneNumbers: [PhoneNumber] = []
friend?.phoneNumbersWithLabel.forEach({ phoneNumber in
friend?.removePhoneNumberWithLabel(phoneNumber: phoneNumber)
})
contact.phoneNumbers.forEach { phone in
do {
if (friendPhoneNumbers.firstIndex(where: {$0.num == phone.num})) == nil {
let labelDrop = String(phone.numLabel.dropFirst(4).dropLast(4))
let phoneNumber = try Factory.Instance.createFriendPhoneNumber(phoneNumber: phone.num, label: labelDrop)
friend!.addPhoneNumberWithLabel(phoneNumber: phoneNumber)
friendPhoneNumbers.append(phone)
friend!.organization = contact.organizationName
var friendAddresses: [Address] = []
friend?.addresses.forEach({ address in
friend?.removeAddress(address: address)
})
contact.sipAddresses.forEach { sipAddress in
let address = core.interpretUrl(url: sipAddress, applyInternationalPrefix: true)
if address != nil && ((friendAddresses.firstIndex(where: {$0.asString() == address?.asString()})) == nil) {
friend!.addAddress(address: address!)
friendAddresses.append(address!)
}
} catch let error {
print("Failed to enumerate contact", error)
}
var friendPhoneNumbers: [PhoneNumber] = []
friend?.phoneNumbersWithLabel.forEach({ phoneNumber in
friend?.removePhoneNumberWithLabel(phoneNumber: phoneNumber)
})
contact.phoneNumbers.forEach { phone in
do {
if (friendPhoneNumbers.firstIndex(where: {$0.num == phone.num})) == nil {
let labelDrop = String(phone.numLabel.dropFirst(4).dropLast(4))
let phoneNumber = try Factory.Instance.createFriendPhoneNumber(phoneNumber: phone.num, label: labelDrop)
friend!.addPhoneNumberWithLabel(phoneNumber: phoneNumber)
friendPhoneNumbers.append(phone)
}
} catch let error {
print("Failed to enumerate contact", error)
}
}
friend!.photo = "file:/" + result
friend!.organization = contact.organizationName
friend!.jobTitle = contact.jobTitle
friend!.done()
return friend
}
friend!.photo = "file:/" + result
friend!.organization = contact.organizationName
friend!.jobTitle = contact.jobTitle
friend!.done()
return friend
} catch let error {
print("Failed to enumerate contact", error)
return nil
}
} catch let error {
print("Failed to enumerate contact", error)
return nil
}
return nil
}

View file

@ -17,74 +17,104 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// swiftlint:disable large_tuple
import linphonesw
import Combine
final class CoreContext: ObservableObject {
static let shared = CoreContext()
var mCore: Core!
var mRegistrationDelegate: CoreDelegate!
var mConfigurationDelegate: CoreDelegate!
var coreVersion: String = Core.getVersion
@Published var loggedIn: Bool = false
@Published var loggingInProgress: Bool = false
@Published var toastMessage: String = ""
@Published var defaultAccount: Account?
private var mCore: Core!
private var mIteratePublisher: AnyCancellable?
private init() {}
func initialiseCore() async throws {
func doOnCoreQueue(synchronous : Bool = false, lambda: @escaping (Core) -> Void) {
if synchronous {
coreQueue.sync {
lambda(self.mCore)
}
} else {
coreQueue.async {
lambda(self.mCore)
}
}
}
func initialiseCore() throws {
LoggingService.Instance.logLevel = LogLevel.Debug
let factory = Factory.Instance
let configDir = factory.getConfigDir(context: nil)
try? mCore = Factory.Instance.createCore(configPath: "\(configDir)/MyConfig", factoryConfigPath: "", systemContext: nil)
mCore.friendsDatabasePath = "\(configDir)/friends.db"
try? mCore.start()
// Create a Core listener to listen for the callback we need
// In this case, we want to know about the account registration status
mRegistrationDelegate =
CoreDelegateStub(
onConfiguringStatus: {(_: Core, state: Config.ConfiguringState, message: String) in
NSLog("New configuration state is \(state) = \(message)\n")
if state == .Successful {
coreQueue.async {
let configDir = Factory.Instance.getConfigDir(context: nil)
try? self.mCore = Factory.Instance.createCore(configPath: "\(configDir)/MyConfig", factoryConfigPath: "", systemContext: nil)
self.mCore.autoIterateEnabled = false
self.mCore.friendsDatabasePath = "\(configDir)/friends.db"
self.mCore.publisher?.onGlobalStateChanged?.postOnMainQueue { (cbVal: (core: Core, state: GlobalState, message: String)) in
if cbVal.state == GlobalState.On {
self.defaultAccount = self.mCore.defaultAccount
} else if cbVal.state == GlobalState.Off {
self.defaultAccount = nil
}
}
try? self.mCore.start()
// Create a Core listener to listen for the callback we need
// In this case, we want to know about the account registration status
self.mCore.publisher?.onConfiguringStatus?.postOnMainQueue { (cbVal: (core: Core, status: Config.ConfiguringState, message: String)) in
NSLog("New configuration state is \(cbVal.status) = \(cbVal.message)\n")
if cbVal.status == Config.ConfiguringState.Successful {
self.toastMessage = "Successful"
} else {
self.toastMessage = "Failed"
}
},
}
onAccountRegistrationStateChanged: {(_: Core, account: Account, state: RegistrationState, message: String) in
self.mCore.publisher?.onAccountRegistrationStateChanged?.postOnMainQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in
// If account has been configured correctly, we will go through Progress and Ok states
// Otherwise, we will be Failed.
NSLog("New registration state is \(state) for user id \( String(describing: account.params?.identityAddress?.asString())) = \(message)\n")
if state == .Ok {
NSLog("New registration state is \(cbVal.state) for user id " +
"\( String(describing: cbVal.account.params?.identityAddress?.asString())) = \(cbVal.message)\n")
if cbVal.state == .Ok {
self.loggingInProgress = false
self.loggedIn = true
} else if state == .Progress {
} else if cbVal.state == .Progress {
self.loggingInProgress = true
} else {
self.toastMessage = "Registration failed"
self.loggingInProgress = false
self.loggedIn = false
let params = account.params
}
}.postOnCoreQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in
// If registration failed, remove account from core
if cbVal.state != .Ok && cbVal.state != .Progress {
let params = cbVal.account.params
let clonedParams = params?.clone()
clonedParams?.registerEnabled = false
account.params = clonedParams
cbVal.account.params = clonedParams
self.mCore!.removeAccount(account: account)
self.mCore!.clearAccounts()
self.mCore!.clearAllAuthInfo()
cbVal.core.removeAccount(account: cbVal.account)
cbVal.core.clearAccounts()
cbVal.core.clearAllAuthInfo()
}
}
)
mCore.addDelegate(delegate: mRegistrationDelegate)
self.mIteratePublisher = Timer.publish(every: 0.02, on: .main, in: .common)
.autoconnect()
.receive(on: coreQueue)
.sink { _ in
self.mCore.iterate()
}
}
}
}
// swiftlint:enable large_tuple

View file

@ -32,10 +32,10 @@ struct LinphoneApp: App {
if isActive {
if !sharedMainViewModel.welcomeViewDisplayed {
WelcomeView(sharedMainViewModel: sharedMainViewModel)
} else if coreContext.mCore.defaultAccount == nil || sharedMainViewModel.displayProfileMode {
} else if coreContext.defaultAccount == nil || sharedMainViewModel.displayProfileMode {
AssistantView(sharedMainViewModel: sharedMainViewModel)
.toast(isShowing: $coreContext.toastMessage)
} else if coreContext.mCore.defaultAccount != nil {
} else if coreContext.defaultAccount != nil {
ContentView(contactViewModel: ContactViewModel(), editContactViewModel: EditContactViewModel(), historyViewModel: HistoryViewModel())
.toast(isShowing: $coreContext.toastMessage)
}

View file

@ -40,7 +40,7 @@ struct SplashScreen: View {
.ignoresSafeArea(.all)
.onAppear {
Task {
try await coreContext.initialiseCore()
try coreContext.initialiseCore()
withAnimation {
self.isActive = true
}

View file

@ -33,83 +33,95 @@ class AccountLoginViewModel: ObservableObject {
init() {}
func login() {
do {
// Get the transport protocol to use.
// TLS is strongly recommended
// Only use UDP if you don't have the choice
var transport: TransportType
if transportType == "TLS" {
transport = TransportType.Tls
} else if transportType == "TCP" {
transport = TransportType.Tcp
} else { transport = TransportType.Udp }
// To configure a SIP account, we need an Account object and an AuthInfo object
// The first one is how to connect to the proxy server, the second one stores the credentials
// The auth info can be created from the Factory as it's only a data class
// userID is set to null as it's the same as the username in our case
// ha1 is set to null as we are using the clear text password. Upon first register, the hash will be computed automatically.
// The realm will be determined automatically from the first register, as well as the algorithm
let authInfo = try Factory.Instance.createAuthInfo(username: username, userid: "", passwd: passwd, ha1: "", realm: "", domain: domain)
// Account object replaces deprecated ProxyConfig object
// Account object is configured through an AccountParams object that we can obtain from the Core
let accountParams = try coreContext.mCore!.createAccountParams()
// A SIP account is identified by an identity address that we can construct from the username and domain
let identity = try Factory.Instance.createAddress(addr: String("sip:" + username + "@" + domain))
try accountParams.setIdentityaddress(newValue: identity)
// We also need to configure where the proxy server is located
let address = try Factory.Instance.createAddress(addr: String("sip:" + domain))
// We use the Address object to easily set the transport protocol
try address.setTransport(newValue: transport)
try accountParams.setServeraddress(newValue: address)
// And we ensure the account will start the registration process
accountParams.registerEnabled = true
// Now that our AccountParams is configured, we can create the Account object
let account = try coreContext.mCore!.createAccount(params: accountParams)
// Now let's add our objects to the Core
coreContext.mCore!.addAuthInfo(info: authInfo)
try coreContext.mCore!.addAccount(account: account)
// Also set the newly added account as default
coreContext.mCore!.defaultAccount = account
} catch { NSLog(error.localizedDescription) }
coreContext.doOnCoreQueue { core in
do {
// Get the transport protocol to use.
// TLS is strongly recommended
// Only use UDP if you don't have the choice
var transport: TransportType
if self.transportType == "TLS" {
transport = TransportType.Tls
} else if self.transportType == "TCP" {
transport = TransportType.Tcp
} else { transport = TransportType.Udp }
// To configure a SIP account, we need an Account object and an AuthInfo object
// The first one is how to connect to the proxy server, the second one stores the credentials
// The auth info can be created from the Factory as it's only a data class
// userID is set to null as it's the same as the username in our case
// ha1 is set to null as we are using the clear text password. Upon first register, the hash will be computed automatically.
// The realm will be determined automatically from the first register, as well as the algorithm
let authInfo = try Factory.Instance.createAuthInfo(username: self.username, userid: "", passwd: self.passwd, ha1: "", realm: "", domain: self.domain)
// Account object replaces deprecated ProxyConfig object
// Account object is configured through an AccountParams object that we can obtain from the Core
let accountParams = try core.createAccountParams()
// A SIP account is identified by an identity address that we can construct from the username and domain
let identity = try Factory.Instance.createAddress(addr: String("sip:" + self.username + "@" + self.domain))
try accountParams.setIdentityaddress(newValue: identity)
// We also need to configure where the proxy server is located
let address = try Factory.Instance.createAddress(addr: String("sip:" + self.domain))
// We use the Address object to easily set the transport protocol
try address.setTransport(newValue: transport)
try accountParams.setServeraddress(newValue: address)
// And we ensure the account will start the registration process
accountParams.registerEnabled = true
// Now that our AccountParams is configured, we can create the Account object
let account = try core.createAccount(params: accountParams)
// Now let's add our objects to the Core
core.addAuthInfo(info: authInfo)
try core.addAccount(account: account)
// Also set the newly added account as default
core.defaultAccount = account
DispatchQueue.main.async {
self.coreContext.defaultAccount = account
}
} catch { NSLog(error.localizedDescription) }
}
}
func unregister() {
// Here we will disable the registration of our Account
if let account = coreContext.mCore!.defaultAccount {
let params = account.params
// Returned params object is const, so to make changes we first need to clone it
let clonedParams = params?.clone()
// Now let's make our changes
clonedParams?.registerEnabled = false
// And apply them
account.params = clonedParams
coreContext.doOnCoreQueue { core in
// Here we will disable the registration of our Account
if let account = core.defaultAccount {
let params = account.params
// Returned params object is const, so to make changes we first need to clone it
let clonedParams = params?.clone()
// Now let's make our changes
clonedParams?.registerEnabled = false
// And apply them
account.params = clonedParams
}
}
}
func delete() {
// To completely remove an Account
if let account = coreContext.mCore!.defaultAccount {
coreContext.mCore!.removeAccount(account: account)
// To remove all accounts use
coreContext.mCore!.clearAccounts()
// Same for auth info
coreContext.mCore!.clearAllAuthInfo()
coreContext.doOnCoreQueue { core in
// To completely remove an Account
if let account = core.defaultAccount {
core.removeAccount(account: account)
DispatchQueue.main.async {
self.coreContext.defaultAccount = nil
}
// To remove all accounts use
core.clearAccounts()
// Same for auth info
core.clearAllAuthInfo()
}
}
}
}

View file

@ -70,14 +70,11 @@ class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
if let url = NSURL(string: result) {
if UIApplication.shared.canOpenURL(url as URL) {
lastResult = result
do {
try coreContext.mCore.setProvisioninguri(newValue: result)
coreContext.mCore.stop()
try coreContext.mCore.start()
} catch {
coreContext.doOnCoreQueue { core in
try? core.setProvisioninguri(newValue: result)
core.stop()
try? core.start()
}
} else {
coreContext.toastMessage = "Invalide URI"
}

View file

@ -25,9 +25,8 @@ final class MagicSearchSingleton: ObservableObject {
private var coreContext = CoreContext.shared
private var magicSearch: MagicSearch!
var magicSearchDelegate: MagicSearchDelegate?
@objc var currentFilter: String = ""
var currentFilter: String = ""
var previousFilter: String?
var needUpdateLastSearchContacts = false
@ -35,36 +34,45 @@ final class MagicSearchSingleton: ObservableObject {
@Published var lastSearch: [SearchResult] = []
private var limitSearchToLinphoneAccounts = true
@Published var allContact = false
private var domainDefaultAccount = ""
@Published var allContact = false
private var domainDefaultAccount = ""
private init() {
domainDefaultAccount = coreContext.mCore.defaultAccount!.params!.domain!
magicSearch = try? coreContext.mCore.createMagicSearch()
magicSearch.limitedSearch = false
magicSearchDelegate = MagicSearchDelegateStub(onSearchResultsReceived: { (magicSearch: MagicSearch) in
self.needUpdateLastSearchContacts = true
self.lastSearch = magicSearch.lastSearch
})
magicSearch.addDelegate(delegate: magicSearchDelegate!)
coreContext.doOnCoreQueue{ core in
self.domainDefaultAccount = core.defaultAccount?.params?.domain ?? ""
self.magicSearch = try? core.createMagicSearch()
self.magicSearch.limitedSearch = false
self.magicSearch.publisher?.onSearchResultsReceived?.postOnMainQueue { (magicSearch: MagicSearch) in
self.needUpdateLastSearchContacts = true
self.lastSearch = magicSearch.lastSearch
}
}
}
func searchForContacts(sourceFlags: Int) {
if let oldFilter = previousFilter {
if oldFilter.count > currentFilter.count || oldFilter != currentFilter {
magicSearch.resetSearchCache()
coreContext.doOnCoreQueue{ core in
var needResetCache = false
DispatchQueue.main.sync {
if let oldFilter = self.previousFilter {
if oldFilter.count > self.currentFilter.count || oldFilter != self.currentFilter {
needResetCache = true
}
}
self.previousFilter = self.currentFilter
}
if needResetCache {
self.magicSearch.resetSearchCache()
}
self.magicSearch.getContactsListAsync(
filter: self.currentFilter,
domain: self.allContact ? "" : self.domainDefaultAccount,
sourceFlags: sourceFlags,
aggregation: MagicSearch.Aggregation.Friend)
}
previousFilter = currentFilter
magicSearch.getContactsListAsync(
filter: currentFilter,
domain: allContact ? "" : domainDefaultAccount,
sourceFlags: sourceFlags,
aggregation: MagicSearch.Aggregation.Friend)
}
}