Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/bitfireAT/vcard4android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicki Hirner <hirner@bitfire.at>2022-03-10 02:00:29 +0300
committerRicki Hirner <hirner@bitfire.at>2022-03-10 02:31:25 +0300
commitcf65ed0f1b3ba68d5e1fc5815f20680be7825219 (patch)
treeb051660298123eb94bf398bd967dd0a9603769a0
parent381d65c7bc9640932f34f68936b9fada150b6598 (diff)
Add various messengersuse-predifined-im-protocols
-rw-r--r--src/androidTest/java/at/bitfire/vcard4android/contactrow/ImBuilderTest.kt34
-rw-r--r--src/androidTest/java/at/bitfire/vcard4android/contactrow/ImHandlerTest.kt10
-rw-r--r--src/androidTest/java/at/bitfire/vcard4android/contactrow/ImMappingTest.kt133
-rw-r--r--src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt73
-rw-r--r--src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt39
-rw-r--r--src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt107
-rw-r--r--src/main/java/at/bitfire/vcard4android/contactrow/SipAddressBuilder.kt2
-rw-r--r--src/main/java/at/bitfire/vcard4android/contactrow/SipAddressHandler.kt2
-rw-r--r--src/main/java/at/bitfire/vcard4android/property/CustomType.kt20
9 files changed, 274 insertions, 146 deletions
diff --git a/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImBuilderTest.kt b/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImBuilderTest.kt
index fb50d6e..cc9f58e 100644
--- a/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImBuilderTest.kt
+++ b/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImBuilderTest.kt
@@ -5,6 +5,7 @@
package at.bitfire.vcard4android.contactrow
import android.net.Uri
+import android.os.Build
import android.provider.ContactsContract.CommonDataKinds
import at.bitfire.vcard4android.Contact
import at.bitfire.vcard4android.LabeledProperty
@@ -38,7 +39,12 @@ class ImBuilderTest {
ImBuilder(Uri.EMPTY, null, Contact().apply {
impps += LabeledProperty(Impp("test@example.com"))
}).build().also { result ->
- assertEquals(0, result.size)
+ assertEquals(1, result.size)
+
+ assertEquals(CommonDataKinds.Im.PROTOCOL_CUSTOM, result[0].values[CommonDataKinds.Im.PROTOCOL])
+ assertEquals("test@example.com", result[0].values[CommonDataKinds.Im.DATA])
+ assertNull(result[0].values[CommonDataKinds.Im.CUSTOM_PROTOCOL])
+ assertNull(result[0].values[CommonDataKinds.Im.LABEL])
}
}
@@ -62,24 +68,26 @@ class ImBuilderTest {
ImBuilder(Uri.EMPTY, null, Contact().apply {
impps += LabeledProperty(Impp.xmpp("jabber@example.com"))
impps += LabeledProperty(Impp.skype("skype-id"))
- impps += LabeledProperty(Impp("qq", "qq-id"))
}).build().also { result ->
- assertEquals(3, result.size)
-
- assertEquals(CommonDataKinds.Im.PROTOCOL_JABBER, result[0].values[CommonDataKinds.Im.PROTOCOL])
+ assertEquals(2, result.size)
+
+ if (Build.VERSION.SDK_INT < 31)
+ assertEquals(CommonDataKinds.Im.PROTOCOL_JABBER, result[0].values[CommonDataKinds.Im.PROTOCOL])
+ else {
+ assertEquals(CommonDataKinds.Im.PROTOCOL_CUSTOM, result[0].values[CommonDataKinds.Im.PROTOCOL])
+ assertEquals(ImMapping.MESSENGER_XMPP, result[0].values[CommonDataKinds.Im.CUSTOM_PROTOCOL])
+ }
assertEquals("jabber@example.com", result[0].values[CommonDataKinds.Im.DATA])
- assertNull(result[0].values[CommonDataKinds.Im.CUSTOM_PROTOCOL])
assertNull(result[0].values[CommonDataKinds.Im.LABEL])
- assertEquals(CommonDataKinds.Im.PROTOCOL_SKYPE, result[1].values[CommonDataKinds.Im.PROTOCOL])
+ if (Build.VERSION.SDK_INT < 31)
+ assertEquals(CommonDataKinds.Im.PROTOCOL_SKYPE, result[1].values[CommonDataKinds.Im.PROTOCOL])
+ else {
+ assertEquals(CommonDataKinds.Im.PROTOCOL_CUSTOM, result[1].values[CommonDataKinds.Im.PROTOCOL])
+ assertEquals(ImMapping.MESSENGER_SKYPE, result[1].values[CommonDataKinds.Im.CUSTOM_PROTOCOL])
+ }
assertEquals("skype-id", result[1].values[CommonDataKinds.Im.DATA])
- assertNull(result[1].values[CommonDataKinds.Im.CUSTOM_PROTOCOL])
assertNull(result[1].values[CommonDataKinds.Im.LABEL])
-
- assertEquals(CommonDataKinds.Im.PROTOCOL_QQ, result[2].values[CommonDataKinds.Im.PROTOCOL])
- assertEquals("qq-id", result[2].values[CommonDataKinds.Im.DATA])
- assertNull(result[2].values[CommonDataKinds.Im.CUSTOM_PROTOCOL])
- assertNull(result[2].values[CommonDataKinds.Im.LABEL])
}
}
diff --git a/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImHandlerTest.kt b/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImHandlerTest.kt
index b729aaf..1a4bd23 100644
--- a/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImHandlerTest.kt
+++ b/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImHandlerTest.kt
@@ -129,14 +129,4 @@ class ImHandlerTest {
assertEquals(ImppType.WORK, contact.impps[0].property.types[0])
}
-
- // tests for helpers
-
- @Test
- fun testProtocolToUriScheme() {
- assertNull(ImHandler.protocolToUriScheme(null))
- assertEquals("", ImHandler.protocolToUriScheme(""))
- assertEquals("protocol", ImHandler.protocolToUriScheme("PrO/ätO\\cOl"))
- }
-
} \ No newline at end of file
diff --git a/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImMappingTest.kt b/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImMappingTest.kt
new file mode 100644
index 0000000..64d396b
--- /dev/null
+++ b/src/androidTest/java/at/bitfire/vcard4android/contactrow/ImMappingTest.kt
@@ -0,0 +1,133 @@
+/***************************************************************************************************
+ * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
+ **************************************************************************************************/
+
+package at.bitfire.vcard4android.contactrow
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import java.net.URI
+
+class ImMappingTest {
+
+ @Test
+ fun testMessengerToUri_Known() {
+ assertEquals(URI("aim:user"), ImMapping.messengerToUri("AIM", "user"))
+ assertEquals(URI("https://facebook.com/user"), ImMapping.messengerToUri("Facebook", "user"))
+ assertEquals(URI("https://icq.im/user"), ImMapping.messengerToUri("ICQ", "user"))
+ assertEquals(URI("irc:/network/user"), ImMapping.messengerToUri("IRC", "/network/user"))
+ assertEquals(URI("mqq://im/chat?uin=user"), ImMapping.messengerToUri("QQ", "user"))
+ assertEquals(URI("skype:user"), ImMapping.messengerToUri("Skype", "user"))
+ assertEquals(
+ URI("https://threema.id/THREEMA_ID"),
+ ImMapping.messengerToUri("Threema", "THREEMA_ID")
+ )
+ assertEquals(
+ URI("xmpp:user@example.com"),
+ ImMapping.messengerToUri("XMPP", "user@example.com")
+ )
+ }
+
+ @Test
+ fun testMessengerToUri_Null() {
+ assertEquals(URI("user@example.com"), ImMapping.messengerToUri(null, "user@example.com"))
+ }
+
+ @Test
+ fun testMessengerToUri_Unknown() {
+ assertEquals(
+ URI("unknown-massenger:user@example.com"),
+ ImMapping.messengerToUri("Unknown Mässenger", "user@example.com")
+ )
+ }
+
+
+ @Test
+ fun testUriToMessenger_Blank() {
+ assertEquals(
+ Pair(null, ""),
+ ImMapping.uriToMessenger(URI(""))
+ )
+ }
+
+ @Test
+ fun testUriToMessenger_Known() {
+ assertEquals(
+ Pair("AIM", "user"),
+ ImMapping.uriToMessenger(URI("aim:user"))
+ )
+ assertEquals(
+ Pair("facebook", "user"),
+ ImMapping.uriToMessenger(URI("https://facebook.com/user"))
+ )
+ assertEquals(
+ Pair("facebook", "user@example.com"),
+ ImMapping.uriToMessenger(URI("xmpp:user@example.com"), "Facebook")
+ )
+ assertEquals(
+ Pair("facebook", "user"),
+ ImMapping.uriToMessenger(URI("xmpp:user@facebook.com"), "Facebook")
+ )
+ assertEquals(
+ Pair("ICQ", "user"),
+ ImMapping.uriToMessenger(URI("icq:user"))
+ )
+ assertEquals(
+ Pair("ICQ", "user"),
+ ImMapping.uriToMessenger(URI("https://icq.im/user"))
+ )
+ assertEquals(
+ Pair("IRC", "freenode/user,isnick"),
+ ImMapping.uriToMessenger(URI("irc:freenode/user,isnick"))
+ )
+ assertEquals(
+ Pair("QQ", "user"),
+ ImMapping.uriToMessenger(URI("mqq://im/chat?chat_type=wpa&uin=user"))
+ )
+ assertEquals(
+ Pair("QQ", "user"),
+ ImMapping.uriToMessenger(URI("mqq:user"))
+ )
+ assertEquals(
+ Pair("QQ", "user"),
+ ImMapping.uriToMessenger(URI("qq:user"))
+ )
+ assertEquals(
+ Pair("Skype", "user"),
+ ImMapping.uriToMessenger(URI("skype:user"))
+ )
+ assertEquals(
+ Pair("Threema", "THREEMA_ID"),
+ ImMapping.uriToMessenger(URI("https://threema.id/THREEMA_ID"))
+ )
+ assertEquals(
+ Pair("XMPP", "user@example.com"),
+ ImMapping.uriToMessenger(URI("xmpp:user@example.com"))
+ )
+ }
+
+ @Test
+ fun testUriToMessenger_RelativeUri() {
+ assertEquals(
+ Pair(null, "relative/uri@example.com"),
+ ImMapping.uriToMessenger(URI("relative/uri@example.com"))
+ )
+ }
+
+ @Test
+ fun testUriToMessenger_RelativeUri_WithType() {
+ assertEquals(
+ Pair("MyMessenger", "uri@example.com"),
+ ImMapping.uriToMessenger(URI("uri@example.com"), "MyMessenger")
+ )
+ }
+
+ @Test
+ fun testUriToMessenger_Unknown() {
+ assertEquals(
+ Pair("Unknown", "write?uid=test"),
+ ImMapping.uriToMessenger(URI("unknown:write?uid=test"))
+ )
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt b/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt
index 0cc9ef2..4092261 100644
--- a/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt
+++ b/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt
@@ -12,7 +12,6 @@ import at.bitfire.vcard4android.BatchOperation
import at.bitfire.vcard4android.Contact
import at.bitfire.vcard4android.property.CustomType
import ezvcard.parameter.ImppType
-import org.apache.commons.lang3.StringUtils
import java.util.*
class ImBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact)
@@ -23,8 +22,9 @@ class ImBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact)
for (labeledIm in contact.impps) {
val impp = labeledIm.property
- var protocol = impp.protocol ?: ""
- var user = impp.handle
+ if ((impp.uri.scheme == null && impp.uri.schemeSpecificPart == "") || // empty URI
+ ImMapping.SCHEME_SIP.equals(impp.uri.scheme, true)) // handled by SipAddressBuilder
+ continue
var typeCode = Im.TYPE_OTHER
var typeLabel: String? = null
@@ -41,71 +41,34 @@ class ImBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact)
}
var protocolCode = Im.PROTOCOL_CUSTOM
- var customProtocol: String? = null
+
+ // We parse SERVICE-TYPE (for instance used by iCloud), but don't use it actively.
+ val serviceType = impp.getParameter(CustomType.Im.PARAMETER_SERVICE_TYPE)
+ ?: impp.getParameter(CustomType.Im.PARAMETER_SERVICE_TYPE_ALT)
+ ?: impp.getParameter("TYPE")
// look for known messengers
- ImMapping.uriToMessenger(impp.uri)?.let { (messenger, handle) ->
+ val customProtocol: String?
+ val user: String
+ ImMapping.uriToMessenger(impp.uri, serviceType).let { (messenger, handle) ->
customProtocol = messenger
user = handle
}
- if (customProtocol == null) {
- // TODO move this code to ImMapping.uriToMessenger
-
- // We parse SERVICE-TYPE (for instance used by iCloud), but don't use it actively.
- val serviceType =
- impp.getParameter(CustomType.Im.PARAMETER_SERVICE_TYPE)
- ?: impp.getParameter(CustomType.Im.PARAMETER_SERVICE_TYPE_ALT)
-
- customProtocol = // protocol name shown in Android
- serviceType?.let { StringUtils.capitalize(it) } // use service type, if available
- ?: StringUtils.capitalize(protocol) // fall back to raw URI scheme
- }
-
if (Build.VERSION.SDK_INT < 31) {
- // Since API level 31, PROTOCOL_XXX values are deprecated and only PROTOCOL_CUSTOM should be used.
+ /* On Android <12, we assign specific protocols like AIM etc. although most of them are not used anymore.
+ It's impossible to keep an up-to-date table of messengers, which is probably the reason why these
+ constants were deprecated in Android 12 (SDK level 31). */
@Suppress("DEPRECATION")
when (customProtocol) {
ImMapping.MESSENGER_AIM -> protocolCode = Im.PROTOCOL_AIM
- // TODO
+ ImMapping.MESSENGER_ICQ -> protocolCode = Im.PROTOCOL_ICQ
+ ImMapping.MESSENGER_SKYPE -> protocolCode = Im.PROTOCOL_SKYPE
+ ImMapping.MESSENGER_QQ -> protocolCode = Im.PROTOCOL_QQ
+ ImMapping.MESSENGER_XMPP -> protocolCode = Im.PROTOCOL_JABBER
}
}
- /*if (Build.VERSION.SDK_INT >= 31) {
-
- } else {
- /* On Android <12, we assign specific protocols like AIM etc. although most of them are not used anymore.
- It's impossible to keep an up-to-date table of messengers, which is probably the reason why these
- constants were deprecated. */
- @Suppress("DEPRECATION")
- when {
- protocol.equals(CustomType.Im.PROTOCOL_AIM, true) ->
- protocolCode = Im.PROTOCOL_AIM
- protocol.equals(CustomType.Im.PROTOCOL_GOOGLE_TALK, true) ||
- protocol.equals(CustomType.Im.PROTOCOL_GOOGLE_TALK_ALT, true) ->
- protocolCode = Im.PROTOCOL_GOOGLE_TALK
- protocol.equals(CustomType.Im.PROTOCOL_ICQ, true) ->
- protocolCode = Im.PROTOCOL_ICQ
- protocol.equals(CustomType.Im.PROTOCOL_XMPP, true) ->
- protocolCode = Im.PROTOCOL_JABBER
- protocol.equals(CustomType.Im.PROTOCOL_MSN, true) ||
- protocol.equals(CustomType.Im.PROTOCOL_MSN_ALT, true) ->
- protocolCode = Im.PROTOCOL_MSN
- protocol.equals(CustomType.Im.PROTOCOL_QQ, true) ||
- protocol.equals(CustomType.Im.PROTOCOL_QQ_ALT, true) ->
- protocolCode = Im.PROTOCOL_QQ
- protocol.equals(CustomType.Im.PROTOCOL_CALLTO, true) || // includes NetMeeting, which is dead
- protocol.equals(CustomType.Im.PROTOCOL_SKYPE, true) ->
- protocolCode = Im.PROTOCOL_SKYPE
- protocol.equals(CustomType.Im.PROTOCOL_YAHOO, true) ->
- protocolCode = Im.PROTOCOL_YAHOO
-
- protocol.equals(CustomType.Im.PROTOCOL_SIP, true) ->
- // IMPP:sip:… is handled by SipAddressBuilder
- continue
- }
- }*/
-
// save as IM address
result += newDataRow()
.withValue(Im.DATA, user)
diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt b/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt
index afcaf7c..18b86a9 100644
--- a/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt
+++ b/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt
@@ -10,12 +10,9 @@ import android.provider.ContactsContract.CommonDataKinds.Im
import at.bitfire.vcard4android.Constants
import at.bitfire.vcard4android.Contact
import at.bitfire.vcard4android.LabeledProperty
-import at.bitfire.vcard4android.Utils.normalizeNFD
import at.bitfire.vcard4android.property.CustomType
import ezvcard.parameter.ImppType
import ezvcard.property.Impp
-import org.apache.commons.lang3.StringUtils
-import java.net.URI
import java.util.logging.Level
object ImHandler: DataRowHandler() {
@@ -33,34 +30,24 @@ object ImHandler: DataRowHandler() {
}
val protocolCode = values.getAsInteger(Im.PROTOCOL)
- val impp = when (protocolCode) {
- Im.PROTOCOL_AIM ->
- Impp.aim(handle)
- Im.PROTOCOL_MSN ->
- Impp.msn(handle)
- Im.PROTOCOL_SKYPE ->
- Impp.skype(handle)
- Im.PROTOCOL_GOOGLE_TALK ->
- Impp(CustomType.Im.PROTOCOL_GOOGLE_TALK, handle)
- Im.PROTOCOL_ICQ ->
- Impp.icq(handle)
- Im.PROTOCOL_JABBER ->
- Impp.xmpp(handle)
- Im.PROTOCOL_NETMEETING ->
- Impp.skype(handle) // NetMeeting is dead and has most likely been replaced by Skype
- Im.PROTOCOL_QQ ->
- Impp(CustomType.Im.PROTOCOL_QQ, handle)
- Im.PROTOCOL_YAHOO ->
- Impp.yahoo(handle)
- Im.PROTOCOL_CUSTOM -> {
- val customProtocol = values.getAsString(Im.CUSTOM_PROTOCOL)
- Impp(ImMapping.messengerToUri(customProtocol, handle))
- }
+ val messenger = when (protocolCode) {
+ Im.PROTOCOL_AIM -> ImMapping.MESSENGER_AIM
+ Im.PROTOCOL_MSN,
+ Im.PROTOCOL_SKYPE -> ImMapping.MESSENGER_SKYPE
+ Im.PROTOCOL_GOOGLE_TALK -> "GoogleTalk" // dead
+ Im.PROTOCOL_ICQ -> ImMapping.MESSENGER_ICQ
+ Im.PROTOCOL_JABBER -> ImMapping.MESSENGER_XMPP
+ Im.PROTOCOL_NETMEETING -> "NetMeeting" // dead
+ Im.PROTOCOL_QQ -> ImMapping.MESSENGER_QQ
+ Im.PROTOCOL_YAHOO -> "Yahoo" // dead
+ Im.PROTOCOL_CUSTOM ->
+ values.getAsString(Im.CUSTOM_PROTOCOL)
else -> {
Constants.log.log(Level.WARNING, "Unknown IM protocol: $protocolCode")
return
}
}
+ val impp = Impp(ImMapping.messengerToUri(messenger, handle))
val labeledImpp = LabeledProperty(impp)
when (values.getAsInteger(Im.TYPE)) {
diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt b/src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt
index a14177e..aff4296 100644
--- a/src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt
+++ b/src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt
@@ -4,8 +4,10 @@
package at.bitfire.vcard4android.contactrow
+import android.net.Uri
import at.bitfire.vcard4android.Constants
import at.bitfire.vcard4android.Utils.normalizeNFD
+import org.apache.commons.lang3.StringUtils
import java.net.URI
import java.net.URISyntaxException
import java.util.logging.Level
@@ -13,18 +15,39 @@ import java.util.logging.Level
object ImMapping {
const val MESSENGER_AIM = "AIM"
+ const val MESSENGER_FACEBOOK = "facebook"
+ const val MESSENGER_ICQ = "ICQ"
const val MESSENGER_IRC = "IRC"
+ const val MESSENGER_QQ = "QQ"
+ const val MESSENGER_SKYPE = "Skype"
+ const val MESSENGER_TELEGRAM = "Telegram"
const val MESSENGER_THREEMA = "Threema"
+ const val MESSENGER_XMPP = "XMPP"
- // TODO Tests
+ const val SCHEME_AIM = "aim"
+ const val SCHEME_ICQ = "icq"
+ const val SCHEME_GOOGLE_TALK = "gtalk"
+ const val SCHEME_HTTPS = "https"
+ const val SCHEME_IRC = "irc"
+ const val SCHEME_QQ = "mqq"
+ const val SCHEME_SIP = "sip"
+ const val SCHEME_SKYPE = "skype"
+ const val SCHEME_XMPP = "xmpp"
- fun messengerToUri(messenger: String, handle: String): URI? =
+ fun messengerToUri(messenger: String?, handle: String): URI? =
try {
- when (messenger.lowercase()) {
- MESSENGER_AIM.lowercase() -> URI("aim", handle, null)
- MESSENGER_IRC.lowercase() -> URI("irc", handle, null)
- MESSENGER_THREEMA.lowercase() -> URI("https", "threema.id", "/${handle}", null)
+ when (messenger?.lowercase()) {
+ null -> URI(null, handle, null)
+ MESSENGER_AIM.lowercase() -> URI(SCHEME_AIM, handle, null)
+ MESSENGER_FACEBOOK.lowercase() -> URI(SCHEME_HTTPS, "facebook.com", "/${handle}", null)
+ MESSENGER_ICQ.lowercase() -> URI(SCHEME_HTTPS, "icq.im", "/${handle}", null)
+ MESSENGER_IRC.lowercase() -> URI(SCHEME_IRC, handle, null)
+ MESSENGER_QQ.lowercase() -> URI(SCHEME_QQ, "im", "/chat", "uin=${handle}", null)
+ MESSENGER_SKYPE.lowercase() -> URI(SCHEME_SKYPE, handle, null)
+ MESSENGER_TELEGRAM.lowercase() -> URI(SCHEME_HTTPS, "t.me", "/${handle}", null)
+ MESSENGER_THREEMA.lowercase() -> URI(SCHEME_HTTPS, "threema.id", "/${handle}", null)
+ MESSENGER_XMPP.lowercase() -> URI(SCHEME_XMPP, handle, null)
else ->
// fallback for unknown messengers
URI(messengerToUriScheme(messenger), handle, null)
@@ -34,28 +57,70 @@ object ImMapping {
null
}
- fun uriToMessenger(uri: URI): Pair<String, String>? =
+ fun uriToMessenger(uri: URI, serviceType: String? = null): Pair<String?, String> =
when {
- uri.scheme.equals("aim", true) ->
+ SCHEME_AIM.equals(uri.scheme, true) ->
Pair(MESSENGER_AIM, uri.schemeSpecificPart)
- uri.scheme.equals("irc", true) ->
+ SCHEME_ICQ.equals(uri.scheme, true) ->
+ Pair(MESSENGER_ICQ, uri.schemeSpecificPart)
+ SCHEME_IRC.equals(uri.scheme, true) ->
Pair(MESSENGER_IRC, uri.schemeSpecificPart)
- uri.authority.equals("threema.id", true) ->
+ SCHEME_QQ.equals(uri.scheme, true) ||
+ "qq".equals(uri.scheme, true) -> {
+ val uri2 = Uri.parse(uri.toString())
+ val uin =
+ try {
+ uri2.getQueryParameter("uin")
+ } catch (e: UnsupportedOperationException) {
+ null
+ }
+ if (uin != null)
+ Pair(MESSENGER_QQ, uin)
+ else
+ Pair(MESSENGER_QQ, uri.schemeSpecificPart)
+ }
+ SCHEME_SKYPE.equals(uri.scheme, true) ->
+ Pair(MESSENGER_SKYPE, uri.schemeSpecificPart)
+ SCHEME_XMPP.equals(uri.scheme, true) ->
+ when (serviceType?.lowercase()) {
+ "facebook" -> Pair(MESSENGER_FACEBOOK, uri.schemeSpecificPart.removeSuffix("@facebook.com"))
+ else ->
+ Pair(MESSENGER_XMPP, uri.schemeSpecificPart)
+ }
+
+ "facebook.com".equals(uri.authority, true) ->
+ Pair(MESSENGER_FACEBOOK, uri.path.trimStart('/'))
+ "icq.im".equals(uri.authority, true) ->
+ Pair(MESSENGER_ICQ, uri.path.trimStart('/'))
+ "t.me".equals(uri.authority, true) ->
+ Pair(MESSENGER_TELEGRAM, uri.path.trimStart('/'))
+ "threema.id".equals(uri.authority, true) ->
Pair(MESSENGER_THREEMA, uri.path.trimStart('/'))
- else -> null
+
+ else -> {
+ // fallback for unknown messengers
+ val messenger: String? =
+ serviceType?.let { StringUtils.capitalize(it) } ?: // use service type, if available
+ StringUtils.capitalize(uri.scheme) // otherwise, use the scheme itself
+ Pair(messenger, uri.schemeSpecificPart)
+ }
}
- fun messengerToUriScheme(s: String?) = s
- ?.normalizeNFD() // normalize with decomposition first (e.g. Á → A+ ́)
+ fun messengerToUriScheme(s: String?): String? {
+ val reduced = s
+ ?.normalizeNFD() // normalize with decomposition first (e.g. Á → A+ ́)
- /* then filter according to RFC 3986 3.1:
- scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
- ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
- DIGIT = %x30-39 ; 0-9
- */
- ?.replace(Regex("^[^a-zA-Z]+"), "")
- ?.replace(Regex("[^\\da-zA-Z+-.]"), "")
- ?.lowercase()
+ /* then filter according to RFC 3986 3.1:
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+ DIGIT = %x30-39 ; 0-9
+ */
+ ?.replace(' ', '-')
+ ?.replace(Regex("^[^a-zA-Z]+"), "")
+ ?.replace(Regex("[^\\da-zA-Z+-.]"), "")
+ ?.lowercase()
+ return StringUtils.stripToNull(reduced)
+ }
} \ No newline at end of file
diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressBuilder.kt b/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressBuilder.kt
index cecfd56..9f47c53 100644
--- a/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressBuilder.kt
+++ b/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressBuilder.kt
@@ -20,7 +20,7 @@ class SipAddressBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact)
val impp = labeledIm.property
val protocol = impp.protocol
- if (protocol != "sip")
+ if (!ImMapping.SCHEME_SIP.equals(protocol, true))
// other protocols are handled by ImBuilder
continue
diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressHandler.kt b/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressHandler.kt
index d3e0469..4187203 100644
--- a/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressHandler.kt
+++ b/src/main/java/at/bitfire/vcard4android/contactrow/SipAddressHandler.kt
@@ -21,7 +21,7 @@ object SipAddressHandler: DataRowHandler() {
val sip = values.getAsString(SipAddress.SIP_ADDRESS) ?: return
try {
- val impp = Impp("sip:$sip")
+ val impp = Impp("${ImMapping.SCHEME_SIP}:$sip")
val labeledImpp = LabeledProperty(impp)
when (values.getAsInteger(SipAddress.TYPE)) {
diff --git a/src/main/java/at/bitfire/vcard4android/property/CustomType.kt b/src/main/java/at/bitfire/vcard4android/property/CustomType.kt
index 9eb1aeb..15fd779 100644
--- a/src/main/java/at/bitfire/vcard4android/property/CustomType.kt
+++ b/src/main/java/at/bitfire/vcard4android/property/CustomType.kt
@@ -21,25 +21,7 @@ object CustomType {
}
object Im {
- // [RFC 4770 and other sources]
- const val PROTOCOL_AIM = "aim"
- const val PROTOCOL_ICQ = "icq"
- const val PROTOCOL_MSN = "msn"
- const val PROTOCOL_MSN_ALT = "msnim"
- const val PROTOCOL_SIP = "sip"
- const val PROTOCOL_SKYPE = "skype"
- const val PROTOCOL_XMPP = "xmpp"
- const val PROTOCOL_YAHOO = "ymsgr"
-
- // own values
- const val PROTOCOL_CALLTO = "callto" // [https://en.wikipedia.org/wiki/List_of_URI_schemes]
- const val PROTOCOL_GOOGLE_TALK = "gtalk" // [https://en.wikipedia.org/wiki/List_of_URI_schemes]
- const val PROTOCOL_GOOGLE_TALK_ALT = "google-talk" // DAVx⁵ <4.2
- const val PROTOCOL_NETMEETING = "netmeeting" // DAVx⁵ <4.2
- const val PROTOCOL_QQ = "mqq" // [https://developpaper.com/common-url-scheme/]
- const val PROTOCOL_QQ_ALT = "qq" // DAVx⁵ <4.2
-
- // [https://datatracker.ietf.org/doc/html/draft-daboo-vcard-service-type]
+ // https://datatracker.ietf.org/doc/html/draft-daboo-vcard-service-type
const val PARAMETER_SERVICE_TYPE = "X-SERVICE-TYPE"
const val PARAMETER_SERVICE_TYPE_ALT = "SERVICE-TYPE"
}