Added Telephony Provider account configuration item
Added support for Contact tel URIs Show account's STUN configuration items only if needed Avoid some lint warnings in baresip.c
This commit is contained in:
@ -362,8 +362,8 @@ static struct mqueue *mq;
|
||||
static void mqueue_handler(int id, void *data, void *arg)
|
||||
{
|
||||
if (id == ID_UA_STOP_ALL) {
|
||||
LOGD("calling ua_stop_all with force %u\n", (unsigned)data);
|
||||
ua_stop_all((bool)data);
|
||||
LOGD("calling ua_stop_all with force %u\n", (unsigned)(uintptr_t)data);
|
||||
ua_stop_all((bool)(uintptr_t)data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@ package com.tutpro.baresip
|
||||
import android.content.Context
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import java.net.URLEncoder
|
||||
import java.net.URLDecoder
|
||||
|
||||
class Account(val accp: String) {
|
||||
|
||||
@ -28,6 +30,7 @@ class Account(val accp: String) {
|
||||
var missedCalls = false
|
||||
var unreadMessages = false
|
||||
var callHistory = true
|
||||
var telProvider = Utils.aorDomain(aor)
|
||||
var resumeUri = ""
|
||||
|
||||
init {
|
||||
@ -56,6 +59,10 @@ class Account(val accp: String) {
|
||||
|
||||
val extra = Api.account_extra(accp)
|
||||
callHistory = Utils.paramValue(extra,"call_history") == ""
|
||||
telProvider = if (Utils.paramExists(extra, "tel_provider"))
|
||||
URLDecoder.decode(Utils.paramValue(extra,"tel_provider"), "UTF-8")
|
||||
else
|
||||
Utils.aorDomain(aor)
|
||||
|
||||
}
|
||||
|
||||
@ -119,6 +126,8 @@ class Account(val accp: String) {
|
||||
if (!callHistory)
|
||||
extra += ";call_history=no"
|
||||
|
||||
extra += ";tel_provider=${URLEncoder.encode(telProvider, "UTF-8")}"
|
||||
|
||||
if (extra != "")
|
||||
res += ";extra=\"" + extra.substringAfter(";") + "\""
|
||||
|
||||
|
||||
@ -2,10 +2,13 @@ package com.tutpro.baresip
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.opengl.Visibility
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.tutpro.baresip.databinding.ActivityAccountBinding
|
||||
@ -33,6 +36,7 @@ class AccountActivity : AppCompatActivity() {
|
||||
private lateinit var outbound1: EditText
|
||||
private lateinit var outbound2: EditText
|
||||
private lateinit var mediaNat: String
|
||||
private lateinit var stun: LinearLayout
|
||||
private lateinit var stunServer: EditText
|
||||
private lateinit var stunUser: EditText
|
||||
private lateinit var stunPass: EditText
|
||||
@ -45,6 +49,7 @@ class AccountActivity : AppCompatActivity() {
|
||||
private var answerMode = Api.ANSWERMODE_MANUAL
|
||||
private lateinit var answerModeSpinner: Spinner
|
||||
private lateinit var vmUri: EditText
|
||||
private lateinit var telProvider: EditText
|
||||
private lateinit var defaultCheck: CheckBox
|
||||
|
||||
private val mediaEncKeys = arrayListOf("zrtp", "dtls_srtp", "srtp-mandf", "srtp-mand", "srtp", "")
|
||||
@ -73,6 +78,7 @@ class AccountActivity : AppCompatActivity() {
|
||||
outbound2 = binding.Outbound2
|
||||
regCheck = binding.Register
|
||||
mediaNatSpinner = binding.mediaNatSpinner
|
||||
stun = binding.Stun
|
||||
stunServer = binding.StunServer
|
||||
stunUser = binding.StunUser
|
||||
stunPass = binding.StunPass
|
||||
@ -80,6 +86,7 @@ class AccountActivity : AppCompatActivity() {
|
||||
dtmfModeSpinner = binding.dtmfModeSpinner
|
||||
answerModeSpinner = binding.answerModeSpinner
|
||||
vmUri = binding.voicemailUri
|
||||
telProvider = binding.telephonyProvider
|
||||
defaultCheck = binding.Default
|
||||
|
||||
aor = intent.getStringExtra("aor")!!
|
||||
@ -230,27 +237,21 @@ class AccountActivity : AppCompatActivity() {
|
||||
stunServer.setText(resources.getString(R.string.stun_server_default))
|
||||
else if ((mediaNat == "ice") && (stunServer.text.toString() == ""))
|
||||
stunServer.setText(resources.getString(R.string.stun_server_default))
|
||||
else if (mediaNat == "") {
|
||||
if (mediaNat == "") {
|
||||
stun.visibility = GONE
|
||||
stunServer.setText("")
|
||||
stunUser.setText("")
|
||||
stunPass.setText("")
|
||||
}
|
||||
stunServer.isEnabled = mediaNat != ""
|
||||
stunUser.isEnabled = mediaNat != ""
|
||||
stunPass.isEnabled = mediaNat != ""
|
||||
} else
|
||||
stun.visibility = VISIBLE
|
||||
}
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||
}
|
||||
}
|
||||
|
||||
stunServer.setText(acc.stunServer)
|
||||
stunServer.isEnabled = mediaNat != ""
|
||||
|
||||
stunUser.setText(acc.stunUser)
|
||||
stunUser.isEnabled = mediaNat != ""
|
||||
|
||||
stunPass.setText(acc.stunPass)
|
||||
stunPass.isEnabled = mediaNat != ""
|
||||
|
||||
mediaEnc = acc.mediaEnc
|
||||
keyIx = mediaEncKeys.indexOf(mediaEnc)
|
||||
@ -313,6 +314,8 @@ class AccountActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
telProvider.setText(acc.telProvider)
|
||||
|
||||
vmUri.setText(acc.vmUri)
|
||||
|
||||
defaultCheck.isChecked = uaIndex == 0
|
||||
@ -563,9 +566,9 @@ class AccountActivity : AppCompatActivity() {
|
||||
if (tVmUri != "") {
|
||||
if (!tVmUri.startsWith("sip:")) tVmUri = "sip:$tVmUri"
|
||||
if (!tVmUri.contains("@")) tVmUri = "$tVmUri@${acc.host()}"
|
||||
if (!Utils.checkSipUri(tVmUri)) {
|
||||
if (!Utils.checkUri(tVmUri)) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_voicemail_uri), tVmUri))
|
||||
String.format(getString(R.string.invalid_sip_or_tel_uri), tVmUri))
|
||||
return false
|
||||
}
|
||||
Api.account_set_mwi(acc.accp, "yes")
|
||||
@ -576,6 +579,17 @@ class AccountActivity : AppCompatActivity() {
|
||||
save = true
|
||||
}
|
||||
|
||||
val hostPart = telProvider.text.toString().trim()
|
||||
if (hostPart != acc.telProvider) {
|
||||
if (hostPart != "" && !Utils.checkHostPortParams(hostPart)) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_sip_uri_hostpart), hostPart))
|
||||
return false
|
||||
}
|
||||
acc.telProvider = hostPart
|
||||
save = true
|
||||
}
|
||||
|
||||
if (defaultCheck.isChecked && (uaIndex > 0)) {
|
||||
val uasTmp = BaresipService.uas[0]
|
||||
val statusTmp = BaresipService.status[0]
|
||||
@ -708,6 +722,12 @@ class AccountActivity : AppCompatActivity() {
|
||||
getString(R.string.voicemain_uri_help)
|
||||
)
|
||||
}
|
||||
binding.TelephonyProviderTitle.setOnClickListener {
|
||||
Utils.alertView(
|
||||
this, getString(R.string.telephony_provider),
|
||||
getString(R.string.telephony_provider_help)
|
||||
)
|
||||
}
|
||||
binding.DefaultTitle.setOnClickListener {
|
||||
Utils.alertView(
|
||||
this, getString(R.string.default_account),
|
||||
|
||||
@ -123,17 +123,14 @@ class ChatsActivity: AppCompatActivity() {
|
||||
plusButton.setOnClickListener {
|
||||
val uriText = peerUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
var uri = ContactsActivity.findContactURI(uriText)
|
||||
if (!uri.startsWith("sip:")) {
|
||||
uri = "sip:$uri"
|
||||
if (!uri.contains("@")) {
|
||||
val host = aor.substring(aor.indexOf("@") + 1)
|
||||
uri = "$uri@$host"
|
||||
}
|
||||
}
|
||||
if (!Utils.checkSipUri(uri)) {
|
||||
val contactUri = ContactsActivity.findContactUri(uriText)
|
||||
val uri = if (contactUri == null)
|
||||
Utils.uriComplete(uriText, Utils.aorDomain(aor))
|
||||
else
|
||||
uriText
|
||||
if (!Utils.checkUri(uri)) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
getString(R.string.invalid_chat_peer_uri))
|
||||
String.format(getString(R.string.invalid_sip_or_tel_uri), uri))
|
||||
} else {
|
||||
peerUri.text.clear()
|
||||
peerUri.isCursorVisible = false
|
||||
|
||||
@ -33,6 +33,7 @@ import com.tutpro.baresip.databinding.ActivityContactBinding
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
|
||||
|
||||
class ContactActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityContactBinding
|
||||
@ -83,12 +84,10 @@ class ContactActivity : AppCompatActivity() {
|
||||
nameView.hint = getString(R.string.contact_name)
|
||||
nameView.setSelection(nameView.text.length)
|
||||
val uri = intent.getStringExtra("uri")!!
|
||||
if (uri == "") {
|
||||
if (uri == "")
|
||||
uriView.setText("")
|
||||
uriView.hint = getString(R.string.sip_uri)
|
||||
} else {
|
||||
else
|
||||
uriView.setText(uri)
|
||||
}
|
||||
uOrI = uri
|
||||
androidCheck.isChecked = false
|
||||
} else {
|
||||
@ -183,6 +182,9 @@ class ContactActivity : AppCompatActivity() {
|
||||
requestPermissions(permissions, CONTACT_PERMISSION_REQUEST_CODE)
|
||||
}
|
||||
|
||||
Log.d(TAG, "********** Android sip contacts ${logAndroidContacts(this, "sip")}")
|
||||
Log.d(TAG, "********** Android tel contacts ${logAndroidContacts(this, "tel")}")
|
||||
|
||||
Utils.addActivity("contact,$newContact,$uOrI")
|
||||
|
||||
}
|
||||
@ -255,7 +257,7 @@ class ContactActivity : AppCompatActivity() {
|
||||
R.id.checkIcon -> {
|
||||
|
||||
var newName = nameView.text.toString().trim()
|
||||
var newUri = uriView.text.toString().trim()
|
||||
var newUri = uriView.text.toString().filterNot{setOf('-', ' ').contains(it)}
|
||||
|
||||
if (newName == "") newName = newUri
|
||||
|
||||
@ -275,15 +277,14 @@ class ContactActivity : AppCompatActivity() {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!newUri.startsWith("sip:")) {
|
||||
newUri = if (newUri.contains("@") || (BaresipService.uas.size != 1))
|
||||
"sip:$newUri"
|
||||
if (!newUri.startsWith("sip:") && !newUri.startsWith("tel:"))
|
||||
newUri = if (Utils.isTelNumber(newUri))
|
||||
"tel:$newUri"
|
||||
else
|
||||
"sip:$newUri@${Utils.aorDomain(BaresipService.uas[0].account.aor)}"
|
||||
}
|
||||
if (!Utils.checkSipUri(newUri)) {
|
||||
"sip:$newUri"
|
||||
if (!Utils.checkUri(newUri)) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_contact_uri), newUri))
|
||||
String.format(getString(R.string.invalid_sip_or_tel_uri), newUri))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -555,13 +556,16 @@ class ContactActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
@Suppress("UNUSED")
|
||||
fun logAndroidSipContacts(ctx: Context): HashMap<Long, MutableList<String>> {
|
||||
fun logAndroidContacts(ctx: Context, type: String): HashMap<Long, MutableList<String>> {
|
||||
val mimeType = if (type == "sip")
|
||||
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
||||
else
|
||||
CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||
val contacts = HashMap<Long, MutableList<String>>()
|
||||
val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME,
|
||||
ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1,
|
||||
ContactsContract.Data.PHOTO_THUMBNAIL_URI)
|
||||
val selection = ContactsContract.Data.MIMETYPE + "='" +
|
||||
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "'"
|
||||
val selection = ContactsContract.Data.MIMETYPE + "='" + mimeType + "'"
|
||||
val cur: Cursor? = ctx.contentResolver.query(ContactsContract.Data.CONTENT_URI, projection,
|
||||
selection, null, null)
|
||||
while (cur != null && cur.moveToNext()) {
|
||||
@ -574,6 +578,7 @@ class ContactActivity : AppCompatActivity() {
|
||||
when (mime) {
|
||||
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> kind = "sip"
|
||||
CommonDataKinds.Photo.CONTENT_ITEM_TYPE -> kind = "thumb"
|
||||
CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> kind = "tel"
|
||||
}
|
||||
Log.d(TAG, "got $id, $name, $kind - $data")
|
||||
var info: MutableList<String>
|
||||
|
||||
@ -11,10 +11,7 @@ import androidx.appcompat.app.AlertDialog
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.*
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
|
||||
import java.io.File
|
||||
@ -79,13 +76,27 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList<C
|
||||
i.putExtra("action", "call")
|
||||
else
|
||||
i.putExtra("action", "message")
|
||||
val ua = UserAgent.ofAor(aor)
|
||||
var ua = UserAgent.ofAor(aor)
|
||||
if (ua == null) {
|
||||
Log.w(TAG, "onClickListener did not find AoR $aor")
|
||||
} else {
|
||||
if (Utils.isTelUri(contact.uri) && ua.account.telProvider == "") {
|
||||
var newUa: UserAgent? = null
|
||||
for (a in Account.accounts())
|
||||
if (a.telProvider != "") {
|
||||
newUa = UserAgent.ofAor(a.aor)
|
||||
break
|
||||
}
|
||||
ua = newUa
|
||||
}
|
||||
}
|
||||
if (ua == null) {
|
||||
Toast.makeText(ctx, ctx.getString(R.string.no_telephony_providers),
|
||||
Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
BaresipService.activities.clear()
|
||||
i.putExtra("uap", ua.uap)
|
||||
i.putExtra("peer", Contact.contacts()[position].uri)
|
||||
i.putExtra("peer", contact.uri)
|
||||
(ctx as Activity).startActivity(i)
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,19 +89,18 @@ class ContactsActivity : AppCompatActivity() {
|
||||
|
||||
companion object {
|
||||
|
||||
fun findContactURI(name: String): String {
|
||||
fun findContactUri(name: String): String? {
|
||||
for (c in Contact.contacts())
|
||||
if (c.name == name)
|
||||
if (c.name.equals(name, ignoreCase = true))
|
||||
return c.uri.removePrefix("<")
|
||||
.replaceAfter(">", "")
|
||||
.replace(">", "")
|
||||
return name
|
||||
return null
|
||||
}
|
||||
|
||||
fun findContact(uri: String): Contact? {
|
||||
for (c in Contact.contacts())
|
||||
if ((Utils.uriUserPart(c.uri) == Utils.uriUserPart(uri)) &&
|
||||
(Utils.uriHostPart(c.uri) == Utils.uriHostPart(uri)))
|
||||
if (Utils.uriMatch(c.uri, uri))
|
||||
return c
|
||||
return null
|
||||
}
|
||||
@ -112,17 +111,14 @@ class ContactsActivity : AppCompatActivity() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Return contact name of uri or uri itself if contact with uri is not found
|
||||
fun contactName(uri: String): String {
|
||||
val uriUser = Utils.uriUserPart(uri)
|
||||
val uriHost = Utils.uriHostPart(uri)
|
||||
for (c in Contact.contacts()) {
|
||||
val contactUser = Utils.uriUserPart(c.uri)
|
||||
if ((contactUser == uriUser) &&
|
||||
(Utils.isE164Number(contactUser) ||
|
||||
(Utils.uriHostPart(c.uri) == uriHost)))
|
||||
return c.name
|
||||
}
|
||||
return uri
|
||||
val userPart = Utils.uriUserPart(uri)
|
||||
return if (Utils.isTelNumber(userPart))
|
||||
findContact("tel:$userPart")?.name ?: uri
|
||||
else
|
||||
findContact(uri)?.name ?: uri
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -774,11 +774,19 @@ class MainActivity : AppCompatActivity() {
|
||||
ua.account.resumeUri = uriStr
|
||||
}
|
||||
"tel" -> {
|
||||
val acc = BaresipService.uas[0].account
|
||||
spinToAor(acc.aor)
|
||||
var account: Account? = null
|
||||
for (a in Account.accounts())
|
||||
if (a.telProvider != "") {
|
||||
account = a
|
||||
break
|
||||
}
|
||||
if (account == null) {
|
||||
Log.w(TAG, "No telephony providers for '$uriStr'")
|
||||
return
|
||||
}
|
||||
spinToAor(account.aor)
|
||||
resumeAction = "call"
|
||||
acc.resumeUri = uriStr.replace("tel", "sip") + "@" +
|
||||
Utils.uriHostPart(acc.aor)
|
||||
account.resumeUri = uriStr
|
||||
}
|
||||
else -> {
|
||||
Log.w(TAG, "Unsupported URI scheme ${uri.scheme}")
|
||||
@ -1369,16 +1377,24 @@ class MainActivity : AppCompatActivity() {
|
||||
setPositiveButton(R.string.transfer) { dialog, _ ->
|
||||
imm.hideSoftInputFromWindow(transferUri.windowToken, 0)
|
||||
dialog.dismiss()
|
||||
val uriText = transferUri.text.toString().trim()
|
||||
var uriText = transferUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
val uri = Utils.uriComplete(
|
||||
ContactsActivity.findContactURI(uriText)
|
||||
.filterNot { it.isWhitespace() },
|
||||
Utils.aorDomain(ua.account.aor)
|
||||
)
|
||||
if (!Utils.checkSipUri(uri)) {
|
||||
uriText = ContactsActivity.findContactUri(uriText) ?: uriText
|
||||
if (Utils.isTelNumber(uriText))
|
||||
uriText = "tel:$uriText"
|
||||
val uri = if (Utils.isTelUri(uriText)) {
|
||||
if (ua.account.telProvider == "") {
|
||||
Utils.alertView(this@MainActivity, getString(R.string.notice),
|
||||
String.format(getString(R.string.no_telephony_provider)))
|
||||
return@setPositiveButton
|
||||
}
|
||||
Utils.telToSip(uriText, ua.account)
|
||||
} else {
|
||||
Utils.uriComplete(uriText, Utils.aorDomain(ua.account.aor))
|
||||
}
|
||||
if (!Utils.checkUri(uri)) {
|
||||
Utils.alertView(this@MainActivity, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_sip_uri), uri))
|
||||
String.format(getString(R.string.invalid_sip_or_tel_uri), uri))
|
||||
} else {
|
||||
if (Call.uaCalls(ua, "").size > 0) {
|
||||
Call.uaCalls(ua, "")[0].transfer(uri)
|
||||
@ -1655,17 +1671,24 @@ class MainActivity : AppCompatActivity() {
|
||||
val ua = UserAgent.uas()[aorSpinner.selectedItemPosition]
|
||||
val aor = ua.account.aor
|
||||
if (Call.calls().isEmpty()) {
|
||||
val uriText = callUri.text.toString().trim()
|
||||
var uriText = callUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
val uri = Utils.uriComplete(
|
||||
ContactsActivity.findContactURI(uriText)
|
||||
.filterNot { it.isWhitespace() },
|
||||
Utils.aorDomain(aor)
|
||||
)
|
||||
if (!Utils.checkSipUri(uri)) {
|
||||
Utils.alertView(
|
||||
this, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_sip_uri), uri)
|
||||
uriText = ContactsActivity.findContactUri(uriText) ?: uriText
|
||||
if (Utils.isTelNumber(uriText))
|
||||
uriText = "tel:$uriText"
|
||||
val uri = if (Utils.isTelUri(uriText)) {
|
||||
if (ua.account.telProvider == "") {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
String.format(getString(R.string.no_telephony_provider)))
|
||||
return
|
||||
}
|
||||
Utils.telToSip(uriText, ua.account)
|
||||
} else {
|
||||
Utils.uriComplete(uriText, Utils.aorDomain(aor))
|
||||
}
|
||||
if (!Utils.checkUri(uri)) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_sip_or_tel_uri), uri)
|
||||
)
|
||||
} else {
|
||||
callUri.isFocusable = false
|
||||
|
||||
@ -105,6 +105,15 @@ object Utils {
|
||||
""
|
||||
}
|
||||
|
||||
fun uriMatch(firstUri: String, secondUri: String): Boolean {
|
||||
if (firstUri.startsWith("tel:"))
|
||||
return firstUri == secondUri
|
||||
if (firstUri.startsWith("sip:"))
|
||||
return uriUserPart(firstUri) == uriUserPart(secondUri) &&
|
||||
uriHostPart(firstUri) == uriHostPart(secondUri)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun uriParams(uri: String): List<String> {
|
||||
val params = uri.split(";")
|
||||
return if (params.size == 1) listOf() else params.subList(1, params.size)
|
||||
@ -121,7 +130,7 @@ object Utils {
|
||||
return if (u.contains("@")) {
|
||||
val user = uriUserPart(u)
|
||||
val host = uriHostPart(u)
|
||||
if (isE164Number(user) || host == domain)
|
||||
if (isTelNumber(user) || host == domain)
|
||||
user
|
||||
else
|
||||
"$user@$host"
|
||||
@ -164,10 +173,6 @@ object Utils {
|
||||
checkTransport(uri.substringAfter("?"), setOf("udp", "tcp")))
|
||||
}
|
||||
|
||||
fun isE164Number(no: String): Boolean {
|
||||
return Regex("^[+][1-9][0-9]{0,14}\$").matches(no)
|
||||
}
|
||||
|
||||
fun checkIpV4(ip: String): Boolean {
|
||||
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)
|
||||
}
|
||||
@ -256,6 +261,12 @@ object Utils {
|
||||
return ""
|
||||
}
|
||||
|
||||
fun paramExists(params: String, name: String): Boolean {
|
||||
for (param in params.split(";"))
|
||||
if (param.substringBefore("=") == name) return true
|
||||
return false
|
||||
}
|
||||
|
||||
fun checkHostPortParams(hpp: String) : Boolean {
|
||||
val restParams = hpp.split(";", limit = 2)
|
||||
return if (restParams.size == 1)
|
||||
@ -264,18 +275,42 @@ object Utils {
|
||||
checkHostPort(restParams[0]) && checkParams(restParams[1])
|
||||
}
|
||||
|
||||
fun checkSipUri(uri: String): Boolean {
|
||||
if (!uri.startsWith("sip:")) return false
|
||||
val userRest = uri.substring(4).split("@")
|
||||
return when (userRest.size) {
|
||||
1 ->
|
||||
checkHostPortParams(userRest[0])
|
||||
2 ->
|
||||
checkUriUser(userRest[0]) && checkHostPortParams(userRest[1])
|
||||
else -> false
|
||||
private fun checkSipUri(uri: String): Boolean {
|
||||
return if (uri.startsWith("sip:")) {
|
||||
val userRest = uri.substring(4).split("@")
|
||||
when (userRest.size) {
|
||||
1 ->
|
||||
checkHostPortParams(userRest[0])
|
||||
2 ->
|
||||
checkUriUser(userRest[0]) && checkHostPortParams(userRest[1])
|
||||
else -> false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isTelNumber(no: String): Boolean {
|
||||
return Regex("^[+][1-9][0-9- ]{0,14}\$").matches(no)
|
||||
}
|
||||
|
||||
fun isTelUri(uri: String): Boolean {
|
||||
return uri.startsWith("tel:") && isTelNumber(uri.substring(4))
|
||||
}
|
||||
|
||||
fun checkUri(uri: String): Boolean {
|
||||
return checkSipUri(uri) || isTelUri(uri)
|
||||
}
|
||||
|
||||
fun telToSip(telUri: String, account: Account): String {
|
||||
val hostPart = if (account.telProvider != "")
|
||||
account.telProvider
|
||||
else
|
||||
aorDomain(account.aor)
|
||||
return "sip:" + telUri.substring(4).filterNot{setOf('-', ' ').contains(it)} +
|
||||
"@" + hostPart + ";user=phone"
|
||||
}
|
||||
|
||||
fun checkName(name: String): Boolean {
|
||||
return name.isNotEmpty() && name == String(name.toByteArray(), Charsets.UTF_8) &&
|
||||
name.lines().size == 1 && !name.contains('"')
|
||||
|
||||
@ -178,69 +178,77 @@
|
||||
android:paddingTop="8dp" >
|
||||
</Spinner>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/StunServerTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/stun_server" >
|
||||
</TextView>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/StunServer"
|
||||
android:layout_height="wrap_content"
|
||||
<LinearLayout
|
||||
android:id="@+id/Stun"
|
||||
android:layout_width="fill_parent"
|
||||
android:textSize="18sp"
|
||||
android:scrollHorizontally="true"
|
||||
android:importantForAutofill="no"
|
||||
android:hint="@string/stun_server_uri"
|
||||
android:inputType="textEmailAddress" >
|
||||
</EditText>
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/StunUserTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/stun_username" >
|
||||
</TextView>
|
||||
<TextView
|
||||
android:id="@+id/StunServerTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/stun_server" >
|
||||
</TextView>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/StunUser"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:hint="@string/user_id"
|
||||
android:textSize="18sp"
|
||||
android:inputType="textEmailAddress"
|
||||
android:autofillHints="username" >
|
||||
</EditText>
|
||||
<EditText
|
||||
android:id="@+id/StunServer"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:textSize="18sp"
|
||||
android:scrollHorizontally="true"
|
||||
android:importantForAutofill="no"
|
||||
android:hint="@string/stun_server_uri"
|
||||
android:inputType="textEmailAddress" >
|
||||
</EditText>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/StunPassTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/stun_password" >
|
||||
</TextView>
|
||||
<TextView
|
||||
android:id="@+id/StunUserTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/stun_username" >
|
||||
</TextView>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:hintEnabled="false"
|
||||
app:endIconMode="password_toggle">
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/StunPass"
|
||||
<EditText
|
||||
android:id="@+id/StunUser"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:hint="@string/user_id"
|
||||
android:textSize="18sp"
|
||||
android:inputType="textEmailAddress"
|
||||
android:autofillHints="username" >
|
||||
</EditText>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/StunPassTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/stun_password" >
|
||||
</TextView>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textPassword"
|
||||
android:hint="@string/password"
|
||||
android:maxLines="1">
|
||||
</androidx.appcompat.widget.AppCompatEditText>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
app:hintEnabled="false"
|
||||
app:endIconMode="password_toggle">
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/StunPass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textPassword"
|
||||
android:hint="@string/password"
|
||||
android:maxLines="1">
|
||||
</androidx.appcompat.widget.AppCompatEditText>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/DtmfModeTitle"
|
||||
@ -293,6 +301,25 @@
|
||||
android:layout_width="fill_parent">
|
||||
</EditText>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TelephonyProviderTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/telephony_provider" >
|
||||
</TextView>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/telephonyProvider"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/telephony_provider_hint"
|
||||
android:textSize="18sp"
|
||||
android:inputType="textUri"
|
||||
android:importantForAutofill="no"
|
||||
android:layout_width="fill_parent">
|
||||
</EditText>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@ -63,19 +63,19 @@
|
||||
</EditText>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/SipUriTitle"
|
||||
android:id="@+id/SipOrTelUriTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"
|
||||
android:paddingTop="10dp"
|
||||
android:text="@string/sip_uri" >
|
||||
android:text="@string/sip_or_tel_uri" >
|
||||
</TextView>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/Uri"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/sip_uri"
|
||||
android:hint="@string/user_domain_or_number"
|
||||
android:inputType="textEmailAddress"
|
||||
android:textSize="18sp"
|
||||
android:importantForAutofill="no"
|
||||
|
||||
@ -182,6 +182,13 @@
|
||||
messages (Message Waiting Indications) are not subscribed to.
|
||||
</string>
|
||||
<string name="invalid_voicemail_uri">Invalid Voicemail URI \'%1$s\'</string>
|
||||
<string name="telephony_provider">Telephony Provider</string>
|
||||
<string name="telephony_provider_help">SIP URI host part used in calls to telephone numbers.
|
||||
Factory default is account\'s domain. If not given, this account cannot be used to call
|
||||
telephone numbers.
|
||||
</string>
|
||||
<string name="telephony_provider_hint">SIP URI host part</string>
|
||||
<string name="invalid_sip_uri_hostpart">Invalid SIP URI host part \'%1$s\'</string>
|
||||
<string name="default_account">Default Account</string>
|
||||
<string name="default_account_help">If checked, this account is selected when baresip is started.
|
||||
</string>
|
||||
@ -247,7 +254,7 @@
|
||||
<string name="today">Today</string>
|
||||
<string name="you">You</string>
|
||||
<string name="new_chat_peer">New Chat Peer</string>
|
||||
<string name="invalid_chat_peer_uri">Invalid SIP URI</string>
|
||||
<string name="invalid_chat_peer_uri">Invalid chat peer URI</string>
|
||||
<string name="long_chat_question">Do you want to delete chat with peer \'%1$s\' or
|
||||
add peer to contacts?</string>
|
||||
<string name="short_chat_question">Do you want to delete chat with \'%1$s\'?</string>
|
||||
@ -341,6 +348,8 @@
|
||||
<string name="contact">Contact</string>
|
||||
<string name="new_contact">New Contact</string>
|
||||
<string name="contact_name">Name</string>
|
||||
<string name="sip_or_tel_uri">SIP or tel URI</string>
|
||||
<string name="user_domain_or_number">user@domain or telephone number</string>
|
||||
<string name="invalid_contact">Invalid contact name \'%1$s\'</string>
|
||||
<string name="contact_already_exists">Contact \'%1$s\' already exists.</string>
|
||||
<string name="invalid_contact_uri">Invalid SIP URI</string>
|
||||
@ -353,6 +362,7 @@
|
||||
<string name="send_message">Send Message</string>
|
||||
<string name="contact_delete_question">Do you want to delete contact \'%1$s\'?</string>
|
||||
<string name="contacts_exceeded">Your maximum number of contacts %1$d has been exceeded.</string>
|
||||
<string name="no_telephony_providers">Telephony provider has not been configured for any account.</string>
|
||||
<!-- Generic -->
|
||||
<string name="alert">Alert</string>
|
||||
<string name="info">Info</string>
|
||||
@ -376,6 +386,7 @@
|
||||
<string name="confirmation">Confirmation</string>
|
||||
<string name="dots" translatable="false">…</string>
|
||||
<string name="bullet_item" translatable="false">\u2022 %1$s</string>
|
||||
<string name="invalid_sip_or_tel_uri">Invalid SIP or tel URI \'%1$s\'</string>
|
||||
<!-- Main Activity -->
|
||||
<string name="backup">Backup</string>
|
||||
<string name="restore">Restore</string>
|
||||
@ -386,6 +397,7 @@
|
||||
<string name="incoming_call_from_dots">Call from …</string>
|
||||
<string name="transferring_call_to_dots">Transferring call to …</string>
|
||||
<string name="invalid_sip_uri">Invalid SIP URI \'%1$s\'</string>
|
||||
<string name="no_telephony_provider">Telephony provider has not been configured for this acccount.</string>
|
||||
<string name="callee">Callee</string>
|
||||
<string name="hangup">Hangup</string>
|
||||
<string name="video_call">Video call</string>
|
||||
|
||||
Reference in New Issue
Block a user