diff options
author | Ricki Hirner <hirner@bitfire.at> | 2022-03-09 18:07:13 +0300 |
---|---|---|
committer | Ricki Hirner <hirner@bitfire.at> | 2022-03-09 18:09:08 +0300 |
commit | 381d65c7bc9640932f34f68936b9fada150b6598 (patch) | |
tree | f285b4511a06cd5fb967b61c37dc48e86963d4a4 | |
parent | bbb197d28dd44c9b98ffa19da88b8ad045c65548 (diff) |
Introduce mapping of IM URIs to Messenger names
3 files changed, 99 insertions, 40 deletions
diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt b/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt index e775f8f..0cc9ef2 100644 --- a/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt +++ b/src/main/java/at/bitfire/vcard4android/contactrow/ImBuilder.kt @@ -23,11 +23,8 @@ class ImBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact) for (labeledIm in contact.impps) { val impp = labeledIm.property - val protocol = impp.protocol ?: "" - /*if (protocol == null) { - Constants.log.warning("Ignoring IM address without protocol") - continue - }*/ + var protocol = impp.protocol ?: "" + var user = impp.handle var typeCode = Im.TYPE_OTHER var typeLabel: String? = null @@ -46,8 +43,35 @@ class ImBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact) var protocolCode = Im.PROTOCOL_CUSTOM var customProtocol: String? = null - if (Build.VERSION.SDK_INT >= 31) { + // look for known messengers + ImMapping.uriToMessenger(impp.uri)?.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. + @Suppress("DEPRECATION") + when (customProtocol) { + ImMapping.MESSENGER_AIM -> protocolCode = Im.PROTOCOL_AIM + // TODO + } + } + + /*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. @@ -80,22 +104,11 @@ class ImBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact) // IMPP:sip:… is handled by SipAddressBuilder continue } - } - - if (protocolCode == Im.PROTOCOL_CUSTOM) { - // 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 - } + }*/ // save as IM address result += newDataRow() - .withValue(Im.DATA, impp.handle) + .withValue(Im.DATA, user) .withValue(Im.TYPE, typeCode) .withValue(Im.LABEL, typeLabel) .withValue(Im.PROTOCOL, protocolCode) diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt b/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt index ee0c8ea..afcaf7c 100644 --- a/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt +++ b/src/main/java/at/bitfire/vcard4android/contactrow/ImHandler.kt @@ -15,6 +15,7 @@ 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() { @@ -31,7 +32,8 @@ object ImHandler: DataRowHandler() { return } - val impp = when (values.getAsInteger(Im.PROTOCOL)) { + val protocolCode = values.getAsInteger(Im.PROTOCOL) + val impp = when (protocolCode) { Im.PROTOCOL_AIM -> Impp.aim(handle) Im.PROTOCOL_MSN -> @@ -51,16 +53,11 @@ object ImHandler: DataRowHandler() { Im.PROTOCOL_YAHOO -> Impp.yahoo(handle) Im.PROTOCOL_CUSTOM -> { - val protocol = StringUtils.trimToNull(values.getAsString(Im.CUSTOM_PROTOCOL)) - try { - Impp(protocolToUriScheme(protocol), handle) - } catch (e: IllegalArgumentException) { - Constants.log.warning("IM type/value can't be expressed as URI; ignoring") - return - } + val customProtocol = values.getAsString(Im.CUSTOM_PROTOCOL) + Impp(ImMapping.messengerToUri(customProtocol, handle)) } else -> { - Constants.log.log(Level.WARNING, "Unknown IM type", values) + Constants.log.log(Level.WARNING, "Unknown IM protocol: $protocolCode") return } } @@ -80,16 +77,4 @@ object ImHandler: DataRowHandler() { contact.impps += labeledImpp } - fun protocolToUriScheme(s: String?) = 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() - }
\ No newline at end of file diff --git a/src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt b/src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt new file mode 100644 index 0000000..a14177e --- /dev/null +++ b/src/main/java/at/bitfire/vcard4android/contactrow/ImMapping.kt @@ -0,0 +1,61 @@ +/*************************************************************************************************** + * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details. + **************************************************************************************************/ + +package at.bitfire.vcard4android.contactrow + +import at.bitfire.vcard4android.Constants +import at.bitfire.vcard4android.Utils.normalizeNFD +import java.net.URI +import java.net.URISyntaxException +import java.util.logging.Level + +object ImMapping { + + const val MESSENGER_AIM = "AIM" + const val MESSENGER_IRC = "IRC" + const val MESSENGER_THREEMA = "Threema" + + // TODO Tests + + + 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) + else -> + // fallback for unknown messengers + URI(messengerToUriScheme(messenger), handle, null) + } + } catch (e: URISyntaxException) { + Constants.log.log(Level.WARNING, "Couldn't generate URI from IM: $messenger / $handle", e) + null + } + + fun uriToMessenger(uri: URI): Pair<String, String>? = + when { + uri.scheme.equals("aim", true) -> + Pair(MESSENGER_AIM, uri.schemeSpecificPart) + uri.scheme.equals("irc", true) -> + Pair(MESSENGER_IRC, uri.schemeSpecificPart) + uri.authority.equals("threema.id", true) -> + Pair(MESSENGER_THREEMA, uri.path.trimStart('/')) + else -> null + } + + + fun messengerToUriScheme(s: String?) = 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() + +}
\ No newline at end of file |