package org.tasks.data import android.app.Activity import android.content.Context import android.os.Parcel import android.os.Parcelable import androidx.core.os.ParcelCompat import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.Ignore import androidx.room.PrimaryKey import com.todoroo.andlib.data.Table import com.todoroo.astrid.data.Task import org.tasks.R import org.tasks.caldav.BaseCaldavAccountSettingsActivity import org.tasks.caldav.CaldavAccountSettingsActivity import org.tasks.caldav.CaldavCalendarSettingsActivity import org.tasks.caldav.LocalListSettingsActivity import org.tasks.data.OpenTaskDao.Companion.isDavx5 import org.tasks.data.OpenTaskDao.Companion.isDecSync import org.tasks.data.OpenTaskDao.Companion.isEteSync import org.tasks.etebase.EtebaseAccountSettingsActivity import org.tasks.etebase.EtebaseCalendarSettingsActivity import org.tasks.etesync.EteSyncAccountSettingsActivity import org.tasks.opentasks.OpenTaskAccountSettingsActivity import org.tasks.opentasks.OpenTasksListSettingsActivity import org.tasks.security.KeyStoreEncryption import org.tasks.sync.microsoft.MicrosoftListSettingsActivity import java.net.HttpURLConnection @Entity(tableName = "caldav_accounts") class CaldavAccount : Parcelable { @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "cda_id") @Transient var id: Long = 0 @ColumnInfo(name = "cda_uuid") var uuid: String? = Task.NO_UUID @ColumnInfo(name = "cda_name") var name: String? = "" @ColumnInfo(name = "cda_url") var url: String? = "" @ColumnInfo(name = "cda_username") var username: String? = "" @ColumnInfo(name = "cda_password") @Transient var password: String? = "" @ColumnInfo(name = "cda_error") @Transient var error: String? = "" @ColumnInfo(name = "cda_account_type") var accountType = TYPE_CALDAV @ColumnInfo(name = "cda_collapsed") var isCollapsed = false @ColumnInfo(name = "cda_server_type") var serverType = SERVER_UNKNOWN constructor() @Ignore constructor(source: Parcel) { id = source.readLong() uuid = source.readString() name = source.readString() url = source.readString() username = source.readString() password = source.readString() error = source.readString() accountType = source.readInt() isCollapsed = ParcelCompat.readBoolean(source) serverType = source.readInt() } fun getPassword(encryption: KeyStoreEncryption): String { return encryption.decrypt(password) ?: "" } val isCaldavAccount: Boolean get() = accountType == TYPE_CALDAV @Deprecated("use etebase") val isEteSyncAccount: Boolean get() = accountType == TYPE_ETESYNC private val isEtebaseAccount: Boolean get() = accountType == TYPE_ETEBASE private val isOpenTasks: Boolean get() = accountType == TYPE_OPENTASKS val isTasksOrg: Boolean get() = accountType == TYPE_TASKS val isMicrosoft: Boolean get() = accountType == TYPE_MICROSOFT val isGoogleTasks: Boolean get() = accountType == TYPE_GOOGLE_TASKS fun listSettingsClass(): Class = when(accountType) { TYPE_LOCAL -> LocalListSettingsActivity::class.java TYPE_ETESYNC, TYPE_OPENTASKS -> OpenTasksListSettingsActivity::class.java TYPE_ETEBASE -> EtebaseCalendarSettingsActivity::class.java TYPE_MICROSOFT -> MicrosoftListSettingsActivity::class.java else -> CaldavCalendarSettingsActivity::class.java } val accountSettingsClass: Class get() = when { isCaldavAccount -> CaldavAccountSettingsActivity::class.java isEteSyncAccount -> EteSyncAccountSettingsActivity::class.java isEtebaseAccount -> EtebaseAccountSettingsActivity::class.java isOpenTasks -> OpenTaskAccountSettingsActivity::class.java else -> throw IllegalArgumentException("Unexpected account type: $this") } val isSuppressRepeatingTasks: Boolean get() = when (serverType) { SERVER_OPEN_XCHANGE, SERVER_MAILBOX_ORG -> true else -> false } val reminderSync: Boolean get() = serverType != SERVER_SYNOLOGY_CALENDAR override fun describeContents() = 0 override fun writeToParcel(dest: Parcel, flags: Int) { with(dest) { writeLong(id) writeString(uuid) writeString(name) writeString(url) writeString(username) writeString(password) writeString(error) writeInt(accountType) ParcelCompat.writeBoolean(this, isCollapsed) writeInt(serverType) } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as CaldavAccount if (id != other.id) return false if (uuid != other.uuid) return false if (name != other.name) return false if (url != other.url) return false if (username != other.username) return false if (password != other.password) return false if (error != other.error) return false if (accountType != other.accountType) return false if (isCollapsed != other.isCollapsed) return false if (serverType != other.serverType) return false return true } override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + (uuid?.hashCode() ?: 0) result = 31 * result + (name?.hashCode() ?: 0) result = 31 * result + (url?.hashCode() ?: 0) result = 31 * result + (username?.hashCode() ?: 0) result = 31 * result + (password?.hashCode() ?: 0) result = 31 * result + (error?.hashCode() ?: 0) result = 31 * result + accountType result = 31 * result + isCollapsed.hashCode() result = 31 * result + serverType return result } override fun toString(): String { return "CaldavAccount(id=$id, uuid=$uuid, name=$name, url=$url, username=$username, password=$password, error=$error, accountType=$accountType, isCollapsed=$isCollapsed, serverType=$serverType)" } fun isTasksSubscription(context: Context): Boolean { val caldavUrl = context.getString(R.string.tasks_caldav_url) return url?.startsWith("${caldavUrl}/calendars/") == true && !isPaymentRequired() && !isLoggedOut() } fun isLoggedOut() = error?.startsWith(ERROR_UNAUTHORIZED) == true fun isPaymentRequired() = error.isPaymentRequired() val hasError: Boolean get() = !error.isNullOrBlank() val prefTitle: Int get() = when { isTasksOrg -> R.string.tasks_org isCaldavAccount -> R.string.caldav isEtebaseAccount || uuid.isEteSync() -> R.string.etesync isEteSyncAccount -> R.string.etesync_v1 uuid.isDavx5() -> R.string.davx5 uuid.isDecSync() -> R.string.decsync isMicrosoft -> R.string.microsoft isGoogleTasks -> R.string.gtasks_GPr_header else -> 0 } val prefIcon: Int get() = when { isTasksOrg -> R.drawable.ic_round_icon isCaldavAccount -> R.drawable.ic_webdav_logo isEtebaseAccount || isEteSyncAccount || uuid.isEteSync() -> R.drawable.ic_etesync uuid.isDavx5() -> R.drawable.ic_davx5_icon_green_bg uuid.isDecSync() -> R.drawable.ic_decsync isMicrosoft -> R.drawable.ic_microsoft_tasks isGoogleTasks -> R.drawable.ic_google else -> 0 } companion object { val TABLE = Table("caldav_accounts") val UUID = TABLE.column("cda_uuid") val ACCOUNT_TYPE = TABLE.column("cda_account_type") const val TYPE_CALDAV = 0 @Deprecated("use etebase") const val TYPE_ETESYNC = 1 const val TYPE_LOCAL = 2 const val TYPE_OPENTASKS = 3 const val TYPE_TASKS = 4 const val TYPE_ETEBASE = 5 const val TYPE_MICROSOFT = 6 const val TYPE_GOOGLE_TASKS = 7 const val SERVER_UNKNOWN = -1 const val SERVER_TASKS = 0 const val SERVER_OWNCLOUD = 1 const val SERVER_SABREDAV = 2 const val SERVER_OPEN_XCHANGE = 3 const val SERVER_NEXTCLOUD = 4 const val SERVER_SYNOLOGY_CALENDAR = 5 const val SERVER_MAILBOX_ORG = 6 const val SERVER_OTHER = 99 const val ERROR_UNAUTHORIZED = "HTTP ${HttpURLConnection.HTTP_UNAUTHORIZED}" const val ERROR_PAYMENT_REQUIRED = "HTTP ${HttpURLConnection.HTTP_PAYMENT_REQUIRED}" fun String?.openTaskType(): String? = this?.split(":")?.get(0) fun String?.isPaymentRequired(): Boolean = this?.startsWith(ERROR_PAYMENT_REQUIRED) == true @JvmField val CREATOR: Parcelable.Creator = object : Parcelable.Creator { override fun createFromParcel(source: Parcel): CaldavAccount = CaldavAccount(source) override fun newArray(size: Int): Array = arrayOfNulls(size) } } }