kde-playground/kdepimlibs/akonadi/calendar/icalimporter.cpp
2015-04-14 21:49:29 +00:00

251 lines
8.1 KiB
C++

/**
This file is part of the akonadi-calendar library.
Copyright (C) 2013 Sérgio Martins <iamsergio@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "icalimporter.h"
#include "icalimporter_p.h"
#include "utils_p.h"
#include <akonadi/agentmanager.h>
#include <akonadi/agentinstancecreatejob.h>
#include <kcalcore/filestorage.h>
#include <kcalcore/memorycalendar.h>
#include <kcalcore/event.h>
#include <kcalcore/todo.h>
#include <kcalcore/journal.h>
#include <KJob>
#include <KLocalizedString>
#include <KDebug>
#include <KDateTime>
#include <KUrl>
#include <KIO/JobClasses>
#include <KIO/Scheduler>
#include <KTemporaryFile>
#include <QUrl>
#include <QFile>
#include <QDBusInterface>
using namespace KCalCore;
using namespace Akonadi;
ICalImporter::Private::Private(IncidenceChanger *changer,
ICalImporter *qq) : QObject(), q(qq)
, m_changer(changer)
, m_numIncidences(0)
, m_working(false)
, m_temporaryFile(0)
{
if (!changer) {
m_changer = new IncidenceChanger(q);
}
connect(m_changer, SIGNAL(createFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
SLOT(onIncidenceCreated(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)));
}
ICalImporter::Private::~Private()
{
delete m_temporaryFile;
}
void ICalImporter::Private::onIncidenceCreated(int changeId,
const Akonadi::Item &,
Akonadi::IncidenceChanger::ResultCode resultCode,
const QString &errorString)
{
if (!m_pendingRequests.contains(changeId))
return; // Not ours
m_pendingRequests.removeAll(changeId);
if (resultCode != IncidenceChanger::ResultCodeSuccess) {
m_working = false;
setErrorMessage(errorString);
m_pendingRequests.clear();
emit q->importIntoExistingFinished(false, m_numIncidences);
} else if (m_pendingRequests.isEmpty()) {
m_working = false;
emit q->importIntoExistingFinished(true, m_numIncidences);
}
}
void ICalImporter::Private::setErrorMessage(const QString &message)
{
m_lastErrorMessage = message;
kError() << message;
}
void ICalImporter::Private::resourceCreated(KJob *job)
{
Akonadi::AgentInstanceCreateJob *createjob = qobject_cast<Akonadi::AgentInstanceCreateJob*>(job);
Q_ASSERT(createjob);
m_working = false;
if (createjob->error()) {
setErrorMessage(i18n("Error creating ical resource: %1", createjob->errorString()));
emit q->importIntoNewFinished(false);
return;
}
Akonadi::AgentInstance instance = createjob->instance();
QDBusInterface iface(QString::fromLatin1("org.freedesktop.Akonadi.Resource.%1").arg(instance.identifier()), QLatin1String("/Settings"));
if (!iface.isValid()) {
setErrorMessage(i18n("Failed to obtain D-Bus interface for remote configuration."));
emit q->importIntoNewFinished(false);
return;
}
const QString path = createjob->property("path").toString();
Q_ASSERT(!path.isEmpty());
iface.call(QLatin1String("setPath"), path);
instance.reconfigure();
emit q->importIntoNewFinished(true);
}
void ICalImporter::Private::remoteDownloadFinished(KIO::Job *job, const QByteArray &data)
{
const bool success = job->error() == 0;
m_working = false;
if (success) {
delete m_temporaryFile;
m_temporaryFile = new KTemporaryFile();
m_temporaryFile->write(data.constData(), data.count());
q->importIntoExistingResource(QUrl(m_temporaryFile->fileName()), m_collection);
} else {
setErrorMessage(i18n("Could not download remote file."));
emit q->importIntoExistingFinished(false, 0);
}
}
ICalImporter::ICalImporter(Akonadi::IncidenceChanger *changer,
QObject *parent) : QObject(parent)
, d(new Private(changer, this))
{
}
QString ICalImporter::errorMessage() const
{
return d->m_lastErrorMessage;
}
bool ICalImporter::importIntoNewResource(const QString &filename)
{
d->m_lastErrorMessage.clear();
if (d->m_working) {
d->setErrorMessage(i18n("An import task is already in progress."));
return false;
}
d->m_working = true;
Akonadi::AgentType type = Akonadi::AgentManager::self()->type(QLatin1String("akonadi_ical_resource"));
Akonadi::AgentInstanceCreateJob *job = new Akonadi::AgentInstanceCreateJob(type, this);
job->setProperty("path", filename);
connect(job, SIGNAL(result(KJob*)), d, SLOT(resourceCreated(KJob*)));
job->start();
return true;
}
bool ICalImporter::importIntoExistingResource(const QUrl &url, Akonadi::Collection collection)
{
d->m_lastErrorMessage.clear();
if (d->m_working) {
d->setErrorMessage(i18n("An import task is already in progress."));
return false;
}
if (url.isEmpty()) {
d->setErrorMessage(i18n("Empty filename. Will not import ical file."));
return false;
}
if (!url.isValid()) {
d->setErrorMessage(i18n("Url to import is malformed."));
return false;
}
if (url.isLocalFile()) {
if (!QFile::exists(url.path())) {
d->setErrorMessage(i18n("The specified file doesn't exist, aborting import."));
return false;
}
MemoryCalendar::Ptr temporaryCalendar(new MemoryCalendar(KDateTime::LocalZone));
FileStorage storage(temporaryCalendar);
storage.setFileName(url.path());
bool success = storage.load();
if (!success) {
d->setErrorMessage(i18n("Failed to load ical file, check permissions."));
return false;
}
d->m_pendingRequests.clear();
Incidence::List incidences = temporaryCalendar->incidences();
if (incidences.isEmpty()) {
d->setErrorMessage(i18n("The ical file to merge is empty."));
return false;
}
if (!collection.isValid()) {
int dialogCode;
QStringList mimeTypes = QStringList() << KCalCore::Event::eventMimeType() << KCalCore::Todo::todoMimeType()
<< KCalCore::Journal::journalMimeType();
collection = CalendarUtils::selectCollection(0, dialogCode /*by-ref*/, mimeTypes);
}
if (!collection.isValid()) {
// user canceled
d->setErrorMessage(QString());
return false;
}
const IncidenceChanger::DestinationPolicy policySaved = d->m_changer->destinationPolicy();
d->m_changer->startAtomicOperation(i18n("Merge ical file into existing calendar."));
d->m_changer->setDestinationPolicy(IncidenceChanger::DestinationPolicyNeverAsk);
foreach(const Incidence::Ptr &incidence, incidences) {
Q_ASSERT(incidence);
if (!incidence)
continue;
const int requestId = d->m_changer->createIncidence(incidence, collection);
Q_ASSERT(requestId != -1); // -1 only happens with invalid incidences
if (requestId != -1)
d->m_pendingRequests << requestId;
}
d->m_changer->endAtomicOperation();
d->m_changer->setDestinationPolicy(policySaved); // restore
d->m_numIncidences = incidences.count();
} else {
d->m_collection = collection;
KIO::StoredTransferJob *job = KIO::storedGet(KUrl(url));
connect(job, SIGNAL(data(KIO::Job*,QByteArray)), d, SLOT(remoteDownloadFinished(KIO::Job*,QByteArray)));
}
d->m_working = true;
return true;
}