Commit 8b6376e0 authored by Ricki Hirner's avatar Ricki Hirner

Use HttpUrl whenever possible

* HttpUrl is the preferred class because we use URLs mainly for okhttp
* don't use URI or String for URLs, if possible
* HttpUrl is not Serializable, so use Parcelable for data classes with HttpUrl

X
parent 5da229ed
Pipeline #22687515 passed with stages
in 7 minutes and 28 seconds
......@@ -14,6 +14,7 @@ import at.bitfire.dav4android.DavResource
import at.bitfire.dav4android.property.ResourceType
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.model.ServiceDB.Collections
import okhttp3.HttpUrl
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
......@@ -113,7 +114,7 @@ class CollectionInfoTest {
assertEquals(CollectionInfo.Type.CALENDAR, info.type)
assertEquals(1.toLong(), info.id)
assertEquals(1.toLong(), info.serviceID)
assertEquals("http://example.com", info.url)
assertEquals(HttpUrl.parse("http://example.com/"), info.url)
assertTrue(info.readOnly)
assertEquals("display name", info.displayName)
assertEquals("description", info.description)
......
......@@ -75,7 +75,7 @@ class DavResourceFinderTest {
finder.rememberIfAddressBookOrHomeset(it, info)
assertEquals(0, info.collections.size)
assertEquals(1, info.homeSets.size)
assertEquals(server.url("$PATH_CARDDAV$SUBPATH_ADDRESSBOOK_HOMESET/").uri(), info.homeSets.first())
assertEquals(server.url("$PATH_CARDDAV$SUBPATH_ADDRESSBOOK_HOMESET/"), info.homeSets.first())
}
}
......@@ -85,7 +85,7 @@ class DavResourceFinderTest {
ServiceInfo().let { info ->
finder.rememberIfAddressBookOrHomeset(it, info)
assertEquals(1, info.collections.size)
assertEquals(server.url("$PATH_CARDDAV$SUBPATH_ADDRESSBOOK/").uri(), info.collections.keys.first())
assertEquals(server.url("$PATH_CARDDAV$SUBPATH_ADDRESSBOOK/"), info.collections.keys.first())
assertEquals(0, info.homeSets.size)
}
}
......@@ -112,13 +112,13 @@ class DavResourceFinderTest {
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_NO_DAV), DavResourceFinder.Service.CARDDAV))
assertEquals(
server.url(PATH_CALDAV + SUBPATH_PRINCIPAL).uri(),
server.url(PATH_CALDAV + SUBPATH_PRINCIPAL),
finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CALDAV)
)
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CARDDAV))
assertEquals(
server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL).uri(),
server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL),
finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CARDDAV)
)
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CALDAV))
......
......@@ -309,7 +309,7 @@ class AccountSettings(
parcel.unmarshall(raw, 0, raw.size)
parcel.setDataPosition(0)
val params = parcel.readBundle()
val url = params.getString("url")
val url = params.getString("url")?.let { HttpUrl.parse(it) }
if (url == null)
Logger.log.info("No address book URL, ignoring account")
else {
......@@ -319,7 +319,7 @@ class AccountSettings(
info.displayName = account.name
Logger.log.log(Level.INFO, "Creating new address book account", url)
val addressBookAccount = Account(LocalAddressBook.accountName(account, info), context.getString(R.string.account_type_address_book))
if (!accountManager.addAccountExplicitly(addressBookAccount, null, LocalAddressBook.initialUserData(account, info.url)))
if (!accountManager.addAccountExplicitly(addressBookAccount, null, LocalAddressBook.initialUserData(account, info.url.toString())))
throw ContactsStorageException("Couldn't create address book account")
// move contacts to new address book
......
......@@ -283,7 +283,7 @@ class DavService: Service() {
val selectedCollections = HashSet<HttpUrl>()
collections.values
.filter { it.selected }
.forEach { (url,_) -> HttpUrl.parse(url)?.let { selectedCollections.add(it) } }
.forEach { (url,_) -> selectedCollections.add(url) }
// now refresh collections (taken from home sets)
val itHomeSets = homeSets.iterator()
......
......@@ -28,11 +28,9 @@ object DavUtils {
return String.format("#%06X%02X", color, alpha)
}
fun lastSegmentOfUrl(url: String): String {
val httpUrl = HttpUrl.parse(url) ?: throw IllegalArgumentException("url not parsable")
fun lastSegmentOfUrl(url: HttpUrl): String {
// the list returned by HttpUrl.pathSegments() is unmodifiable, so we have to create a copy
val segments = LinkedList<String>(httpUrl.pathSegments())
val segments = LinkedList<String>(url.pathSegments())
segments.reverse()
return segments.firstOrNull { it.isNotEmpty() } ?: "/"
......
......@@ -9,14 +9,25 @@
package at.bitfire.davdroid.model
import android.content.ContentValues
import android.os.Parcel
import android.os.Parcelable
import at.bitfire.dav4android.DavResponse
import at.bitfire.dav4android.UrlUtils
import at.bitfire.dav4android.property.*
import at.bitfire.davdroid.model.ServiceDB.Collections
import java.io.Serializable
import okhttp3.HttpUrl
/**
* Represents a WebDAV collection.
*
* @constructor always appends a trailing slash to the URL
*/
data class CollectionInfo(
val url: String,
/**
* URL of the collection (including trailing slash)
*/
val url: HttpUrl,
var id: Long? = null,
var serviceID: Long? = null,
......@@ -39,7 +50,7 @@ data class CollectionInfo(
// non-persistent properties
var confirmed: Boolean = false
): Serializable {
): Parcelable {
enum class Type {
ADDRESS_BOOK,
......@@ -61,7 +72,7 @@ data class CollectionInfo(
}
constructor(dav: DavResponse): this(UrlUtils.withTrailingSlash(dav.url).toString()) {
constructor(dav: DavResponse): this(UrlUtils.withTrailingSlash(dav.url)) {
dav[ResourceType::class.java]?.let { type ->
when {
type.types.contains(ResourceType.ADDRESSBOOK) -> this.type = Type.ADDRESS_BOOK
......@@ -104,7 +115,7 @@ data class CollectionInfo(
}
constructor(values: ContentValues): this(values.getAsString(Collections.URL)) {
constructor(values: ContentValues): this(UrlUtils.withTrailingSlash(HttpUrl.parse(values.getAsString(Collections.URL))!!)) {
id = values.getAsLong(Collections.ID)
serviceID = values.getAsLong(Collections.SERVICE_ID)
type = try {
......@@ -134,7 +145,7 @@ data class CollectionInfo(
// Collections.SERVICE_ID is never changed
type?.let { values.put(Collections.TYPE, it.name) }
values.put(Collections.URL, url)
values.put(Collections.URL, url.toString())
values.put(Collections.READ_ONLY, if (readOnly) 1 else 0)
values.put(Collections.FORCE_READ_ONLY, if (forceReadOnly) 1 else 0)
values.put(Collections.DISPLAY_NAME, displayName)
......@@ -160,4 +171,79 @@ data class CollectionInfo(
(i != 0)
}
override fun describeContents(): Int = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
fun<T> writeOrNull(value: T?, write: (T) -> Unit) {
if (value == null)
dest.writeByte(0)
else {
dest.writeByte(1)
write(value)
}
}
dest.writeString(url.toString())
writeOrNull(id, { dest.writeLong(it) })
writeOrNull(serviceID, { dest.writeLong(it) })
dest.writeString(type?.name)
dest.writeByte(if (readOnly) 1 else 0)
dest.writeByte(if (forceReadOnly) 1 else 0)
dest.writeString(displayName)
dest.writeString(description)
writeOrNull(color, { dest.writeInt(it) })
dest.writeString(timeZone)
dest.writeByte(if (supportsVEVENT) 1 else 0)
dest.writeByte(if (supportsVTODO) 1 else 0)
dest.writeByte(if (selected) 1 else 0)
dest.writeString(source)
dest.writeByte(if (confirmed) 1 else 0)
}
@Suppress("unused")
@JvmField
val CREATOR = object: Parcelable.Creator<CollectionInfo> {
override fun createFromParcel(parcel: Parcel): CollectionInfo {
fun<T> readOrNull(parcel: Parcel, read: () -> T): T? {
return if (parcel.readByte() == 0.toByte())
null
else
read()
}
return CollectionInfo(
HttpUrl.parse(parcel.readString())!!,
readOrNull(parcel, { parcel.readLong() }),
readOrNull(parcel, { parcel.readLong() }),
parcel.readString()?.let { Type.valueOf(it) },
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readString(),
parcel.readString(),
readOrNull(parcel, { parcel.readInt() }),
parcel.readString(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readString(),
parcel.readByte() != 0.toByte()
)
}
override fun newArray(size: Int) = arrayOfNulls<CollectionInfo>(size)
}
}
\ No newline at end of file
......@@ -52,7 +52,7 @@ class LocalAddressBook(
val accountManager = AccountManager.get(context)
val account = Account(accountName(mainAccount, info), context.getString(R.string.account_type_address_book))
if (!accountManager.addAccountExplicitly(account, null, initialUserData(mainAccount, info.url)))
if (!accountManager.addAccountExplicitly(account, null, initialUserData(mainAccount, info.url.toString())))
throw IllegalStateException("Couldn't create address book account")
val addressBook = LocalAddressBook(context, account, provider)
......
......@@ -54,7 +54,7 @@ class LocalCalendar private constructor(
private fun valuesFromCollectionInfo(info: CollectionInfo, withColor: Boolean): ContentValues {
val values = ContentValues()
values.put(Calendars.NAME, info.url)
values.put(Calendars.NAME, info.url.toString())
values.put(Calendars.CALENDAR_DISPLAY_NAME, if (info.displayName.isNullOrBlank()) DavUtils.lastSegmentOfUrl(info.url) else info.displayName)
if (withColor)
......
......@@ -73,7 +73,7 @@ class LocalTaskList private constructor(
private fun valuesFromCollectionInfo(info: CollectionInfo, withColor: Boolean): ContentValues {
val values = ContentValues(3)
values.put(TaskLists._SYNC_ID, info.url)
values.put(TaskLists._SYNC_ID, info.url.toString())
values.put(TaskLists.LIST_NAME, if (info.displayName.isNullOrBlank()) DavUtils.lastSegmentOfUrl(info.url) else info.displayName)
if (withColor)
......
......@@ -21,6 +21,7 @@ import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.model.ServiceDB.Collections
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.ISettings
import okhttp3.HttpUrl
import java.util.logging.Level
class AddressBooksSyncAdapterService: SyncAdapterService() {
......@@ -32,7 +33,7 @@ class AddressBooksSyncAdapterService: SyncAdapterService() {
context: Context
): SyncAdapter(context) {
override fun sync(settings: ISettings, account: Account, extras: Bundle, authority: String, addressBooksProvider: ContentProviderClient, syncResult: SyncResult) {
override fun sync(settings: ISettings, account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
val contactsProvider = context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)
if (contactsProvider == null) {
Logger.log.severe("Couldn't access contacts provider")
......@@ -81,8 +82,8 @@ class AddressBooksSyncAdapterService: SyncAdapterService() {
null
}
fun remoteAddressBooks(service: Long?): MutableMap<String, CollectionInfo> {
val collections = mutableMapOf<String, CollectionInfo>()
fun remoteAddressBooks(service: Long?): MutableMap<HttpUrl, CollectionInfo> {
val collections = mutableMapOf<HttpUrl, CollectionInfo>()
service?.let {
db.query(Collections._TABLE, null,
Collections.SERVICE_ID + "=? AND " + Collections.SYNC, arrayOf(service.toString()), null, null, null)?.use { cursor ->
......@@ -103,7 +104,7 @@ class AddressBooksSyncAdapterService: SyncAdapterService() {
// delete/update local address books
for (addressBook in LocalAddressBook.findAll(context, provider, account)) {
val url = addressBook.url
val url = HttpUrl.parse(addressBook.url)!!
val info = remote[url]
if (info == null) {
Logger.log.log(Level.INFO, "Deleting obsolete local address book", url)
......
......@@ -20,6 +20,7 @@ import at.bitfire.davdroid.model.ServiceDB.Collections
import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.settings.ISettings
import at.bitfire.ical4android.AndroidCalendar
import okhttp3.HttpUrl
import java.util.logging.Level
class CalendarsSyncAdapterService: SyncAdapterService() {
......@@ -75,8 +76,8 @@ class CalendarsSyncAdapterService: SyncAdapterService() {
null
}
fun remoteCalendars(service: Long?): MutableMap<String, CollectionInfo> {
val collections = mutableMapOf<String, CollectionInfo>()
fun remoteCalendars(service: Long?): MutableMap<HttpUrl, CollectionInfo> {
val collections = mutableMapOf<HttpUrl, CollectionInfo>()
service?.let {
db.query(Collections._TABLE, null,
"${Collections.SERVICE_ID}=? AND ${Collections.SUPPORTS_VEVENT}!=0 AND ${Collections.SYNC}",
......@@ -100,7 +101,8 @@ class CalendarsSyncAdapterService: SyncAdapterService() {
val updateColors = settings.getManageCalendarColors()
for (calendar in AndroidCalendar.find(account, provider, LocalCalendar.Factory, null, null))
calendar.name?.let { url ->
calendar.name?.let {
val url = HttpUrl.parse(it)!!
val info = remote[url]
if (info == null) {
Logger.log.log(Level.INFO, "Deleting obsolete local calendar", url)
......
......@@ -29,6 +29,7 @@ import at.bitfire.davdroid.settings.ISettings
import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.ical4android.AndroidTaskList
import at.bitfire.ical4android.TaskProvider
import okhttp3.HttpUrl
import org.dmfs.tasks.contract.TaskContract
import java.util.logging.Level
......@@ -108,8 +109,8 @@ class TasksSyncAdapterService: SyncAdapterService() {
null
}
fun remoteTaskLists(service: Long?): MutableMap<String, CollectionInfo> {
val collections = mutableMapOf<String, CollectionInfo>()
fun remoteTaskLists(service: Long?): MutableMap<HttpUrl, CollectionInfo> {
val collections = mutableMapOf<HttpUrl, CollectionInfo>()
service?.let {
db.query(Collections._TABLE, null,
"${Collections.SERVICE_ID}=? AND ${Collections.SUPPORTS_VTODO}!=0 AND ${Collections.SYNC}",
......@@ -133,7 +134,8 @@ class TasksSyncAdapterService: SyncAdapterService() {
val updateColors = settings.getManageCalendarColors()
for (list in AndroidTaskList.find(account, provider, LocalTaskList.Factory, null, null))
list.syncId?.let { url ->
list.syncId?.let {
val url = HttpUrl.parse(it)!!
val info = remote[url]
if (info == null) {
Logger.log.fine("Deleting obsolete local task list $url")
......
......@@ -556,7 +556,7 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
checked.isChecked = info.selected
var tv: TextView = v.findViewById(R.id.title)
tv.text = if (!info.displayName.isNullOrBlank()) info.displayName else info.url
tv.text = if (!info.displayName.isNullOrBlank()) info.displayName else info.url.toString()
tv = v.findViewById(R.id.description)
if (info.description.isNullOrBlank())
......@@ -600,7 +600,7 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
} ?: View.INVISIBLE
var tv: TextView = v.findViewById(R.id.title)
tv.text = if (!info.displayName.isNullOrBlank()) info.displayName else info.url
tv.text = if (!info.displayName.isNullOrBlank()) info.displayName else info.url.toString()
tv = v.findViewById(R.id.description)
if (info.description.isNullOrBlank())
......
......@@ -67,7 +67,7 @@ class CreateAddressBookActivity: AppCompatActivity(), LoaderManager.LoaderCallba
var ok = true
HttpUrl.parse(homeSet)?.let {
val info = CollectionInfo(it.resolve(UUID.randomUUID().toString() + "/").toString())
val info = CollectionInfo(it.resolve(UUID.randomUUID().toString() + "/")!!)
info.displayName = display_name.text.toString()
if (info.displayName.isNullOrBlank()) {
display_name.error = getString(R.string.create_collection_display_name_required)
......
......@@ -78,7 +78,7 @@ class CreateCalendarActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks
var ok = true
HttpUrl.parse(homeSet)?.let {
val info = CollectionInfo(it.resolve(UUID.randomUUID().toString() + "/").toString())
val info = CollectionInfo(it.resolve(UUID.randomUUID().toString() + "/")!!)
info.displayName = display_name.text.toString()
if (info.displayName.isNullOrBlank()) {
display_name.error = getString(R.string.create_collection_display_name_required)
......
......@@ -27,7 +27,6 @@ import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.CollectionInfo
import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.settings.Settings
import okhttp3.HttpUrl
import java.io.IOException
import java.io.StringWriter
import java.util.logging.Level
......@@ -44,7 +43,7 @@ class CreateCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
val frag = CreateCollectionFragment()
val args = Bundle(2)
args.putParcelable(ARG_ACCOUNT, account)
args.putSerializable(ARG_COLLECTION_INFO, info)
args.putParcelable(ARG_COLLECTION_INFO, info)
frag.arguments = args
return frag
}
......@@ -59,7 +58,7 @@ class CreateCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
val args = requireNotNull(arguments)
account = args.getParcelable(ARG_ACCOUNT)
info = args.getSerializable(ARG_COLLECTION_INFO) as CollectionInfo
info = args.getParcelable(ARG_COLLECTION_INFO)
loaderManager.initLoader(0, null, this)
}
......@@ -190,7 +189,7 @@ class CreateCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
.setForeground(true)
.build().use { httpClient ->
try {
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(info.url)!!)
val collection = DavResource(httpClient.okHttpClient, info.url)
// create collection on remote server
collection.mkCol(writer.toString())
......
......@@ -25,7 +25,6 @@ import at.bitfire.davdroid.R
import at.bitfire.davdroid.model.CollectionInfo
import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.settings.Settings
import okhttp3.HttpUrl
@Suppress("DEPRECATION")
class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<Exception> {
......@@ -89,7 +88,7 @@ class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
.setForeground(true)
.build().use { httpClient ->
try {
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(collectionInfo.url)!!)
val collection = DavResource(httpClient.okHttpClient, collectionInfo.url)
// delete collection from server
collection.delete(null)
......@@ -117,7 +116,7 @@ class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
val frag = ConfirmDeleteCollectionFragment()
val args = Bundle(2)
args.putParcelable(ARG_ACCOUNT, account)
args.putSerializable(ARG_COLLECTION_INFO, collectionInfo)
args.putParcelable(ARG_COLLECTION_INFO, collectionInfo)
frag.arguments = args
return frag
}
......@@ -125,9 +124,9 @@ class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val collectionInfo = arguments!!.getSerializable(ARG_COLLECTION_INFO) as CollectionInfo
val collectionInfo = arguments!!.getParcelable(ARG_COLLECTION_INFO) as CollectionInfo
val name = if (collectionInfo.displayName.isNullOrBlank())
collectionInfo.url
collectionInfo.url.toString()
else
collectionInfo.displayName
......
......@@ -45,7 +45,7 @@ class AccountDetailsFragment: Fragment(), LoaderManager.LoaderCallbacks<CreateSe
fun newInstance(config: DavResourceFinder.Configuration): AccountDetailsFragment {
val frag = AccountDetailsFragment()
val args = Bundle(1)
args.putSerializable(KEY_CONFIG, config)
args.putParcelable(KEY_CONFIG, config)
frag.arguments = args
return frag
}
......@@ -63,7 +63,7 @@ class AccountDetailsFragment: Fragment(), LoaderManager.LoaderCallbacks<CreateSe
})
val args = requireNotNull(arguments)
val config = args.getSerializable(KEY_CONFIG) as DavResourceFinder.Configuration
val config = args.getParcelable(KEY_CONFIG) as DavResourceFinder.Configuration
v.account_name.setText(config.calDAV?.email ?:
config.credentials.userName ?:
......@@ -81,7 +81,7 @@ class AccountDetailsFragment: Fragment(), LoaderManager.LoaderCallbacks<CreateSe
if (name.isEmpty())
v.account_name.error = getString(R.string.login_account_name_required)
else {
if (createAccount(name, args.getSerializable(KEY_CONFIG) as DavResourceFinder.Configuration)) {
if (createAccount(name, args.getParcelable(KEY_CONFIG) as DavResourceFinder.Configuration)) {
requireActivity().setResult(Activity.RESULT_OK)
requireActivity().finish()
} else
......
......@@ -8,6 +8,8 @@
package at.bitfire.davdroid.ui.setup
import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import at.bitfire.dav4android.DavResource
import at.bitfire.dav4android.DavResponse
import at.bitfire.dav4android.UrlUtils
......@@ -22,11 +24,9 @@ import at.bitfire.davdroid.model.Credentials
import at.bitfire.davdroid.settings.Settings
import okhttp3.HttpUrl
import org.apache.commons.lang3.builder.ReflectionToStringBuilder
import org.apache.commons.lang3.builder.ToStringBuilder
import org.xbill.DNS.Lookup
import org.xbill.DNS.Type
import java.io.IOException
import java.io.Serializable
import java.net.URI
import java.net.URISyntaxException
import java.util.*
......@@ -129,7 +129,7 @@ class DavResourceFinder(
if (config.principal != null && service == Service.CALDAV) {
// query email address (CalDAV scheduling: calendar-user-address-set)
val davPrincipal = DavResource(httpClient.okHttpClient, HttpUrl.get(config.principal)!!, log)
val davPrincipal = DavResource(httpClient.okHttpClient, config.principal!!, log)
try {
davPrincipal.propfind(0, CalendarUserAddressSet.NAME).use { response ->
response[CalendarUserAddressSet::class.java]?.let { addressSet ->
......@@ -206,7 +206,7 @@ class DavResourceFinder(
// If a principal has been detected successfully, ensure that it provides the required service.
principal?.let {
if (providesService(it, service))
config.principal = it.uri()
config.principal = it
}
} catch(e: Exception) {
log.log(Level.FINE, "PROPFIND/OPTIONS on user-given URL failed", e)
......@@ -223,8 +223,9 @@ class DavResourceFinder(
// Is there an address book?
for ((addressBook, resourceType) in dav.searchProperties(ResourceType::class.java)) {
if (resourceType.types.contains(ResourceType.ADDRESSBOOK)) {
log.info("Found address book at ${addressBook.url}")
config.collections[addressBook.url.uri()] = CollectionInfo(addressBook)
val info = CollectionInfo(addressBook)
log.info("Found address book at ${info.url}")
config.collections[info.url] = info
}
}
......@@ -234,7 +235,7 @@ class DavResourceFinder(
dav.url.resolve(href)?.let {
val location = UrlUtils.withTrailingSlash(it)
log.info("Found address book home-set at $location")
config.homeSets.add(location.uri())
config.homeSets += location
}
}
}
......@@ -244,8 +245,9 @@ class DavResourceFinder(
// Is the collection a calendar collection?
for ((calendar, resourceType) in dav.searchProperties(ResourceType::class.java)) {
if (resourceType.types.contains(ResourceType.CALENDAR)) {
log.info("Found calendar at ${calendar.url}")
config.collections[calendar.url.uri()] = CollectionInfo(calendar)
val info = CollectionInfo(calendar)
log.info("Found calendar at ${info.url}")
config.collections[info.url] = info
}
}
......@@ -255,7 +257,7 @@ class DavResourceFinder(
dav.url.resolve(href)?.let {
val location = UrlUtils.withTrailingSlash(it)
log.info("Found calendar home-set at $location")
config.homeSets.add(location.uri())
config.homeSets += location
}
}
}
......@@ -289,7 +291,7 @@ class DavResourceFinder(
* @return principal URL, or null if none found
*/
@Throws(IOException::class, HttpException::class, DavException::class)
private fun discoverPrincipalUrl(domain: String, service: Service): URI? {
private fun discoverPrincipalUrl(domain: String, service: Service): HttpUrl? {
val scheme: String
val fqdn: String
var port = 443
......@@ -349,7 +351,7 @@ class DavResourceFinder(
* @return current-user-principal URL that provides required service, or null if none
*/
@Throws(IOException::class, HttpException::class, DavException::class)
fun getCurrentUserPrincipal(url: HttpUrl, service: Service?): URI? {
fun getCurrentUserPrincipal(url: HttpUrl, service: Service?): HttpUrl? {
val dav = DavResource(httpClient.okHttpClient, url, log)
dav.propfind(0, CurrentUserPrincipal.NAME).use {
it.searchProperty(CurrentUserPrincipal::class.java)?.let { (dav, currentUserPrincipal) ->
......@@ -363,7 +365,7 @@ class DavResourceFinder(
return null
}
return principal.uri()
return principal
}
}
}
......@@ -381,18 +383,15 @@ class DavResourceFinder(
val calDAV: ServiceInfo?,
val logs: String
): Serializable {
// We have to use URI here because HttpUrl is not serializable!
): Parcelable {
class ServiceInfo: Serializable {
var principal: URI? = null
val homeSets = HashSet<URI>()
val collections = HashMap<URI, CollectionInfo>()
data class ServiceInfo(
var principal: HttpUrl? = null,
val homeSets: MutableSet<HttpUrl> = HashSet(),
val collections: MutableMap<HttpUrl, CollectionInfo> = HashMap(),
var email: String? = null
override fun toString() = ToStringBuilder.reflectionToString(this)!!
}
var email: String? = null
)
override fun toString(): String {
val builder = ReflectionToStringBuilder(this)
......@@ -400,6 +399,74 @@ class DavResourceFinder(
return builder.toString()
}
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
fun writeServiceInfo(info: ServiceInfo?) {
if (info == null)
dest.writeByte(0)
else {
dest.writeByte(1)
dest.writeString(info.principal?.toString())
dest.writeInt(info.homeSets.size)
info.homeSets.forEach { dest.writeString(it.toString()) }
dest.writeInt(info.collections.size)
info.collections.forEach { url, collectionInfo ->
dest.writeString(url.toString())
dest.writeParcelable(collectionInfo, 0)
}
dest.writeString(info.email)
}
}
dest.writeSerializable(credentials)
writeServiceInfo(cardDAV)
writeServiceInfo(calDAV)
dest.writeString(logs)
}
@Suppress("unused")
@JvmField
val