2
This file is part of the akonadi-calendar library.
4
Copyright (C) 2013 Sérgio Martins <iamsergio@gmail.com>
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License as published by the Free Software Foundation; either
9
version 2 of the License, or (at your option) any later version.
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Library General Public License for more details.
16
You should have received a copy of the GNU Library General Public License
17
along with this library; see the file COPYING.LIB. If not, write to
18
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
Boston, MA 02110-1301, USA.
22
#include "icalimporter.h"
23
#include "icalimporter_p.h"
26
#include <akonadi/agentmanager.h>
27
#include <akonadi/agentinstancecreatejob.h>
29
#include <kcalcore/filestorage.h>
30
#include <kcalcore/memorycalendar.h>
31
#include <kcalcore/event.h>
32
#include <kcalcore/todo.h>
33
#include <kcalcore/journal.h>
40
#include <KIO/JobClasses>
41
#include <KIO/Scheduler>
42
#include <KTemporaryFile>
46
#include <QMetaObject>
47
#include <QDBusInterface>
49
using namespace KCalCore;
50
using namespace Akonadi;
52
ICalImporter::Private::Private(IncidenceChanger *changer,
53
ICalImporter *qq) : QObject(), q(qq)
60
m_changer = new IncidenceChanger(q);
62
connect(m_changer, SIGNAL(createFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
63
SLOT(onIncidenceCreated(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) );
67
ICalImporter::Private::~Private()
69
delete m_temporaryFile;
72
void ICalImporter::Private::onIncidenceCreated(int changeId,
73
const Akonadi::Item &,
74
Akonadi::IncidenceChanger::ResultCode resultCode,
75
const QString &errorString)
77
if (!m_pendingRequests.contains(changeId))
80
m_pendingRequests.removeAll(changeId);
82
if (resultCode != IncidenceChanger::ResultCodeSuccess) {
84
setErrorMessage(errorString);
85
m_pendingRequests.clear();
86
emit q->importIntoExistingFinished(false, m_numIncidences);
87
} else if (m_pendingRequests.isEmpty()) {
89
emit q->importIntoExistingFinished(true, m_numIncidences);
93
void ICalImporter::Private::setErrorMessage(const QString &message)
95
m_lastErrorMessage = message;
99
void ICalImporter::Private::resourceCreated(KJob *job)
101
Akonadi::AgentInstanceCreateJob *createjob = qobject_cast<Akonadi::AgentInstanceCreateJob*>(job);
104
if (createjob->error()) {
105
setErrorMessage(i18n("Error creating ical resource: %1", createjob->errorString()));
106
emit q->importIntoNewFinished(false);
110
Akonadi::AgentInstance instance = createjob->instance();
111
QDBusInterface iface(QString::fromLatin1("org.freedesktop.Akonadi.Resource.%1").arg(instance.identifier()), QLatin1String("/Settings"));
113
if (!iface.isValid()) {
114
setErrorMessage(i18n("Failed to obtain D-Bus interface for remote configuration."));
115
emit q->importIntoNewFinished(false);
119
const QString path = createjob->property("path").toString();
120
Q_ASSERT(!path.isEmpty());
122
iface.call(QLatin1String("setPath"), path);
123
instance.reconfigure();
125
emit q->importIntoNewFinished(true);
128
void ICalImporter::Private::remoteDownloadFinished(KIO::Job *job, const QByteArray &data)
130
const bool success = job->error() == 0;
133
delete m_temporaryFile;
134
m_temporaryFile = new KTemporaryFile();
135
m_temporaryFile->write(data.constData(), data.count());
136
q->importIntoExistingResource(QUrl(m_temporaryFile->fileName()), m_collection);
138
setErrorMessage(i18n("Could not download remote file."));
139
emit q->importIntoExistingFinished(false, 0);
143
ICalImporter::ICalImporter(Akonadi::IncidenceChanger *changer,
144
QObject *parent) : QObject(parent)
145
, d(new Private(changer, this))
149
QString ICalImporter::errorMessage() const
151
return d->m_lastErrorMessage;
154
bool ICalImporter::importIntoNewResource(const QString &filename)
156
d->m_lastErrorMessage.clear();
159
d->setErrorMessage(i18n("An import task is already in progress."));
165
Akonadi::AgentType type = Akonadi::AgentManager::self()->type(QLatin1String("akonadi_ical_resource"));
166
Akonadi::AgentInstanceCreateJob *job = new Akonadi::AgentInstanceCreateJob(type, this);
167
job->setProperty("path", filename);
168
connect(job, SIGNAL(result(KJob*)), d, SLOT(resourceCreated(KJob*)));
174
bool ICalImporter::importIntoExistingResource(const QUrl &url, Akonadi::Collection collection)
176
d->m_lastErrorMessage.clear();
179
d->setErrorMessage(i18n("An import task is already in progress."));
184
d->setErrorMessage(i18n("Empty filename. Will not import ical file."));
188
if (!url.isValid()) {
189
d->setErrorMessage(i18n("Url to import is malformed."));
193
if (url.isLocalFile()) {
194
if (!QFile::exists(url.path())) {
195
d->setErrorMessage(i18n("The specified file doesn't exist, aborting import."));
198
MemoryCalendar::Ptr temporaryCalendar(new MemoryCalendar(KDateTime::LocalZone));
199
FileStorage storage(temporaryCalendar);
200
storage.setFileName(url.path());
201
bool success = storage.load();
203
d->setErrorMessage(i18n("Failed to load ical file, check permissions."));
207
d->m_pendingRequests.clear();
208
Incidence::List incidences = temporaryCalendar->incidences();
210
if (incidences.isEmpty()) {
211
d->setErrorMessage(i18n("The ical file to merge is empty."));
215
if (!collection.isValid()) {
217
QStringList mimeTypes = QStringList() << KCalCore::Event::eventMimeType() << KCalCore::Todo::todoMimeType()
218
<< KCalCore::Journal::journalMimeType();
219
collection = CalendarUtils::selectCollection( 0, dialogCode /*by-ref*/, mimeTypes );
222
if (!collection.isValid()) {
224
d->setErrorMessage(QString());
228
const IncidenceChanger::DestinationPolicy policySaved = d->m_changer->destinationPolicy();
229
d->m_changer->startAtomicOperation(i18n("Merge ical file into existing calendar."));
230
d->m_changer->setDestinationPolicy(IncidenceChanger::DestinationPolicyNeverAsk);
231
foreach (const Incidence::Ptr &incidence, incidences) {
235
const int requestId = d->m_changer->createIncidence(incidence, collection);
236
Q_ASSERT(requestId != -1); // -1 only happens with invalid incidences
238
d->m_pendingRequests << requestId;
240
d->m_changer->endAtomicOperation();
242
d->m_changer->setDestinationPolicy(policySaved); // restore
243
d->m_numIncidences = incidences.count();
245
d->m_collection = collection;
246
KIO::StoredTransferJob *job = KIO::storedGet(KUrl(url));
247
connect(job, SIGNAL(data(KIO::Job*,QByteArray)), d, SLOT(remoteDownloadFinished(KIO::Job*,QByteArray)));