// // BasicChat.swift // BasicChat // // Created by QuentinArguillere on 08/09/2021. // Copyright © 2021 BelledonneCommunications. All rights reserved. // import linphonesw class BasicChatTutorialContext : ObservableObject { var mCore: Core! @Published var coreVersion: String = Core.getVersion var mRegistrationDelegate : CoreDelegate! @Published var username : String = "user" @Published var passwd : String = "pwd" @Published var domain : String = "sip.example.org" @Published var loggedIn: Bool = false @Published var transportType : String = "TLS" /*------------ Basic chat tutorial related variables -------*/ var mChatroom : ChatRoom? var mChatMessageDelegate : ChatMessageDelegate! var mChatMessage : ChatMessage? var mLastFileMessageReceived : ChatMessage? @Published var msgToSend : String = "msg" @Published var remoteAddress : String = "sip:remote@sip.example.org" @Published var canEditAddress : Bool = true @Published var isDownloading : Bool = false @Published var messagesReceived : String = "" var fileFolderUrl : URL! var fileUrl : URL! init() { LoggingService.Instance.logLevel = LogLevel.Debug try? mCore = Factory.Instance.createCore(configPath: "", factoryConfigPath: "", systemContext: nil) try? mCore.start() mRegistrationDelegate = CoreDelegateStub(onMessageReceived : { (core: Core, chatRoom: ChatRoom, message: ChatMessage) in // We will be called in this when a message is received // If the chat room wasn't existing, it is automatically created by the library // If we already sent a chat message, the chatRoom variable will be the same as the one we already have if (self.mChatroom == nil) { if (chatRoom.hasCapability(mask: ChatRoomCapabilities.Basic.rawValue)) { // Keep the chatRoom object to use it to send messages if it hasn't been created yet self.mChatroom = chatRoom if let remoteAddress = chatRoom.peerAddress?.asStringUriOnly() { self.remoteAddress = remoteAddress } self.canEditAddress = false } } // We will notify the sender the message has been read by us chatRoom.markAsRead() for content in message.contents { if (content.isFileTransfer) { self.mLastFileMessageReceived = message self.messagesReceived += "\n--File available for download--" } else if (content.isText) { self.messagesReceived += "\nThem: \(message.utf8Text)" } } }, onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in NSLog("New registration state is \(state) for user id \( String(describing: account.params?.identityAddress?.asString()))\n") if (state == .Ok) { self.loggedIn = true } else if (state == .Cleared) { self.loggedIn = false } }) mCore.addDelegate(delegate: mRegistrationDelegate) // This delegate has to be attached to each specific chat message we want to monitor, before sending it mChatMessageDelegate = ChatMessageDelegateStub(onMsgStateChanged : { (message: ChatMessage, state: ChatMessage.State) in print("MessageTrace - msg state changed: \(state)\n") if (state == ChatMessage.State.FileTransferDone && self.isDownloading == true) { self.isDownloading = false } else if (state == .Delivered) { self.messagesReceived += "\nMe: \(message.utf8Text)" } }) // example file to send let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]) fileFolderUrl = documentsPath.appendingPathComponent("TutorialFiles") fileUrl = fileFolderUrl?.appendingPathComponent("file_to_transfer.txt") do{ try FileManager.default.createDirectory(atPath: fileFolderUrl!.path, withIntermediateDirectories: true, attributes: nil) try String("My file content").write(to: fileUrl!, atomically: false, encoding: .utf8) }catch let error as NSError{ print("Unable to create d)irectory",error) } } func login() { do { var transport : TransportType if (transportType == "TLS") { transport = TransportType.Tls } else if (transportType == "TCP") { transport = TransportType.Tcp } else { transport = TransportType.Udp } let authInfo = try Factory.Instance.createAuthInfo(username: username, userid: "", passwd: passwd, ha1: "", realm: "", domain: domain) let accountParams = try mCore.createAccountParams() let identity = try Factory.Instance.createAddress(addr: String("sip:" + username + "@" + domain)) try! accountParams.setIdentityaddress(newValue: identity) let address = try Factory.Instance.createAddress(addr: String("sip:" + domain)) try address.setTransport(newValue: transport) try accountParams.setServeraddress(newValue: address) accountParams.registerEnabled = true let account = try mCore.createAccount(params: accountParams) mCore.addAuthInfo(info: authInfo) try mCore.addAccount(account: account) mCore.defaultAccount = account } catch { NSLog(error.localizedDescription) } } func unregister() { if let account = mCore.defaultAccount { let params = account.params let clonedParams = params?.clone() clonedParams?.registerEnabled = false account.params = clonedParams } } func delete() { if let account = mCore.defaultAccount { mCore.removeAccount(account: account) mCore.clearAccounts() mCore.clearAllAuthInfo() } } func createBasicChatRoom() { do { // In this tutorial we will create a Basic chat room // It doesn't include advanced features such as end-to-end encryption or groups // But it is interoperable with any SIP service as it's relying on SIP SIMPLE messages // If you try to enable a feature not supported by the basic backend, isValid() will return false let params = try mCore.createDefaultChatRoomParams() params.backend = ChatRoomBackend.Basic params.encryptionEnabled = false params.groupEnabled = false if (params.isValid) { // We also need the SIP address of the person we will chat with let remote = try Factory.Instance.createAddress(addr: remoteAddress) // And finally we will need our local SIP address let localAddress = mCore.defaultAccount?.params?.identityAddress mChatroom = try mCore.createChatRoom(params: params, localAddr: localAddress, participants: [remote]) if (mChatroom != nil) { canEditAddress = false } } } catch { NSLog(error.localizedDescription) } } func sendMessage() { do { if (mChatroom == nil) { // We need a ChatRoom object to send chat messages in it, so let's create it if it hasn't been done yet createBasicChatRoom() } mChatMessage = nil // We need to create a ChatMessage object using the ChatRoom mChatMessage = try mChatroom!.createMessageFromUtf8(message: msgToSend) // Then we can send it, progress will be notified using the onMsgStateChanged callback mChatMessage!.addDelegate(delegate: mChatMessageDelegate) // Send the message mChatMessage!.send() // Clear the message input field msgToSend.removeAll() } catch { NSLog(error.localizedDescription) } } func sendFile() { do { if (mChatroom == nil) { // We need a ChatRoom object to send chat messages in it, so let's create it if it hasn't been done yet createBasicChatRoom() } // We need to create a Content for our file transfer let content = try Factory.Instance.createContent() // Every content needs a content type & subtype content.name = "file_to_transfer.txt" content.type = "text" content.subtype = "plain" // The simplest way to upload a file is to provide it's path content.filePath = fileUrl.path // We need to create a ChatMessage object using the ChatRoom let chatMessage = try mChatroom!.createFileTransferMessage(initialContent: content) // Then we can send it, progress will be notified using the onMsgStateChanged callback chatMessage.addDelegate(delegate: mChatMessageDelegate) // Ensure a file sharing server URL is correctly set in the Core mCore.fileTransferServer = "https://www.linphone.org:444/lft.php" // Send the message chatMessage.send() } catch { NSLog(error.localizedDescription) } } func downloadLastFileMessage() { if let message = mLastFileMessageReceived { for content in message.contents { if (content.isFileTransfer && content.filePath.isEmpty) { let contentName = content.name if (!contentName.isEmpty) { content.filePath = fileFolderUrl!.appendingPathComponent(contentName).path print("Start downloading \(content.name) into \(content.filePath)") isDownloading = true if (!message.downloadContent(content: content)) { print ("Download of \(contentName) failed") } } } } } } }