1
0
mirror of https://github.com/etesync/android synced 2025-07-16 03:28:14 +00:00
etesync-android/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.kt
Tom Hacohen 16f7187a77 Mostly fix email sending for events with attendees.
We need to correctly set the organizer (and for that we need the email
address of the account).
2020-09-25 10:05:30 +03:00

207 lines
7.7 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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.syncadapter
import android.accounts.Account
import android.content.Context
import android.content.SyncResult
import android.os.Build
import android.os.Bundle
import at.bitfire.ical4android.CalendarStorageException
import at.bitfire.ical4android.Event
import at.bitfire.ical4android.InvalidCalendarException
import at.bitfire.vcard4android.ContactsStorageException
import com.etebase.client.Item
import com.etesync.syncadapter.AccountSettings
import com.etesync.syncadapter.Constants
import com.etesync.syncadapter.R
import com.etesync.journalmanager.Exceptions
import com.etesync.journalmanager.JournalEntryManager
import com.etesync.syncadapter.log.Logger
import com.etesync.syncadapter.model.CollectionInfo
import com.etesync.journalmanager.model.SyncEntry
import com.etesync.syncadapter.resource.LocalCalendar
import com.etesync.syncadapter.resource.LocalEvent
import com.etesync.syncadapter.utils.EventEmailInvitation
import okhttp3.HttpUrl
import java.io.IOException
import java.io.StringReader
/**
*
* Synchronization manager for CardDAV collections; handles contacts and groups.
*/
class CalendarSyncManager @Throws(Exceptions.IntegrityException::class, Exceptions.GenericCryptoException::class)
constructor(context: Context, account: Account, settings: AccountSettings, extras: Bundle, authority: String, result: SyncResult, calendar: LocalCalendar, private val remote: HttpUrl) : SyncManager<LocalEvent>(context, account, settings, extras, authority, result, calendar.name!!, CollectionInfo.Type.CALENDAR, account.name) {
override val syncErrorTitle: String
get() = context.getString(R.string.sync_error_calendar, account.name)
override val syncSuccessfullyTitle: String
get() = context.getString(R.string.sync_successfully_calendar, localCalendar().displayName,
account.name)
init {
localCollection = calendar
}
override fun notificationId(): Int {
return Constants.NOTIFICATION_CALENDAR_SYNC
}
@Throws(ContactsStorageException::class, CalendarStorageException::class)
override fun prepare(): Boolean {
if (!super.prepare())
return false
if (isLegacy) {
journal = JournalEntryManager(httpClient.okHttpClient, remote, localCalendar().name!!)
}
return true
}
@Throws(CalendarStorageException::class, ContactsStorageException::class)
override fun prepareDirty() {
super.prepareDirty()
localCalendar().processDirtyExceptions()
}
// helpers
private fun localCalendar(): LocalCalendar {
return localCollection as LocalCalendar
}
override fun processItem(item: Item) {
val local = localCollection!!.findByFilename(item.uid)
if (!item.isDeleted) {
val inputReader = StringReader(String(item.content))
val events = Event.eventsFromReader(inputReader)
if (events.size == 0) {
Logger.log.warning("Received VCard without data, ignoring")
return
} else if (events.size > 1) {
Logger.log.warning("Received multiple VCALs, using first one")
}
val event = events[0]
processEvent(item, event, local)
} else {
if (local != null) {
Logger.log.info("Removing local record #" + local.id + " which has been deleted on the server")
local.delete()
} else {
Logger.log.warning("Tried deleting a non-existent record: " + item.uid)
}
}
}
@Throws(IOException::class, ContactsStorageException::class, CalendarStorageException::class, InvalidCalendarException::class)
override fun processSyncEntryImpl(cEntry: SyncEntry) {
val inputReader = StringReader(cEntry.content)
val events = Event.eventsFromReader(inputReader)
if (events.size == 0) {
Logger.log.warning("Received VCard without data, ignoring")
return
} else if (events.size > 1) {
Logger.log.warning("Received multiple VCALs, using first one")
}
val event = events[0]
val local = localCollection!!.findByUid(event.uid!!)
if (cEntry.isAction(SyncEntry.Actions.ADD) || cEntry.isAction(SyncEntry.Actions.CHANGE)) {
legacyProcessEvent(event, local)
} else {
if (local != null) {
Logger.log.info("Removing local record #" + local.id + " which has been deleted on the server")
local.delete()
} else {
Logger.log.warning("Tried deleting a non-existent record: " + event.uid)
}
}
}
@Throws(CalendarStorageException::class, ContactsStorageException::class, IOException::class)
override fun prepareLocal() {
super.prepareLocal()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
createInviteAttendeesNotification()
}
}
@Throws(CalendarStorageException::class, ContactsStorageException::class, IOException::class)
private fun createInviteAttendeesNotification() {
for (local in localDirty) {
val event = local.event
if (event?.attendees?.isEmpty()!!) {
return
}
createInviteAttendeesNotification(event, local.content)
}
}
private fun createInviteAttendeesNotification(event: Event, icsContent: String) {
val intent = EventEmailInvitation(context, account).createIntent(event, icsContent)
if (intent != null) {
val notificationHelper = SyncNotification(context, icsContent, event.hashCode())
notificationHelper.notify(
context.getString(
R.string.sync_calendar_attendees_notification_title, event.summary),
context.getString(R.string.sync_calendar_attendees_notification_content), null,
intent,
R.drawable.ic_email_black)
}
}
private fun processEvent(item: Item, newData: Event, _localEvent: LocalEvent?): LocalEvent {
var localEvent = _localEvent
// delete local event, if it exists
if (localEvent != null) {
Logger.log.info("Updating " + newData.uid + " in local calendar")
localEvent.eTag = item.etag
localEvent.update(newData)
syncResult.stats.numUpdates++
} else {
Logger.log.info("Adding " + newData.uid + " to local calendar")
localEvent = LocalEvent(localCalendar(), newData, item.uid, item.etag)
localEvent.add()
syncResult.stats.numInserts++
}
return localEvent
}
@Throws(IOException::class, ContactsStorageException::class, CalendarStorageException::class)
private fun legacyProcessEvent(newData: Event, _localEvent: LocalEvent?): LocalEvent {
var localEvent = _localEvent
// delete local event, if it exists
if (localEvent != null) {
Logger.log.info("Updating " + newData.uid + " in local calendar")
localEvent.eTag = newData.uid
localEvent.update(newData)
syncResult.stats.numUpdates++
} else {
Logger.log.info("Adding " + newData.uid + " to local calendar")
localEvent = LocalEvent(localCalendar(), newData, newData.uid, newData.uid)
localEvent.add()
syncResult.stats.numInserts++
}
return localEvent
}
}