- Added to main menu possibility to export and import all application date.
- Improved encryption/decryption of exported/imported data. If accounts were exported, they need to be exported again. - Lots of other implemetation improvements.
This commit is contained in:
@ -3,7 +3,6 @@ package com.tutpro.baresip
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
@ -12,7 +11,6 @@ import android.app.AlertDialog
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
class AccountsActivity : AppCompatActivity() {
|
class AccountsActivity : AppCompatActivity() {
|
||||||
@ -20,7 +18,6 @@ class AccountsActivity : AppCompatActivity() {
|
|||||||
internal lateinit var alAdapter: AccountListAdapter
|
internal lateinit var alAdapter: AccountListAdapter
|
||||||
|
|
||||||
internal var aor = ""
|
internal var aor = ""
|
||||||
internal var password = ""
|
|
||||||
|
|
||||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
@ -69,6 +66,7 @@ class AccountsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
@ -92,7 +90,6 @@ class AccountsActivity : AppCompatActivity() {
|
|||||||
if (Utils.requestPermission(this,
|
if (Utils.requestPermission(this,
|
||||||
android.Manifest.permission.READ_EXTERNAL_STORAGE))
|
android.Manifest.permission.READ_EXTERNAL_STORAGE))
|
||||||
askPassword(getString(R.string.decrypt_password))
|
askPassword(getString(R.string.decrypt_password))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
@ -120,7 +117,6 @@ class AccountsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun askPassword(title: String) {
|
private fun askPassword(title: String) {
|
||||||
val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
|
||||||
val builder = AlertDialog.Builder(this)
|
val builder = AlertDialog.Builder(this)
|
||||||
builder.setTitle(title)
|
builder.setTitle(title)
|
||||||
val viewInflated = LayoutInflater.from(this)
|
val viewInflated = LayoutInflater.from(this)
|
||||||
@ -130,17 +126,17 @@ class AccountsActivity : AppCompatActivity() {
|
|||||||
builder.setView(viewInflated)
|
builder.setView(viewInflated)
|
||||||
builder.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
builder.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
password = input.text.toString()
|
val password = input.text.toString()
|
||||||
if (password != "") {
|
if (password != "") {
|
||||||
if (title == getString(R.string.encrypt_password)) {
|
if (title == getString(R.string.encrypt_password)) {
|
||||||
if (exportAccounts(dir, password))
|
if (exportAccounts(password))
|
||||||
Utils.alertView(this, getString(R.string.info),
|
Utils.alertView(this, getString(R.string.info),
|
||||||
getString(R.string.exported_accounts))
|
getString(R.string.exported_accounts))
|
||||||
else
|
else
|
||||||
Utils.alertView(this, getString(R.string.error),
|
Utils.alertView(this, getString(R.string.error),
|
||||||
getString(R.string.export_accounts_error))
|
getString(R.string.export_accounts_error))
|
||||||
} else {
|
} else {
|
||||||
if (importAccounts(dir, password))
|
if (importAccounts(password))
|
||||||
Utils.alertView(this, getString(R.string.info),
|
Utils.alertView(this, getString(R.string.info),
|
||||||
getString(R.string.imported_accounts))
|
getString(R.string.imported_accounts))
|
||||||
else
|
else
|
||||||
@ -153,6 +149,7 @@ class AccountsActivity : AppCompatActivity() {
|
|||||||
dialog.cancel()
|
dialog.cancel()
|
||||||
}
|
}
|
||||||
builder.show()
|
builder.show()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -169,30 +166,27 @@ class AccountsActivity : AppCompatActivity() {
|
|||||||
fun saveAccounts() {
|
fun saveAccounts() {
|
||||||
var accounts = ""
|
var accounts = ""
|
||||||
for (a in Account.accounts()) accounts = accounts + a.print() + "\n"
|
for (a in Account.accounts()) accounts = accounts + a.print() + "\n"
|
||||||
Utils.putFileContents(File(BaresipService.filesPath + "/accounts"), accounts)
|
Utils.putFileContents(BaresipService.filesPath + "/accounts", accounts.toByteArray())
|
||||||
// Log.d("Baresip", "Saved accounts '${accounts}' to '${BaresipService.filesPath}/accounts'")
|
// Log.d("Baresip", "Saved accounts '${accounts}' to '${BaresipService.filesPath}/accounts'")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exportAccounts(path: File, password: String): Boolean {
|
fun exportAccounts(password: String): Boolean {
|
||||||
var accounts = ""
|
val content = Utils.getFileContents("${BaresipService.filesPath}/accounts")
|
||||||
for (a in Account.accounts())
|
if (content == null) return false
|
||||||
accounts = accounts + a.print() + "\n"
|
return Utils.encryptToFile("${BaresipService.downloadsPath}/accounts.bs",
|
||||||
return Utils.putFileContents(File(path, "accounts.bs"),
|
content, password)
|
||||||
Utils.encrypt(accounts, password))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun importAccounts(path: File, password: String): Boolean {
|
fun importAccounts(password: String): Boolean {
|
||||||
val content = Utils.getFileContents(File(path, "accounts.bs"))
|
val content = Utils.decryptFromFile("${BaresipService.downloadsPath}/accounts.bs",
|
||||||
if (content == "Failed") return false
|
password)
|
||||||
val accounts = Utils.decrypt(content, password)
|
if (content == null) return false
|
||||||
if (accounts == "") return false
|
return Utils.putFileContents("${BaresipService.filesPath}/accounts", content)
|
||||||
return Utils.putFileContents(File(BaresipService.filesPath + "/accounts"),
|
|
||||||
accounts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun noAccounts(): Boolean {
|
fun noAccounts(): Boolean {
|
||||||
return Utils.getFileContents(File(BaresipService.filesPath + "/accounts"))
|
val contents = Utils.getFileContents(BaresipService.filesPath + "/accounts")
|
||||||
.length == 0
|
return contents == null || contents.size == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import android.view.View
|
|||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import android.support.v4.content.LocalBroadcastManager
|
import android.support.v4.content.LocalBroadcastManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
import android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE
|
import android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE
|
||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
@ -55,6 +56,7 @@ class BaresipService: Service() {
|
|||||||
intent.setPackage("com.tutpro.baresip")
|
intent.setPackage("com.tutpro.baresip")
|
||||||
|
|
||||||
filesPath = filesDir.absolutePath
|
filesPath = filesDir.absolutePath
|
||||||
|
downloadsPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path
|
||||||
|
|
||||||
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
|
||||||
@ -146,7 +148,7 @@ class BaresipService: Service() {
|
|||||||
try {
|
try {
|
||||||
File(filesPath).mkdirs()
|
File(filesPath).mkdirs()
|
||||||
} catch (e: Error) {
|
} catch (e: Error) {
|
||||||
Log.e(LOG_TAG, "Failed to create directory: " + e.toString())
|
Log.e(LOG_TAG, "Failed to create directory: $e")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (a in assets) {
|
for (a in assets) {
|
||||||
@ -172,8 +174,9 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsActivity.restoreContacts(applicationContext.filesDir, "contacts")
|
Contact.restore()
|
||||||
Message.restoreMessages()
|
CallHistory.restore()
|
||||||
|
Message.restore()
|
||||||
|
|
||||||
Thread(Runnable { baresipStart(filesPath) }).start()
|
Thread(Runnable { baresipStart(filesPath) }).start()
|
||||||
isServiceRunning = true
|
isServiceRunning = true
|
||||||
@ -212,7 +215,7 @@ class BaresipService: Service() {
|
|||||||
Api.ua_hangup(call.ua.uap, callp, 486, "Rejected")
|
Api.ua_hangup(call.ua.uap, callp, 486, "Rejected")
|
||||||
if (call.ua.account.callHistory) {
|
if (call.ua.account.callHistory) {
|
||||||
CallHistory.add(CallHistory(aor, peerUri, "in", false))
|
CallHistory.add(CallHistory(aor, peerUri, "in", false))
|
||||||
CallHistory.save(filesPath)
|
CallHistory.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,7 +423,7 @@ class BaresipService: Service() {
|
|||||||
Api.ua_hangup(uap, callp, 486, "Busy Here")
|
Api.ua_hangup(uap, callp, 486, "Busy Here")
|
||||||
if (ua.account.callHistory) {
|
if (ua.account.callHistory) {
|
||||||
CallHistory.add(CallHistory(aor, peerUri, "in", false))
|
CallHistory.add(CallHistory(aor, peerUri, "in", false))
|
||||||
CallHistory.save(filesPath)
|
CallHistory.save()
|
||||||
ua.account.missedCalls = true
|
ua.account.missedCalls = true
|
||||||
}
|
}
|
||||||
if (!Utils.isVisible())
|
if (!Utils.isVisible())
|
||||||
@ -499,7 +502,7 @@ class BaresipService: Service() {
|
|||||||
call.onhold = false
|
call.onhold = false
|
||||||
if (ua.account.callHistory) {
|
if (ua.account.callHistory) {
|
||||||
CallHistory.add(CallHistory(aor, call.peerURI, call.dir, true))
|
CallHistory.add(CallHistory(aor, call.peerURI, call.dir, true))
|
||||||
CallHistory.save(filesPath)
|
CallHistory.save()
|
||||||
call.hasHistory = true
|
call.hasHistory = true
|
||||||
}
|
}
|
||||||
if (call.dir == "in") {
|
if (call.dir == "in") {
|
||||||
@ -589,7 +592,7 @@ class BaresipService: Service() {
|
|||||||
calls.remove(call)
|
calls.remove(call)
|
||||||
if (ua.account.callHistory && !call.hasHistory) {
|
if (ua.account.callHistory && !call.hasHistory) {
|
||||||
CallHistory.add(CallHistory(aor, call.peerURI, call.dir, false))
|
CallHistory.add(CallHistory(aor, call.peerURI, call.dir, false))
|
||||||
CallHistory.save(filesPath)
|
CallHistory.save()
|
||||||
if (call.dir == "in") ua.account.missedCalls = true
|
if (call.dir == "in") ua.account.missedCalls = true
|
||||||
}
|
}
|
||||||
if (Call.calls().size == 0) {
|
if (Call.calls().size == 0) {
|
||||||
@ -636,7 +639,7 @@ class BaresipService: Service() {
|
|||||||
Log.d(LOG_TAG, "Message event for $uap from $peer at $timeStamp")
|
Log.d(LOG_TAG, "Message event for $uap from $peer at $timeStamp")
|
||||||
Message.add(Message(ua.account.aor, peer, text, timeStamp.toLong(),
|
Message.add(Message(ua.account.aor, peer, text, timeStamp.toLong(),
|
||||||
R.drawable.arrow_down_green, 0, "", true))
|
R.drawable.arrow_down_green, 0, "", true))
|
||||||
Message.saveMessages()
|
Message.save()
|
||||||
ua.account.unreadMessages = true
|
ua.account.unreadMessages = true
|
||||||
if (!Utils.isVisible()) {
|
if (!Utils.isVisible()) {
|
||||||
val intent = Intent(this, BaresipService::class.java)
|
val intent = Intent(this, BaresipService::class.java)
|
||||||
@ -930,6 +933,7 @@ class BaresipService: Service() {
|
|||||||
var dynDns = false
|
var dynDns = false
|
||||||
|
|
||||||
var filesPath = ""
|
var filesPath = ""
|
||||||
|
var downloadsPath = ""
|
||||||
var uas = ArrayList<UserAgent>()
|
var uas = ArrayList<UserAgent>()
|
||||||
var status = ArrayList<Int>()
|
var status = ArrayList<Int>()
|
||||||
var calls = ArrayList<Call>()
|
var calls = ArrayList<Call>()
|
||||||
|
|||||||
@ -45,9 +45,9 @@ class CallHistory(val aor: String, val peerURI: String, val direction: String,
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save(path: String) {
|
fun save() {
|
||||||
Log.d("Baresip", "Saving history of size ${BaresipService.history.size}")
|
Log.d("Baresip", "Saving call history of size ${BaresipService.history.size}")
|
||||||
val file = File(path, "history")
|
val file = File(BaresipService.filesPath, "history")
|
||||||
try {
|
try {
|
||||||
val fos = FileOutputStream(file)
|
val fos = FileOutputStream(file)
|
||||||
val oos = ObjectOutputStream(fos)
|
val oos = ObjectOutputStream(fos)
|
||||||
@ -60,21 +60,19 @@ class CallHistory(val aor: String, val peerURI: String, val direction: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restore(path: String) {
|
fun restore() {
|
||||||
val file = File(path + "/history")
|
val file = File(BaresipService.filesPath, "history")
|
||||||
if (file.exists()) {
|
if (file.exists())
|
||||||
try {
|
try {
|
||||||
val fis = FileInputStream(file)
|
val fis = FileInputStream(file)
|
||||||
val ois = ObjectInputStream(fis)
|
val ois = ObjectInputStream(fis)
|
||||||
BaresipService.history = ois.readObject() as ArrayList<CallHistory>
|
BaresipService.history = ois.readObject() as ArrayList<CallHistory>
|
||||||
ois.close()
|
ois.close()
|
||||||
fis.close()
|
fis.close()
|
||||||
Log.d("Baresip", "Restored history of size ${BaresipService.history.size}")
|
Log.d("Baresip", "Restored call history of size ${BaresipService.history.size}")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("Baresip", "InputStream exception: - " + e.toString())
|
Log.e("Baresip", "InputStream exception: - " + e.toString())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun print() {
|
fun print() {
|
||||||
|
|||||||
@ -127,7 +127,7 @@ class CallsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
|
||||||
CallHistory.save(applicationContext.filesDir.absolutePath)
|
CallHistory.save()
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ class CallsActivity : AppCompatActivity() {
|
|||||||
aor.substringAfter(":")))
|
aor.substringAfter(":")))
|
||||||
deleteDialog.setPositiveButton(getText(R.string.delete)) { dialog, _ ->
|
deleteDialog.setPositiveButton(getText(R.string.delete)) { dialog, _ ->
|
||||||
CallHistory.clear(aor)
|
CallHistory.clear(aor)
|
||||||
CallHistory.save(applicationContext.filesDir.absolutePath)
|
CallHistory.save()
|
||||||
aorGenerateHistory(aor)
|
aorGenerateHistory(aor)
|
||||||
clAdapter.notifyDataSetChanged()
|
clAdapter.notifyDataSetChanged()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class ChatActivity : AppCompatActivity() {
|
|||||||
if (chatMessages.size == 0) {
|
if (chatMessages.size == 0) {
|
||||||
listView.removeFooterView(footerView)
|
listView.removeFooterView(footerView)
|
||||||
}
|
}
|
||||||
Message.saveMessages()
|
Message.save()
|
||||||
}
|
}
|
||||||
DialogInterface.BUTTON_NEUTRAL -> {
|
DialogInterface.BUTTON_NEUTRAL -> {
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ class ChatActivity : AppCompatActivity() {
|
|||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (save) Message.saveMessages()
|
if (save) Message.save()
|
||||||
imm.hideSoftInputFromWindow(newMessage.windowToken, 0)
|
imm.hideSoftInputFromWindow(newMessage.windowToken, 0)
|
||||||
BaresipService.activities.removeAt(0)
|
BaresipService.activities.removeAt(0)
|
||||||
val i = Intent()
|
val i = Intent()
|
||||||
|
|||||||
@ -72,7 +72,7 @@ class ChatsActivity: AppCompatActivity() {
|
|||||||
clAdapter.remove(m)
|
clAdapter.remove(m)
|
||||||
clAdapter.notifyDataSetChanged()
|
clAdapter.notifyDataSetChanged()
|
||||||
BaresipService.messages = msgs
|
BaresipService.messages = msgs
|
||||||
Message.saveMessages()
|
Message.save()
|
||||||
uaMessages = uaMessages(aor)
|
uaMessages = uaMessages(aor)
|
||||||
}
|
}
|
||||||
DialogInterface.BUTTON_NEUTRAL -> {
|
DialogInterface.BUTTON_NEUTRAL -> {
|
||||||
@ -159,7 +159,7 @@ class ChatsActivity: AppCompatActivity() {
|
|||||||
aor.substringAfter(":")))
|
aor.substringAfter(":")))
|
||||||
deleteDialog.setPositiveButton(getText(R.string.delete)) { dialog, _ ->
|
deleteDialog.setPositiveButton(getText(R.string.delete)) { dialog, _ ->
|
||||||
Message.clear(aor)
|
Message.clear(aor)
|
||||||
Message.saveMessages()
|
Message.save()
|
||||||
uaMessages.clear()
|
uaMessages.clear()
|
||||||
clAdapter.notifyDataSetChanged()
|
clAdapter.notifyDataSetChanged()
|
||||||
Account.findUa(aor)!!.account.unreadMessages = false
|
Account.findUa(aor)!!.account.unreadMessages = false
|
||||||
@ -227,7 +227,7 @@ class ChatsActivity: AppCompatActivity() {
|
|||||||
if ((Message.messages()[i].aor == aor) &&
|
if ((Message.messages()[i].aor == aor) &&
|
||||||
(Message.messages()[i].timeStamp == time)) {
|
(Message.messages()[i].timeStamp == time)) {
|
||||||
Message.messages()[i].new = false
|
Message.messages()[i].new = false
|
||||||
Message.saveMessages()
|
Message.save()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +237,7 @@ class ChatsActivity: AppCompatActivity() {
|
|||||||
if ((Message.messages()[i].aor == aor) &&
|
if ((Message.messages()[i].aor == aor) &&
|
||||||
(Message.messages()[i].timeStamp == time)) {
|
(Message.messages()[i].timeStamp == time)) {
|
||||||
Message.messages().removeAt(i)
|
Message.messages().removeAt(i)
|
||||||
Message.saveMessages()
|
Message.save()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import java.io.File
|
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
object Config {
|
object Config {
|
||||||
|
|
||||||
private val path = BaresipService.filesPath + "/config"
|
private val configPath = BaresipService.filesPath + "/config"
|
||||||
private val file = File(path)
|
private var config = String(Utils.getFileContents(configPath)!!, StandardCharsets.ISO_8859_1)
|
||||||
private var config = Utils.getFileContents(file)
|
|
||||||
|
|
||||||
fun initialize(dnsServers: List<InetAddress>) {
|
fun initialize(dnsServers: List<InetAddress>) {
|
||||||
|
Log.d("Baresip", "Config is '$config'")
|
||||||
var write = false
|
var write = false
|
||||||
if (!config.contains("zrtp_hash")) {
|
if (!config.contains("zrtp_hash")) {
|
||||||
config = "${config}zrtp_hash yes\n"
|
config = "${config}zrtp_hash yes\n"
|
||||||
@ -41,10 +42,10 @@ object Config {
|
|||||||
}
|
}
|
||||||
if (!config.contains("opus_samplerate")) {
|
if (!config.contains("opus_samplerate")) {
|
||||||
config = "${config}opus_samplerate 16000\n"
|
config = "${config}opus_samplerate 16000\n"
|
||||||
val accountsFile = File(BaresipService.filesPath + "/config")
|
val accountsPath = BaresipService.filesPath + "/accounts"
|
||||||
var accounts = Utils.getFileContents(accountsFile)
|
var accounts = String(Utils.getFileContents(accountsPath)!!, StandardCharsets.ISO_8859_1)
|
||||||
accounts = accounts.replace("opus/48000/1", "opus/16000/1")
|
accounts = accounts.replace("opus/48000/1", "opus/16000/1")
|
||||||
Utils.putFileContents(accountsFile, accounts)
|
Utils.putFileContents(accountsPath, accounts.toByteArray())
|
||||||
write = true
|
write = true
|
||||||
}
|
}
|
||||||
if (!config.contains("opus_stereo")) {
|
if (!config.contains("opus_stereo")) {
|
||||||
@ -95,7 +96,7 @@ object Config {
|
|||||||
}
|
}
|
||||||
if (write) {
|
if (write) {
|
||||||
Log.e("Baresip", "Writing config '$config'")
|
Log.e("Baresip", "Writing config '$config'")
|
||||||
Utils.putFileContents(file, config)
|
Utils.putFileContents(configPath, config.toByteArray())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +116,7 @@ object Config {
|
|||||||
|
|
||||||
fun remove(variable: String) {
|
fun remove(variable: String) {
|
||||||
config = Utils.removeLinesStartingWithName(config, variable)
|
config = Utils.removeLinesStartingWithName(config, variable)
|
||||||
Utils.putFileContents(file, config)
|
Utils.putFileContents(configPath, config.toByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replace(variable: String, value: String) {
|
fun replace(variable: String, value: String) {
|
||||||
@ -124,7 +125,7 @@ object Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun reset(ctx: Context) {
|
fun reset(ctx: Context) {
|
||||||
Utils.copyAssetToFile(ctx, "config", path)
|
Utils.copyAssetToFile(ctx, "config", configPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
@ -133,7 +134,7 @@ object Config {
|
|||||||
if (line.length > 0)
|
if (line.length > 0)
|
||||||
result = result + line + '\n'
|
result = result + line + '\n'
|
||||||
config = result
|
config = result
|
||||||
Utils.putFileContents(file, config)
|
Utils.putFileContents(configPath, config.toByteArray())
|
||||||
Log.d("Baresip", "New config '$result'")
|
Log.d("Baresip", "New config '$result'")
|
||||||
// Api.reload_config()
|
// Api.reload_config()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,15 +6,12 @@ import android.content.Intent
|
|||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class ConfigActivity : AppCompatActivity() {
|
class ConfigActivity : AppCompatActivity() {
|
||||||
|
|
||||||
internal lateinit var autoStart: CheckBox
|
internal lateinit var autoStart: CheckBox
|
||||||
@ -44,8 +41,6 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
private var callVolume = BaresipService.callVolume
|
private var callVolume = BaresipService.callVolume
|
||||||
private var save = false
|
private var save = false
|
||||||
private var restart = false
|
private var restart = false
|
||||||
private var downloadsDir =
|
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
@ -226,14 +221,13 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
if (!Utils.requestPermission(this,
|
if (!Utils.requestPermission(this,
|
||||||
android.Manifest.permission.READ_EXTERNAL_STORAGE))
|
android.Manifest.permission.READ_EXTERNAL_STORAGE))
|
||||||
return false
|
return false
|
||||||
val content = Utils.getFileContents(File(downloadsDir, "cert.pem"))
|
val content = Utils.getFileContents(BaresipService.downloadsPath + "/cert.pem")
|
||||||
if (content == "Failed") {
|
if (content == null) {
|
||||||
Utils.alertView(this, getString(R.string.error),
|
Utils.alertView(this, getString(R.string.error),
|
||||||
getString(R.string.read_cert_error))
|
getString(R.string.read_cert_error))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Utils.putFileContents(File(BaresipService.filesPath + "/cert.pem"),
|
Utils.putFileContents(BaresipService.filesPath + "/cert.pem", content)
|
||||||
content)
|
|
||||||
Config.remove("sip_certificate")
|
Config.remove("sip_certificate")
|
||||||
Config.add("sip_certificate", BaresipService.filesPath + "/cert.pem")
|
Config.add("sip_certificate", BaresipService.filesPath + "/cert.pem")
|
||||||
} else {
|
} else {
|
||||||
@ -248,13 +242,13 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
if (!Utils.requestPermission(this,
|
if (!Utils.requestPermission(this,
|
||||||
android.Manifest.permission.READ_EXTERNAL_STORAGE))
|
android.Manifest.permission.READ_EXTERNAL_STORAGE))
|
||||||
return false
|
return false
|
||||||
val content = Utils.getFileContents(File(downloadsDir, "ca_certs.crt"))
|
val content = Utils.getFileContents(BaresipService.downloadsPath + "/ca_certs.crt")
|
||||||
if (content == "Failed") {
|
if (content == null) {
|
||||||
Utils.alertView(this, getString(R.string.error),
|
Utils.alertView(this, getString(R.string.error),
|
||||||
getString(R.string.read_ca_certs_error))
|
getString(R.string.read_ca_certs_error))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Utils.putFileContents(File(BaresipService.filesPath + "/ca_certs.crt"),
|
Utils.putFileContents(BaresipService.filesPath + "/ca_certs.crt",
|
||||||
content)
|
content)
|
||||||
Config.remove("sip_cafile")
|
Config.remove("sip_cafile")
|
||||||
Config.add("sip_cafile", BaresipService.filesPath + "/ca_certs.crt")
|
Config.add("sip_cafile", BaresipService.filesPath + "/ca_certs.crt")
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
class Contact(var name: String, var uri: String) {
|
class Contact(var name: String, var uri: String) {
|
||||||
@ -12,5 +13,47 @@ class Contact(var name: String, var uri: String) {
|
|||||||
return BaresipService.contacts
|
return BaresipService.contacts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun save(): Boolean {
|
||||||
|
var contents = ""
|
||||||
|
for (c in BaresipService.contacts) contents += "\"${c.name}\" <${c.uri}>\n"
|
||||||
|
return Utils.putFileContents(BaresipService.filesPath + "/contacts",
|
||||||
|
contents.toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun restore(): Boolean {
|
||||||
|
val content = Utils.getFileContents(BaresipService.filesPath + "/contacts")
|
||||||
|
if (content == null) return false
|
||||||
|
val contacts = String(content, StandardCharsets.ISO_8859_1)
|
||||||
|
Api.contacts_remove()
|
||||||
|
BaresipService.contacts.clear()
|
||||||
|
contacts.lines().forEach {
|
||||||
|
val parts = it.split("\"")
|
||||||
|
if (parts.size == 3) {
|
||||||
|
val name = parts[1]
|
||||||
|
var uri = parts[2].trim()
|
||||||
|
if (uri.startsWith("<"))
|
||||||
|
uri = uri.substringAfter("<").substringBefore(">")
|
||||||
|
// Currently no need to make baresip aware of the contact
|
||||||
|
// Api.contact_add("\"$name\" $uri")
|
||||||
|
BaresipService.contacts.add(Contact(name, uri))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun export(): Boolean {
|
||||||
|
return Utils.putFileContents(BaresipService.downloadsPath + "/contacts.bs",
|
||||||
|
Utils.getFileContents(BaresipService.filesPath + "/contacts")!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun import(): Boolean {
|
||||||
|
val contacts = Utils.getFileContents(BaresipService.downloadsPath + "/contacts.bs")
|
||||||
|
if (contacts != null) {
|
||||||
|
Utils.putFileContents(BaresipService.filesPath + "/contacts", contacts)
|
||||||
|
return restore()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ class ContactActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Contact.contacts().sortBy { Contact -> Contact.name }
|
Contact.contacts().sortBy { Contact -> Contact.name }
|
||||||
ContactsActivity.saveContacts(applicationContext.filesDir, "contacts")
|
Contact.save()
|
||||||
|
|
||||||
i.putExtra("name", newName)
|
i.putExtra("name", newName)
|
||||||
setResult(Activity.RESULT_OK, i)
|
setResult(Activity.RESULT_OK, i)
|
||||||
|
|||||||
@ -67,7 +67,7 @@ class ContactListAdapter(private val cxt: Context, private val rows: ArrayList<C
|
|||||||
when (which) {
|
when (which) {
|
||||||
DialogInterface.BUTTON_POSITIVE -> {
|
DialogInterface.BUTTON_POSITIVE -> {
|
||||||
Contact.contacts().removeAt(pos)
|
Contact.contacts().removeAt(pos)
|
||||||
ContactsActivity.saveContacts(cxt.applicationContext.filesDir, "contacts")
|
Contact.save()
|
||||||
this.notifyDataSetChanged()
|
this.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
DialogInterface.BUTTON_NEGATIVE -> {
|
DialogInterface.BUTTON_NEGATIVE -> {
|
||||||
|
|||||||
@ -3,15 +3,12 @@ package com.tutpro.baresip
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.ListView
|
import android.widget.ListView
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class ContactsActivity : AppCompatActivity() {
|
class ContactsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
internal lateinit var clAdapter: ContactListAdapter
|
internal lateinit var clAdapter: ContactListAdapter
|
||||||
@ -63,12 +60,10 @@ class ContactsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
|
||||||
val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
|
||||||
|
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
|
||||||
R.id.export_contacts -> {
|
R.id.export_contacts -> {
|
||||||
if (saveContacts(dir, "contacts.bs"))
|
if (Contact.export())
|
||||||
Utils.alertView(this, "",
|
Utils.alertView(this, "",
|
||||||
getString(R.string.exported_contacts))
|
getString(R.string.exported_contacts))
|
||||||
else
|
else
|
||||||
@ -77,11 +72,11 @@ class ContactsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.import_contacts -> {
|
R.id.import_contacts -> {
|
||||||
if (restoreContacts(dir, "contacts.bs")) {
|
if (Contact.import()) {
|
||||||
Utils.alertView(this, "",
|
Utils.alertView(this, "",
|
||||||
getString(R.string.imported_contacts))
|
getString(R.string.imported_contacts))
|
||||||
clAdapter.notifyDataSetChanged()
|
clAdapter.notifyDataSetChanged()
|
||||||
saveContacts(applicationContext.filesDir, "contacts")
|
Contact.save()
|
||||||
} else
|
} else
|
||||||
Utils.alertView(this,getString(R.string.error),
|
Utils.alertView(this,getString(R.string.error),
|
||||||
getString(R.string.import_error))
|
getString(R.string.import_error))
|
||||||
@ -111,33 +106,6 @@ class ContactsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun saveContacts(path: File, file: String): Boolean {
|
|
||||||
var contents = ""
|
|
||||||
for (c in Contact.contacts())
|
|
||||||
contents += "\"${c.name}\" <${c.uri}>\n"
|
|
||||||
return Utils.putFileContents(File(path, file), contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun restoreContacts(path: File, file: String): Boolean {
|
|
||||||
val content = Utils.getFileContents(File(path, file))
|
|
||||||
if (content == "Failed") return false
|
|
||||||
Api.contacts_remove()
|
|
||||||
Contact.contacts().clear()
|
|
||||||
content.lines().forEach {
|
|
||||||
val parts = it.split("\"")
|
|
||||||
if (parts.size == 3) {
|
|
||||||
val name = parts[1]
|
|
||||||
var uri = parts[2].trim()
|
|
||||||
if (uri.startsWith("<"))
|
|
||||||
uri = uri.substringAfter("<").substringBefore(">")
|
|
||||||
// Currently no need to make baresip aware of the contact
|
|
||||||
// Api.contact_add("\"$name\" $uri")
|
|
||||||
Contact.contacts().add(Contact(name, uri))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findContactURI(name: String): String {
|
fun findContactURI(name: String): String {
|
||||||
for (c in Contact.contacts())
|
for (c in Contact.contacts())
|
||||||
if (c.name == name)
|
if (c.name == name)
|
||||||
|
|||||||
@ -404,8 +404,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intentAction == null)
|
|
||||||
CallHistory.restore(applicationContext.filesDir.absolutePath)
|
|
||||||
callsButton.setOnClickListener {
|
callsButton.setOnClickListener {
|
||||||
if (aorSpinner.selectedItemPosition >= 0) {
|
if (aorSpinner.selectedItemPosition >= 0) {
|
||||||
val i = Intent(this@MainActivity, CallsActivity::class.java)
|
val i = Intent(this@MainActivity, CallsActivity::class.java)
|
||||||
@ -891,22 +889,28 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
baresipService.setAction("ToggleSpeaker")
|
baresipService.setAction("ToggleSpeaker")
|
||||||
startService(baresipService)
|
startService(baresipService)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
R.id.config -> {
|
R.id.config -> {
|
||||||
i = Intent(this, ConfigActivity::class.java)
|
i = Intent(this, ConfigActivity::class.java)
|
||||||
startActivityForResult(i, CONFIG_CODE)
|
startActivityForResult(i, CONFIG_CODE)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
R.id.accounts -> {
|
R.id.accounts -> {
|
||||||
i = Intent(this, AccountsActivity::class.java)
|
i = Intent(this, AccountsActivity::class.java)
|
||||||
startActivityForResult(i, ACCOUNTS_CODE)
|
startActivityForResult(i, ACCOUNTS_CODE)
|
||||||
return true
|
}
|
||||||
|
R.id.export_all -> {
|
||||||
|
if (Utils.requestPermission(this,
|
||||||
|
android.Manifest.permission.WRITE_EXTERNAL_STORAGE))
|
||||||
|
askPassword(getString(R.string.encrypt_password))
|
||||||
|
}
|
||||||
|
R.id.import_all -> {
|
||||||
|
if (Utils.requestPermission(this,
|
||||||
|
android.Manifest.permission.READ_EXTERNAL_STORAGE))
|
||||||
|
askPassword(getString(R.string.decrypt_password))
|
||||||
}
|
}
|
||||||
R.id.about -> {
|
R.id.about -> {
|
||||||
i = Intent(this, AboutActivity::class.java)
|
i = Intent(this, AboutActivity::class.java)
|
||||||
startActivityForResult(i, ABOUT_CODE)
|
startActivityForResult(i, ABOUT_CODE)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
R.id.restart, R.id.quit -> {
|
R.id.restart, R.id.quit -> {
|
||||||
if (stopState == "initial") {
|
if (stopState == "initial") {
|
||||||
@ -921,10 +925,77 @@ class MainActivity : AppCompatActivity() {
|
|||||||
System.exit(0)
|
System.exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
else -> return super.onOptionsItemSelected(item)
|
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun askPassword(title: String) {
|
||||||
|
val builder = android.app.AlertDialog.Builder(this)
|
||||||
|
builder.setTitle(title)
|
||||||
|
val viewInflated = LayoutInflater.from(this)
|
||||||
|
.inflate(R.layout.password_dialog, findViewById(android.R.id.content) as ViewGroup,
|
||||||
|
false)
|
||||||
|
val input = viewInflated.findViewById(R.id.password) as EditText
|
||||||
|
builder.setView(viewInflated)
|
||||||
|
builder.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
val password = input.text.toString()
|
||||||
|
if (password != "") {
|
||||||
|
if (title == getString(R.string.encrypt_password))
|
||||||
|
exportAll(password)
|
||||||
|
else
|
||||||
|
importAll(password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.setNegativeButton(android.R.string.cancel) { dialog, _ ->
|
||||||
|
dialog.cancel()
|
||||||
|
}
|
||||||
|
builder.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exportAll(password: String) {
|
||||||
|
val files = arrayOf("accounts", "config", "contacts", "history", "messages", "uuid",
|
||||||
|
"zrtp_cache.dat", "zrtp_zid", "cert.pem", "ca_cert", "ca_certs.crt")
|
||||||
|
val exportFilePath = BaresipService.downloadsPath + "/baresip.bs"
|
||||||
|
val zipFilePath = BaresipService.filesPath + "/baresip.zip"
|
||||||
|
if (!Utils.zip(files, "baresip.zip")) {
|
||||||
|
Utils.alertView(this, getString(R.string.error), "Failed to write zip file 'baresip.zip")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val content = Utils.getFileContents(zipFilePath)
|
||||||
|
if (content == null) {
|
||||||
|
Utils.alertView(this, getString(R.string.error), "Failed to read zip file 'baresip.zip")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!Utils.encryptToFile(exportFilePath, content, password)) {
|
||||||
|
Utils.alertView(this, getString(R.string.error), getString(R.string.export_all_failed))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Utils.alertView(this, getString(R.string.info), getString(R.string.exported_all))
|
||||||
|
Utils.deleteFile(zipFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun importAll(password: String) {
|
||||||
|
val importFilePath = BaresipService.downloadsPath + "/baresip.bs"
|
||||||
|
val zipFilePath = BaresipService.filesPath + "/baresip.zip"
|
||||||
|
val zipData = Utils.decryptFromFile(importFilePath, password)
|
||||||
|
if (zipData == null) {
|
||||||
|
Utils.alertView(this, getString(R.string.error), getString(R.string.import_all_failed))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!Utils.putFileContents(zipFilePath, zipData)) {
|
||||||
|
Utils.alertView(this, getString(R.string.error),
|
||||||
|
"Failed to write file 'baresip.zip'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!Utils.unZip(zipFilePath)) {
|
||||||
|
Utils.alertView(this, getString(R.string.error),
|
||||||
|
"Failed to unzip file 'baresip.zip'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Utils.alertView(this, getString(R.string.info), getString(R.string.imported_all))
|
||||||
|
Utils.deleteFile(zipFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim
|
|||||||
while (it.hasNext()) if (it.next().aor == aor) it.remove()
|
while (it.hasNext()) if (it.next().aor == aor) it.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveMessages() {
|
fun save() {
|
||||||
val file = File(BaresipService.filesPath, "messages")
|
val file = File(BaresipService.filesPath, "messages")
|
||||||
try {
|
try {
|
||||||
val fos = FileOutputStream(file)
|
val fos = FileOutputStream(file)
|
||||||
@ -51,7 +51,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restoreMessages() {
|
fun restore() {
|
||||||
val file = File(BaresipService.filesPath, "messages")
|
val file = File(BaresipService.filesPath, "messages")
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
|
||||||
import java.io.File
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
class RunOnStartup : BroadcastReceiver() {
|
class RunOnStartup : BroadcastReceiver() {
|
||||||
|
|
||||||
@ -13,8 +13,8 @@ class RunOnStartup : BroadcastReceiver() {
|
|||||||
Log.i("Baresip", "RunOnStartup received intent ${intent.action}")
|
Log.i("Baresip", "RunOnStartup received intent ${intent.action}")
|
||||||
if ((intent.action == Intent.ACTION_BOOT_COMPLETED) or
|
if ((intent.action == Intent.ACTION_BOOT_COMPLETED) or
|
||||||
(intent.action == "com.tutpro.baresip.Restart")) {
|
(intent.action == "com.tutpro.baresip.Restart")) {
|
||||||
val configFile = File(context.filesDir.absolutePath + "/config")
|
val configPath = context.filesDir.absolutePath + "/config"
|
||||||
val config = Utils.getFileContents(configFile)
|
val config = String(Utils.getFileContents(configPath)!!, StandardCharsets.ISO_8859_1)
|
||||||
val asCv = Utils.getNameValue(config,"auto_start")
|
val asCv = Utils.getNameValue(config,"auto_start")
|
||||||
if ((asCv.size > 0) && (asCv[0] == "yes")) {
|
if ((asCv.size > 0) && (asCv[0] == "yes")) {
|
||||||
Log.d("Baresip", "Start baresip upon boot completed or restart")
|
Log.d("Baresip", "Start baresip upon boot completed or restart")
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import android.app.Activity
|
|||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.os.PowerManager
|
|
||||||
import android.app.KeyguardManager
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -13,8 +11,6 @@ import android.support.v4.app.ActivityCompat
|
|||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.util.Base64
|
|
||||||
import android.util.Base64.encodeToString
|
|
||||||
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.Exception
|
import kotlin.Exception
|
||||||
@ -22,57 +18,16 @@ import kotlin.Exception
|
|||||||
import java.io.*
|
import java.io.*
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.nio.ByteBuffer
|
import java.util.zip.*
|
||||||
|
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.SecretKeyFactory
|
import javax.crypto.SecretKeyFactory
|
||||||
import javax.crypto.spec.GCMParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
import javax.crypto.spec.PBEKeySpec
|
import javax.crypto.spec.PBEKeySpec
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
object Utils {
|
object Utils {
|
||||||
|
|
||||||
fun getFileContents(file: File): String {
|
|
||||||
if (!file.exists()) {
|
|
||||||
Log.e("Baresip", "Failed to find file: " + file.path)
|
|
||||||
return "Failed"
|
|
||||||
} else {
|
|
||||||
val length = file.length().toInt()
|
|
||||||
val bytes = ByteArray(length)
|
|
||||||
try {
|
|
||||||
val `in` = FileInputStream(file)
|
|
||||||
try {
|
|
||||||
`in`.read(bytes)
|
|
||||||
} finally {
|
|
||||||
`in`.close()
|
|
||||||
}
|
|
||||||
return String(bytes)
|
|
||||||
} catch (e: java.io.IOException) {
|
|
||||||
Log.e("Baresip", "Failed to read file: " + file.path + ": " +
|
|
||||||
e.toString())
|
|
||||||
return "Failed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun putFileContents(file: File, contents: String): Boolean {
|
|
||||||
try {
|
|
||||||
val fOut = FileOutputStream(file.absoluteFile, false)
|
|
||||||
val fWriter = OutputStreamWriter(fOut)
|
|
||||||
try {
|
|
||||||
fWriter.write(contents)
|
|
||||||
fWriter.close()
|
|
||||||
fOut.close()
|
|
||||||
} catch (e: java.io.IOException) {
|
|
||||||
Log.e("Baresip", "Failed to put contents to file: " + e.toString())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: java.io.FileNotFoundException) {
|
|
||||||
Log.e("Baresip", "Failed to find contents file: " + e.toString())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getNameValue(string: String, name: String): ArrayList<String> {
|
fun getNameValue(string: String, name: String): ArrayList<String> {
|
||||||
val lines = string.split("\n")
|
val lines = string.split("\n")
|
||||||
val result = ArrayList<String>()
|
val result = ArrayList<String>()
|
||||||
@ -90,24 +45,6 @@ object Utils {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyAssetToFile(context: Context, asset: String, path: String) {
|
|
||||||
try {
|
|
||||||
val `is` = context.assets.open(asset)
|
|
||||||
val os = FileOutputStream(path)
|
|
||||||
val buffer = ByteArray(512)
|
|
||||||
var byteRead: Int = `is`.read(buffer)
|
|
||||||
while (byteRead != -1) {
|
|
||||||
os.write(buffer, 0, byteRead)
|
|
||||||
byteRead = `is`.read(buffer)
|
|
||||||
}
|
|
||||||
os.close()
|
|
||||||
`is`.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e("Baresip", "Failed to read asset " + asset + ": " +
|
|
||||||
e.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun alertView(context: Context, title: String, message: String) {
|
fun alertView(context: Context, title: String, message: String) {
|
||||||
val builder = AlertDialog.Builder(context)
|
val builder = AlertDialog.Builder(context)
|
||||||
builder.setTitle(title)
|
builder.setTitle(title)
|
||||||
@ -142,7 +79,7 @@ object Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun aorUser(aor: String): String {
|
private fun aorUser(aor: String): String {
|
||||||
val user = aor.substringBefore("@")
|
val user = aor.substringBefore("@")
|
||||||
return if (user == aor) "" else user
|
return if (user == aor) "" else user
|
||||||
}
|
}
|
||||||
@ -164,20 +101,20 @@ object Utils {
|
|||||||
return Regex("^(([0-1]?[0-9]{1,2}\\.)|(2[0-4][0-9]\\.)|(25[0-5]\\.)){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))$").matches(ip)
|
return Regex("^(([0-1]?[0-9]{1,2}\\.)|(2[0-4][0-9]\\.)|(25[0-5]\\.)){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))$").matches(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkIpV6(ip: String): Boolean {
|
private fun checkIpV6(ip: String): Boolean {
|
||||||
return Regex("^(([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4})$").matches(ip)
|
return Regex("^(([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4})$").matches(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkIpv6InBrackets(bracketedIp: String): Boolean {
|
private fun checkIpv6InBrackets(bracketedIp: String): Boolean {
|
||||||
return bracketedIp.startsWith("[") && bracketedIp.endsWith("]") &&
|
return bracketedIp.startsWith("[") && bracketedIp.endsWith("]") &&
|
||||||
checkIpV6(bracketedIp.substring(1, bracketedIp.length - 2))
|
checkIpV6(bracketedIp.substring(1, bracketedIp.length - 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkIp(ip: String): Boolean {
|
private fun checkIp(ip: String): Boolean {
|
||||||
return checkIpV4(ip) || checkIpV6(ip)
|
return checkIpV4(ip) || checkIpV6(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkUriUser(user: String): Boolean {
|
private fun checkUriUser(user: String): Boolean {
|
||||||
for (c in user)
|
for (c in user)
|
||||||
if (!(c.isLetterOrDigit() || c in "-_.!~*'()&=+$,;?/")) return false
|
if (!(c.isLetterOrDigit() || c in "-_.!~*'()&=+$,;?/")) return false
|
||||||
return user.length > 0
|
return user.length > 0
|
||||||
@ -193,7 +130,7 @@ object Utils {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkPort(port: String): Boolean {
|
private fun checkPort(port: String): Boolean {
|
||||||
val number = port.toIntOrNull()
|
val number = port.toIntOrNull()
|
||||||
if (number == null) return false
|
if (number == null) return false
|
||||||
return (number > 0) && (number < 65536)
|
return (number > 0) && (number < 65536)
|
||||||
@ -208,7 +145,7 @@ object Utils {
|
|||||||
checkPort(ipPort.substringAfterLast(":"))
|
checkPort(ipPort.substringAfterLast(":"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkDomainPort(domainPort: String): Boolean {
|
private fun checkDomainPort(domainPort: String): Boolean {
|
||||||
return checkDomain(domainPort.substringBeforeLast(":")) &&
|
return checkDomain(domainPort.substringBeforeLast(":")) &&
|
||||||
checkPort(domainPort.substringAfterLast(":"))
|
checkPort(domainPort.substringAfterLast(":"))
|
||||||
}
|
}
|
||||||
@ -218,13 +155,13 @@ object Utils {
|
|||||||
checkIpPort(hostPort) || checkDomainPort(hostPort)
|
checkIpPort(hostPort) || checkDomainPort(hostPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkParams(params: String): Boolean {
|
private fun checkParams(params: String): Boolean {
|
||||||
for (param in params.split(";"))
|
for (param in params.split(";"))
|
||||||
if (!checkParam(param)) return false
|
if (!checkParam(param)) return false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkParam(param: String): Boolean {
|
private fun checkParam(param: String): Boolean {
|
||||||
val nameValue = param.split("=")
|
val nameValue = param.split("=")
|
||||||
if (nameValue.size == 1)
|
if (nameValue.size == 1)
|
||||||
/* Todo: do proper check */
|
/* Todo: do proper check */
|
||||||
@ -295,23 +232,6 @@ object Utils {
|
|||||||
return appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
return appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isDeviceLocked(context: Context): Boolean {
|
|
||||||
val isLocked: Boolean
|
|
||||||
|
|
||||||
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
|
||||||
val inKeyguardRestrictedInputMode = keyguardManager.inKeyguardRestrictedInputMode()
|
|
||||||
|
|
||||||
if (inKeyguardRestrictedInputMode) {
|
|
||||||
isLocked = true
|
|
||||||
} else {
|
|
||||||
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
|
||||||
isLocked = !powerManager.isInteractive
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d("Baresip", "Now device is ${if (isLocked) "locked" else "unlocked"}")
|
|
||||||
return isLocked
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dtmfWatcher(callp: String): TextWatcher {
|
fun dtmfWatcher(callp: String): TextWatcher {
|
||||||
return object : TextWatcher {
|
return object : TextWatcher {
|
||||||
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
|
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
@ -341,81 +261,183 @@ object Utils {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encrypt(plainText: String, password: String): String {
|
fun copyAssetToFile(context: Context, asset: String, path: String) {
|
||||||
val sr = SecureRandom.getInstance("SHA1PRNG")
|
try {
|
||||||
val salt = ByteArray(16)
|
val `is` = context.assets.open(asset)
|
||||||
sr.nextBytes(salt)
|
val os = FileOutputStream(path)
|
||||||
val iterationCount = Random().nextInt(1024) + 512
|
val buffer = ByteArray(512)
|
||||||
val spec = PBEKeySpec(password.toCharArray(), salt, iterationCount, 256)
|
var byteRead: Int = `is`.read(buffer)
|
||||||
val secretKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec)
|
while (byteRead != -1) {
|
||||||
val iv = ByteArray(12)
|
os.write(buffer, 0, byteRead)
|
||||||
SecureRandom().nextBytes(iv)
|
byteRead = `is`.read(buffer)
|
||||||
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
}
|
||||||
val parameterSpec = GCMParameterSpec(128, iv)
|
os.close()
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec)
|
`is`.close()
|
||||||
val cipherText = cipher.doFinal(plainText.toByteArray())
|
} catch (e: IOException) {
|
||||||
val byteBuffer = ByteBuffer.allocate(Int.SIZE_BYTES + salt.size + Int.SIZE_BYTES +
|
Log.e("Baresip", "Failed to copy asset '$asset' to file: $e")
|
||||||
Int.SIZE_BYTES + iv.size + cipherText.size)
|
}
|
||||||
byteBuffer.putInt(salt.size)
|
|
||||||
byteBuffer.put(salt)
|
|
||||||
byteBuffer.putInt(iterationCount)
|
|
||||||
byteBuffer.putInt(iv.size)
|
|
||||||
byteBuffer.put(iv)
|
|
||||||
byteBuffer.put(cipherText)
|
|
||||||
return encodeToString(byteBuffer.array(), Base64.DEFAULT)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decrypt(cipherMessage: String, password: String): String {
|
fun deleteFile(filePath: String) {
|
||||||
val byteBuffer = ByteBuffer.wrap(Base64.decode(cipherMessage, Base64.DEFAULT))
|
val file = File(filePath)
|
||||||
val saltLength = byteBuffer.getInt()
|
if (file.exists()) file.delete()
|
||||||
if (saltLength != 16) {
|
}
|
||||||
Log.w("Baresip", "invalid salt length $saltLength")
|
|
||||||
return ""
|
fun getFileContents(filePath: String): ByteArray? {
|
||||||
}
|
|
||||||
val salt = ByteArray(saltLength)
|
|
||||||
byteBuffer.get(salt)
|
|
||||||
val iterationCount = byteBuffer.getInt()
|
|
||||||
if ((iterationCount < 512) || (iterationCount > 1023 + 512)) {
|
|
||||||
Log.w("Baresip", "invalid iteratorCount $iterationCount")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
val spec = PBEKeySpec(password.toCharArray(), salt, iterationCount, 256)
|
|
||||||
val secretKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec)
|
|
||||||
val ivLength = byteBuffer.getInt()
|
|
||||||
if (ivLength != 12) {
|
|
||||||
Log.d("Baresip", "invalid iv length $ivLength")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
val iv = ByteArray(ivLength)
|
|
||||||
byteBuffer.get(iv)
|
|
||||||
val cipherText = ByteArray(byteBuffer.remaining())
|
|
||||||
byteBuffer.get(cipherText)
|
|
||||||
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, iv))
|
|
||||||
try {
|
try {
|
||||||
return String(cipher.doFinal(cipherText))
|
return File(filePath).readBytes()
|
||||||
|
} catch(e: FileNotFoundException) {
|
||||||
|
Log.e("Baresip", "File '$filePath' not found: ${e.printStackTrace()}")
|
||||||
|
return null
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w("Baresip", "Decryption failed ${e.printStackTrace()}")
|
Log.e("Baresip", "Failed to read file '$filePath': ${e.printStackTrace()}")
|
||||||
return ""
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun putFileContents(filePath: String, contents: ByteArray): Boolean {
|
||||||
|
try {
|
||||||
|
File(filePath).writeBytes(contents)
|
||||||
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
Log.e("Baresip", "Failed to write file '$filePath': $e")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
class Crypto(val salt: ByteArray, val iter: Int, val iv: ByteArray, val data: ByteArray):
|
||||||
|
Serializable {
|
||||||
|
val serialVersionUID = -29238082928391L
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun encrypt(content: ByteArray, password: CharArray): Crypto? {
|
||||||
|
var obj: Crypto? = null
|
||||||
|
try {
|
||||||
|
val sr = SecureRandom()
|
||||||
|
val salt = ByteArray(128)
|
||||||
|
sr.nextBytes(salt)
|
||||||
|
val iterationCount = Random().nextInt(1024) + 512
|
||||||
|
val pbKeySpec = PBEKeySpec(password, salt, iterationCount, 128)
|
||||||
|
val secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
|
||||||
|
val keyBytes = secretKeyFactory.generateSecret(pbKeySpec).encoded
|
||||||
|
val keySpec = SecretKeySpec(keyBytes, "AES")
|
||||||
|
val ivRandom = SecureRandom()
|
||||||
|
val iv = ByteArray(16)
|
||||||
|
ivRandom.nextBytes(iv)
|
||||||
|
val ivSpec = IvParameterSpec(iv)
|
||||||
|
val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
|
||||||
|
val cipherData = cipher.doFinal(content)
|
||||||
|
obj = Crypto(salt, iterationCount, iv, cipherData)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("Baresip", "Encrypt failed: ${e.printStackTrace()}")
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun decrypt(obj: Crypto, password: CharArray): ByteArray? {
|
||||||
|
var plainData: ByteArray? = null
|
||||||
|
try {
|
||||||
|
val pbKeySpec = PBEKeySpec(password, obj.salt, obj.iter, 128)
|
||||||
|
val secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
|
||||||
|
val keyBytes = secretKeyFactory.generateSecret(pbKeySpec).encoded
|
||||||
|
val keySpec = SecretKeySpec(keyBytes, "AES")
|
||||||
|
val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
|
||||||
|
val ivSpec = IvParameterSpec(obj.iv)
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
|
||||||
|
plainData = cipher.doFinal(obj.data)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("Baresip", "Decrypt failed: ${e.printStackTrace()}")
|
||||||
|
}
|
||||||
|
return plainData
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun encryptToFile(filePath: String, content: ByteArray, password: String): Boolean {
|
||||||
|
val obj = encrypt(content, password.toCharArray())
|
||||||
|
try {
|
||||||
|
ObjectOutputStream(FileOutputStream(File(filePath))).use {
|
||||||
|
it.writeObject(obj)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("Baresip", "Write failed: ${e.printStackTrace()}")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decryptFromFile(filePath: String, password: String): ByteArray? {
|
||||||
|
var plainData: ByteArray? = null
|
||||||
|
try {
|
||||||
|
ObjectInputStream(FileInputStream(File(filePath))).use { it ->
|
||||||
|
val obj = it.readObject() as Crypto
|
||||||
|
plainData = decrypt(obj, password.toCharArray())
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("Baresip", "Decrypt failed from file '$filePath'")
|
||||||
|
}
|
||||||
|
return plainData
|
||||||
|
}
|
||||||
|
|
||||||
|
fun zip(fileNames: Array<String>, zipFileName: String): Boolean {
|
||||||
|
val zipFilePath = BaresipService.filesPath + "/" + zipFileName
|
||||||
|
try {
|
||||||
|
ZipOutputStream(BufferedOutputStream(FileOutputStream(zipFilePath))).use { out ->
|
||||||
|
val data = ByteArray(1024)
|
||||||
|
for (file in fileNames) {
|
||||||
|
val filePath = BaresipService.filesPath + "/" + file
|
||||||
|
if (File(filePath).exists()) {
|
||||||
|
FileInputStream(filePath).use { fi ->
|
||||||
|
BufferedInputStream(fi).use { origin ->
|
||||||
|
val entry = ZipEntry(filePath)
|
||||||
|
out.putNextEntry(entry)
|
||||||
|
while (true) {
|
||||||
|
val readBytes = origin.read(data)
|
||||||
|
if (readBytes == -1) break
|
||||||
|
out.write(data, 0, readBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e("Baresip", "Failed to zip file '$zipFilePath': $e")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unZip(zipFilePath: String): Boolean {
|
||||||
|
try {
|
||||||
|
ZipFile(zipFilePath).use { zip ->
|
||||||
|
zip.entries().asSequence().forEach { entry ->
|
||||||
|
zip.getInputStream(entry).use { input ->
|
||||||
|
File(entry.name).outputStream().use { output ->
|
||||||
|
input.copyTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e("Baresip", "Failed to unzip file '$zipFilePath': $e")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fun dumpIntent(intent: Intent) {
|
fun dumpIntent(intent: Intent) {
|
||||||
|
|
||||||
val bundle: Bundle = intent.extras ?: return
|
val bundle: Bundle = intent.extras ?: return
|
||||||
|
|
||||||
val keys = bundle.keySet()
|
val keys = bundle.keySet()
|
||||||
val it = keys.iterator()
|
val it = keys.iterator()
|
||||||
|
|
||||||
Log.d("Baresip", "Dumping intent start")
|
Log.d("Baresip", "Dumping intent start")
|
||||||
|
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
val key = it.next()
|
val key = it.next()
|
||||||
Log.d("Baresip","[" + key + "=" + bundle.get(key)+"]");
|
Log.d("Baresip","[" + key + "=" + bundle.get(key)+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d("Baresip", "Dumping intent finish")
|
Log.d("Baresip", "Dumping intent finish")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,12 @@
|
|||||||
<item android:id="@+id/accounts"
|
<item android:id="@+id/accounts"
|
||||||
android:title="@string/accounts" />
|
android:title="@string/accounts" />
|
||||||
|
|
||||||
|
<item android:id="@+id/export_all"
|
||||||
|
android:title="@string/export_all" />
|
||||||
|
|
||||||
|
<item android:id="@+id/import_all"
|
||||||
|
android:title="@string/import_all" />
|
||||||
|
|
||||||
<item android:id="@+id/about"
|
<item android:id="@+id/about"
|
||||||
android:title="@string/about" />
|
android:title="@string/about" />
|
||||||
|
|
||||||
|
|||||||
@ -238,26 +238,20 @@
|
|||||||
<string name="contact_action_question">Haluatko soittaa tai lähettää
|
<string name="contact_action_question">Haluatko soittaa tai lähettää
|
||||||
viestin kontaktille \'%1$s\'?</string>
|
viestin kontaktille \'%1$s\'?</string>
|
||||||
<string name="send_message">Lähetä viesti</string>
|
<string name="send_message">Lähetä viesti</string>
|
||||||
<string name="contact_delete_question">Haluatko poistaa kontaktin
|
<string name="contact_delete_question">Haluatko poistaa kontaktin \'%1$s\'?</string>
|
||||||
\'%1$s\'?
|
<string name="contacts_exceeded">Kontaktiesi enimmäismäärä %1$d on ylittynyt.</string>
|
||||||
</string>
|
|
||||||
<string name="contacts_exceeded">Kontaktiesi enimmäismäärä %1$d on
|
|
||||||
ylittynyt.
|
|
||||||
</string>
|
|
||||||
<string name="export_contacts">Tallenna</string>
|
<string name="export_contacts">Tallenna</string>
|
||||||
<string name="exported_contacts">Kontaktit tallennettiin
|
<string name="exported_contacts">Kontaktit tallennettiin Download-kansion tiedostoon
|
||||||
Download-kansion tiedostoon \'contacts.bs\'.
|
\'contacts.bs\'.
|
||||||
</string>
|
</string>
|
||||||
<string name="export_error">"Kontaktien tallennus Download kansioon epäonnistui.
|
<string name="export_error">"Kontaktien tallennus Download kansioon epäonnistui.
|
||||||
Tarkista Sovellukset → baresip → Käyttöluvat → Tallennustila.
|
Tarkista Sovellukset → baresip → Käyttöluvat → Tallennustila.
|
||||||
</string>
|
</string>
|
||||||
<string name="import_contacts">Palauta</string>
|
<string name="import_contacts">Palauta</string>
|
||||||
<string name="imported_contacts">Kontaktit palautettiin Download-kansiosta.
|
<string name="imported_contacts">Kontaktit palautettiin.</string>
|
||||||
</string>
|
<string name="import_error">Kontantien palauttaminen Download-kansiosta epäonnistui.
|
||||||
<string name="import_error">Kontantien palauttaminen
|
|
||||||
Download-kansiosta epäonnistui.
|
|
||||||
Tarkista Sovellukset → baresip → Käyttöluvat → Tallennustila ja että tiedosto \'contacts.bs\' on
|
Tarkista Sovellukset → baresip → Käyttöluvat → Tallennustila ja että tiedosto \'contacts.bs\' on
|
||||||
kansiossa.
|
Download-kansiossa.
|
||||||
</string>
|
</string>
|
||||||
<!-- Generic -->
|
<!-- Generic -->
|
||||||
<string name="alert">Varoitus</string>
|
<string name="alert">Varoitus</string>
|
||||||
@ -311,14 +305,12 @@
|
|||||||
TLS sertifikaattitiedostosta. Niiden oletusarvot on palautettu. Käynnistä
|
TLS sertifikaattitiedostosta. Niiden oletusarvot on palautettu. Käynnistä
|
||||||
baresip uudelleen.
|
baresip uudelleen.
|
||||||
</string>
|
</string>
|
||||||
<string name="registering_failed">Tilin \'%1$s\' rekisteröinti
|
<string name="registering_failed">Tilin \'%1$s\' rekisteröinti epäonnistui.</string>
|
||||||
epäonnistui.</string>
|
|
||||||
<string name="no_microphone_permission">Et ole sallinut mikrofonin
|
<string name="no_microphone_permission">Et ole sallinut mikrofonin
|
||||||
käyttöä.
|
käyttöä.
|
||||||
</string>
|
</string>
|
||||||
<string name="verify">Todenna</string>
|
<string name="verify">Todenna</string>
|
||||||
<string name="verify_sas">Todennatko SAS:n <%1$s>
|
<string name="verify_sas">Todennatko SAS:n <%1$s> <%2$s>?
|
||||||
<%2$s>?
|
|
||||||
</string>
|
</string>
|
||||||
<string name="transfer_query">Hyväksytkö puhelun siirron kohteeseen
|
<string name="transfer_query">Hyväksytkö puhelun siirron kohteeseen
|
||||||
\'%1$s\'?
|
\'%1$s\'?
|
||||||
@ -334,8 +326,23 @@
|
|||||||
<string name="call_is_secure">Tämä pulelu on turvallinen ja kohde on
|
<string name="call_is_secure">Tämä pulelu on turvallinen ja kohde on
|
||||||
todennettu! Haluatko poistaa todennuksen?</string>
|
todennettu! Haluatko poistaa todennuksen?</string>
|
||||||
<string name="unverify">Poista todennus</string>
|
<string name="unverify">Poista todennus</string>
|
||||||
qqqq <string name="tls_ca_file">TLS CA-tiedosto</string>
|
<string name="tls_ca_file">TLS CA-tiedosto</string>
|
||||||
<string name="tls_ca_file_help">Jos merkitty, tiedosto \'ca_certs.crt\', joka sisältää todennusauktoriteettien TLS-sertifikaatit, on ladattu tai ladataan Download-kansiosta.</string>
|
<string name="tls_ca_file_help">Jos merkitty, tiedosto \'ca_certs.crt\', joka sisältää
|
||||||
|
todennusauktoriteettien TLS-sertifikaatit, on ladattu tai ladataan Download-kansiosta.
|
||||||
|
</string>
|
||||||
<string name="tls_certificate_file">TLS sertifikaattitiedosto</string>
|
<string name="tls_certificate_file">TLS sertifikaattitiedosto</string>
|
||||||
<string name="tls_certificate_file_help">"Jos merkitty, tiedosto \'cert.pem\', joka sisältää tämän baresip-sovelluksen TLS-sertifikaatin ja yksityisen avaimen, on ladattu tai ladataan Download-kansiosta."</string>
|
<string name="tls_certificate_file_help">"Jos merkitty, tiedosto \'cert.pem\', joka sisältää
|
||||||
|
tämän baresip-sovelluksen TLS-sertifikaatin ja yksityisen avaimen, on ladattu tai ladataan
|
||||||
|
Download-kansiosta."
|
||||||
|
</string>
|
||||||
|
<string name="exported_all">Sovelluksen kaikki data talletettiin Download-kansion tiedostoon
|
||||||
|
\'baresip.bs\'.
|
||||||
|
</string>
|
||||||
|
<string name="imported_all">Sovelluksen kaikki data palautettiin. Sinun pitää käynnistää
|
||||||
|
baresip uudelleen.
|
||||||
|
</string>
|
||||||
|
<string name="import_all_failed">Sovelluksen data palauttaminen Download-kansiosta epäonnistui.
|
||||||
|
Tarkista Sovellukset → baresip → Käyttöluvat → Tallennustila ja että tallennettu tiedosto
|
||||||
|
\'baresip.bs\' on kansiossa ja (jos on) että annoit oikean salasanan.
|
||||||
|
</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@ -103,10 +103,9 @@
|
|||||||
Check Apps → baresip → Permissions → Storage."
|
Check Apps → baresip → Permissions → Storage."
|
||||||
</string>
|
</string>
|
||||||
<string name="import_accounts">Import</string>
|
<string name="import_accounts">Import</string>
|
||||||
<string name="imported_accounts">Imported accounts from Download folder. You need to restart
|
<string name="imported_accounts">Accounts imported. You need to restart baresip.</string>
|
||||||
baresip.</string>
|
|
||||||
<string name="import_accounts_error">Failed to import accounts from Download folder file.
|
<string name="import_accounts_error">Failed to import accounts from Download folder file.
|
||||||
Check Apps → baresip → Permissions → Storage and that file \'accounts.bs\' exists in
|
Check Apps → baresip → Permissions → Storage and that exported file \'accounts.bs\' exists in
|
||||||
the folder and, if so, you gave correct Decrypt Password."
|
the folder and, if so, you gave correct Decrypt Password."
|
||||||
</string>
|
</string>
|
||||||
<string name="delete_account">Do you want to delete account \'%1$s\'?</string>
|
<string name="delete_account">Do you want to delete account \'%1$s\'?</string>
|
||||||
@ -195,7 +194,8 @@ Check Apps → baresip → Permissions → Storage and that file \'accounts.bs\'
|
|||||||
Valid values are 6000-510000. Factory default is 28000.</string>
|
Valid values are 6000-510000. Factory default is 28000.</string>
|
||||||
<string name="_28000" translatable="false">28000</string>
|
<string name="_28000" translatable="false">28000</string>
|
||||||
<string name="opus_packet_loss">Expected Opus packet-loss</string>
|
<string name="opus_packet_loss">Expected Opus packet-loss</string>
|
||||||
<string name="opus_packet_loss_help">Expected Opus audio stream packet loss percentage, from 0-100. By default 0, turning off Opus Forward Error Correction (FEC).</string>
|
<string name="opus_packet_loss_help">Expected Opus audio stream packet loss percentage,
|
||||||
|
from 0–100. By default 0, turning off Opus Forward Error Correction (FEC).</string>
|
||||||
<string name="_0" translatable="false">0</string>
|
<string name="_0" translatable="false">0</string>
|
||||||
<string name="invalid_opus_bitrate">Invalid Opus bitrate</string>
|
<string name="invalid_opus_bitrate">Invalid Opus bitrate</string>
|
||||||
<string name="invalid_opus_packet_loss">Invalid Opus Packet Loss Percentage</string>
|
<string name="invalid_opus_packet_loss">Invalid Opus Packet Loss Percentage</string>
|
||||||
@ -230,7 +230,7 @@ Check Apps → baresip → Permissions → Storage and that file \'accounts.bs\'
|
|||||||
<string name="exported_contacts">Exported contacts to Download folder file \'contacts.bs\'.</string>
|
<string name="exported_contacts">Exported contacts to Download folder file \'contacts.bs\'.</string>
|
||||||
<string name="export_error">"Failed to export contacts to Download folder.
|
<string name="export_error">"Failed to export contacts to Download folder.
|
||||||
Check Apps → baresip → Permissions → Storage."</string>
|
Check Apps → baresip → Permissions → Storage."</string>
|
||||||
<string name="imported_contacts">Imported contacts from Download folder.</string>
|
<string name="imported_contacts">Contacs imported.</string>
|
||||||
<string name="import_error">Failed to import contacts from Download folder. Check Apps →
|
<string name="import_error">Failed to import contacts from Download folder. Check Apps →
|
||||||
baresip → Permissions → Storage and that file \'contacts.bs\' exists in the folder.</string>
|
baresip → Permissions → Storage and that file \'contacts.bs\' exists in the folder.</string>
|
||||||
|
|
||||||
@ -256,6 +256,8 @@ Check Apps → baresip → Permissions → Storage and that file \'accounts.bs\'
|
|||||||
<string name="dots" translatable="false">…</string>
|
<string name="dots" translatable="false">…</string>
|
||||||
|
|
||||||
<!-- Main Activity -->
|
<!-- Main Activity -->
|
||||||
|
<string name="export_all">Export</string>
|
||||||
|
<string name="import_all">Import</string>
|
||||||
<string name="about">About</string>
|
<string name="about">About</string>
|
||||||
<string name="restart">Restart</string>
|
<string name="restart">Restart</string>
|
||||||
<string name="quit">Quit</string>
|
<string name="quit">Quit</string>
|
||||||
@ -285,7 +287,8 @@ Check Apps → baresip → Permissions → Storage and that file \'accounts.bs\'
|
|||||||
<string name="dialpad">Dialpad</string>
|
<string name="dialpad">Dialpad</string>
|
||||||
<string name="call_already_active">You already have an active call.</string>
|
<string name="call_already_active">You already have an active call.</string>
|
||||||
<string name="start_failed">Baresip failed to start. This may be due to invalid Listen Address
|
<string name="start_failed">Baresip failed to start. This may be due to invalid Listen Address
|
||||||
or TLS file. They have been reset. Restart baresip.</string>
|
or TLS file. They have been reset. Restart baresip.
|
||||||
|
</string>
|
||||||
<string name="registering_failed">Registering of \`%1$s\` failed.</string>
|
<string name="registering_failed">Registering of \`%1$s\` failed.</string>
|
||||||
<string name="no_microphone_permission">You have not granted microphone permission.</string>
|
<string name="no_microphone_permission">You have not granted microphone permission.</string>
|
||||||
<string name="verify">Verify</string>
|
<string name="verify">Verify</string>
|
||||||
@ -297,7 +300,16 @@ Check Apps → baresip → Permissions → Storage and that file \'accounts.bs\'
|
|||||||
<string name="call_not_secure">This call is NOT secure!</string>
|
<string name="call_not_secure">This call is NOT secure!</string>
|
||||||
<string name="peer_not_verified">This call is SECURE, but peer is NOT verified!</string>
|
<string name="peer_not_verified">This call is SECURE, but peer is NOT verified!</string>
|
||||||
<string name="call_is_secure">This call is SECURE and peer is VERIFIED!
|
<string name="call_is_secure">This call is SECURE and peer is VERIFIED!
|
||||||
Do you want to unverify the peer?</string>
|
Do you want to unverify the peer?
|
||||||
|
</string>
|
||||||
<string name="unverify">Unverify</string>
|
<string name="unverify">Unverify</string>
|
||||||
|
<string name="exported_all">Exported all application data to Download folder file \'baresip.bs\'.</string>
|
||||||
|
<string name="export_all_failed">Failed to export application data to Download folder file
|
||||||
|
\'baresip.bs\'. Check Apps → baresip → Permissions → Storage</string>
|
||||||
|
<string name="imported_all">All application data imported. You need to restart baresip.</string>
|
||||||
|
<string name="import_all_failed">Failed to import application data from Download folder. Check Apps →
|
||||||
|
baresip → Permissions → Storage and that exported file \'baresip.bs\' exists in the folder
|
||||||
|
and, if so, you gave correct Decrypt Password.
|
||||||
|
</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user