You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
etesync-android/app/src/main/java/com/etesync/syncadapter/AccountSettings.kt

264 lines
9.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright © 2013 2015 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package com.etesync.syncadapter
import android.accounts.Account
import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.BroadcastReceiver
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import at.bitfire.vcard4android.ContactsStorageException
import at.bitfire.vcard4android.GroupMethod
import com.etesync.journalmanager.Crypto
import com.etesync.syncadapter.log.Logger
import com.etesync.syncadapter.utils.Base64
import java.net.URI
import java.net.URISyntaxException
import java.util.logging.Level
class AccountSettings @TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Throws(InvalidAccountException::class)
constructor(internal val context: Context, internal val account: Account) {
internal val accountManager: AccountManager
// authentication settings
var uri: URI?
get() {
val uri = accountManager.getUserData(account, KEY_URI)
if (uri == null) {
return null
}
try {
return URI(uri)
} catch (e: URISyntaxException) {
return null
}
}
set(uri) = accountManager.setUserData(account, KEY_URI, uri.toString())
var authToken: String
get() = accountManager.getUserData(account, KEY_TOKEN)
set(token) = accountManager.setUserData(account, KEY_TOKEN, token)
var keyPair: Crypto.AsymmetricKeyPair?
get() {
if (accountManager.getUserData(account, KEY_ASYMMETRIC_PUBLIC_KEY) != null) {
val pubkey = Base64.decode(accountManager.getUserData(account, KEY_ASYMMETRIC_PUBLIC_KEY), Base64.NO_WRAP)
val privkey = Base64.decode(accountManager.getUserData(account, KEY_ASYMMETRIC_PRIVATE_KEY), Base64.NO_WRAP)
return Crypto.AsymmetricKeyPair(privkey, pubkey)
}
return null
}
set(keyPair) {
accountManager.setUserData(account, KEY_ASYMMETRIC_PUBLIC_KEY, Base64.encodeToString(keyPair?.publicKey, Base64.NO_WRAP))
accountManager.setUserData(account, KEY_ASYMMETRIC_PRIVATE_KEY, Base64.encodeToString(keyPair?.privateKey, Base64.NO_WRAP))
}
val syncWifiOnly: Boolean
get() = accountManager.getUserData(account, KEY_WIFI_ONLY) != null
var syncWifiOnlySSID: String?
get() = accountManager.getUserData(account, KEY_WIFI_ONLY_SSID)
set(ssid) = accountManager.setUserData(account, KEY_WIFI_ONLY_SSID, ssid)
var etebaseSession: String?
get() = accountManager.getUserData(account, KEY_ETEBASE_SESSION)
set(value) = accountManager.setUserData(account, KEY_ETEBASE_SESSION, value)
val isLegacy: Boolean
get() = authToken != null
// CalDAV settings
var manageCalendarColors: Boolean
get() = accountManager.getUserData(account, KEY_MANAGE_CALENDAR_COLORS) == null
set(manage) = accountManager.setUserData(account, KEY_MANAGE_CALENDAR_COLORS, if (manage) null else "0")
// CardDAV settings
var groupMethod: GroupMethod
get() {
val name = accountManager.getUserData(account, KEY_CONTACT_GROUP_METHOD)
return if (name != null)
GroupMethod.valueOf(name)
else
GroupMethod.GROUP_VCARDS
}
set(method) {
val name = if (method == GroupMethod.GROUP_VCARDS) null else method.name
accountManager.setUserData(account, KEY_CONTACT_GROUP_METHOD, name)
}
init {
accountManager = AccountManager.get(context)
synchronized(AccountSettings::class.java) {
val versionStr = accountManager.getUserData(account, KEY_SETTINGS_VERSION)
?: throw InvalidAccountException(account)
var version = 0
try {
version = Integer.parseInt(versionStr)
} catch (ignored: NumberFormatException) {
}
Logger.log.fine("Account " + account.name + " has version " + version + ", current version: " + CURRENT_VERSION)
if (version < CURRENT_VERSION)
update(version)
}
}
fun username(): String {
return accountManager.getUserData(account, KEY_USERNAME)
}
fun username(userName: String) {
accountManager.setUserData(account, KEY_USERNAME, userName)
}
fun password(): String {
return accountManager.getPassword(account)
}
fun password(password: String) {
accountManager.setPassword(account, password)
}
// sync. settings
fun getSyncInterval(authority: String): Long? {
if (ContentResolver.getIsSyncable(account, authority) <= 0)
return null
if (ContentResolver.getSyncAutomatically(account, authority)) {
val syncs = ContentResolver.getPeriodicSyncs(account, authority)
return if (syncs.isEmpty())
SYNC_INTERVAL_MANUALLY
else
syncs[0].period
} else
return SYNC_INTERVAL_MANUALLY
}
fun setSyncInterval(authority: String, seconds: Long) {
if (seconds == SYNC_INTERVAL_MANUALLY) {
ContentResolver.setSyncAutomatically(account, authority, false)
} else {
ContentResolver.setSyncAutomatically(account, authority, true)
ContentResolver.addPeriodicSync(account, authority, Bundle(), seconds)
}
}
fun setSyncWiFiOnly(wiFiOnly: Boolean) {
accountManager.setUserData(account, KEY_WIFI_ONLY, if (wiFiOnly) "1" else null)
}
// update from previous account settings
private fun update(fromVersion: Int) {
val toVersion = CURRENT_VERSION
Logger.log.info("Updating account " + account.name + " from version " + fromVersion + " to " + toVersion)
try {
updateInner(fromVersion)
accountManager.setUserData(account, KEY_SETTINGS_VERSION, toVersion.toString())
} catch (e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't update account settings", e)
}
}
@Throws(ContactsStorageException::class)
private fun updateInner(fromVersion: Int) {
if (fromVersion < 2) {
}
}
class AppUpdatedReceiver : BroadcastReceiver() {
@SuppressLint("UnsafeProtectedBroadcastReceiver,MissingPermission")
override fun onReceive(context: Context, intent: Intent) {
Logger.log.info("EteSync was updated, checking for AccountSettings version")
// peek into AccountSettings to initiate a possible migration
val accountManager = AccountManager.get(context)
for (account in accountManager.getAccountsByType(App.accountType))
try {
Logger.log.info("Checking account " + account.name)
AccountSettings(context, account)
} catch (e: InvalidAccountException) {
Logger.log.log(Level.SEVERE, "Couldn't check for updated account settings", e)
}
}
}
class AccountMigrationException(msg: String) : Exception(msg)
companion object {
private val CURRENT_VERSION = 2
private val KEY_SETTINGS_VERSION = "version"
private val KEY_URI = "uri"
private val KEY_USERNAME = "user_name"
private val KEY_TOKEN = "auth_token"
private val KEY_ASYMMETRIC_PRIVATE_KEY = "asymmetric_private_key"
private val KEY_ASYMMETRIC_PUBLIC_KEY = "asymmetric_public_key"
private val KEY_WIFI_ONLY = "wifi_only"
private val KEY_ETEBASE_SESSION = "etebase_session"
// sync on WiFi only (default: false)
private val KEY_WIFI_ONLY_SSID = "wifi_only_ssid" // restrict sync to specific WiFi SSID
/**
* Time range limitation to the past [in days]
* value = null default value (DEFAULT_TIME_RANGE_PAST_DAYS)
* < 0 (-1) no limit
* >= 0 entries more than n days in the past won't be synchronized
*/
private val KEY_TIME_RANGE_PAST_DAYS = "time_range_past_days"
private val DEFAULT_TIME_RANGE_PAST_DAYS = 90
/* Whether DAVdroid sets the local calendar color to the value from service DB at every sync
value = null (not existing) true (default)
"0" false */
private val KEY_MANAGE_CALENDAR_COLORS = "manage_calendar_colors"
/**
* Contact group method:
* value = null (not existing) groups as separate VCards (default)
* "CATEGORIES" groups are per-contact CATEGORIES
*/
private val KEY_CONTACT_GROUP_METHOD = "contact_group_method"
val SYNC_INTERVAL_MANUALLY: Long = -1
// XXX: Workaround a bug in Android where passing a bundle to addAccountExplicitly doesn't work.
fun setUserData(accountManager: AccountManager, account: Account, uri: URI?, userName: String) {
accountManager.setUserData(account, KEY_SETTINGS_VERSION, CURRENT_VERSION.toString())
accountManager.setUserData(account, KEY_USERNAME, userName)
accountManager.setUserData(account, KEY_URI, uri?.toString())
}
}
}