Commit 64f31f0e authored by Shashwat Jolly's avatar Shashwat Jolly
Browse files

Remove v1 resource code

- Handlers for different types are no longer required - everything is handled in etesyncresource.cpp
- etesyncadapter has been replaced with etebaseadapter
- Removed v1 code from clientstate
parent 856bc49d
add_definitions(-DTRANSLATION_DOMAIN=\"akonadi_etesync_resource\")
set(etesyncresource_common_SRCS
etesyncadapter.cpp
etebaseadapter.cpp
)
......@@ -19,12 +18,7 @@ set(etesyncresource_SRCS
etesyncclientstate.cpp
journalsfetchjob.cpp
entriesfetchjob.cpp
loginjob.cpp
contacthandler.cpp
basehandler.cpp
calendartaskbasehandler.cpp
calendarhandler.cpp
taskhandler.cpp
loginjob.cpp
setupwizard.cpp
${etesyncconfig_SRCS}
......
/*
* SPDX-FileCopyrightText: 2020 Shashwat Jolly <shashwat.jolly@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "basehandler.h"
#include <AkonadiCore/CollectionModifyJob>
#include <ItemSync>
#include "entriesfetchjob.h"
#include "etesync_debug.h"
#include "etesyncresource.h"
using namespace Akonadi;
using namespace EteSyncAPI;
BaseHandler::BaseHandler(EteSyncResource *resource)
: mResource(resource)
, mClientState((resource->mClientState).get())
{
}
void BaseHandler::initialiseBaseDirectory()
{
mResource->initialiseDirectory(baseDirectoryPath());
}
void BaseHandler::setupItems(std::vector<EteSyncEntryPtr> &entries, Akonadi::Collection &collection, QString &prevUid)
{
qCDebug(ETESYNC_LOG) << "BaseHandler: Setting up items";
const QString journalUid = collection.remoteId();
const bool isIncremental = (prevUid.isEmpty() || prevUid.isNull()) ? false : true;
Item::List changedItems;
Item::List removedItems;
getItemListFromEntries(entries, changedItems, removedItems, collection, journalUid, prevUid);
if (isIncremental) {
mResource->itemsRetrievedIncremental(changedItems, removedItems);
} else {
mResource->itemsRetrieved(changedItems);
}
collection.setRemoteRevision(prevUid);
new CollectionModifyJob(collection, this);
}
bool BaseHandler::createEteSyncEntry(const EteSyncSyncEntry *syncEntry, const EteSyncCryptoManager *cryptoManager, const Collection &collection)
{
EteSyncEntryPtr entry = etesync_entry_from_sync_entry(cryptoManager, syncEntry, collection.remoteRevision());
if (!entry) {
qCDebug(ETESYNC_LOG) << "Could not create entry from sync entry";
qCDebug(ETESYNC_LOG) << "EteSync error" << QStringFromCharPtr(CharPtr(etesync_get_error_message()));
return false;
}
EteSyncEntryManagerPtr entryManager = etesync_entry_manager_new(mClientState->client(), collection.remoteId());
EteSyncEntry *entries[] = {entry.get(), nullptr};
if (etesync_entry_manager_create(entryManager.get(), entries, collection.remoteRevision())) {
handleConflictError(collection);
mResource->handleError();
return false;
}
updateCollectionRevision(entry.get(), collection);
return true;
}
void BaseHandler::updateCollectionRevision(const EteSyncEntry *entry, const Collection &collection)
{
const QString entryUid = QStringFromCharPtr(CharPtr(etesync_entry_get_uid(entry)));
Collection col = collection;
col.setRemoteRevision(entryUid);
new CollectionModifyJob(col, this);
}
void BaseHandler::syncCollection(const QVariant &collectionVariant)
{
// const Collection collection = collectionVariant.value<Collection>();
// qCDebug(ETESYNC_LOG) << "Syncing journal" << collection.remoteId();
// auto job = new EntriesFetchJob(mClientState->client(), collection, this);
// connect(job, &EntriesFetchJob::finished, this, &BaseHandler::slotItemsRetrieved);
// job->start();
}
void BaseHandler::slotItemsRetrieved(KJob *job)
{
// if (job->error()) {
// qCWarning(ETESYNC_LOG) << job->errorText();
// return;
// }
// std::vector<EteSyncEntryPtr> entries = qobject_cast<EntriesFetchJob *>(job)->getEntries();
// Collection collection = qobject_cast<EntriesFetchJob *>(job)->collection();
// qCDebug(ETESYNC_LOG) << "BaseHandler: Syncing items";
// QString prevUid = collection.remoteRevision();
// const QString journalUid = collection.remoteId();
// const bool isIncremental = (prevUid.isEmpty() || prevUid.isNull()) ? false : true;
// Item::List changedItems;
// Item::List removedItems;
// getItemListFromEntries(entries, changedItems, removedItems, collection, journalUid, prevUid);
// collection.setRemoteRevision(prevUid);
// new CollectionModifyJob(collection, this);
// ItemSync *syncer = new ItemSync(collection);
// if (isIncremental) {
// syncer->setIncrementalSyncItems(changedItems, removedItems);
// } else {
// syncer->setFullSyncItems(changedItems);
// }
// connect(syncer, SIGNAL(result(KJob*)), this, SLOT(taskDone()));
}
bool BaseHandler::handleConflictError(const Collection &collection)
{
if (etesync_get_error_code() == EteSyncErrorCode::ETESYNC_ERROR_CODE_CONFLICT) {
qCDebug(ETESYNC_LOG) << "Conflict error";
mResource->deferTask();
mResource->scheduleCustomTask(this, "syncCollection", QVariant::fromValue(collection), EteSyncResource::Prepend);
return true;
}
return false;
}
void BaseHandler::taskDone()
{
mResource->taskDone();
}
/*
* SPDX-FileCopyrightText: 2020 Shashwat Jolly <shashwat.jolly@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef BASEHANDLER_H
#define BASEHANDLER_H
#include <AkonadiCore/Collection>
#include <AkonadiCore/Item>
#include <KCalendarCore/Incidence>
#include "etesyncclientstate.h"
using namespace Akonadi;
class EteSyncResource;
class BaseHandler : public QObject
{
Q_OBJECT
public:
typedef std::unique_ptr<BaseHandler> Ptr;
explicit BaseHandler(EteSyncResource *resource);
virtual const QString mimeType() = 0;
virtual void setupItems(std::vector<EteSyncEntryPtr> &entries, Akonadi::Collection &collection, QString &prevUid);
virtual void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) = 0;
virtual void itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &parts) = 0;
virtual void itemRemoved(const Akonadi::Item &item) = 0;
virtual void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) = 0;
virtual void collectionChanged(const Akonadi::Collection &collection) = 0;
virtual void collectionRemoved(const Akonadi::Collection &collection) = 0;
protected Q_SLOTS:
void slotItemsRetrieved(KJob *job);
virtual void syncCollection(const QVariant &collectionVariant);
void taskDone();
protected:
void initialiseBaseDirectory();
bool createEteSyncEntry(const EteSyncSyncEntry *syncEntry, const EteSyncCryptoManager *cryptoManager, const Collection &collection);
void updateCollectionRevision(const EteSyncEntry *entry, const Collection &collection);
virtual QString baseDirectoryPath() const = 0;
virtual const QString etesyncCollectionType() = 0;
virtual void getItemListFromEntries(std::vector<EteSyncEntryPtr> &entries, Item::List &changedItems, Item::List &removedItems, Collection &collection, const QString &journalUid, QString &prevUid) = 0;
bool handleConflictError(const Collection &collection);
EteSyncResource *mResource = nullptr;
EteSyncClientState *mClientState = nullptr;
};
#endif
/*
* SPDX-FileCopyrightText: 2020 Shashwat Jolly <shashwat.jolly@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "calendarhandler.h"
CalendarHandler::CalendarHandler(EteSyncResource *resource) : CalendarTaskBaseHandler(resource)
{
}
const QString CalendarHandler::mimeType()
{
return KCalendarCore::Event::eventMimeType();
}
const QString CalendarHandler::etesyncCollectionType()
{
return QStringLiteral(ETESYNC_COLLECTION_TYPE_CALENDAR);
}
/*
* SPDX-FileCopyrightText: 2020 Shashwat Jolly <shashwat.jolly@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef CALENDARHANDLER_H
#define CALENDARHANDLER_H
#include <KCalendarCore/Event>
#include "calendartaskbasehandler.h"
#include "etesyncadapter.h"
#include "etesyncclientstate.h"
class EteSyncResource;
class CalendarHandler : public CalendarTaskBaseHandler
{
Q_OBJECT
public:
explicit CalendarHandler(EteSyncResource *resource);
const QString mimeType() override;
protected:
const QString etesyncCollectionType() override;
};
#endif
/*
* SPDX-FileCopyrightText: 2020 Shashwat Jolly <shashwat.jolly@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "calendartaskbasehandler.h"
#include <AkonadiCore/AttributeFactory>
#include <AkonadiCore/CollectionColorAttribute>
#include <AkonadiCore/CollectionModifyJob>
#include <AkonadiCore/ItemModifyJob>
#include <KCalendarCore/FileStorage>
#include <KCalendarCore/ICalFormat>
#include <KCalendarCore/MemoryCalendar>
#include <KLocalizedString>
#include <QFile>
#include "entriesfetchjob.h"
#include "etesync_debug.h"
#include "etesyncresource.h"
using namespace Akonadi;
using namespace KCalendarCore;
CalendarTaskBaseHandler::CalendarTaskBaseHandler(EteSyncResource *resource) : BaseHandler(resource)
{
initialiseBaseDirectory();
AttributeFactory::registerAttribute<CollectionColorAttribute>();
}
void CalendarTaskBaseHandler::getItemListFromEntries(std::vector<EteSyncEntryPtr> &entries, Item::List &changedItems, Item::List &removedItems, Collection &collection, const QString &journalUid, QString &prevUid)
{
const EteSyncJournalPtr &journal = mResource->getJournal(journalUid);
if (!journal) {
qCDebug(ETESYNC_LOG) << "SetupItems: Could not get journal" << journalUid;
mResource->cancelTask(i18n("Could not get journal"));
return;
}
EteSyncCryptoManagerPtr cryptoManager = etesync_journal_get_crypto_manager(journal.get(), mClientState->derived(), mClientState->keypair());
QMap<QString, KCalendarCore::Incidence::Ptr> incidences;
for (auto &entry : entries) {
if (!entry) {
qCDebug(ETESYNC_LOG) << "SetupItems: Entry is null";
prevUid = QStringFromCharPtr(CharPtr(etesync_entry_get_uid(entry.get())));
continue;
}
EteSyncSyncEntryPtr syncEntry = etesync_entry_get_sync_entry(entry.get(), cryptoManager.get(), prevUid);
if (!syncEntry) {
qCDebug(ETESYNC_LOG) << "SetupItems: syncEntry is null for entry" << etesync_entry_get_uid(entry.get());
qCDebug(ETESYNC_LOG) << "EteSync error" << QStringFromCharPtr(CharPtr(etesync_get_error_message()));
prevUid = QStringFromCharPtr(CharPtr(etesync_entry_get_uid(entry.get())));
continue;
}
CharPtr contentStr(etesync_sync_entry_get_content(syncEntry.get()));
KCalendarCore::ICalFormat format;
const KCalendarCore::Incidence::Ptr incidence = format.fromString(QStringFromCharPtr(contentStr));
if (!incidence || (incidence->uid()).isEmpty()) {
qCDebug(ETESYNC_LOG) << "Couldn't parse entry with uid" << etesync_entry_get_uid(entry.get());
prevUid = QStringFromCharPtr(CharPtr(etesync_entry_get_uid(entry.get())));
continue;
}
qCDebug(ETESYNC_LOG) << "Entry parsed into incidence - UID" << incidence->uid();
const QString action = QStringFromCharPtr(CharPtr(etesync_sync_entry_get_action(syncEntry.get())));
if (action == QStringLiteral(ETESYNC_SYNC_ENTRY_ACTION_ADD) || action == QStringLiteral(ETESYNC_SYNC_ENTRY_ACTION_CHANGE)) {
incidences[incidence->uid()] = incidence;
} else if (action == QStringLiteral(ETESYNC_SYNC_ENTRY_ACTION_DELETE)) {
if (incidences.contains(incidence->uid())) {
incidences.remove(incidence->uid());
} else {
Item item;
item.setMimeType(mimeType());
item.setParentCollection(collection);
item.setRemoteId(incidence->uid());
removedItems.push_back(item);
deleteLocalCalendar(incidence->uid());
}
}
prevUid = QStringFromCharPtr(CharPtr(etesync_entry_get_uid(entry.get())));
}
for (auto it = incidences.constBegin(); it != incidences.constEnd(); it++) {
Item item;
item.setMimeType(mimeType());
item.setParentCollection(collection);
item.setRemoteId(it.key());
item.setPayload<KCalendarCore::Incidence::Ptr>(it.value());
changedItems.push_back(item);
updateLocalCalendar(it.value());
}
}
QString CalendarTaskBaseHandler::baseDirectoryPath() const
{
return mResource->baseDirectoryPath() + QStringLiteral("/Calendar");
}
QString CalendarTaskBaseHandler::getLocalCalendar(const QString &incidenceUid) const
{
const QString path = baseDirectoryPath() + QLatin1Char('/') + incidenceUid + QLatin1String(".ical");
const auto calendar = Calendar::Ptr(new MemoryCalendar(QTimeZone::utc()));
const auto fileStorage = FileStorage::Ptr(new FileStorage(calendar, path, new ICalFormat()));
if (!fileStorage->load()) {
qCDebug(ETESYNC_LOG) << "Unable to read" << path;
return QString();
}
KCalendarCore::ICalFormat format;
return format.toString(calendar);
}
bool CalendarTaskBaseHandler::updateLocalCalendar(const KCalendarCore::Incidence::Ptr &incidence)
{
const QString path = baseDirectoryPath() + QLatin1Char('/') + incidence->uid() + QLatin1String(".ical");
const auto calendar = Calendar::Ptr(new MemoryCalendar(QTimeZone::utc()));
calendar->addIncidence(incidence);
const auto fileStorage = FileStorage::Ptr(new FileStorage(calendar, path, new ICalFormat()));
if (!fileStorage->save()) {
qCDebug(ETESYNC_LOG) << "Unable to write" << path;
return false;
}
return true;
}
void CalendarTaskBaseHandler::deleteLocalCalendar(const QString &incidenceUid)
{
const QString path = baseDirectoryPath() + QLatin1Char('/') + incidenceUid + QLatin1String(".ical");
QFile file(path);
if (!file.remove()) {
qCDebug(ETESYNC_LOG) << "Unable to remove " << path << file.errorString();
return;
}
}
void CalendarTaskBaseHandler::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
{
if (!item.hasPayload<Incidence::Ptr>()) {
qCDebug(ETESYNC_LOG) << "Received item with unknown payload - Remote ID: " << item.remoteId();
mResource->cancelTask(i18n("Received item with unknown payload %1", item.mimeType()));
return;
}
KCalendarCore::Calendar::Ptr calendar(new MemoryCalendar(QTimeZone::utc()));
const auto incidence = item.payload<Incidence::Ptr>();
qCDebug(ETESYNC_LOG) << "Incidence mime type" << incidence->mimeType();
if (!collection.contentMimeTypes().contains(incidence->mimeType())) {
qCDebug(ETESYNC_LOG) << "Received item of different type";
mResource->cancelTask(i18n("Received item of different type"));
return;
}
calendar->addIncidence(incidence);
KCalendarCore::ICalFormat format;
const QString journalUid = collection.remoteId();
const EteSyncJournalPtr &journal = mResource->getJournal(journalUid);
if (!journal) {
qCDebug(ETESYNC_LOG) << "Could not get journal" << journalUid;
mResource->cancelTask(i18n("Could not get journal"));
return;
}
EteSyncCryptoManagerPtr cryptoManager = etesync_journal_get_crypto_manager(journal.get(), mClientState->derived(), mClientState->keypair());
EteSyncSyncEntryPtr syncEntry = etesync_sync_entry_new(QStringLiteral(ETESYNC_SYNC_ENTRY_ACTION_ADD), format.toString(calendar));
if (!createEteSyncEntry(syncEntry.get(), cryptoManager.get(), collection)) {
qCDebug(ETESYNC_LOG) << "Could not create EteSync entry";
mResource->cancelTask(i18n("Could not create EteSync entry"));
return;
}
Item newItem(item);
newItem.setRemoteId(incidence->uid());
newItem.setPayload<Incidence::Ptr>(incidence);
mResource->changeCommitted(newItem);
updateLocalCalendar(item.payload<Incidence::Ptr>());
}
void CalendarTaskBaseHandler::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &parts)
{
Q_UNUSED(parts);
if (!item.hasPayload<Incidence::Ptr>()) {
qCDebug(ETESYNC_LOG) << "Received item with unknown payload";
mResource->cancelTask(i18n("Received item with unknown payload %1", item.mimeType()));
return;
}
Collection collection = item.parentCollection();
KCalendarCore::Calendar::Ptr calendar(new MemoryCalendar(QTimeZone::utc()));
const auto incidence = item.payload<Incidence::Ptr>();
calendar->addIncidence(incidence);
KCalendarCore::ICalFormat format;
const QString journalUid = collection.remoteId();
const EteSyncJournalPtr &journal = mResource->getJournal(journalUid);
if (!journal) {
qCDebug(ETESYNC_LOG) << "Could not get journal" << journalUid;
mResource->cancelTask(i18n("Could not get journal"));
return;
}
EteSyncCryptoManagerPtr cryptoManager = etesync_journal_get_crypto_manager(journal.get(), mClientState->derived(), mClientState->keypair());
EteSyncSyncEntryPtr syncEntry = etesync_sync_entry_new(QStringLiteral(ETESYNC_SYNC_ENTRY_ACTION_CHANGE), format.toString(calendar));
if (!createEteSyncEntry(syncEntry.get(), cryptoManager.get(), collection)) {
qCDebug(ETESYNC_LOG) << "Could not create EteSync entry";
mResource->cancelTask(i18n("Could not create EteSync entry"));
return;
}
// Using ItemModifyJob + changeProcessed() instead of changeCommitted to handle conflict error - ItemSync modifies local item payload
Item newItem(item);
newItem.setPayload<Incidence::Ptr>(incidence);
Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob(newItem);
modifyJob->disableRevisionCheck();
mResource->changeProcessed();
updateLocalCalendar(item.payload<Incidence::Ptr>());
}
void CalendarTaskBaseHandler::itemRemoved(const Akonadi::Item &item)
{
Collection collection = item.parentCollection();
const QString calendar = getLocalCalendar(item.remoteId());
if (calendar.isEmpty()) {
qCDebug(ETESYNC_LOG) << "Could not get local calendar";
mResource->cancelTask(i18n("Could not get local calendar"));
return;
}
// Delete now, because itemRemoved() may be called when collection is removed
deleteLocalCalendar(item.remoteId());
const QString journalUid = collection.remoteId();
const EteSyncJournalPtr &journal = mResource->getJournal(journalUid);
if (!journal) {
mResource->cancelTask();
return;
}
EteSyncCryptoManagerPtr cryptoManager = etesync_journal_get_crypto_manager(journal.get(), mClientState->derived(), mClientState->keypair());
EteSyncSyncEntryPtr syncEntry = etesync_sync_entry_new(QStringLiteral(ETESYNC_SYNC_ENTRY_ACTION_DELETE), calendar);
if (!createEteSyncEntry(syncEntry.get(), cryptoManager.get(), collection)) {
qCDebug(ETESYNC_LOG) << "Could not create EteSync entry";
mResource->cancelTask(i18n("Could not create EteSync entry"));
return;
}
mResource->changeProcessed();
}
void CalendarTaskBaseHandler::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
{
Q_UNUSED(parent);
const QString journalUid = QStringFromCharPtr(CharPtr(etesync_gen_uid()));
EteSyncJournalPtr journal = etesync_journal_new(journalUid, ETESYNC_CURRENT_VERSION);
EteSyncCollectionInfoPtr info = etesync_collection_info_new(etesyncCollectionType(), collection.displayName(), QString(), ETESYNC_COLLECTION_DEFAULT_COLOR);
EteSyncCryptoManagerPtr cryptoManager = etesync_journal_get_crypto_manager(journal.get(), mClientState->derived(), mClientState->keypair());
if (etesync_journal_set_info(journal.get(), cryptoManager.get(), info.get())) {
qCDebug(ETESYNC_LOG) << "Could not set journal info";
qCDebug(ETESYNC_LOG) << "EteSync error" << QStringFromCharPtr(CharPtr(etesync_get_error_message()));
mResource->cancelTask(i18n("Could not set journal info"));
return;
}
if (etesync_journal_manager_create(mClientState->journalManager(), journal.get())) {
qCDebug(ETESYNC_LOG) << "Could not create journal";
qCDebug(ETESYNC_LOG) << "EteSync error" << QStringFromCharPtr(CharPtr(etesync_get_error_message()));
mResource->handleError();
return;
}
Collection newCollection(collection);
mResource->setupCollection(newCollection, journal.get());
mResource->mJournalsCache[newCollection.remoteId()] = std::move(journal);
mResource->changeCommitted(newCollection);
}
void CalendarTaskBaseHandler::collectionChanged(const Akonadi::Collection &collection)
{
const QString journalUid = collection.remoteId();
const EteSyncJournalPtr &journal = mResource->getJournal(journalUid);
if (!journal) {
qCDebug(ETESYNC_LOG) << "Could not get journal" << journalUid;
mResource->cancelTask(i18n("Could not get journal"));