summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Mollekopf <mollekopf@kolabsys.com>2013-11-11 13:22:20 (GMT)
committerChristian Mollekopf <mollekopf@kolabsys.com>2013-11-11 13:22:20 (GMT)
commit0c5b5a9596d2bda0ac20bddd3eb1fc87c85efbf8 (patch)
tree5dc4283cf94330492264230180ee3b2421945527
parent6cc0d839c258e6253bc79a5accc9dc86878a6776 (diff)
parent5cc21d084a89f871e009df2f5696040b32c379ac (diff)
downloadkolab-utils-0c5b5a9596d2bda0ac20bddd3eb1fc87c85efbf8.tar.gz
Merge branch 'dev/googlemigration'
-rw-r--r--CMakeLists.txt1
-rw-r--r--fbdaemon/CMakeLists.txt12
-rw-r--r--fbdaemon/fbaggregatorjob.cpp6
-rw-r--r--fbdaemon/fbaggregatorjob.h2
-rw-r--r--fbdaemon/fbgeneratorjob.cpp8
-rw-r--r--fbdaemon/fbgeneratorjob.h2
-rw-r--r--fbdaemon/kolabjob.cpp34
-rw-r--r--fbdaemon/kolabjob.h7
-rw-r--r--fbdaemon/tests/CMakeLists.txt25
-rw-r--r--fbdaemon/tests/fbaggregatortest.cpp182
-rw-r--r--fbdaemon/tests/fbaggregatortest.h46
-rw-r--r--fbdaemon/tests/fbgeneratortest.cpp179
-rw-r--r--fbdaemon/tests/fbgeneratortest.h47
-rw-r--r--lib/CMakeLists.txt6
-rw-r--r--lib/jobs/CMakeLists.txt2
-rw-r--r--lib/jobs/createkolabfolderjob.cpp109
-rw-r--r--lib/jobs/createkolabfolderjob.h54
-rw-r--r--lib/jobs/findkolabfoldersjob.cpp23
-rw-r--r--lib/jobs/probeimapserverjob.cpp93
-rw-r--r--lib/jobs/probeimapserverjob.h53
-rw-r--r--lib/jobs/probekolabserverjob.cpp82
-rw-r--r--lib/jobs/probekolabserverjob.h10
-rw-r--r--lib/jobs/setupkolabfoldersjob.cpp75
-rw-r--r--lib/jobs/setupkolabfoldersjob.h6
-rw-r--r--lib/kolabaccount.cpp43
-rw-r--r--lib/sessionfactory.h2
-rw-r--r--lib/testlib/testutils.h8
-rw-r--r--migrationutility/CMakeLists.txt64
-rw-r--r--migrationutility/coordinationjob.cpp7
-rw-r--r--migrationutility/coordinationjob.h1
-rw-r--r--migrationutility/exchangesourceaccount.cpp134
-rw-r--r--migrationutility/exchangesourceaccount.h36
-rw-r--r--migrationutility/googlesourceaccount.cpp378
-rw-r--r--migrationutility/googlesourceaccount.h192
-rw-r--r--migrationutility/googlesourceserver.cpp79
-rw-r--r--migrationutility/googlesourceserver.h47
-rw-r--r--migrationutility/imapsourceaccount.cpp180
-rw-r--r--migrationutility/imapsourceaccount.h84
-rw-r--r--migrationutility/kolabsourceaccount.cpp103
-rw-r--r--migrationutility/kolabsourceaccount.h39
-rw-r--r--migrationutility/main.cpp53
-rw-r--r--migrationutility/migratefolderjob.cpp18
-rw-r--r--migrationutility/migratefolderjob.h1
-rw-r--r--migrationutility/migrateuserjob.cpp114
-rw-r--r--migrationutility/migrateuserjob.h23
-rw-r--r--migrationutility/sourceaccount.cpp363
-rw-r--r--migrationutility/sourceaccount.h174
-rw-r--r--migrationutility/sourceserver.cpp120
-rw-r--r--migrationutility/sourceserver.h52
-rw-r--r--migrationutility/tests/CMakeLists.txt51
-rw-r--r--migrationutility/tests/exchangeimaptest.cpp484
-rw-r--r--migrationutility/tests/exchangeimaptest.h66
-rw-r--r--migrationutility/tests/migrationscenariotest.cpp454
-rw-r--r--migrationutility/tests/migrationscenariotest.h68
-rw-r--r--migrationutility/tests/migrationtest.cpp59
-rw-r--r--migrationutility/tests/migrationtest.h30
56 files changed, 3172 insertions, 1419 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1df6bc8..c852cb9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,7 @@ set(Kolabutils_VERSION ${Kolabutils_VERSION_MAJOR}.${Kolabutils_VERSION_MINOR} )
set(Kolabutils_VERSION_STRING ${CMAKE_PROJECT_NAME}-${Kolabutils_VERSION})
option( USE_LIBCALENDARING "Use libcalendaring" FALSE )
+option(BUILD_GOOGLESUPPORT "Build modues that require libkgoogle" FALSE)
set(CMAKE_MODULE_PATH ${KolabUtilsFormat_SOURCE_DIR}/cmake/modules)
diff --git a/fbdaemon/CMakeLists.txt b/fbdaemon/CMakeLists.txt
index a7cc449..23aff08 100644
--- a/fbdaemon/CMakeLists.txt
+++ b/fbdaemon/CMakeLists.txt
@@ -16,7 +16,15 @@ QT4_WRAP_CPP(FB_MOC
${CMAKE_CURRENT_SOURCE_DIR}/kolabjob.h
${CMAKE_CURRENT_SOURCE_DIR}/fbaggregatorjob.h
)
-set( FBDAEMON_SRCS ${FBDAEMON_SRCS} ${FB_MOC} ${JOBS_SRCS} )
+
+set(FBDAEMON_SRCS ${FBDAEMON_SRCS} ${FB_MOC})
+
+#We require 1.0, otherwise fb objects are not correctly generated:
+#"Failed iTIP restrictions for FREEBUSY property. Expected one or more instances of the property and got 0"
+#find_package(libical 1.0)
+
+add_library(fb_static STATIC ${FBDAEMON_SRCS})
+target_link_libraries(fb_static ${COMMON_DEPENDENCIES} kolabutils)
add_executable(kolab-freebusyd ${FBDAEMON_SRCS} ${JOB_SRCS} main.cpp)
target_link_libraries(kolab-freebusyd ${COMMON_DEPENDENCIES} kolabutils)
@@ -27,4 +35,4 @@ install(TARGETS kolab-freebusyd
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
)
-# add_subdirectory(tests)
+add_subdirectory(tests)
diff --git a/fbdaemon/fbaggregatorjob.cpp b/fbdaemon/fbaggregatorjob.cpp
index 4531336..47a283a 100644
--- a/fbdaemon/fbaggregatorjob.cpp
+++ b/fbdaemon/fbaggregatorjob.cpp
@@ -39,16 +39,16 @@ QStringList FBAggregatorJob::requiredFolders()
return QStringList() << KOLAB_FOLDER_TYPE_FREEBUSY;
}
-void FBAggregatorJob::startWork(ProbeKolabServerJob* capabilitiesJob)
+void FBAggregatorJob::startWork()
{
Debug() << "starting aggregator job for " << mSessionSettings.userName;
- if (capabilitiesJob->kolabFolders().values(KOLAB_FOLDER_TYPE_FREEBUSY).isEmpty()) {
+ if (mKolabFolders.values(KOLAB_FOLDER_TYPE_FREEBUSY).isEmpty()) {
kWarning() << "no freebusy folder found";
setError(KJob::UserDefinedError);
logout();
return;
}
- mFreebusyFolder = capabilitiesJob->kolabFolders().values(KOLAB_FOLDER_TYPE_FREEBUSY).first();
+ mFreebusyFolder = mKolabFolders.values(KOLAB_FOLDER_TYPE_FREEBUSY).first();
FetchMessagesJob *fetchJob = new FetchMessagesJob(mFreebusyFolder, mSession, this);
connect( fetchJob, SIGNAL(result(KJob*)), this, SLOT(onFetchFBDone(KJob*)) );
diff --git a/fbdaemon/fbaggregatorjob.h b/fbdaemon/fbaggregatorjob.h
index 0b4c270..24c45ee 100644
--- a/fbdaemon/fbaggregatorjob.h
+++ b/fbdaemon/fbaggregatorjob.h
@@ -40,7 +40,7 @@ private Q_SLOTS:
// void onGenerateFBDone(KJob*);
// void onModDone(KJob*);
private:
- virtual void startWork(ProbeKolabServerJob* job);
+ virtual void startWork();
QString mFreebusyFolder;
QString mGeneratedFile;
diff --git a/fbdaemon/fbgeneratorjob.cpp b/fbdaemon/fbgeneratorjob.cpp
index 3617637..25afbe6 100644
--- a/fbdaemon/fbgeneratorjob.cpp
+++ b/fbdaemon/fbgeneratorjob.cpp
@@ -49,16 +49,16 @@ QStringList FBGeneratorJob::requiredFolders()
}
-void FBGeneratorJob::startWork(ProbeKolabServerJob* capabilitiesJob)
+void FBGeneratorJob::startWork()
{
- if (capabilitiesJob->kolabFolders().values(KOLAB_FOLDER_TYPE_FREEBUSY).isEmpty()) {
+ if (mKolabFolders.values(KOLAB_FOLDER_TYPE_FREEBUSY).isEmpty()) {
kWarning() << "no freebusy folder found";
setError(KJob::UserDefinedError);
logout();
return;
}
- mFreebusyFolder = capabilitiesJob->kolabFolders().values(KOLAB_FOLDER_TYPE_FREEBUSY).first();
- mEventFolders = capabilitiesJob->kolabFolders().values(KOLAB_FOLDER_TYPE_EVENT);
+ mFreebusyFolder = mKolabFolders.values(KOLAB_FOLDER_TYPE_FREEBUSY).first();
+ mEventFolders = mKolabFolders.values(KOLAB_FOLDER_TYPE_EVENT);
if (mEventFolders.isEmpty()) {
kWarning() << "no event folders available";
logout();
diff --git a/fbdaemon/fbgeneratorjob.h b/fbdaemon/fbgeneratorjob.h
index bdfc5a6..47ee128 100644
--- a/fbdaemon/fbgeneratorjob.h
+++ b/fbdaemon/fbgeneratorjob.h
@@ -35,7 +35,7 @@ private Q_SLOTS:
protected:
virtual QStringList requiredFolders();
private:
- virtual void startWork(ProbeKolabServerJob* job);
+ virtual void startWork();
QString mFreebusyFolder;
QStringList mEventFolders;
diff --git a/fbdaemon/kolabjob.cpp b/fbdaemon/kolabjob.cpp
index 373b08b..be50a90 100644
--- a/fbdaemon/kolabjob.cpp
+++ b/fbdaemon/kolabjob.cpp
@@ -24,6 +24,7 @@
#include "uiproxy.h"
#include "authenticationjob.h"
#include "jobs/probekolabserverjob.h"
+#include <jobs/setupkolabfoldersjob.h>
#include <sessionsettings.h>
KolabJob::KolabJob(const SessionSettings &sessionSettings, QObject* parent)
@@ -72,7 +73,6 @@ void KolabJob::onAuthDone(KJob *job)
}
// Debug() << "login successful";
ProbeKolabServerJob *probeJob = new ProbeKolabServerJob(mSession, this);
- probeJob->createDefaultsIfMissing(requiredFolders());
QObject::connect(probeJob, SIGNAL(result(KJob*)), this, SLOT(onProbeDone(KJob*)));
probeJob->start();
}
@@ -85,9 +85,35 @@ void KolabJob::onProbeDone(KJob* job)
emitResult();
return;
}
- ProbeKolabServerJob *capabilitiesJob = qobject_cast<ProbeKolabServerJob*>( job );
- Q_ASSERT(capabilitiesJob);
- startWork(capabilitiesJob);
+ ProbeKolabServerJob *probeJob = static_cast<ProbeKolabServerJob*>(job);
+ mKolabFolders = probeJob->kolabFolders();
+
+ QString rootFolder;
+ QStringList toCreate;
+ foreach (const QString &folderType, requiredFolders()) {
+ if (!mKolabFolders.contains(folderType)) {
+ toCreate << folderType;
+ }
+ }
+ if (toCreate.isEmpty()) {
+ startWork();
+ } else {
+ SetupKolabFoldersJob *setupJob = new SetupKolabFoldersJob(probeJob->capabilities(), rootFolder, mSession, this);
+ setupJob->setKolabFolders(toCreate);
+ connect(setupJob, SIGNAL(result(KJob*)), this, SLOT(onSetupDone(KJob*)));
+ setupJob->start();
+ }
+}
+
+void KolabJob::onSetupDone(KJob *job)
+{
+ if ( job->error() ) {
+ Warning() << job->errorString();
+ setError(KJob::UserDefinedError);
+ emitResult();
+ return;
+ }
+ startWork();
}
void KolabJob::logout()
diff --git a/fbdaemon/kolabjob.h b/fbdaemon/kolabjob.h
index 8a1749e..30595b1 100644
--- a/fbdaemon/kolabjob.h
+++ b/fbdaemon/kolabjob.h
@@ -19,6 +19,8 @@
#define KOLABJOB_H
#include <kimap/session.h>
#include <QStringList>
+#include <QHash>
+#include <kimap/listjob.h>
#include <sessionsettings.h>
#define X_ORIGIN_HEADER "X-Freebusy-Origin"
@@ -36,17 +38,18 @@ private Q_SLOTS:
void onAuthDone(KJob*);
void onProbeDone(KJob* job);
void onLogoutDone(KJob*);
+ void onSetupDone(KJob*);
protected:
virtual QStringList requiredFolders();
- virtual void startWork(ProbeKolabServerJob *job) = 0;
+ virtual void startWork() = 0;
void logout();
SessionSettings mSessionSettings;
QString mFreebusyFolder;
KIMAP::Session *mSession;
-
+ QMultiHash<QString, QString> mKolabFolders;
};
#endif // KOLABJOB_H
diff --git a/fbdaemon/tests/CMakeLists.txt b/fbdaemon/tests/CMakeLists.txt
index eff88ac..e28ccc0 100644
--- a/fbdaemon/tests/CMakeLists.txt
+++ b/fbdaemon/tests/CMakeLists.txt
@@ -1,17 +1,14 @@
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
-include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. )
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
+set(FBTEST_DEPENDENCIES ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils fb_static)
-qt4_generate_moc(
- ${CMAKE_CURRENT_SOURCE_DIR}/fbgeneratortest.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/fbgeneratortest.moc
-)
-add_executable(fbgeneratortest ${FBDAEMON_SRCS} fbgeneratortest.cpp fbgeneratortest.moc)
-target_link_libraries(fbgeneratortest ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils)
+qt4_automoc(fbgeneratortest.cpp)
+add_executable(fbgeneratortest fbgeneratortest.cpp)
+target_link_libraries(fbgeneratortest ${FBTEST_DEPENDENCIES})
-qt4_generate_moc(
- ${CMAKE_CURRENT_SOURCE_DIR}/fbaggregatortest.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/fbaggregatortest.moc
-)
-add_executable(fbaggregatortest ${FBDAEMON_SRCS} fbaggregatortest.cpp fbaggregatortest.moc)
-target_link_libraries(fbaggregatortest ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils) \ No newline at end of file
+qt4_automoc(fbaggregatortest.cpp)
+add_executable(fbaggregatortest fbaggregatortest.cpp)
+target_link_libraries(fbaggregatortest ${FBTEST_DEPENDENCIES}) \ No newline at end of file
diff --git a/fbdaemon/tests/fbaggregatortest.cpp b/fbdaemon/tests/fbaggregatortest.cpp
index 11da8ff..18569fb 100644
--- a/fbdaemon/tests/fbaggregatortest.cpp
+++ b/fbdaemon/tests/fbaggregatortest.cpp
@@ -15,125 +15,107 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <QObject>
+#include "fbaggregatortest.h"
+
#include <QTest>
#include <QDebug>
#include <QDir>
-#include <kolabobject.h>
-#include <freebusy.h>
-#include <kcalconversion.h>
#include <kcalcore/memorycalendar.h>
#include <kcalcore/icalformat.h>
+#include <freebusy.h>
+#include <kcalconversion.h>
+#include <kolabobject.h>
#include "fbdaemon/fbgeneratorjob.h"
+#include "fbdaemon/fbaggregatorjob.h"
#include "settings.h"
-#include <fbaggregatorjob.h>
#include "kolabaccount.h"
#include "testlib/testutils.h"
-class FBAggregatorTest: public QObject
+FBAggregatorTest::FBAggregatorTest(QObject* parent)
+ : QObject(parent),
+ targethost("192.168.122.10"),
+ user("john.doe@example.org"),
+ admin("cyrus-admin"),
+ adminpw("admin"),
+ port(143)
{
- Q_OBJECT
-
-// QString sourcehost;
- QString targethost;
- QString user;
- QString admin;
- QString adminpw;
- qint16 port;
- QList<Folder> folders;
- QString generatedFile;
+ Object fbObj1;
+ Kolab::Freebusy fb;
+ fb.setOrganizer(Kolab::ContactReference("mail@example.com", "john doe"));
+ fb.setStart(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
+ fb.setEnd(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime().addDays(60)));
+ fbObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeFreebusy(fb, Kolab::KolabV3, "fbtest"));
-public:
- explicit FBAggregatorTest(QObject* parent = 0)
- : QObject(parent),
-// sourcehost("192.168.122.104"),
- targethost("192.168.122.10"),
- user("john.doe@example.org"),
- admin("cyrus-admin"),
- adminpw("admin"),
- port(143)
- {
- Object fbObj1;
- Kolab::Freebusy fb;
- fb.setOrganizer(Kolab::ContactReference("mail@example.com", "john doe"));
- fb.setStart(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
- fb.setEnd(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime().addDays(60)));
- fbObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeFreebusy(fb, Kolab::KolabV3, "fbtest"));
-
- Object fbObj2;
- Kolab::Freebusy fb2;
- fb2.setStart(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
- fb2.setEnd(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime().addDays(60)));
- fbObj2.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeFreebusy(fb2, Kolab::KolabV3, "fbtest"));
-
- folders << Folder("Freebusy", Kolab::FreebusyType, QList<Object>() << fbObj1 << fbObj2);
- }
+ Object fbObj2;
+ Kolab::Freebusy fb2;
+ fb2.setStart(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
+ fb2.setEnd(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime().addDays(60)));
+ fbObj2.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeFreebusy(fb2, Kolab::KolabV3, "fbtest"));
-private:
+ folders << Folder("Freebusy", Kolab::FreebusyType, QList<Object>() << fbObj1 << fbObj2);
+}
- void setupTargetAccount()
- {
- QObject obj;
- KolabAccount *account = new KolabAccount(&obj);
- account->setHost(targethost, port);
- account->setCredentials(user, adminpw, admin);
- account->setEncryptionMode(KIMAP::LoginJob::TlsV1);
- QVERIFY(account->init());
+void FBAggregatorTest::setupTargetAccount()
+{
+ QObject obj;
+ KolabAccount *account = new KolabAccount(&obj);
+ account->setHost(targethost, port);
+ account->setCredentials(user, adminpw, admin);
+ account->setEncryptionMode(KIMAP::LoginJob::TlsV1);
+ QVERIFY(account->init());
+
+ account->cleanAccount();
+ createFolders(account, folders);
+}
- account->cleanAccount();
- createFolders(account, folders);
- }
+void FBAggregatorTest::executeAggregation()
+{
+ Settings::instance().setAuthorizationUser(admin);
+ Settings::instance().setPassword(adminpw);
+ Settings::instance().setServerUri(targethost);
+ Settings::instance().setThreshold(10);
+ Settings::instance().setTimeframe(60);
+ Settings::instance().setAggregatedICalOutputDirectory(QDir::tempPath());
+ SessionSettings sessionSettings = Settings::instance().getSessionSettings();
+ sessionSettings.userName = user;
- void executeAggregation()
- {
- Settings::instance().setAuthorizationUser(admin);
- Settings::instance().setPassword(adminpw);
- Settings::instance().setServerUri(targethost);
- Settings::instance().setThreshold(10);
- Settings::instance().setTimeframe(60);
- Settings::instance().setAggregatedICalOutputDirectory(QDir::tempPath());
- SessionSettings sessionSettings = Settings::instance().getSessionSettings();
- sessionSettings.userName = user;
-
- QObject obj;
- FBAggregatorJob *job = new FBAggregatorJob(sessionSettings, &obj);
- job->exec();
- generatedFile = job->generatedFile();
- }
+ QObject obj;
+ FBAggregatorJob *job = new FBAggregatorJob(sessionSettings, &obj);
+ job->exec();
+ generatedFile = job->generatedFile();
+}
- void checkFbObject()
- {
- QVERIFY(QFileInfo(generatedFile).exists());
- QFile file(generatedFile);
- QVERIFY(file.open(QIODevice::ReadOnly|QIODevice::Text));
- QTextStream in(&file);
- QString data = in.readAll();
+void FBAggregatorTest::checkFbObject()
+{
+ QVERIFY(QFileInfo(generatedFile).exists());
+ QFile file(generatedFile);
+ QVERIFY(file.open(QIODevice::ReadOnly|QIODevice::Text));
+ QTextStream in(&file);
+ QString data = in.readAll();
- qDebug() << data;
-
- KCalCore::ICalFormat format;
- KCalCore::Calendar::Ptr cal(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
- KCalCore::ScheduleMessage::Ptr msg = format.parseScheduleMessage(cal, data);
- QVERIFY(msg);
- QCOMPARE(msg->method(), KCalCore::iTIPPublish);
- QCOMPARE(format.timeSpec(), KDateTime::Spec::UTC());
- QVERIFY(msg->event());
- QCOMPARE(msg->event()->organizer()->email(), QLatin1String("john.doe@example.org"));
- QVERIFY(!msg->event()->uid().isEmpty());
- QVERIFY(msg->event()->lastModified().isValid());
-
- //Check that aggregated fb object has been created
- }
+ qDebug() << data;
+
+ KCalCore::ICalFormat format;
+ KCalCore::Calendar::Ptr cal(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
+ KCalCore::ScheduleMessage::Ptr msg = format.parseScheduleMessage(cal, data);
+ QVERIFY(msg);
+ QCOMPARE(msg->method(), KCalCore::iTIPPublish);
+ QCOMPARE(format.timeSpec(), KDateTime::Spec::UTC());
+ QVERIFY(msg->event());
+ QCOMPARE(msg->event()->organizer()->email(), QLatin1String("john.doe@example.org"));
+ QVERIFY(!msg->event()->uid().isEmpty());
+ QVERIFY(msg->event()->lastModified().isValid());
+
+ //Check that aggregated fb object has been created
+}
-private slots:
- void testGenerator()
- {
- setupTargetAccount();
- executeAggregation();
- checkFbObject();
- }
+void FBAggregatorTest::testGenerator()
+{
+ setupTargetAccount();
+ executeAggregation();
+ checkFbObject();
+}
-};
-QTEST_MAIN( FBAggregatorTest )
+QTEST_MAIN(FBAggregatorTest)
#include "fbaggregatortest.moc" \ No newline at end of file
diff --git a/fbdaemon/tests/fbaggregatortest.h b/fbdaemon/tests/fbaggregatortest.h
new file mode 100644
index 0000000..9564ed2
--- /dev/null
+++ b/fbdaemon/tests/fbaggregatortest.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef FBAGGREGATORTEST_H
+#define FBAGGREGATORTEST_H
+
+#include <QObject>
+#include "testlib/testutils.h"
+
+class FBAggregatorTest: public QObject
+{
+ Q_OBJECT
+public:
+ explicit FBAggregatorTest(QObject* parent = 0);
+
+private slots:
+ void testGenerator();
+
+private:
+ void setupTargetAccount();
+ void executeAggregation();
+ void checkFbObject();
+
+ QString targethost;
+ QString user;
+ QString admin;
+ QString adminpw;
+ qint16 port;
+ QList<Folder> folders;
+ QString generatedFile;
+};
+
+#endif
diff --git a/fbdaemon/tests/fbgeneratortest.cpp b/fbdaemon/tests/fbgeneratortest.cpp
index 7757bb2..2faf078 100644
--- a/fbdaemon/tests/fbgeneratortest.cpp
+++ b/fbdaemon/tests/fbgeneratortest.cpp
@@ -14,8 +14,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "fbgeneratortest.h"
-#include <QObject>
#include <QTest>
#include <QDebug>
#include <QDir>
@@ -25,120 +25,101 @@
#include "fbdaemon/fbgeneratorjob.h"
#include "settings.h"
#include "kolabaccount.h"
-#include "testlib/testutils.h"
-class FBGeneratorTest: public QObject
+FBGeneratorTest::FBGeneratorTest(QObject* parent)
+ : QObject(parent),
+ targethost("192.168.122.10"),
+ user("john.doe@example.org"),
+ admin("cyrus-admin"),
+ adminpw("admin"),
+ port(143)
{
- Q_OBJECT
-
-// QString sourcehost;
- QString targethost;
- QString user;
- QString admin;
- QString adminpw;
- qint16 port;
- QList<Folder> folders;
+ Object calObj1;
+ KCalCore::Event::Ptr event(new KCalCore::Event());
+ event->setUid("uid1");
+ event->setDtStart(KDateTime::currentUtcDateTime());
+ event->setDtEnd(KDateTime::currentUtcDateTime().addSecs(3600));
+ calObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV3, "fbtest"));
+ folders << Folder("Calendar", Kolab::EventType, QList<Object>() << calObj1);
-public:
- explicit FBGeneratorTest(QObject* parent = 0)
- : QObject(parent),
-// sourcehost("192.168.122.104"),
- targethost("192.168.122.10"),
- user("john.doe@example.org"),
- admin("cyrus-admin"),
- adminpw("admin"),
- port(143)
- {
- Object calObj1;
- KCalCore::Event::Ptr event(new KCalCore::Event());
- event->setUid("uid1");
- event->setDtStart(KDateTime::currentUtcDateTime());
- event->setDtEnd(KDateTime::currentUtcDateTime().addSecs(3600));
- calObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV3, "fbtest"));
- folders << Folder("Calendar", Kolab::EventType, QList<Object>() << calObj1);
-
// folders << Folder("Freebusy", Kolab::FreebusyType, QList<Object>()/* << fbObj1*/);
- }
+}
-private:
+void FBGeneratorTest::setupTargetAccount()
+{
+ QObject obj;
+ KolabAccount *account = new KolabAccount(&obj);
+ account->setHost(targethost, port);
+ account->setCredentials(user, adminpw, admin);
+ QVERIFY(account->init());
- void setupTargetAccount()
- {
- QObject obj;
- KolabAccount *account = new KolabAccount(&obj);
- account->setHost(targethost, port);
- account->setCredentials(user, adminpw, admin);
- QVERIFY(account->init());
+ account->cleanAccount();
+ createFolders(account, folders);
+}
- account->cleanAccount();
- createFolders(account, folders);
- }
+void FBGeneratorTest::executeGeneration()
+{
+ Settings::instance().setAuthorizationUser(admin);
+ Settings::instance().setPassword(adminpw);
+ Settings::instance().setServerUri(targethost);
+ Settings::instance().setThreshold(10);
+ Settings::instance().setTimeframe(60);
+ Settings::instance().setAggregatedICalOutputDirectory(QDir::tempPath());
+ SessionSettings sessionSettings = Settings::instance().getSessionSettings();
+ sessionSettings.userName = user;
- void executeGeneration()
- {
- Settings::instance().setAuthorizationUser(admin);
- Settings::instance().setPassword(adminpw);
- Settings::instance().setServerUri(targethost);
- Settings::instance().setThreshold(10);
- Settings::instance().setTimeframe(60);
- Settings::instance().setAggregatedICalOutputDirectory(QDir::tempPath());
- SessionSettings sessionSettings = Settings::instance().getSessionSettings();
- sessionSettings.userName = user;
-
- QObject obj;
- FBGeneratorJob *job = new FBGeneratorJob(sessionSettings, &obj);
- job->exec();
- }
+ QObject obj;
+ FBGeneratorJob *job = new FBGeneratorJob(sessionSettings, &obj);
+ job->exec();
+}
- void checkFolders(KolabAccount *account, const QList<Folder> &folders)
- {
- const QStringList &receivedFolders = account->lookupFolderList();
- qDebug() << receivedFolders;
- foreach(const Folder &folder, folders) {
- qDebug() << folder.name;
- QVERIFY(receivedFolders.contains(folder.name));
- const QList<Object> &objects = account->getObjects(folder.name);
- QCOMPARE(objects.size(), folder.objects.size());
-
- QList<Object>::const_iterator recObjIt = objects.constBegin();
- QList<Object>::const_iterator objIt = folder.objects.constBegin();
- for (;objIt != folder.objects.constEnd() && recObjIt != objects.constEnd(); ++objIt, ++recObjIt) {
- //TODO Check fb objects
- }
+void FBGeneratorTest::checkFolders(KolabAccount *account, const QList<Folder> &folders)
+{
+ const QStringList &receivedFolders = account->lookupFolderList();
+ qDebug() << receivedFolders;
+ foreach(const Folder &folder, folders) {
+ qDebug() << folder.name;
+ QVERIFY(receivedFolders.contains(folder.name));
+ const QList<Object> &objects = account->getObjects(folder.name);
+ QCOMPARE(objects.size(), folder.objects.size());
+
+ QList<Object>::const_iterator recObjIt = objects.constBegin();
+ QList<Object>::const_iterator objIt = folder.objects.constBegin();
+ for (;objIt != folder.objects.constEnd() && recObjIt != objects.constEnd(); ++objIt, ++recObjIt) {
+ //TODO Check fb objects
}
}
+}
- void checkTargetAccount()
- {
- //Check that fb-object and aggregated fb object has been created
- QObject obj;
- KolabAccount *account = new KolabAccount(&obj);
- account->setHost(targethost, port);
- account->setCredentials(user, adminpw, admin);
- account->init();
+void FBGeneratorTest::checkTargetAccount()
+{
+ //Check that fb-object and aggregated fb object has been created
+ QObject obj;
+ KolabAccount *account = new KolabAccount(&obj);
+ account->setHost(targethost, port);
+ account->setCredentials(user, adminpw, admin);
+ account->init();
- Object fbObj1;
- Kolab::Freebusy fb;
- fb.setStart(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
- fb.setEnd(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime().addDays(60)));
- fbObj1.object = QVariant(Kolab::KolabObjectWriter::writeFreebusy(fb, Kolab::KolabV3, "fbtest"));
-
- QList<Folder> targetFolders;
- targetFolders << Folder("Freebusy", Kolab::FreebusyType, QList<Object>() << fbObj1);
- checkFolders(account, targetFolders);
- account->logout();
- }
+ Object fbObj1;
+ Kolab::Freebusy fb;
+ fb.setStart(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
+ fb.setEnd(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime().addDays(60)));
+ fbObj1.object = QVariant(Kolab::KolabObjectWriter::writeFreebusy(fb, Kolab::KolabV3, "fbtest"));
+
+ QList<Folder> targetFolders;
+ targetFolders << Folder("Freebusy", Kolab::FreebusyType, QList<Object>() << fbObj1);
+ checkFolders(account, targetFolders);
+ account->logout();
+}
-private slots:
- void testGenerator()
- {
- setupTargetAccount();
- executeGeneration();
- checkTargetAccount();
- }
+void FBGeneratorTest::testGenerator()
+{
+ setupTargetAccount();
+ executeGeneration();
+ checkTargetAccount();
+}
-};
QTEST_MAIN( FBGeneratorTest )
#include "fbgeneratortest.moc" \ No newline at end of file
diff --git a/fbdaemon/tests/fbgeneratortest.h b/fbdaemon/tests/fbgeneratortest.h
new file mode 100644
index 0000000..eefbfc9
--- /dev/null
+++ b/fbdaemon/tests/fbgeneratortest.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef FBGENERATORTEST_H
+#define FBGENERATORTEST_H
+
+#include <QObject>
+#include "testlib/testutils.h"
+
+class KolabAccount;
+class FBGeneratorTest: public QObject
+{
+ Q_OBJECT
+public:
+ explicit FBGeneratorTest(QObject* parent = 0);
+
+private slots:
+ void testGenerator();
+
+private:
+ void setupTargetAccount();
+ void executeGeneration();
+ void checkFolders(KolabAccount *account, const QList<Folder> &folders);
+ void checkTargetAccount();
+
+ QString targethost;
+ QString user;
+ QString admin;
+ QString adminpw;
+ qint16 port;
+ QList<Folder> folders;
+};
+
+#endif \ No newline at end of file
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 4b7f731..4fb4ffc 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -7,12 +7,14 @@ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default" )
add_subdirectory(jobs)
QT4_WRAP_CPP(JOB_MOC
${CMAKE_CURRENT_SOURCE_DIR}/jobs/findkolabfoldersjob.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/jobs/probeimapserverjob.h
${CMAKE_CURRENT_SOURCE_DIR}/jobs/probekolabserverjob.h
${CMAKE_CURRENT_SOURCE_DIR}/jobs/sequentialcompositejob.h
${CMAKE_CURRENT_SOURCE_DIR}/jobs/messagemodifyjob.h
${CMAKE_CURRENT_SOURCE_DIR}/jobs/fetchmessagesjob.h
${CMAKE_CURRENT_SOURCE_DIR}/jobs/setupkolabfoldersjob.h
${CMAKE_CURRENT_SOURCE_DIR}/jobs/getuserlistjob.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/jobs/createkolabfolderjob.h
)
set( JOBS_SRCS ${JOBS_SRCS} ${JOB_MOC} )
@@ -32,6 +34,4 @@ install(TARGETS kolabutils
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
-)
-
-add_subdirectory(testlib) \ No newline at end of file
+) \ No newline at end of file
diff --git a/lib/jobs/CMakeLists.txt b/lib/jobs/CMakeLists.txt
index a9796ef..8667abb 100644
--- a/lib/jobs/CMakeLists.txt
+++ b/lib/jobs/CMakeLists.txt
@@ -1,10 +1,12 @@
set (JOBS_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/findkolabfoldersjob.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/probeimapserverjob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/probekolabserverjob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sequentialcompositejob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/messagemodifyjob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fetchmessagesjob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/setupkolabfoldersjob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/getuserlistjob.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/createkolabfolderjob.cpp
PARENT_SCOPE)
diff --git a/lib/jobs/createkolabfolderjob.cpp b/lib/jobs/createkolabfolderjob.cpp
new file mode 100644
index 0000000..51f67bb
--- /dev/null
+++ b/lib/jobs/createkolabfolderjob.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "createkolabfolderjob.h"
+
+#include <kimap/createjob.h>
+#include <kimap/setmetadatajob.h>
+#include <QStringList>
+
+#include <errorhandler.h>
+#include <kolabdefinitions.h>
+
+CreateKolabFolderJob::CreateKolabFolderJob(const QString& name, const QByteArray& sharedAnnotation, const QByteArray& privateAnnotation, CreateKolabFolderJob::MetadataCapability cap, KIMAP::Session* session, QObject* parent)
+: KJob(parent),
+ m_session(session),
+ m_name(name),
+ m_sharedAnnotation(sharedAnnotation),
+ m_privateAnnotation(privateAnnotation),
+ m_metadataCapability(cap)
+{
+
+}
+
+void CreateKolabFolderJob::start()
+{
+ KIMAP::CreateJob *createJob = new KIMAP::CreateJob(m_session);
+ createJob->setMailBox(m_name);
+ connect(createJob, SIGNAL(result(KJob*)), this, SLOT(onCreateDone(KJob*)));
+ createJob->start();
+}
+
+CreateKolabFolderJob::MetadataCapability CreateKolabFolderJob::capablitiesFromString(const QString &cap)
+{
+ if (cap.contains(QLatin1String("ANNOTATEMORE"))) {
+ return Annotatemore;
+ }
+ return Metadata;
+}
+
+CreateKolabFolderJob::MetadataCapability CreateKolabFolderJob::capablitiesFromString(const QStringList &cap)
+{
+ if (cap.contains(QLatin1String("ANNOTATEMORE"))) {
+ return Annotatemore;
+ }
+ return Metadata;
+}
+
+void CreateKolabFolderJob::onCreateDone(KJob *job)
+{
+ if (job->error()) {
+ Warning() << job->errorString() << "Trying to fix the metadata";
+ } else {
+ KIMAP::CreateJob *createJob = static_cast<KIMAP::CreateJob*>(job);
+ Debug() << "Created folder " << createJob->mailBox();
+ }
+
+ KIMAP::SetMetaDataJob *setMetadataJob = new KIMAP::SetMetaDataJob(m_session);
+ setMetadataJob->setMailBox(m_name);
+ if ( m_metadataCapability == Metadata ) {
+ setMetadataJob->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
+ if (!m_sharedAnnotation.isEmpty()) {
+ setMetadataJob->addMetaData("/shared" KOLAB_FOLDER_TYPE_ANNOTATION, m_sharedAnnotation);
+ }
+ if (!m_privateAnnotation.isEmpty()) {
+ setMetadataJob->addMetaData("/private" KOLAB_FOLDER_TYPE_ANNOTATION, m_privateAnnotation);
+ }
+ } else {
+ setMetadataJob->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
+ setMetadataJob->setEntry( KOLAB_FOLDER_TYPE_ANNOTATION );
+ if (!m_sharedAnnotation.isEmpty()) {
+ setMetadataJob->addMetaData("value.shared", m_sharedAnnotation);
+ }
+ if (!m_privateAnnotation.isEmpty()) {
+ setMetadataJob->addMetaData("value.priv", m_privateAnnotation);
+ }
+ }
+ connect(setMetadataJob, SIGNAL(result(KJob*)), this, SLOT(onMetadataSetDone(KJob*)));
+ setMetadataJob->start();
+}
+
+void CreateKolabFolderJob::onMetadataSetDone(KJob *job)
+{
+ if ( job->error() ) {
+ Warning() << job->errorString();
+ setErrorText("Failed to create folder: " + m_name);
+ setError(KJob::UserDefinedError);
+ }
+ emitResult();
+}
+
+QString CreateKolabFolderJob::folder() const
+{
+ return m_name;
+}
+
diff --git a/lib/jobs/createkolabfolderjob.h b/lib/jobs/createkolabfolderjob.h
new file mode 100644
index 0000000..b293e35
--- /dev/null
+++ b/lib/jobs/createkolabfolderjob.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CREATEKOLABFOLDERJOB_H
+#define CREATEKOLABFOLDERJOB_H
+
+#include <kjob.h>
+
+namespace KIMAP {
+class Session;
+}
+
+class CreateKolabFolderJob : public KJob
+{
+ Q_OBJECT
+public:
+ enum MetadataCapability {
+ Metadata,
+ Annotatemore
+ };
+ explicit CreateKolabFolderJob(const QString &name, const QByteArray &sharedAnnotation, const QByteArray &privateAnnotation, MetadataCapability cap, KIMAP::Session *session, QObject* parent = 0);
+ virtual void start();
+
+ QString folder() const;
+
+ static MetadataCapability capablitiesFromString(const QString &);
+ static MetadataCapability capablitiesFromString(const QStringList &);
+
+private slots:
+ void onCreateDone(KJob*);
+ void onMetadataSetDone(KJob*);
+private:
+ KIMAP::Session *m_session;
+ QString m_name;
+ QByteArray m_sharedAnnotation;
+ QByteArray m_privateAnnotation;
+ MetadataCapability m_metadataCapability;
+};
+
+#endif
diff --git a/lib/jobs/findkolabfoldersjob.cpp b/lib/jobs/findkolabfoldersjob.cpp
index ce3bdf6..d0895c7 100644
--- a/lib/jobs/findkolabfoldersjob.cpp
+++ b/lib/jobs/findkolabfoldersjob.cpp
@@ -82,10 +82,15 @@ void FindKolabFoldersJob::onMailBoxesReceived( const QList< KIMAP::MailBoxDescri
meta->setMailBox( descriptor.name );
if ( m_serverCapabilities.contains( "METADATA" ) ) {
meta->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
- meta->addEntry( KOLAB_FOLDER_TYPE_ANNOTATION );
- } else {
+ //TODO support shared/private
+ meta->addEntry( "/shared" KOLAB_FOLDER_TYPE_ANNOTATION );
+ } else if ( m_serverCapabilities.contains( "ANNOTATEMORE" ) ) {
meta->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
meta->addEntry( KOLAB_FOLDER_TYPE_ANNOTATION, "value.shared" );
+ } else {
+ Warning() << "Server does not support annotations";
+ emitResult();
+ return;
}
connect( meta, SIGNAL(result(KJob*)), SLOT(onGetMetaDataDone(KJob*)) );
m_metadataRetrieveJobs++;
@@ -120,18 +125,16 @@ void FindKolabFoldersJob::onGetMetaDataDone( KJob *job )
QMap<QByteArray, QMap<QByteArray, QByteArray> > rawAnnotations = meta->allMetaData( meta->mailBox() );
QByteArray attribute = "";
+ QByteArray annotation = KOLAB_FOLDER_TYPE_ANNOTATION;
if ( meta->serverCapability()==KIMAP::MetaDataJobBase::Annotatemore ) {
attribute = "value.shared";
}
-
-// QMap<QByteArray, QByteArray> annotations;
-// foreach ( const QByteArray &entry, rawAnnotations.keys() ) {
-// annotations[entry] = rawAnnotations[entry][attribute];
-// Debug() << entry << annotations[entry];
-// }
+ if ( meta->serverCapability()==KIMAP::MetaDataJobBase::Metadata ) {
+ annotation = "/shared" KOLAB_FOLDER_TYPE_ANNOTATION;
+ }
//TODO default flag?
- const QByteArray &kolabType = rawAnnotations[KOLAB_FOLDER_TYPE_ANNOTATION][attribute];
+ const QByteArray &kolabType = rawAnnotations[annotation][attribute];
// Debug() << meta->mailBox() << kolabType;
if (!kolabType.isEmpty()) {
if (kolabType.contains(KOLAB_FOLDER_TYPE_CONTACT)) {
@@ -146,7 +149,7 @@ void FindKolabFoldersJob::onGetMetaDataDone( KJob *job )
m_kolabFolders.insertMulti(KOLAB_FOLDER_TYPE_NOTE, meta->mailBox());
} else if (kolabType.contains(KOLAB_FOLDER_TYPE_FREEBUSY)) {
m_kolabFolders.insertMulti(KOLAB_FOLDER_TYPE_FREEBUSY, meta->mailBox());
- } else if (kolabType.contains("mail") || kolabType.contains("configuration")) {
+ } else if (kolabType.contains("mail") || kolabType.contains("configuration") || kolabType.contains("file") || kolabType == "NIL") {
//ignore silently
} else {
Warning() << "invalid/unhandled folder-type " << kolabType;
diff --git a/lib/jobs/probeimapserverjob.cpp b/lib/jobs/probeimapserverjob.cpp
new file mode 100644
index 0000000..512a77e
--- /dev/null
+++ b/lib/jobs/probeimapserverjob.cpp
@@ -0,0 +1,93 @@
+
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "probeimapserverjob.h"
+#include <kimap/capabilitiesjob.h>
+#include <kimap/namespacejob.h>
+#include <errorhandler.h>
+
+ProbeIMAPServerJob::ProbeIMAPServerJob(KIMAP::Session *session, QObject* parent)
+: KJob(parent),
+ mSession(session)
+{
+
+}
+
+ProbeIMAPServerJob::~ProbeIMAPServerJob()
+{
+
+}
+
+void ProbeIMAPServerJob::start()
+{
+ KIMAP::CapabilitiesJob *capabilities = new KIMAP::CapabilitiesJob(mSession);
+ connect(capabilities, SIGNAL(result(KJob*)), this, SLOT(onCapabilitiesTestDone(KJob*)));
+ capabilities->start();
+}
+
+void ProbeIMAPServerJob::onCapabilitiesTestDone(KJob* job)
+{
+ if ( job->error() ) {
+ Warning() << job->errorString();
+ setError(KJob::UserDefinedError);
+ emitResult();
+ return;
+ }
+ KIMAP::CapabilitiesJob *capabilitiesJob = qobject_cast<KIMAP::CapabilitiesJob*>( job );
+ Q_ASSERT(capabilitiesJob);
+ mCapabilities = capabilitiesJob->capabilities();
+ if ( mCapabilities.contains( "NAMESPACE" ) ) {
+ KIMAP::NamespaceJob *nsJob = new KIMAP::NamespaceJob( mSession );
+ QObject::connect( nsJob, SIGNAL(result(KJob*)), SLOT(onNamespacesTestDone(KJob*)) );
+ nsJob->start();
+ return;
+ } else {
+ emitResult();
+ }
+}
+
+void ProbeIMAPServerJob::onNamespacesTestDone( KJob *job )
+{
+ if ( job->error() ) {
+ Warning() << job->errorString();
+ setError(KJob::UserDefinedError);
+ emitResult();
+ return;
+ }
+ KIMAP::NamespaceJob *nsJob = qobject_cast<KIMAP::NamespaceJob*>( job );
+ Q_ASSERT(nsJob);
+ mPersonalNamespace = nsJob->personalNamespaces();
+ mExcludedNamespace = nsJob->userNamespaces()+nsJob->sharedNamespaces();
+
+ emitResult();
+}
+
+QStringList ProbeIMAPServerJob::capabilities() const
+{
+ return mCapabilities;
+}
+
+QList< KIMAP::MailBoxDescriptor > ProbeIMAPServerJob::personalNamespace() const
+{
+ return mPersonalNamespace;
+}
+
+QList< KIMAP::MailBoxDescriptor > ProbeIMAPServerJob::excludedNamespaces() const
+{
+ return mExcludedNamespace;
+}
diff --git a/lib/jobs/probeimapserverjob.h b/lib/jobs/probeimapserverjob.h
new file mode 100644
index 0000000..6cf0197
--- /dev/null
+++ b/lib/jobs/probeimapserverjob.h
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PROBEIMAPSERVERJOB_H
+#define PROBEIMAPSERVERJOB_H
+#include <kcompositejob.h>
+#include <QStringList>
+#include <QHash>
+#include <kimap/session.h>
+#include <kimap/listjob.h>
+
+/**
+ * Probeserver for supported IMAP features
+ */
+class ProbeIMAPServerJob: public KJob
+{
+ Q_OBJECT
+public:
+ explicit ProbeIMAPServerJob(KIMAP::Session *, QObject* parent = 0);
+ virtual ~ProbeIMAPServerJob();
+ virtual void start();
+
+ QList<KIMAP::MailBoxDescriptor> personalNamespace() const;
+ QList<KIMAP::MailBoxDescriptor> excludedNamespaces() const;
+ QStringList capabilities() const;
+
+protected Q_SLOTS:
+ void onCapabilitiesTestDone(KJob *);
+ void onNamespacesTestDone(KJob *);
+
+private:
+ KIMAP::Session *mSession;
+ QStringList mCapabilities;
+ QList<KIMAP::MailBoxDescriptor> mPersonalNamespace;
+ QList<KIMAP::MailBoxDescriptor> mExcludedNamespace;
+};
+
+#endif
diff --git a/lib/jobs/probekolabserverjob.cpp b/lib/jobs/probekolabserverjob.cpp
index 60cd89e..324e989 100644
--- a/lib/jobs/probekolabserverjob.cpp
+++ b/lib/jobs/probekolabserverjob.cpp
@@ -18,8 +18,7 @@
#include "probekolabserverjob.h"
#include "findkolabfoldersjob.h"
#include "setupkolabfoldersjob.h"
-#include <kimap/capabilitiesjob.h>
-#include <kimap/namespacejob.h>
+#include "probeimapserverjob.h"
#include <errorhandler.h>
ProbeKolabServerJob::ProbeKolabServerJob(KIMAP::Session *session, QObject* parent)
@@ -36,53 +35,23 @@ ProbeKolabServerJob::~ProbeKolabServerJob()
void ProbeKolabServerJob::start()
{
- KIMAP::CapabilitiesJob *capabilities = new KIMAP::CapabilitiesJob(mSession);
- connect(capabilities, SIGNAL(result(KJob*)), this, SLOT(onCapabilitiesTestDone(KJob*)));
- capabilities->start();
+ ProbeIMAPServerJob *probeJob = new ProbeIMAPServerJob(mSession, this);
+ connect(probeJob, SIGNAL(result(KJob*)), this, SLOT(onProbeJobDone(KJob*)));
+ probeJob->start();
}
-void ProbeKolabServerJob::createDefaultsIfMissing(const QStringList &folders)
+void ProbeKolabServerJob::onProbeJobDone(KJob* job)
{
- mFoldersToCreate = folders;
-}
-
-void ProbeKolabServerJob::onCapabilitiesTestDone(KJob* job)
-{
- if ( job->error() ) {
- Warning() << job->errorString();
- setError(KJob::UserDefinedError);
- emitResult();
- return;
- }
- KIMAP::CapabilitiesJob *capabilitiesJob = qobject_cast<KIMAP::CapabilitiesJob*>( job );
- Q_ASSERT(capabilitiesJob);
- mCapabilities = capabilitiesJob->capabilities();
- if ( mCapabilities.contains( "NAMESPACE" ) ) {
- KIMAP::NamespaceJob *nsJob = new KIMAP::NamespaceJob( mSession );
- QObject::connect( nsJob, SIGNAL(result(KJob*)), SLOT(onNamespacesTestDone(KJob*)) );
- nsJob->start();
- return;
- } else {
- FindKolabFoldersJob *findJob = new FindKolabFoldersJob(mCapabilities, mPersonalNamespace, mExcludedNamespace, mSession, this);
- connect(findJob, SIGNAL(result(KJob*)), this, SLOT(findKolabFoldersDone(KJob*)));
- findJob->start();
- }
-}
-
-
-void ProbeKolabServerJob::onNamespacesTestDone( KJob *job )
-{
- if ( job->error() ) {
+ if (job->error()) {
Warning() << job->errorString();
setError(KJob::UserDefinedError);
emitResult();
return;
}
- KIMAP::NamespaceJob *nsJob = qobject_cast<KIMAP::NamespaceJob*>( job );
- Q_ASSERT(nsJob);
- mPersonalNamespace = nsJob->personalNamespaces();
- mExcludedNamespace = nsJob->userNamespaces()+nsJob->sharedNamespaces();
-
+ ProbeIMAPServerJob *probeJob = static_cast<ProbeIMAPServerJob*>(job);
+ mCapabilities = probeJob->capabilities();
+ mPersonalNamespace = probeJob->personalNamespace();
+ mExcludedNamespace = probeJob->excludedNamespaces();
FindKolabFoldersJob *findJob = new FindKolabFoldersJob(mCapabilities, mPersonalNamespace, mExcludedNamespace, mSession, this);
connect(findJob, SIGNAL(result(KJob*)), this, SLOT(findKolabFoldersDone(KJob*)));
findJob->start();
@@ -99,40 +68,9 @@ void ProbeKolabServerJob::findKolabFoldersDone(KJob *job)
FindKolabFoldersJob *findJob = static_cast<FindKolabFoldersJob*>(job);
// qDebug() << "Found kolab folders: " << findJob->getKolabFolders();
mKolabFolders = findJob->getKolabFolders();
-
- //TODO Setting up the missing folders shouldn't be part of the ProbeJob, and it's probably only used in one place in here => separate
- QString rootFolder;
- QStringList toCreate;
- foreach (const QString &folderType, mFoldersToCreate) {
- if (!mKolabFolders.contains(folderType)) {
- toCreate << folderType;
- }
- }
- if (toCreate.isEmpty()) {
- emitResult();
- return;
- }
- SetupKolabFoldersJob *setupJob = new SetupKolabFoldersJob(mCapabilities, rootFolder, mSession, this);
- setupJob->setKolabFolders(toCreate);
- connect(setupJob, SIGNAL(result(KJob*)), this, SLOT(onSetupDone(KJob*)));
- setupJob->start();
-}
-
-void ProbeKolabServerJob::onSetupDone(KJob *job)
-{
- if (job->error()) {
- Warning() << job->errorString();
- setError(KJob::UserDefinedError);
- }
- SetupKolabFoldersJob *setupJob = static_cast<SetupKolabFoldersJob*>(job);
- const QMap<QString, QString> createdFolders = setupJob->createdFolders();
- foreach (const QString &folderType, createdFolders.keys()) {
- mKolabFolders.insert(folderType, createdFolders.value(folderType));
- }
emitResult();
}
-
QMultiHash<QString, QString> ProbeKolabServerJob::kolabFolders() const
{
return mKolabFolders;
diff --git a/lib/jobs/probekolabserverjob.h b/lib/jobs/probekolabserverjob.h
index eff69e9..16e2e92 100644
--- a/lib/jobs/probekolabserverjob.h
+++ b/lib/jobs/probekolabserverjob.h
@@ -17,7 +17,6 @@
#ifndef PROBEKOLABSERVERJOB_H
#define PROBEKOLABSERVERJOB_H
-#include <kcompositejob.h>
#include <QStringList>
#include <QHash>
#include <kimap/session.h>
@@ -34,26 +33,21 @@ public:
virtual ~ProbeKolabServerJob();
virtual void start();
- void createDefaultsIfMissing(const QStringList &);
-
QList<KIMAP::MailBoxDescriptor> personalNamespace() const;
QList<KIMAP::MailBoxDescriptor> excludedNamespaces() const;
QStringList capabilities() const;
QMultiHash<QString, QString> kolabFolders() const;
protected Q_SLOTS:
- void onCapabilitiesTestDone( KJob *job );
- void onNamespacesTestDone( KJob *job );
+ void onProbeJobDone(KJob *job);
void findKolabFoldersDone(KJob*);
+
private:
KIMAP::Session *mSession;
QStringList mCapabilities;
QList<KIMAP::MailBoxDescriptor> mPersonalNamespace;
QList<KIMAP::MailBoxDescriptor> mExcludedNamespace;
QMultiHash<QString, QString> mKolabFolders;
- QStringList mFoldersToCreate;
-public slots:
- void onSetupDone(KJob*);
};
#endif // PROBEKOLABSERVERJOB_H
diff --git a/lib/jobs/setupkolabfoldersjob.cpp b/lib/jobs/setupkolabfoldersjob.cpp
index c30b43e..79bfb71 100644
--- a/lib/jobs/setupkolabfoldersjob.cpp
+++ b/lib/jobs/setupkolabfoldersjob.cpp
@@ -16,16 +16,16 @@
*/
#include "setupkolabfoldersjob.h"
+
#include <kimap/session.h>
-#include <kimap/createjob.h>
#include <kimap/selectjob.h>
-#include <kimap/setmetadatajob.h>
-#include <QStringList>
#include <errorhandler.h>
#include <kolabdefinitions.h>
#include <formathelpers.h>
+#include "createkolabfolderjob.h"
+
SetupKolabFoldersJob::SetupKolabFoldersJob(const QStringList &serverCapabilities, QString rootFolder, KIMAP::Session* session, QObject* parent)
: KJob(parent),
m_session(session),
@@ -53,7 +53,7 @@ void SetupKolabFoldersJob::start()
connect(selectJob, SIGNAL(result(KJob*)), this, SLOT(onSelectDone(KJob*)));
selectJob->start();
} else {
- createMailbox();
+ createNext();
}
}
@@ -65,7 +65,7 @@ void SetupKolabFoldersJob::onSelectDone(KJob *job)
emitResult();
return;
}
- createMailbox();
+ createNext();
}
static QString getFolderName(Kolab::FolderType type)
@@ -78,68 +78,53 @@ static Kolab::FolderType getFolderType(const QString &typeString)
return Kolab::folderTypeFromString(typeString.toStdString());
}
-void SetupKolabFoldersJob::createMailbox()
+void SetupKolabFoldersJob::createNext()
{
if (m_folderTypes.isEmpty()) {
emitResult();
return;
}
- m_currentFolderType = m_folderTypes.takeFirst();
- Kolab::FolderType folderType = getFolderType(m_currentFolderType);
+ createMailbox(m_folderTypes.takeFirst());
+}
+
+void SetupKolabFoldersJob::createMailbox(const QString &currentFolderType)
+{
+ const Kolab::FolderType folderType = getFolderType(currentFolderType);
if (folderType == Kolab::MailType) {
- Warning() << "unknown kolab type: " << m_currentFolderType;
+ Warning() << "unknown kolab type: " << currentFolderType;
setError(KJob::UserDefinedError);
emitResult();
return;
}
- KIMAP::CreateJob *createJob = new KIMAP::CreateJob(m_session);
- createJob->setMailBox(getFolderName(folderType));
+ const QString name = getFolderName(folderType);
+ const QByteArray privateAnnotation = QString::fromStdString(Kolab::folderAnnotation(folderType, true)).toLatin1();
+ const QByteArray sharedAnnotation = QString::fromStdString(Kolab::folderAnnotation(folderType, false)).toLatin1();
+
+ m_createdFolders.insert(currentFolderType, name);
+
+ CreateKolabFolderJob *createJob = new CreateKolabFolderJob(name,
+ sharedAnnotation,
+ privateAnnotation,
+ CreateKolabFolderJob::capablitiesFromString(m_serverCapabilities),
+ m_session,
+ this
+ );
connect(createJob, SIGNAL(result(KJob*)), this, SLOT(onCreateDone(KJob*)));
createJob->start();
}
void SetupKolabFoldersJob::onCreateDone(KJob *job)
{
- QString mailbox;
if (job->error()) {
- Warning() << job->errorString() << "Trying to fix the metadata";
- mailbox = getFolderName(getFolderType(m_currentFolderType));
+ Warning() << job->errorString() << "Failed to create folder";
} else {
- KIMAP::CreateJob *createJob = static_cast<KIMAP::CreateJob*>(job);
- mailbox = createJob->mailBox();
- Debug() << "Created folder " << m_rootFolder << createJob->mailBox();
+ CreateKolabFolderJob *createJob = static_cast<CreateKolabFolderJob*>(job);
+ Debug() << "Created folder " << m_rootFolder << createJob->folder();
}
- m_createdFolders.insert(m_currentFolderType, mailbox);
-
- KIMAP::SetMetaDataJob *setMetadataJob = new KIMAP::SetMetaDataJob(m_session);
- setMetadataJob->setMailBox(mailbox);
- Kolab::FolderType folderType = Kolab::folderTypeFromString(m_currentFolderType.toStdString());
- if ( m_serverCapabilities.contains( "METADATA" ) ) {
- setMetadataJob->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
- setMetadataJob->addMetaData("/shared" KOLAB_FOLDER_TYPE_ANNOTATION, QString::fromStdString(Kolab::folderAnnotation(folderType, false)).toLatin1() );
- } else {
- setMetadataJob->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
- setMetadataJob->setEntry( KOLAB_FOLDER_TYPE_ANNOTATION );
- setMetadataJob->addMetaData( "value.shared", QString::fromStdString(Kolab::folderAnnotation(folderType, false)).toLatin1() );
- }
- //TODO also set the private annotation with the .default suffix
- connect(setMetadataJob, SIGNAL(result(KJob*)), this, SLOT(onMetadataSetDone(KJob*)));
- setMetadataJob->start();
-}
-
-void SetupKolabFoldersJob::onMetadataSetDone(KJob *job)
-{
- if ( job->error() ) {
- Warning() << job->errorString();
- setErrorText("Failed to create the folder for type: " + m_currentFolderType);
- setError(KJob::UserDefinedError);
- }
- createMailbox();
+ createNext();
}
QMap< QString, QString > SetupKolabFoldersJob::createdFolders() const
{
return m_createdFolders;
}
-
-
diff --git a/lib/jobs/setupkolabfoldersjob.h b/lib/jobs/setupkolabfoldersjob.h
index 2062d38..8dfd3d3 100644
--- a/lib/jobs/setupkolabfoldersjob.h
+++ b/lib/jobs/setupkolabfoldersjob.h
@@ -42,12 +42,12 @@ public:
private slots:
void onSelectDone(KJob*);
void onCreateDone(KJob*);
- void onMetadataSetDone(KJob*);
+
private:
- void createMailbox();
+ void createNext();
+ void createMailbox(const QString &folderType);
KIMAP::Session *m_session;
QStringList m_folderTypes;
- QString m_currentFolderType;
QString m_rootFolder;
QStringList m_serverCapabilities;
QMap<QString, QString> m_createdFolders;
diff --git a/lib/kolabaccount.cpp b/lib/kolabaccount.cpp
index 587d597..a0b616c 100644
--- a/lib/kolabaccount.cpp
+++ b/lib/kolabaccount.cpp
@@ -19,6 +19,7 @@
#include "sessionfactory.h"
#include "jobs/setupkolabfoldersjob.h"
#include "jobs/fetchmessagesjob.h"
+#include "jobs/createkolabfolderjob.h"
#include <kimap/session.h>
#include <kimap/logoutjob.h>
#include <kimap/appendjob.h>
@@ -94,6 +95,9 @@ void KolabAccount::setWipeTargetFolders(bool enable)
bool KolabAccount::init()
{
+ if (mDryRun) {
+ return true;
+ }
if (mSession) {
return false;
}
@@ -173,7 +177,7 @@ KJob* KolabAccount::appendObject(Object obj, const QString& folder)
Debug() << "append object in folder: " << folder;
return 0;
}
- if (!mFolders.contains(folder)) {
+ if (!mFolders.contains(folder, Qt::CaseInsensitive)) {
Error() << "failed to find target folder: " << folder;
qDebug() << mFolders;
return 0;
@@ -184,6 +188,8 @@ KJob* KolabAccount::appendObject(Object obj, const QString& folder)
Error() << "got empty message";
return 0;
}
+
+ Q_ASSERT(mSession);
KIMAP::AppendJob *job = new KIMAP::AppendJob( mSession );
job->setMailBox( folder );
job->setContent( message->encodedContent( true ) );
@@ -208,7 +214,9 @@ void KolabAccount::appendObjectSync(Object obj, const QString& folder)
void KolabAccount::logout()
{
- Q_ASSERT(mSession);
+ if (!mSession) {
+ return;
+ }
KIMAP::LogoutJob *logoutJob = new KIMAP::LogoutJob(mSession);
logoutJob->exec();
mSession->close();
@@ -225,6 +233,10 @@ void KolabAccount::cleanAccount()
Debug() << "wiping of target folders disabled";
return;
}
+ if (mDryRun) {
+ Debug() << "wiping account";
+ return;
+ }
Q_ASSERT(mSession);
KIMAP::ListJob *listJob = new KIMAP::ListJob(mSession);
listJob->setOption(KIMAP::ListJob::IncludeUnsubscribed);
@@ -314,31 +326,13 @@ void KolabAccount::createFolder(const QString &name, const QByteArray &annotatio
Debug() << "creating folder: " << name << annotation;
return;
}
-
- KIMAP::CreateJob *createJob = new KIMAP::CreateJob(mSession);
- createJob->setMailBox(name);
+ CreateKolabFolderJob *createJob = new CreateKolabFolderJob(name, annotation, QByteArray(), CreateKolabFolderJob::capablitiesFromString(mCapabilities), mSession, this);
createJob->exec();
- Debug() << "created folder: " << name;
if (createJob->error()) {
Error() << createJob->errorString();
return;
}
-
- KIMAP::SetMetaDataJob *setMetadataJob = new KIMAP::SetMetaDataJob(mSession);
- setMetadataJob->setMailBox(createJob->mailBox());
- if ( mCapabilities.contains( "METADATA" ) ) {
- setMetadataJob->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
- setMetadataJob->addMetaData( "/shared" KOLAB_FOLDER_TYPE_ANNOTATION, annotation );
- } else {
- setMetadataJob->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
- setMetadataJob->setEntry( KOLAB_FOLDER_TYPE_ANNOTATION );
- setMetadataJob->addMetaData( "value.shared", annotation );
- }
- setMetadataJob->exec();
- if (setMetadataJob->error()) {
- Error() << setMetadataJob->errorString();
- }
-
+ Debug() << "created folder: " << name;
mFolders.append(name);
}
@@ -353,19 +347,20 @@ void KolabAccount::setupFolders()
Debug() << "setup default folders";
return;
}
+ Q_ASSERT(mSession);
SetupKolabFoldersJob *setupJob = new SetupKolabFoldersJob(mCapabilities, QString(), mSession, this);
setupJob->setKolabFolders(QStringList() << KOLAB_FOLDER_TYPE_CONTACT << KOLAB_FOLDER_TYPE_EVENT << KOLAB_FOLDER_TYPE_TASK << KOLAB_FOLDER_TYPE_JOURNAL << KOLAB_FOLDER_TYPE_NOTE << KOLAB_FOLDER_TYPE_CONFIGURATION);
setupJob->exec();
if (setupJob->error()) {
Error() << setupJob->errorString();
}
+ mFolders.append("inbox");
foreach (const QString &folder, setupJob->createdFolders().values()) {
mFolders.append(folder);
}
KIMAP::SelectJob *selectJob = new KIMAP::SelectJob(mSession);
selectJob->setMailBox(QString());
//TODO internationalize folder names
- //TODO make part of setupkolabfoldersjob after adding types to folderTypeFromString in formathelpers.cpp
//TODO the suffixes should go in the private namespace
createFolder("Drafts", KOLAB_FOLDER_TYPE_MAIL KOLAB_FOLDER_TYPE_DRAFT_SUFFIX);
createFolder("Sent", KOLAB_FOLDER_TYPE_MAIL KOLAB_FOLDER_TYPE_SENT_SUFFIX);
@@ -375,6 +370,7 @@ void KolabAccount::setupFolders()
QList<Object> KolabAccount::getObjects(const QString& folder)
{
// Debug() << folder;
+ Q_ASSERT(mSession);
FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
fetchJob->exec();
Debug() << fetchJob->getMessages().size();
@@ -394,6 +390,7 @@ QStringList KolabAccount::lookupFolderList()
init();
mMailboxes.clear();
+ Q_ASSERT(mSession);
KIMAP::ListJob *listJob = new KIMAP::ListJob(mSession);
listJob->setOption(KIMAP::ListJob::IncludeUnsubscribed);
listJob->setQueriedNamespaces(mPersonalNamespaces);
diff --git a/lib/sessionfactory.h b/lib/sessionfactory.h
index 19c0744..4075e8d 100644
--- a/lib/sessionfactory.h
+++ b/lib/sessionfactory.h
@@ -21,7 +21,7 @@
#include <kimap/session.h>
#include "uiproxy.h"
-KIMAP::Session *createSession(const QString &host, qint16 port, QObject *parent)
+static KIMAP::Session *createSession(const QString &host, qint16 port, QObject *parent)
{
KIMAP::Session *session = new KIMAP::Session(host, port, parent);
session->setUiProxy(KIMAP::SessionUiProxy::Ptr(new UiProxy()));
diff --git a/lib/testlib/testutils.h b/lib/testlib/testutils.h
index fb43c63..96c7cbe 100644
--- a/lib/testlib/testutils.h
+++ b/lib/testlib/testutils.h
@@ -1,7 +1,9 @@
+#ifndef TESTUTILS_H
+#define TESTUTILS_H
+
#include <QList>
#include "kolabaccount.h"
-
struct Folder
{
Folder(){}
@@ -51,4 +53,6 @@ void createFolders(KolabAccount *account, const QList<Folder> &folders)
account->appendObjectSync(obj, folder.name);
}
}
-} \ No newline at end of file
+}
+
+#endif
diff --git a/migrationutility/CMakeLists.txt b/migrationutility/CMakeLists.txt
index a1d67b5..c117ed8 100644
--- a/migrationutility/CMakeLists.txt
+++ b/migrationutility/CMakeLists.txt
@@ -1,13 +1,6 @@
-# set(MIGRATION_SRCS
-# ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
-# ${CMAKE_CURRENT_SOURCE_DIR}/migrateuserjob.cpp
-# ${CMAKE_CURRENT_SOURCE_DIR}/coordinationjob.cpp
-# ${CMAKE_CURRENT_SOURCE_DIR}/sourceaccount.cpp
-# ${CMAKE_CURRENT_SOURCE_DIR}/sourceserver.cpp
-# PARENT_SCOPE
-# )
-
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
set(MIGRATION_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/migrateuserjob.cpp
@@ -17,9 +10,11 @@ set(MIGRATION_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/sourceserver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/kolabserver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/statefile.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/imapsourceaccount.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/kolabsourceaccount.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/exchangesourceaccount.cpp
)
-
QT4_WRAP_CPP(MIGRATION_MOC
${CMAKE_CURRENT_SOURCE_DIR}/migrateuserjob.h
${CMAKE_CURRENT_SOURCE_DIR}/migratefolderjob.h
@@ -28,11 +23,52 @@ QT4_WRAP_CPP(MIGRATION_MOC
${CMAKE_CURRENT_SOURCE_DIR}/sourceserver.h
${CMAKE_CURRENT_SOURCE_DIR}/kolabserver.h
${CMAKE_CURRENT_SOURCE_DIR}/statefile.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/imapsourceaccount.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/kolabsourceaccount.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/exchangesourceaccount.h
+)
+
+set(MIGRATION_SRCS
+ ${MIGRATION_SRCS}
+ ${MIGRATION_MOC}
+ ${JOBS_SRCS}
)
+set(MIGRATION_LIBRARIES
+ kolabutils
+ ${COMMON_DEPENDENCIES}
+)
+
+if(BUILD_GOOGLESUPPORT)
+ find_package(LibKGAPI2 2.0 REQUIRED)
+ include_directories(
+ ${LibKGAPI2_INCLUDE_DIR}
+ )
+
+ QT4_WRAP_CPP(GOOGLE_MOC
+ ${CMAKE_CURRENT_SOURCE_DIR}/googlesourceserver.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/googlesourceaccount.h
+ )
+
+ set(MIGRATION_SRCS
+ ${MIGRATION_SRCS}
+ ${GOOGLE_MOC}
+ ${CMAKE_CURRENT_SOURCE_DIR}/googlesourceserver.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/googlesourceaccount.cpp
+ )
+
+ set(MIGRATION_LIBRARIES
+ ${MIGRATION_LIBRARIES}
+ ${LibKGAPI2_LIBRARY}
+ )
+ add_definitions("-DBUILD_GOOGLESUPPORT")
+endif()
+
+add_library(migration_static STATIC ${MIGRATION_SRCS})
+target_link_libraries(migration_static ${COMMON_DEPENDENCIES} ${MIGRATION_LIBRARIES})
-add_executable(kolab-migration ${MIGRATION_SRCS} ${MIGRATION_MOC} ${JOBS_SRCS} main.cpp)
-target_link_libraries(kolab-migration ${COMMON_DEPENDENCIES} kolabutils)
+add_executable(kolab-migration ${MIGRATION_SRCS} main.cpp)
+target_link_libraries(kolab-migration ${MIGRATION_LIBRARIES})
install(TARGETS kolab-migration
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
@@ -40,4 +76,4 @@ install(TARGETS kolab-migration
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
)
-# add_subdirectory(tests)
+add_subdirectory(tests)
diff --git a/migrationutility/coordinationjob.cpp b/migrationutility/coordinationjob.cpp
index cb8fab7..f7a402f 100644
--- a/migrationutility/coordinationjob.cpp
+++ b/migrationutility/coordinationjob.cpp
@@ -32,6 +32,11 @@ CoordinationJob::CoordinationJob(SourceServer *sourceServer, KolabServer *kolabS
void CoordinationJob::start()
{
+ QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
+}
+
+void CoordinationJob::doStart()
+{
mUserList = mSourceServer->getUserList();
if (mUserList.isEmpty()) {
Debug() << "no users found";
@@ -50,7 +55,7 @@ void CoordinationJob::processUser()
return;
}
const QString user = mUserList.takeFirst();
- MigrateUserJob *job = new MigrateUserJob(mSourceServer->getSourceAccount(user), mKolabServer->getAccount(user), this);
+ MigrateUserJob *job = new MigrateUserJob(mSourceServer->getSourceAccounts(user), mKolabServer->getAccount(user), this);
connect(job, SIGNAL(result(KJob*)), this, SLOT(userMigrated(KJob*)));
job->start();
}
diff --git a/migrationutility/coordinationjob.h b/migrationutility/coordinationjob.h
index 9e9c1e6..94a57a6 100644
--- a/migrationutility/coordinationjob.h
+++ b/migrationutility/coordinationjob.h
@@ -31,6 +31,7 @@ public:
explicit CoordinationJob(SourceServer *sourceServer, KolabServer *kolabServer, QObject* parent = 0);
virtual void start();
private slots:
+ void doStart();
void userMigrated(KJob *job);
private:
void processUser();
diff --git a/migrationutility/exchangesourceaccount.cpp b/migrationutility/exchangesourceaccount.cpp
new file mode 100644
index 0000000..c4ef8f9
--- /dev/null
+++ b/migrationutility/exchangesourceaccount.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "exchangesourceaccount.h"
+
+#include <jobs/fetchmessagesjob.h>
+#include <errorhandler.h>
+#include <kabc/vcardconverter.h>
+#include <kcalcore/memorycalendar.h>
+#include <kcalcore/icalformat.h>
+
+ExchangeIMAPSourceAccount::ExchangeIMAPSourceAccount(QObject* parent)
+: IMAPSourceAccount(parent)
+{
+
+}
+
+QPair<Kolab::ObjectType, KMime::Content*> ExchangeIMAPSourceAccount::getObjectType(const KMime::Message::Ptr &msg) const
+{
+ const QByteArray calendarType("text/calendar");
+ const QByteArray vcardType("text/vcard");
+ Q_FOREACH(KMime::Content *c, msg->contents()) {
+ Debug() << c->contentType()->mimeType();
+ if (c->contentType()->mimeType() == calendarType) {
+ KCalCore::ICalFormat format;
+ KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
+ format.fromRawString(calendar, c->decodedContent());
+ if (!calendar->events().isEmpty()) {
+ return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::EventObject, c);
+ } else if (!calendar->todos().isEmpty()) {
+ return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::TodoObject, c);
+ } else if (!calendar->journals().isEmpty()) {
+ return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::JournalObject, c);
+ }
+ }
+ if (c->contentType()->mimeType() == vcardType) {
+ return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::ContactObject, c);
+ }
+ }
+ return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::InvalidObject, 0);
+}
+
+Kolab::FolderType ExchangeIMAPSourceAccount::getFolderType(const QString &folder)
+{
+ FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, getSession(), this);
+ //Theoretically one would be enough, but in case we have a couple of invalid ones...
+ fetchJob->setMaxNumberOfMessagesToFetch(10);
+ fetchJob->exec();
+ Debug() << fetchJob->getMessages().size();
+ QList<Object> messages;
+ foreach (const KMime::Message::Ptr &msg, fetchJob->getMessages()) {
+ Kolab::ObjectType type = getObjectType(msg).first;
+ if (type == Kolab::EventObject) {
+ return Kolab::EventType;
+ }
+ if (type == Kolab::TodoObject) {
+ return Kolab::TaskType;
+ }
+ if (type == Kolab::JournalObject) {
+ return Kolab::JournalType;
+ }
+ if (type == Kolab::ContactObject) {
+ return Kolab::ContactType;
+ }
+ }
+ return Kolab::MailType;
+}
+
+QPair<Kolab::FolderType, QString> ExchangeIMAPSourceAccount::translateFolder(const QString& folder)
+{
+ return QPair<Kolab::FolderType, QString>(getFolderType(folder), folder);
+}
+
+Object ExchangeIMAPSourceAccount::convertObject(const Object& object, const QString& /*folder*/) const
+{
+ KMime::Message::Ptr msg = object.object.value<KMime::Message::Ptr>();
+ QPair<Kolab::ObjectType, KMime::Content*> type = getObjectType(msg);
+ Debug() << type.first;
+ if (type.first == Kolab::InvalidObject) {
+ Object obj;
+ obj.object = QVariant::fromValue(msg);
+ obj.flags = object.flags;
+ return obj;
+ } else if (type.first == Kolab::EventObject || type.first == Kolab::TodoObject || type.first == Kolab::JournalObject) {
+ const QByteArray content = type.second->decodedContent();
+ Debug() << "Found incidence object: " << content;
+ KCalCore::ICalFormat format;
+ KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
+ format.fromRawString(calendar, content);
+
+ //We're simply assuming here that we never have different incidence types mixed in a folder
+ foreach (const KCalCore::Incidence::Ptr &inc, calendar->incidences()) {
+ Object obj;
+ obj.object = QVariant::fromValue(inc);
+ obj.flags = object.flags;
+ if (!obj.object.isValid()) {
+ Error() << "got empty message";
+ continue;
+ }
+ return obj;
+ }
+ } else if (type.first == Kolab::ContactObject) {
+ const QByteArray content = type.second->decodedContent();
+ Debug() << "Found contact object: " << content;
+ KABC::VCardConverter format;
+ const KABC::Addressee addressee = format.parseVCard(content);
+
+ Object obj;
+ obj.object = QVariant::fromValue(addressee);
+ obj.flags = object.flags;
+ if (!obj.object.isValid()) {
+ Error() << "got empty message";
+ return object;
+ }
+ return obj;
+ }
+ return object;
+}
+
+
diff --git a/migrationutility/exchangesourceaccount.h b/migrationutility/exchangesourceaccount.h
new file mode 100644
index 0000000..59169bd
--- /dev/null
+++ b/migrationutility/exchangesourceaccount.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EXCHANGESOURCEACCOUNT_H
+#define EXCHANGESOURCEACCOUNT_H
+
+#include "imapsourceaccount.h"
+
+class ExchangeIMAPSourceAccount: public IMAPSourceAccount
+{
+ Q_OBJECT
+public:
+ explicit ExchangeIMAPSourceAccount(QObject* parent = 0);
+ virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
+ virtual Object convertObject(const Object& object, const QString& folder) const;
+
+private:
+ QPair<Kolab::ObjectType, KMime::Content*> getObjectType(const KMime::Message::Ptr &msg) const;
+ Kolab::FolderType getFolderType(const QString &folder);
+};
+
+#endif
diff --git a/migrationutility/googlesourceaccount.cpp b/migrationutility/googlesourceaccount.cpp
new file mode 100644
index 0000000..a920719
--- /dev/null
+++ b/migrationutility/googlesourceaccount.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "googlesourceaccount.h"
+
+#include <libkgapi2/contacts/contact.h>
+#include <libkgapi2/contacts/contactfetchjob.h>
+#include <libkgapi2/calendar/calendar.h>
+#include <libkgapi2/calendar/calendarfetchjob.h>
+#include <libkgapi2/calendar/event.h>
+#include <libkgapi2/calendar/eventfetchjob.h>
+#include <libkgapi2/tasks/tasklistfetchjob.h>
+#include <libkgapi2/tasks/task.h>
+#include <libkgapi2/tasks/taskfetchjob.h>
+#include <libkgapi2/tasks/tasklist.h>
+#include <libkgapi2/authjob.h>
+#include <libkgapi2/account.h>
+
+#include <errorhandler.h>
+
+GoogleFetchObjectsJob::GoogleFetchObjectsJob(const QString &currentFolder, const KGAPI2::AccountPtr& account, QObject* parent)
+: FetchObjectsJob(parent),
+ mAccount(account),
+ mCurrentFolder(currentFolder)
+{
+
+}
+
+void GoogleFetchObjectsJob::start()
+{
+ if (mAccount.isNull()) {
+ Error() << "Error: Please authenticate first";
+ setError(KJob::UserDefinedError);
+ setErrorText("Error: Please authenticate first");
+ emitResult();
+ return;
+ }
+
+ KGAPI2::FetchJob *fetchJob = getFetchJob(mAccount, mCurrentFolder);
+ connect(fetchJob, SIGNAL(finished(KGAPI2::Job*)), this, SLOT(slotFetchJobFinished(KGAPI2::Job*)));
+}
+
+
+void GoogleFetchObjectsJob::slotFetchJobFinished(KGAPI2::Job* job)
+{
+ KGAPI2::FetchJob *fetchJob = qobject_cast<KGAPI2::FetchJob*>(job);
+ Q_ASSERT(fetchJob);
+ fetchJob->deleteLater();
+
+ if (fetchJob->error() != KGAPI2::NoError) {
+ Error() << fetchJob->errorString();
+ setError(KJob::UserDefinedError);
+ setErrorText(fetchJob->errorString());
+ emitResult();
+ return;
+ }
+
+ QList<Object> objects;
+ foreach (const KGAPI2::ObjectPtr &i, fetchJob->items()) {
+ objects << getObject(i);
+ }
+ emit objectsReceived(mCurrentFolder, objects);
+ emitResult();
+}
+
+GoogleFetchFoldersJob::GoogleFetchFoldersJob(const KGAPI2::AccountPtr& account, QObject* parent)
+: FetchFoldersJob(parent),
+ mAccount(account)
+{
+
+}
+
+void GoogleFetchFoldersJob::start()
+{
+ if (mAccount.isNull()) {
+ Error() << "Error: Please authenticate first";
+ setError(KJob::UserDefinedError);
+ setErrorText("Error: Please authenticate first");
+ emitResult();
+ return;
+ }
+
+ KGAPI2::FetchJob *fetchJob = getFetchJob(mAccount);
+ connect(fetchJob, SIGNAL(finished(KGAPI2::Job*)), this, SLOT(slotFetchJobFinished(KGAPI2::Job*)));
+}
+
+
+void GoogleFetchFoldersJob::slotFetchJobFinished(KGAPI2::Job* job)
+{
+ KGAPI2::FetchJob *fetchJob = qobject_cast<KGAPI2::FetchJob*>(job);
+ Q_ASSERT(fetchJob);
+ fetchJob->deleteLater();
+
+ if (fetchJob->error() != KGAPI2::NoError) {
+ Error() << fetchJob->errorString();
+ setError(KJob::UserDefinedError);
+ setErrorText(fetchJob->errorString());
+ emitResult();
+ return;
+ }
+
+ QStringList folders;
+ foreach (const KGAPI2::ObjectPtr &i, fetchJob->items()) {
+ const QPair<QString, QString> folder = getFolder(i);
+ folders << folder.first;
+ mNames.insert(folder.first, folder.second);
+ }
+ emit foldersReceived(folders);
+ emitResult();
+}
+
+
+
+FetchContactObjectsJob::FetchContactObjectsJob(const KGAPI2::AccountPtr &account, QObject* parent)
+: GoogleFetchObjectsJob(QLatin1String("Contacts"), account, parent)
+{
+
+}
+
+KGAPI2::FetchJob* FetchContactObjectsJob::getFetchJob(const KGAPI2::AccountPtr& account, const QString& folder)
+{
+ Q_UNUSED(folder);
+ return new KGAPI2::ContactFetchJob(account, this);
+}
+
+Object FetchContactObjectsJob::getObject(const KGAPI2::ObjectPtr& object)
+{
+ const KABC::Addressee contact = *object.dynamicCast<KGAPI2::Contact>();
+ Debug() << "contact: " << contact.name();
+ qDebug() << contact.emails();
+ Object obj;
+ obj.object = QVariant::fromValue(contact);
+ return obj;
+}
+
+FetchCalendarObjectsJob::FetchCalendarObjectsJob(const QString &calendarId, const KGAPI2::AccountPtr& account, QObject* parent)
+: GoogleFetchObjectsJob(calendarId, account, parent)
+{
+}
+
+KGAPI2::FetchJob* FetchCalendarObjectsJob::getFetchJob(const KGAPI2::AccountPtr &account, const QString& folder)
+{
+ return new KGAPI2::EventFetchJob(folder, account, this);
+}
+
+Object FetchCalendarObjectsJob::getObject(const KGAPI2::ObjectPtr &object)
+{
+ KCalCore::Incidence::Ptr event(object.dynamicCast<KGAPI2::Event>()->clone());
+ Debug() << event->uid() << event->summary();
+ Object obj;
+ obj.object = QVariant::fromValue(event);
+ return obj;
+}
+
+
+
+FetchCalendarFoldersJob::FetchCalendarFoldersJob(const KGAPI2::AccountPtr& account, QObject* parent)
+: GoogleFetchFoldersJob(account, parent)
+{
+}
+
+KGAPI2::FetchJob* FetchCalendarFoldersJob::getFetchJob(const KGAPI2::AccountPtr& account)
+{
+ return new KGAPI2::CalendarFetchJob(account, this);
+}
+
+QPair<QString, QString> FetchCalendarFoldersJob::getFolder(const KGAPI2::ObjectPtr& object)
+{
+ const KGAPI2::Calendar &calendar = *object.dynamicCast<KGAPI2::Calendar>();
+ //TODO prefix with Calendar/
+ QString name = calendar.title();
+ //normalize so it works as imap mailbox name
+ name.replace(QLatin1String("@"), QLatin1String("at"));
+ Debug() << "calendar: " << name;
+ return qMakePair<QString, QString>(calendar.uid(), name);
+}
+
+FetchTaskObjectsJob::FetchTaskObjectsJob(const QString &tasklistId, const KGAPI2::AccountPtr& account, QObject* parent)
+: GoogleFetchObjectsJob(tasklistId, account, parent)
+{
+}
+
+KGAPI2::FetchJob* FetchTaskObjectsJob::getFetchJob(const KGAPI2::AccountPtr &account, const QString& folder)
+{
+ return new KGAPI2::TaskFetchJob(folder, account, this);
+}
+
+Object FetchTaskObjectsJob::getObject(const KGAPI2::ObjectPtr &object)
+{
+ KCalCore::Incidence::Ptr task(object.dynamicCast<KGAPI2::Task>()->clone());
+ Debug() << task->uid() << task->summary();
+ Object obj;
+ obj.object = QVariant::fromValue(task);
+ return obj;
+}
+
+FetchTaskListsJob::FetchTaskListsJob(const KGAPI2::AccountPtr& account, QObject* parent)
+: GoogleFetchFoldersJob(account, parent)
+{
+}
+
+KGAPI2::FetchJob* FetchTaskListsJob::getFetchJob(const KGAPI2::AccountPtr& account)
+{
+ return new KGAPI2::TaskListFetchJob(account, this);
+}
+
+QPair<QString, QString> FetchTaskListsJob::getFolder(const KGAPI2::ObjectPtr& object)
+{
+ const KGAPI2::TaskList &list = *object.dynamicCast<KGAPI2::TaskList>();
+ //TODO prefix with Task/
+ QString name = list.title();
+ //normalize so it works as imap mailbox name
+ name.replace(QLatin1String("@"), QLatin1String("at"));
+ Debug() << "calendar: " << name;
+ return qMakePair<QString, QString>(list.uid(), name);
+}
+
+LoginJob::LoginJob(const KGAPI2::AccountPtr &account, QObject* parent)
+: KJob(parent),
+ mAccount(account)
+{
+
+}
+
+void LoginJob::start()
+{
+ Debug() << "login";
+ /* Create AuthJob to retrieve OAuth tokens for the account */
+ KGAPI2::AuthJob *authJob = new KGAPI2::AuthJob(
+ mAccount,
+ QLatin1String("583467588400.apps.googleusercontent.com"),
+ QLatin1String("_AwtLuOqS5JcCHWGpq8fxKdd"), this);
+// GoogleAuthJob *authJob = new GoogleAuthJob(
+// account,
+// QLatin1String("583467588400.apps.googleusercontent.com"),
+// QLatin1String("_AwtLuOqS5JcCHWGpq8fxKdd"));
+ connect(authJob, SIGNAL(finished(KGAPI2::Job*)), this, SLOT(slotAuthJobFinished(KGAPI2::Job*)));
+}
+
+void LoginJob::slotAuthJobFinished(KGAPI2::Job *job)
+{
+ Debug() << "login done";
+ KGAPI2::AuthJob *authJob = qobject_cast<KGAPI2::AuthJob*>(job);
+ Q_ASSERT(authJob);
+ authJob->deleteLater();
+
+ if (authJob->error() != KGAPI2::NoError) {
+ setError(KJob::UserDefinedError);
+ setErrorText(authJob->errorString());
+ }
+ emitResult();
+}
+
+
+GoogleSourceAccount::GoogleSourceAccount(QObject* parent)
+: SourceAccount(parent)
+{
+
+}
+
+QPair<Kolab::FolderType, QString> GoogleSourceAccount::translateFolder(const QString& folder)
+{
+ return QPair<Kolab::FolderType, QString>(Kolab::ContactType, folder);
+}
+
+void GoogleSourceAccount::setUser(const QString& username)
+{
+ mUser = username;
+}
+
+KJob* GoogleSourceAccount::login()
+{
+ mAccount = KGAPI2::AccountPtr(new KGAPI2::Account);
+ mAccount->setScopes(QList<QUrl>() << KGAPI2::Account::contactsScopeUrl() << KGAPI2::Account::calendarScopeUrl() << KGAPI2::Account::tasksScopeUrl());
+ mAccount->setAccountName(mUser);
+
+ LoginJob *authJob = new LoginJob(mAccount, this);
+ return authJob;
+}
+
+KJob *GoogleSourceAccount::logout()
+{
+ mAccount.clear();
+ return 0;
+}
+
+
+GoogleContactsSourceAccount::GoogleContactsSourceAccount(QObject* parent)
+: GoogleSourceAccount(parent)
+{
+}
+
+QStringList GoogleContactsSourceAccount::lookupFolderList()
+{
+ return QStringList() << "Contacts";
+}
+
+FetchObjectsJob* GoogleContactsSourceAccount::fetchObjects(const QString& folder)
+{
+ return new FetchContactObjectsJob(mAccount, this);
+}
+
+
+GoogleCalendarSourceAccount::GoogleCalendarSourceAccount(QObject* parent)
+: GoogleSourceAccount(parent)
+{
+}
+
+FetchFoldersJob* GoogleCalendarSourceAccount::fetchFolderList()
+{
+ FetchCalendarFoldersJob *job = new FetchCalendarFoldersJob(mAccount, this);
+ connect(job, SIGNAL(result(KJob*)), this, SLOT(onFetchedCalendars(KJob*)));
+ return job;
+}
+
+void GoogleCalendarSourceAccount::onFetchedCalendars(KJob *job)
+{
+ if (!job->error()) {
+ FetchCalendarFoldersJob *calendarFolderJob = static_cast<FetchCalendarFoldersJob*>(job);
+ mCalendarNames = calendarFolderJob->mNames;
+ }
+}
+
+FetchObjectsJob* GoogleCalendarSourceAccount::fetchObjects(const QString& folder)
+{
+ return new FetchCalendarObjectsJob(folder, mAccount, this);
+}
+
+QPair< Kolab::FolderType, QString > GoogleCalendarSourceAccount::translateFolder(const QString& folder)
+{
+ return QPair<Kolab::FolderType, QString>(Kolab::EventType, mCalendarNames.value(folder));
+}
+
+
+GoogleTasksSourceAccount::GoogleTasksSourceAccount(QObject* parent)
+: GoogleSourceAccount(parent)
+{
+}
+
+FetchFoldersJob* GoogleTasksSourceAccount::fetchFolderList()
+{
+ FetchTaskListsJob *job = new FetchTaskListsJob(mAccount, this);
+ connect(job, SIGNAL(result(KJob*)), this, SLOT(onFetchedTasklists(KJob*)));
+ return job;
+}
+
+void GoogleTasksSourceAccount::onFetchedTasklists(KJob* job)
+{
+ if (!job->error()) {
+ FetchTaskListsJob *fetchJob = static_cast<FetchTaskListsJob*>(job);
+ mTasklists = fetchJob->mNames;
+ }
+}
+
+FetchObjectsJob* GoogleTasksSourceAccount::fetchObjects(const QString& folder)
+{
+ return new FetchTaskObjectsJob(folder, mAccount, this);
+}
+
+QPair< Kolab::FolderType, QString > GoogleTasksSourceAccount::translateFolder(const QString& folder)
+{
+ return QPair<Kolab::FolderType, QString>(Kolab::EventType, mTasklists.value(folder));
+}
+
diff --git a/migrationutility/googlesourceaccount.h b/migrationutility/googlesourceaccount.h
new file mode 100644
index 0000000..e1c1bf7
--- /dev/null
+++ b/migrationutility/googlesourceaccount.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GOOGLESOURCEACCOUNT_H
+#define GOOGLESOURCEACCOUNT_H
+
+#include <libkgapi2/types.h>
+#include <QStringList>
+
+#include "sourceaccount.h"
+
+namespace KGAPI2 {
+class Job;
+class FetchJob;
+}
+
+class GoogleSourceAccount: public SourceAccount
+{
+public:
+ explicit GoogleSourceAccount(QObject* parent = 0);
+
+ void setUser(const QString &username);
+ virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
+
+ virtual KJob *login();
+ virtual KJob *logout();
+
+protected:
+ KGAPI2::AccountPtr mAccount;
+ QString mUser;
+};
+
+class GoogleContactsSourceAccount: public GoogleSourceAccount
+{
+public:
+ explicit GoogleContactsSourceAccount(QObject* parent = 0);
+
+ virtual QStringList lookupFolderList();
+ virtual FetchObjectsJob *fetchObjects(const QString &folder);
+};
+
+class GoogleCalendarSourceAccount: public GoogleSourceAccount
+{
+ Q_OBJECT
+public:
+ explicit GoogleCalendarSourceAccount(QObject* parent = 0);
+
+ virtual FetchFoldersJob *fetchFolderList();
+ virtual FetchObjectsJob *fetchObjects(const QString &folder);
+ virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
+
+private slots:
+ void onFetchedCalendars(KJob *job);
+
+private:
+ QHash<QString, QString> mCalendarNames;
+};
+
+class GoogleTasksSourceAccount: public GoogleSourceAccount
+{
+ Q_OBJECT
+public:
+ explicit GoogleTasksSourceAccount(QObject* parent = 0);
+
+ virtual FetchFoldersJob *fetchFolderList();
+ virtual FetchObjectsJob *fetchObjects(const QString &folder);
+ virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
+
+private slots:
+ void onFetchedTasklists(KJob *job);
+
+private:
+ QHash<QString, QString> mTasklists;
+};
+
+class GoogleFetchObjectsJob : public FetchObjectsJob
+{
+ Q_OBJECT
+public:
+ explicit GoogleFetchObjectsJob(const QString &folder, const KGAPI2::AccountPtr &account, QObject* parent = 0);
+ virtual void start();
+
+protected:
+ virtual Object getObject(const KGAPI2::ObjectPtr &) = 0;
+ virtual KGAPI2::FetchJob *getFetchJob(const KGAPI2::AccountPtr &, const QString &folder) = 0;
+
+private slots:
+ void slotFetchJobFinished(KGAPI2::Job *job);
+
+private:
+ const KGAPI2::AccountPtr mAccount;
+ const QString mCurrentFolder;
+};
+
+class GoogleFetchFoldersJob : public FetchFoldersJob
+{
+ Q_OBJECT
+public:
+ explicit GoogleFetchFoldersJob(const KGAPI2::AccountPtr &account, QObject* parent = 0);
+ virtual void start();
+ QHash<QString, QString> mNames;
+
+protected:
+ virtual QPair<QString, QString> getFolder(const KGAPI2::ObjectPtr &object) = 0;
+ virtual KGAPI2::FetchJob *getFetchJob(const KGAPI2::AccountPtr &account) = 0;
+
+private slots:
+ void slotFetchJobFinished(KGAPI2::Job *job);
+
+private:
+ const KGAPI2::AccountPtr mAccount;
+};
+
+class FetchContactObjectsJob : public GoogleFetchObjectsJob
+{
+public:
+ explicit FetchContactObjectsJob(const KGAPI2::AccountPtr &account, QObject* parent = 0);
+
+protected:
+ virtual KGAPI2::FetchJob* getFetchJob(const KGAPI2::AccountPtr &account, const QString& folder);
+ virtual Object getObject(const KGAPI2::ObjectPtr &object);
+};
+
+class LoginJob : public KJob
+{
+ Q_OBJECT
+public:
+ explicit LoginJob(const KGAPI2::AccountPtr &account, QObject* parent = 0);
+ virtual void start();
+
+private slots:
+ void slotAuthJobFinished(KGAPI2::Job *job);
+
+private:
+ KGAPI2::AccountPtr mAccount;
+};
+
+class FetchCalendarObjectsJob : public GoogleFetchObjectsJob
+{
+public:
+ explicit FetchCalendarObjectsJob(const QString &mCalendarId, const KGAPI2::AccountPtr &account, QObject* parent = 0);
+
+protected:
+ virtual KGAPI2::FetchJob* getFetchJob(const KGAPI2::AccountPtr& , const QString& folder);
+ virtual Object getObject(const KGAPI2::ObjectPtr& );
+};
+
+class FetchCalendarFoldersJob : public GoogleFetchFoldersJob
+{
+public:
+ explicit FetchCalendarFoldersJob(const KGAPI2::AccountPtr &account, QObject* parent = 0);
+
+protected:
+ virtual KGAPI2::FetchJob* getFetchJob(const KGAPI2::AccountPtr& account);
+ virtual QPair<QString, QString> getFolder(const KGAPI2::ObjectPtr& object);
+};
+
+class FetchTaskObjectsJob : public GoogleFetchObjectsJob
+{
+public:
+ explicit FetchTaskObjectsJob(const QString &mTasklistId, const KGAPI2::AccountPtr &account, QObject* parent = 0);
+
+protected:
+ virtual KGAPI2::FetchJob* getFetchJob(const KGAPI2::AccountPtr& , const QString& folder);
+ virtual Object getObject(const KGAPI2::ObjectPtr& );
+};
+
+class FetchTaskListsJob : public GoogleFetchFoldersJob
+{
+public:
+ explicit FetchTaskListsJob(const KGAPI2::AccountPtr &account, QObject* parent = 0);
+
+protected:
+ virtual KGAPI2::FetchJob* getFetchJob(const KGAPI2::AccountPtr& account);
+ virtual QPair< QString, QString > getFolder(const KGAPI2::ObjectPtr& object);
+};
+
+#endif \ No newline at end of file
diff --git a/migrationutility/googlesourceserver.cpp b/migrationutility/googlesourceserver.cpp
new file mode 100644
index 0000000..978149c
--- /dev/null
+++ b/migrationutility/googlesourceserver.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "googlesourceserver.h"
+#include "googlesourceaccount.h"
+#include "imapsourceaccount.h"
+
+#include <jobs/getuserlistjob.h>
+#include <kimap/listjob.h>
+#include <kimap/logoutjob.h>
+#include <commonconversion.h>
+#include <errorhandler.h>
+
+GoogleSourceServer::GoogleSourceServer(QObject* parent)
+: SourceServer(parent),
+ mEncryptionMode(KIMAP::LoginJob::TlsV1),
+ mAuthenticationMode(KIMAP::LoginJob::Plain)
+{
+
+}
+
+void GoogleSourceServer::setHost(const QString& host, qint16 port)
+{
+ mHost = host;
+ mPort = port;
+}
+
+void GoogleSourceServer::setAdminCredentials(const QString& username, const QString& pw)
+{
+ mUsername = username;
+ mPw = pw;
+}
+
+void GoogleSourceServer::setEncryption(KIMAP::LoginJob::EncryptionMode enc)
+{
+ mEncryptionMode = enc;
+}
+
+void GoogleSourceServer::setAuthentication(KIMAP::LoginJob::AuthenticationMode auth)
+{
+ mAuthenticationMode = auth;
+}
+
+QList<SourceAccount*> GoogleSourceServer::getSourceAccountsImpl(const QString& user)
+{
+ QList <SourceAccount*> sourceAccounts;
+
+ GoogleContactsSourceAccount *contactsAccount = new GoogleContactsSourceAccount(this);
+ contactsAccount->setUser(user);
+ sourceAccounts << contactsAccount;
+
+ GoogleCalendarSourceAccount *calendarAccount = new GoogleCalendarSourceAccount(this);
+ calendarAccount->setUser(user);
+ sourceAccounts << calendarAccount;
+
+ GoogleTasksSourceAccount *tasksAccount = new GoogleTasksSourceAccount(this);
+ tasksAccount->setUser(user);
+ sourceAccounts << tasksAccount;
+
+ IMAPSourceAccount *imapAccount = new IMAPSourceAccount(this);
+ imapAccount->prepareConnection(mHost, mPort, user, user, mPw, mEncryptionMode, mAuthenticationMode);
+ sourceAccounts << imapAccount;
+
+ return sourceAccounts;
+} \ No newline at end of file
diff --git a/migrationutility/googlesourceserver.h b/migrationutility/googlesourceserver.h
new file mode 100644
index 0000000..2af8f04
--- /dev/null
+++ b/migrationutility/googlesourceserver.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GOOGLESOURCESERVER_H
+#define GOOGLESOURCESERVER_H
+
+#include <kimap/loginjob.h>
+#include <QStringList>
+
+#include "sourceserver.h"
+
+class GoogleSourceServer: public SourceServer
+{
+ Q_OBJECT
+public:
+ explicit GoogleSourceServer(QObject* parent = 0);
+
+ void setHost(const QString &host, qint16 port);
+ void setAdminCredentials(const QString &username, const QString &pw);
+ void setEncryption(KIMAP::LoginJob::EncryptionMode);
+ void setAuthentication(KIMAP::LoginJob::AuthenticationMode);
+protected:
+ virtual QList<SourceAccount*> getSourceAccountsImpl(const QString& user);
+ void logout();
+ QString mHost;
+ int mPort;
+ QString mUsername;
+ QString mPw;
+ KIMAP::LoginJob::EncryptionMode mEncryptionMode;
+ KIMAP::LoginJob::AuthenticationMode mAuthenticationMode;
+};
+
+#endif \ No newline at end of file
diff --git a/migrationutility/imapsourceaccount.cpp b/migrationutility/imapsourceaccount.cpp
new file mode 100644
index 0000000..91a4e2b
--- /dev/null
+++ b/migrationutility/imapsourceaccount.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "imapsourceaccount.h"
+
+#include <jobs/fetchmessagesjob.h>
+#include <jobs/probeimapserverjob.h>
+#include <sessionfactory.h>
+#include <kimap/session.h>
+#include <kimap/listjob.h>
+#include <kimap/logoutjob.h>
+#include <kimap/capabilitiesjob.h>
+#include <kimap/namespacejob.h>
+#include <errorhandler.h>
+
+FetchIMAPObjectsJob::FetchIMAPObjectsJob(FetchMessagesJob *fetchJob, QObject *parent)
+: FetchObjectsJob(parent), mFetchMessagesJob(fetchJob)
+{
+}
+
+void FetchIMAPObjectsJob::start()
+{
+ connect(mFetchMessagesJob, SIGNAL(messagesReceived(QString,QList<Object>)), this, SIGNAL(objectsReceived(QString,QList<Object>)));
+ connect(mFetchMessagesJob, SIGNAL(result(KJob*)), this, SLOT(onJobDone(KJob*)));
+ mFetchMessagesJob->start();
+}
+
+void FetchIMAPObjectsJob::onJobDone(KJob *job)
+{
+ Debug() << "fetch done ";
+ if (job->error()) {
+ setError(job->error());
+ setErrorText(job->errorString());
+ }
+ emitResult();
+}
+
+
+IMAPSourceAccount::IMAPSourceAccount(QObject* parent)
+: SourceAccount(parent),
+ mSession(0)
+{
+
+}
+
+IMAPSourceAccount::~IMAPSourceAccount()
+{
+ if (mSession) {
+ mSession->close();
+ mSession->deleteLater();
+ }
+}
+
+QPair<Kolab::FolderType, QString> IMAPSourceAccount::translateFolder(const QString& folder)
+{
+ return QPair<Kolab::FolderType, QString>(Kolab::MailType, folder);
+}
+
+void IMAPSourceAccount::init()
+{
+ ProbeIMAPServerJob *probeJob = new ProbeIMAPServerJob(mSession, this);
+ probeJob->exec();
+ mPersonalNamespaces = probeJob->personalNamespace();
+}
+
+QStringList IMAPSourceAccount::lookupFolderList()
+{
+ Q_ASSERT(mSession);
+// Debug() << "lookupFolderList" << mSession->state();
+
+ init();
+
+ mMailboxes.clear();
+
+ KIMAP::ListJob *listJob = new KIMAP::ListJob(mSession);
+ listJob->setOption(KIMAP::ListJob::IncludeUnsubscribed);
+ listJob->setQueriedNamespaces(mPersonalNamespaces);
+ QObject::connect( listJob, SIGNAL(mailBoxesReceived(QList<KIMAP::MailBoxDescriptor>,QList<QList<QByteArray> >)),
+ this, SLOT(mailBoxesReceived(QList<KIMAP::MailBoxDescriptor>,QList<QList<QByteArray> >)));
+ listJob->exec();
+ Debug() << "found " << mMailboxes.size();
+
+ QStringList mailboxes;
+ foreach (const KIMAP::MailBoxDescriptor &descriptor, mMailboxes) {
+ mailboxes.append(descriptor.name);
+ }
+ return mailboxes;
+}
+
+void IMAPSourceAccount::mailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList< QList< QByteArray > > &/* flags */)
+{
+ mMailboxes.append(descriptors);
+}
+
+void IMAPSourceAccount::recordSuccessfulMigration(const QList<Object> &objects, const QString &folder)
+{
+ if (mStatefile.isValid()) {
+ QList<qint64> uids;
+ foreach (const Object &obj, objects) {
+ uids << obj.imapUid;
+ }
+ mStatefile.appendMigratedUids(folder, uids);
+ }
+}
+
+FetchObjectsJob* IMAPSourceAccount::fetchObjects(const QString& folder)
+{
+ FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
+ fetchJob->setTransient(true);
+ if (mStatefile.isValid()) {
+ fetchJob->setUidsToSkip(mStatefile.getMigratedUids(folder));
+ }
+ return new FetchIMAPObjectsJob(fetchJob, this);
+}
+
+Object IMAPSourceAccount::convertObject(const Object& object, const QString& /*folder*/) const
+{
+ return object;
+}
+
+QList<qint64> IMAPSourceAccount::getImapUids(const QString &folder)
+{
+ FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
+ fetchJob->fetchScope().mode = KIMAP::FetchJob::FetchScope::Headers;
+ fetchJob->exec();
+ Debug() << fetchJob->getMessages().size();
+ return fetchJob->getImapUids();
+}
+
+KIMAP::Session* IMAPSourceAccount::getSession()
+{
+ Q_ASSERT(mSession);
+ return mSession;
+}
+
+void IMAPSourceAccount::prepareConnection(QString host, qint16 port, const QString& authorizationName, const QString& userName, const QString& password, KIMAP::LoginJob::EncryptionMode encryptionMode, KIMAP::LoginJob::AuthenticationMode authenticationMode)
+{
+ mHost = host;
+ mPort = port;
+ mAuthorizationName = authorizationName;
+ mUsername = userName;
+ mPw = password;
+ mEncryptionMode = encryptionMode;
+ mAuthenticationMode = authenticationMode;
+}
+
+KJob *IMAPSourceAccount::login()
+{
+ mSession = createSession(mHost, mPort, this);
+
+ KIMAP::LoginJob *loginJob = new KIMAP::LoginJob(mSession);
+ if (mAuthorizationName != mUsername) {
+ loginJob->setAuthorizationName(mAuthorizationName);
+ }
+ loginJob->setUserName(mUsername);
+ loginJob->setPassword(mPw);
+ loginJob->setEncryptionMode(mEncryptionMode);
+ loginJob->setAuthenticationMode(mAuthenticationMode);
+ return loginJob;
+}
+
+KJob *IMAPSourceAccount::logout()
+{
+ KIMAP::LogoutJob *logoutJob = new KIMAP::LogoutJob(mSession);
+ return logoutJob;
+} \ No newline at end of file
diff --git a/migrationutility/imapsourceaccount.h b/migrationutility/imapsourceaccount.h
new file mode 100644
index 0000000..53f51cb
--- /dev/null
+++ b/migrationutility/imapsourceaccount.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IMAPSOURCEACCOUNT_H
+#define IMAPSOURCEACCOUNT_H
+
+#include "sourceaccount.h"
+
+class IMAPSourceAccount: public SourceAccount
+{
+ Q_OBJECT
+public:
+ explicit IMAPSourceAccount(QObject* parent = 0);
+ virtual ~IMAPSourceAccount();
+ virtual QStringList lookupFolderList();
+ virtual FetchObjectsJob *fetchObjects(const QString &folder);
+ virtual Object convertObject(const Object &object, const QString& folder) const;
+ virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
+
+ /**
+ * Prepare the connection for a login attempt.
+ */
+ void prepareConnection(QString host, qint16 port, const QString &authorizationName, const QString &userName, const QString &password, KIMAP::LoginJob::EncryptionMode encryptionMode, KIMAP::LoginJob::AuthenticationMode authenticationMode);
+
+ KJob *login();
+ KJob *logout();
+ virtual void recordSuccessfulMigration(const QList<Object> &obj, const QString &folder);
+
+private slots:
+ void mailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList< QList< QByteArray > > &flags);
+
+protected:
+ //get namespace
+ virtual void init();
+ Kolab::FolderType getFolderType(const QString &folder);
+ KIMAP::Session *getSession();
+ QList<KIMAP::MailBoxDescriptor> mPersonalNamespaces;
+
+private:
+ /**
+ * Get UIDS of all messages in the folder on the source account
+ *
+ * This is used to find out which objects to migrate by subtracting already migrated uids from the list.
+ */
+ QList<qint64> getImapUids(const QString &folder);
+
+ QList<KIMAP::MailBoxDescriptor> mMailboxes;
+ KIMAP::Session *mSession;
+ QString mHost;
+ int mPort;
+ QString mUsername;
+ QString mAuthorizationName;
+ QString mPw;
+ KIMAP::LoginJob::EncryptionMode mEncryptionMode;
+ KIMAP::LoginJob::AuthenticationMode mAuthenticationMode;
+};
+
+class FetchIMAPObjectsJob : public FetchObjectsJob
+{
+ Q_OBJECT
+public:
+ FetchIMAPObjectsJob(FetchMessagesJob *fetchJob, QObject *parent);
+ virtual void start();
+ FetchMessagesJob * const mFetchMessagesJob;
+private slots:
+ void onJobDone(KJob *job);
+};
+
+
+#endif
diff --git a/migrationutility/kolabsourceaccount.cpp b/migrationutility/kolabsourceaccount.cpp
new file mode 100644
index 0000000..522be2f
--- /dev/null
+++ b/migrationutility/kolabsourceaccount.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2013 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "kolabsourceaccount.h"
+
+#include <jobs/probekolabserverjob.h>
+#include <errorhandler.h>
+#include <kolabobject.h>
+
+KolabSourceAccount::KolabSourceAccount(QObject* parent)
+: IMAPSourceAccount(parent)
+{
+
+}
+
+Kolab::FolderType KolabSourceAccount::getFolderType(const QString &folder) const
+{
+ if (mKolabFolders.values().contains(folder)) {
+ return Kolab::folderTypeFromString(mKolabFolders.key(folder).toStdString());
+ }
+ return Kolab::MailType;
+}
+
+QPair<Kolab::FolderType, QString> KolabSourceAccount::translateFolder(const QString& folder)
+{
+ return QPair<Kolab::FolderType, QString>(getFolderType(folder), folder);
+}
+
+void KolabSourceAccount::init()
+{
+ ProbeKolabServerJob *probeJob = new ProbeKolabServerJob(getSession(), this);
+ probeJob->exec();
+ mKolabFolders = probeJob->kolabFolders();
+ mPersonalNamespaces = probeJob->personalNamespace();
+}
+
+// void KolabSourceAccount::mailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList< QList< QByteArray > > &/* flags */)
+// {
+// mMailboxes.append(descriptors);
+// //TODO store folder type from metadata
+// // for (int i = 0; i < descriptors.size(); i++) {
+// // Debug() << descriptors.at(i).name;
+// // foreach (const QByteArray &arr, flags.at(i)) {
+// // Debug() << arr;
+// // }
+// // }
+// }
+
+QVariant upgradeMessage(const KMime::Message::Ptr &msg)
+{
+ //TODO deduplicate with upgradetool, check for errors during reading.
+ Kolab::KolabObjectReader reader;
+ switch (reader.parseMimeMessage(msg)) {
+ case Kolab::EventObject:
+ case Kolab::TodoObject:
+ case Kolab::JournalObject:
+ return QVariant::fromValue(reader.getIncidence());
+ case Kolab::ContactObject:
+ return QVariant::fromValue(reader.getContact());
+ case Kolab::DistlistObject:
+ return QVariant::fromValue(reader.getDistlist());
+ case Kolab::NoteObject: {
+ Note note;
+ note.msg = reader.getNote();
+ return QVariant::fromValue(note);
+ }
+ case Kolab::DictionaryConfigurationObject: {
+ Dictionary dictionary;
+ dictionary.dict = reader.getDictionary(dictionary.lang);
+ return QVariant::fromValue(dictionary);
+ }
+ case Kolab::InvalidObject:
+ default:
+ //TODO handle configuration objects
+ Error() << "failed to read mime file";
+ }
+ return QVariant();
+}
+
+Object KolabSourceAccount::convertObject(const Object& object, const QString& folder) const
+{
+ const bool isKolabType = mKolabFolders.values().contains(folder);
+ if (isKolabType) {
+ Object obj(object);
+ obj.object = upgradeMessage(object.object.value<KMime::Message::Ptr>());
+ return obj;
+ }
+ return object;
+}
diff --git a/migrationutility/kolabsourceaccount.h b/migrationutility/kolabsourceaccount.h
new file mode 100644
index 0000000..e9213a5
--- /dev/null
+++ b/migrationutility/kolabsourceaccount.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KOLABSOURCEACCOUNT_H
+#define KOLABSOURCEACCOUNT_H
+
+#include "imapsourceaccount.h"
+
+class KolabSourceAccount: public IMAPSourceAccount
+{
+ Q_OBJECT
+public:
+ explicit KolabSourceAccount(QObject* parent = 0);
+ virtual Object convertObject(const Object &object, const QString& folder) const;
+ virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
+
+protected:
+ virtual void init();
+ Kolab::FolderType getFolderType(const QString &folder) const;
+
+private:
+ QMultiHash<QString, QString> mKolabFolders;
+};
+
+#endif
diff --git a/migrationutility/main.cpp b/migrationutility/main.cpp
index 6d3b165..8913295 100644
--- a/migrationutility/main.cpp
+++ b/migrationutility/main.cpp
@@ -16,6 +16,7 @@
*/
#include <QtCore/qcoreapplication.h>
+#include <QtGui/QApplication>
#include <QtCore/QStringList>
#include <QtCore/qfile.h>
#include <kcmdlineargs.h>
@@ -24,6 +25,9 @@
#include "coordinationjob.h"
#include "sourceserver.h"
#include "kolabserver.h"
+#ifdef BUILD_GOOGLESUPPORT
+#include "googlesourceserver.h"
+#endif
KIMAP::LoginJob::EncryptionMode getEncryptionMode(const QString &encrypt)
{
@@ -66,13 +70,15 @@ KIMAP::LoginJob::AuthenticationMode getAuthenticationMode(const QString &auth)
}
/**
- * kolab-migrate --from caldav --to kolab (implied?) --caldav-host caldav.example.org --caldav-authn <admin> --caldav-authz <user> --caldav-pass <pass> --<folder-selection> --<folder-mapping> --kolab-host kolab.example.org --kolab-authn <admin> --kolab-authz <user> --kolab-pass <pass>
-
-* --regextrans2 '/Public Folders/shared/' Regex transformation of folder paths
-* Incremental conversion (folder by folder or even by batch of messages)
-* Save state persistently and resume from there after interruption (Wipe before starting and start all over as first step)
+ * kolab-migrate --from caldav --to kolab (implied?)
+ * --caldav-host caldav.example.org --caldav-authn <admin> --caldav-authz <user> --caldav-pass <pass>
+ * --<folder-selection> --<folder-mapping>
+ * --kolab-host kolab.example.org
+ * --kolab-authn <admin> --kolab-authz <user> --kolab-pass <pass>
+ * --regextrans2 '/Public Folders/shared/' Regex transformation of folder paths
+ * Incremental conversion (folder by folder or even by batch of messages)
+ * Save state persistently and resume from there after interruption (Wipe before starting and start all over as first step)
*/
-
int main(int argc, char *argv[])
{
KCmdLineArgs::init(argc, argv, "migrationutility", "migrationutility",ki18n("migrationutility"), "0.1");
@@ -81,7 +87,9 @@ int main(int argc, char *argv[])
options.add("dry", ki18n("Dry run, doesn't change anything on the server, but only prints what would be done (Use with care until this is well tested)."));
options.add("wipeTargetFolders", ki18n("Wipe and recreate target folders (Will only wipe folders in the personal namespace which are existing on the source server)."));
options.add("statefile", ki18n("Resume from migration-state file"), "/tmp/kolabmigration.state");
- options.add("from <type>", ki18n("Source host type (kolab2, kolab3, exchangeimap)"));
+ options.add("skipFolder <sourcefolder>", ki18n("Source-folders to skip. Uses a simple \"contains\"-filter."));
+
+ options.add("from <type>", ki18n("Source host type (kolab2, kolab3, exchangeimap, google)"));
options.add("from-host <host>", ki18n("Source host"));
options.add("from-port <port>", ki18n("Port"), "143");
@@ -102,7 +110,7 @@ int main(int argc, char *argv[])
options.add("to-auth <mode>", ki18n("Authentication mode to be used (PLAIN, LOGIN, CRAMMD5, DIGESTMD5, NTLM, GSSAPI, ANONYMOUS, CLEARTEXT)"), "PLAIN");
KCmdLineArgs::addCmdLineOptions( options );
- QCoreApplication app(argc, argv);
+ QApplication app(argc, argv);
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
@@ -141,6 +149,32 @@ int main(int argc, char *argv[])
}
sourceServer = source;
}
+#ifdef BUILD_GOOGLESUPPORT
+ else if (!args->getOption("from").compare("google", Qt::CaseInsensitive)) {
+ Debug() << "From Google Server";
+ GoogleSourceServer *source = new GoogleSourceServer(&app);
+ source->setHost("imap.googlemail.com", 993);
+ source->setAdminCredentials(args->getOption("from-proxyauth"), args->getOption("from-password"));
+ source->setEncryption(KIMAP::LoginJob::TlsV1);
+ source->setAuthentication(KIMAP::LoginJob::ClearText);
+ if (args->isSet("from-user")) {
+ source->setSingleUser(args->getOption("from-user"));
+ }
+ sourceServer = source;
+ }
+#endif //BUILD_GOOGLESUPPORT
+ else if (!args->getOption("from").compare("imap", Qt::CaseInsensitive)) {
+ Debug() << "From IMAP Server";
+ IMAPSourceServer *source = new IMAPSourceServer(&app);
+ source->setHost(args->getOption("from-host"), args->getOption("from-port").toInt());
+ source->setAdminCredentials(args->getOption("from-proxyauth"), args->getOption("from-password"));
+ source->setEncryption(getEncryptionMode(args->getOption("from-encrypt")));
+ source->setAuthentication(getAuthenticationMode(args->getOption("from-auth")));
+ if (args->isSet("from-user")) {
+ source->setSingleUser(args->getOption("from-user"));
+ }
+ sourceServer = source;
+ }
KolabServer *kolabServer = 0;
if (!args->getOption("to").compare("kolab2", Qt::CaseInsensitive)) {
@@ -180,6 +214,9 @@ int main(int argc, char *argv[])
if (args->isSet("statefile")) {
sourceServer->setStatefile(args->getOption("statefile"));
}
+ if (!args->getOptionList("skipFolder").isEmpty()) {
+ sourceServer->setIgnoredFolders(args->getOptionList("skipFolder"));
+ }
CoordinationJob *job = new CoordinationJob(sourceServer, kolabServer, &app);
QObject::connect(job, SIGNAL(finished(KJob*)), &app, SLOT(quit()));
job->start();
diff --git a/migrationutility/migratefolderjob.cpp b/migrationutility/migratefolderjob.cpp
index 32b8200..fd1a09a 100644
--- a/migrationutility/migratefolderjob.cpp
+++ b/migrationutility/migratefolderjob.cpp
@@ -33,14 +33,24 @@ MigrateFolderJob::MigrateFolderJob(const QString &folder, SourceAccount* sourceA
void MigrateFolderJob::start()
{
- qDebug() << "migrating " << mFolder;
+ QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
+}
+
+void MigrateFolderJob::doStart()
+{
+ Debug() << "migrating " << mFolder;
const QPair<Kolab::FolderType, QString> &targetFolder = mSourceAccount->translateFolder(mFolder);
mTargetFolder = targetFolder.second;
mKolabAccount->createFolder(targetFolder.second, targetFolder.first);
- FetchMessagesJob *fetchJob = mSourceAccount->fetchObjects(mFolder);
- fetchJob->setTransient(true);
- connect(fetchJob, SIGNAL(messagesReceived(QString, QList<Object>)), this, SLOT(processMessages(QString, QList<Object>)));
+ FetchObjectsJob *fetchJob = mSourceAccount->fetchObjects(mFolder);
+ if (!fetchJob) {
+ setErrorText("Invalid FetchMessagesJob");
+ setError(KJob::UserDefinedError);
+ emitResult();
+ return;
+ }
+ connect(fetchJob, SIGNAL(objectsReceived(QString, QList<Object>)), this, SLOT(processMessages(QString, QList<Object>)));
connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(fetchJobFinished(KJob*)));
fetchJob->start();
}
diff --git a/migrationutility/migratefolderjob.h b/migrationutility/migratefolderjob.h
index 144ed23..a2f95d8 100644
--- a/migrationutility/migratefolderjob.h
+++ b/migrationutility/migratefolderjob.h
@@ -30,6 +30,7 @@ public:
explicit MigrateFolderJob(const QString &folder, SourceAccount *sourceAccount, KolabAccount *kolabAccount, QObject* parent = 0);
virtual void start();
private Q_SLOTS:
+ void doStart();
void fetchJobFinished(KJob*);
void appendJobFinished(KJob*);
void processMessages(const QString &,const QList<Object>&);
diff --git a/migrationutility/migrateuserjob.cpp b/migrationutility/migrateuserjob.cpp
index c83412e..3b894a9 100644
--- a/migrationutility/migrateuserjob.cpp
+++ b/migrationutility/migrateuserjob.cpp
@@ -21,17 +21,17 @@
#include "kolabaccount.h"
#include <errorhandler.h>
-MigrateUserJob::MigrateUserJob(SourceAccount *sourceAccount, KolabAccount *kolabAccount, QObject* parent)
+MigrateUserJob::MigrateUserJob(const QList<SourceAccount*> &sourceAccounts, KolabAccount *kolabAccount, QObject* parent)
: KJob(parent),
- mSourceAccount(sourceAccount),
+ mSourceAccounts(sourceAccounts),
+ mCurrentSourceAccount(0),
mKolabAccount(kolabAccount)
{
- connect(mSourceAccount, SIGNAL(folderList(QStringList)), this, SLOT(migrateFolders(QStringList)));
}
void MigrateUserJob::start()
{
- if (!mKolabAccount || !mSourceAccount) {
+ if (!mKolabAccount || mSourceAccounts.isEmpty()) {
setError(KJob::UserDefinedError);
setErrorText("Failed to get source or target account");
emitResult();
@@ -39,19 +39,107 @@ void MigrateUserJob::start()
}
mKolabAccount->cleanAccount();
mKolabAccount->setupFolders();
- migrateFolders(mSourceAccount->lookupFolderList());
+ migrateNextAccount();
}
-void MigrateUserJob::migrateFolders(const QStringList &folders)
+void MigrateUserJob::migrateNextAccount()
{
- foreach (const QString &folder, folders) {
- MigrateFolderJob *job = new MigrateFolderJob(folder, mSourceAccount, mKolabAccount, this);
- job->exec();
+ if (mCurrentSourceAccount) {
+ mCurrentSourceAccount->deleteLater();
}
- mSourceAccount->logout();
- mKolabAccount->logout();
- emitResult();
+ if (mSourceAccounts.isEmpty()) {
+ mKolabAccount->logout();
+ emitResult();
+ return;
+ }
+ mCurrentSourceAccount = mSourceAccounts.takeFirst();
+ KJob *loginJob = mCurrentSourceAccount->login();
+ Q_ASSERT(loginJob);
+ connect(loginJob, SIGNAL(result(KJob*)), this, SLOT(onLoginDone(KJob*)));
+ loginJob->start();
+}
+
+void MigrateUserJob::onLoginDone(KJob *job)
+{
+ if (job->error()) {
+ Error() << "Failed to login in source account: " << job->errorString();
+ emitResult();
+ return;
+ }
+ Debug() << "login successful";
+ //Go to eventloop first, to ensure the session is fully initialized before running further jobs
+ QMetaObject::invokeMethod(this, "fetchFolders", Qt::QueuedConnection);
+}
+
+void MigrateUserJob::fetchFolders()
+{
+ FetchFoldersJob *fetchJob = mCurrentSourceAccount->fetchFolderList();
+ if (!fetchJob) {
+ mFolderQueue = mCurrentSourceAccount->lookupFolderList();
+ migrateNextFolder();
+ } else {
+ connect(fetchJob, SIGNAL(foldersReceived(QStringList)), this, SLOT(onFoldersReceived(QStringList)));
+ connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onFoldersFetched(KJob*)));
+ fetchJob->start();
+ }
+}
+
+void MigrateUserJob::onFoldersReceived(const QStringList &folders)
+{
+ mFolderQueue.append(folders);
+}
+
+void MigrateUserJob::onFoldersFetched(KJob* )
+{
+ migrateNextFolder();
}
+void MigrateUserJob::migrateNextFolder()
+{
+ if (!mCurrentFolder.isEmpty()) {
+ Warning() << "already migrating a folder";
+ return;
+ }
+ if (mFolderQueue.isEmpty()) {
+ Debug() << "Account migrated, logging out";
+ KJob *logoutJob = mCurrentSourceAccount->logout();
+ if (logoutJob) {
+ connect(logoutJob, SIGNAL(result(KJob*)), this, SLOT(migrateNextAccount()));
+ logoutJob->start();
+ } else {
+ QMetaObject::invokeMethod(this, "migrateNextAccount", Qt::QueuedConnection);
+ }
+ //TODO here we could delete the source account
+ return;
+ }
+ mCurrentFolder = mFolderQueue.takeFirst();
+ if (isIgnored(mCurrentFolder)) {
+ Debug() << "Skipping source folder: " << mCurrentFolder;
+ mCurrentFolder.clear();
+ migrateNextFolder();
+ }
-// #include "migrateuserjob.moc"
+ MigrateFolderJob *job = new MigrateFolderJob(mCurrentFolder, mCurrentSourceAccount, mKolabAccount, this);
+ connect(job, SIGNAL(result(KJob*)), this, SLOT(onFolderMigrated(KJob*)));
+ job->start();
+}
+
+void MigrateUserJob::onFolderMigrated(KJob *job)
+{
+ if (job->error()) {
+ Error() << "Failed to migrate folder: " << mCurrentFolder;
+ Error() << job->errorString();
+ }
+ mCurrentFolder.clear();
+ migrateNextFolder();
+}
+
+bool MigrateUserJob::isIgnored(const QString &sourceFolder) const
+{
+ foreach (const QString &ignoredFolder, mCurrentSourceAccount->ignoredFolders()) {
+ if (sourceFolder.contains(ignoredFolder)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/migrationutility/migrateuserjob.h b/migrationutility/migrateuserjob.h
index a667708..de5442b 100644
--- a/migrationutility/migrateuserjob.h
+++ b/migrationutility/migrateuserjob.h
@@ -19,20 +19,37 @@
#define MIGRATEUSERJOB_H
#include <kjob.h>
+#include <QStringList>
class SourceAccount;
class KolabAccount;
+
+/**
+ * Migrates a user to his new target account (currently limited to a kolab account as target).
+ *
+ * A user may have multiple source accounts on the source server (i.e. one imap account, one cardav account, ...)
+ */
class MigrateUserJob: public KJob
{
Q_OBJECT
public:
- explicit MigrateUserJob(SourceAccount *sourceAccount, KolabAccount *kolabAccount, QObject* parent = 0);
+ explicit MigrateUserJob(const QList<SourceAccount*> &sourceAccounts, KolabAccount *kolabAccount, QObject* parent = 0);
virtual void start();
private slots:
- void migrateFolders(const QStringList &);
+ void onLoginDone(KJob*);
+ void onFolderMigrated(KJob*);
+ void onFoldersFetched(KJob*);
+ void onFoldersReceived(const QStringList &);
+ void fetchFolders();
+ void migrateNextFolder();
+ void migrateNextAccount();
private:
- SourceAccount *mSourceAccount;
+ bool isIgnored(const QString &) const;
+ QStringList mFolderQueue;
+ QList<SourceAccount*> mSourceAccounts;
+ SourceAccount *mCurrentSourceAccount;
KolabAccount *mKolabAccount;
+ QString mCurrentFolder;
};
#endif // MIGRATEUSERJOB_H
diff --git a/migrationutility/sourceaccount.cpp b/migrationutility/sourceaccount.cpp
index f627f5b..d26dbb1 100644
--- a/migrationutility/sourceaccount.cpp
+++ b/migrationutility/sourceaccount.cpp
@@ -30,383 +30,126 @@
#include <kcalcore/memorycalendar.h>
#include <kcalcore/icalformat.h>
-SourceAccount::SourceAccount(QObject* parent)
-: QObject(parent)
+FetchObjectsJob::FetchObjectsJob(QObject* parent)
+: KJob(parent)
{
}
-QStringList SourceAccount::lookupFolderList()
+FetchFoldersJob::FetchFoldersJob(QObject* parent)
+: KJob(parent)
{
- return QStringList();
-}
-QList<Object> SourceAccount::getObjects(const QString& /* folder */)
-{
- return QList<Object>();
}
-void SourceAccount::logout()
-{
-
-}
-QPair<Kolab::FolderType, QString> SourceAccount::translateFolder(const QString& folder)
-{
- return QPair<Kolab::FolderType, QString>(Kolab::MailType, folder);
-}
-
-void SourceAccount::setStatefile(const StateFile &statefile)
-{
- mStatefile = statefile;
-}
-
-void SourceAccount::recordSuccessfulMigration(const Object &object, const QString &folder)
+SourceAccount::SourceAccount(QObject* parent)
+: QObject(parent)
{
- recordSuccessfulMigration(QList<Object>() << object, folder);
-}
-void SourceAccount::recordSuccessfulMigration(const QList<Object> &/* object */, const QString &/* folder */)
-{
}
-FetchMessagesJob* SourceAccount::fetchObjects(const QString& /* folder */)
+KJob* SourceAccount::login()
{
return 0;
}
-Object SourceAccount::convertObject(const Object &, const QString &)
-{
- return Object();
-}
-
-
-TestAccount::TestAccount(QObject* parent)
- : SourceAccount(parent)
-{
- mFolderList << QLatin1String("folder1");
- mFolderList << QLatin1String("folder2");
- mFolderList << QLatin1String("folder3");
-}
-
-QStringList TestAccount::lookupFolderList()
-{
- return mFolderList;
-}
-
-QList<Object> TestAccount::getObjects(const QString& folder)
-{
- Debug() << folder;
- Q_ASSERT(mFolderList.removeAll(folder) == 1);
- return QList<Object>();
-}
-
-//--------------------------------------------------------------
-
-
-KolabSourceAccount::KolabSourceAccount(KIMAP::Session *session, QObject* parent)
-: SourceAccount(parent),
- mSession(session)
+QStringList SourceAccount::lookupFolderList()
{
-
+ return QStringList();
}
-void KolabSourceAccount::init()
+FetchFoldersJob* SourceAccount::fetchFolderList()
{
- Q_ASSERT(mSession);
-
- ProbeKolabServerJob *probeJob = new ProbeKolabServerJob(mSession, this);
- probeJob->exec();
- mKolabFolders = probeJob->kolabFolders();
- mPersonalNamespaces = probeJob->personalNamespace();
+ return 0;
}
-Kolab::FolderType KolabSourceAccount::getFolderType(const QString &folder)
+QList<Object> SourceAccount::getObjects(const QString &folder)
{
- if (mKolabFolders.values().contains(folder)) {
- return Kolab::folderTypeFromString(mKolabFolders.key(folder).toStdString());
+ mObjectList.clear();
+ FetchObjectsJob *job = fetchObjects(folder);
+ connect(job, SIGNAL(objectsReceived(QString,QList<Object>)), this, SLOT(onObjectsReceived(QString,QList<Object>)));
+ job->exec();
+ QList<Object> objects;
+ foreach (const Object &object, mObjectList) {
+ objects.append(convertObject(object, folder));
}
- return Kolab::MailType;
+ mObjectList.clear();
+ return objects;
}
-QPair<Kolab::FolderType, QString> KolabSourceAccount::translateFolder(const QString& folder)
+void SourceAccount::onObjectsReceived(const QString &, const QList<Object> &objects)
{
- return QPair<Kolab::FolderType, QString>(getFolderType(folder), folder);
+ mObjectList.append(objects);
}
-QStringList KolabSourceAccount::lookupFolderList()
+KJob *SourceAccount::logout()
{
-// Debug() << "lookupFolderList" << mHost << mPort << mUsername << mPw;
- init();
- mMailboxes.clear();
-
- KIMAP::ListJob *listJob = new KIMAP::ListJob(mSession);
- listJob->setOption(KIMAP::ListJob::IncludeUnsubscribed);
- listJob->setQueriedNamespaces(mPersonalNamespaces);
- QObject::connect( listJob, SIGNAL(mailBoxesReceived(QList<KIMAP::MailBoxDescriptor>,QList<QList<QByteArray> >)),
- this, SLOT(mailBoxesReceived(QList<KIMAP::MailBoxDescriptor>,QList<QList<QByteArray> >)));
- listJob->exec();
- Debug() << "found " << mMailboxes.size();
-
- QStringList mailboxes;
- foreach (const KIMAP::MailBoxDescriptor &descriptor, mMailboxes) {
- mailboxes.append(descriptor.name);
- }
- return mailboxes;
+ return 0;
}
-void KolabSourceAccount::mailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList< QList< QByteArray > > &/* flags */)
+QPair<Kolab::FolderType, QString> SourceAccount::translateFolder(const QString& folder)
{
- mMailboxes.append(descriptors);
- //TODO store folder type from metadata
-// for (int i = 0; i < descriptors.size(); i++) {
-// Debug() << descriptors.at(i).name;
-// foreach (const QByteArray &arr, flags.at(i)) {
-// Debug() << arr;
-// }
-// }
+ return QPair<Kolab::FolderType, QString>(Kolab::MailType, folder);
}
-QVariant upgradeMessage(KMime::Message::Ptr msg)
+void SourceAccount::setStatefile(const StateFile &statefile)
{
- //TODO deduplicate with upgradetool, check for errors during reading.
- Kolab::KolabObjectReader reader;
- switch (reader.parseMimeMessage(msg)) {
- case Kolab::EventObject:
- case Kolab::TodoObject:
- case Kolab::JournalObject:
- return QVariant::fromValue(reader.getIncidence());
- case Kolab::ContactObject:
- return QVariant::fromValue(reader.getContact());
- case Kolab::DistlistObject:
- return QVariant::fromValue(reader.getDistlist());
- case Kolab::NoteObject: {
- Note note;
- note.msg = reader.getNote();
- return QVariant::fromValue(note);
- }
- case Kolab::DictionaryConfigurationObject: {
- Dictionary dictionary;
- dictionary.dict = reader.getDictionary(dictionary.lang);
- return QVariant::fromValue(dictionary);
- }
- case Kolab::InvalidObject:
- default:
- //TODO handle configuration objects
- Error() << "failed to read mime file";
- }
- return QVariant();
+ mStatefile = statefile;
}
-void KolabSourceAccount::recordSuccessfulMigration(const QList<Object> &objects, const QString &folder)
+void SourceAccount::recordSuccessfulMigration(const Object &object, const QString &folder)
{
- if (mStatefile.isValid()) {
- QList<qint64> uids;
- foreach (const Object &obj, objects) {
- uids << obj.imapUid;
- }
- mStatefile.appendMigratedUids(folder, uids);
- }
+ recordSuccessfulMigration(QList<Object>() << object, folder);
}
-QList< Object > KolabSourceAccount::getObjects(const QString& folder)
+void SourceAccount::recordSuccessfulMigration(const QList<Object> &/* object */, const QString &/* folder */)
{
- if (mStatefile.isValid()) {
- qDebug() << "Found statfile, only migrating what isn't yet";
- QSet<qint64> sourceUids = getImapUids(folder).toSet();
- qDebug() << "source uids: " << sourceUids.toList();
- sourceUids.subtract(mStatefile.getMigratedUids(folder).toSet());
- qDebug() << "source uids to migrate: " << sourceUids.toList();
- return getObjects(folder, sourceUids.toList());
- }
- return getObjects(folder, QList<qint64>());
}
-QList< Object > KolabSourceAccount::getObjects(const QString& folder, const QList< qint64 >& uids)
+void SourceAccount::setIgnoredFolders(const QStringList &ignoredFolders)
{
- FetchMessagesJob *fetchJob = fetchObjects(folder);
- fetchJob->setTransient(false);
- if (!uids.isEmpty()) {
- fetchJob->setUidsToFetch(uids);
- }
- fetchJob->exec();
- Debug() << fetchJob->getMessages().size();
- QList<Object> messages;
- foreach (const KMime::Message::Ptr &msg, fetchJob->getMessages()) {
- Object obj;
- obj.object = QVariant::fromValue(msg);
- obj.flags = fetchJob->getFlags(msg);
- obj.imapUid = fetchJob->getImapUid(msg);
- obj = convertObject(obj, folder);
- if (!obj.object.isValid()) {
- //TODO just migrate message 1:1, instead of skipping?
- Error() << "got empty message";
- continue;
- }
- messages.append(obj);
- }
- return messages;
+ mIgnoredFolders = ignoredFolders;
}
-FetchMessagesJob* KolabSourceAccount::fetchObjects(const QString& folder)
+QStringList SourceAccount::ignoredFolders() const
{
- FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
- if (mStatefile.isValid()) {
- fetchJob->setUidsToSkip(mStatefile.getMigratedUids(folder));
- }
- return fetchJob;
+ return mIgnoredFolders;
}
-Object KolabSourceAccount::convertObject(const Object& object, const QString& folder)
-{
- bool isKolabType = false;
- if (mKolabFolders.values().contains(folder)) {
- isKolabType = true;
- }
- const KMime::Message::Ptr msg = object.object.value<KMime::Message::Ptr>();
- Object obj(object);
- if (isKolabType) {
- obj.object = upgradeMessage(msg);
- } else {
- obj.object = QVariant::fromValue(msg);
- }
- return obj;
-}
-QList<qint64> KolabSourceAccount::getImapUids(const QString &folder)
+FetchObjectsJob* SourceAccount::fetchObjects(const QString& /* folder */)
{
- FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
- fetchJob->fetchScope().mode = KIMAP::FetchJob::FetchScope::Headers;
- fetchJob->exec();
- Debug() << fetchJob->getMessages().size();
- return fetchJob->getImapUids();
+ return 0;
}
-void KolabSourceAccount::logout()
+Object SourceAccount::convertObject(const Object &object, const QString &) const
{
- KIMAP::LogoutJob *logoutJob = new KIMAP::LogoutJob(mSession);
- logoutJob->exec();
- mSession->close();
- mSession->deleteLater();
- mSession = 0;
- Debug() << "logout done";
+ return object;
}
-
-//--------------------------------------------------------
-
-
-ExchangeIMAPSourceAccount::ExchangeIMAPSourceAccount(KIMAP::Session* session, QObject* parent)
-: KolabSourceAccount(session, parent)
+TestAccount::TestAccount(QObject* parent)
+ : SourceAccount(parent)
{
-
+ mFolderList << QLatin1String("folder1");
+ mFolderList << QLatin1String("folder2");
+ mFolderList << QLatin1String("folder3");
}
-QPair<Kolab::ObjectType, KMime::Content*> ExchangeIMAPSourceAccount::getObjectType(const KMime::Message::Ptr &msg)
+QStringList TestAccount::lookupFolderList()
{
- const QByteArray calendarType("text/calendar");
- const QByteArray vcardType("text/vcard");
- Q_FOREACH(KMime::Content *c, msg->contents()) {
- Debug() << c->contentType()->mimeType();
- if (c->contentType()->mimeType() == calendarType) {
- KCalCore::ICalFormat format;
- KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
- format.fromRawString(calendar, c->decodedContent());
- if (!calendar->events().isEmpty()) {
- return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::EventObject, c);
- } else if (!calendar->todos().isEmpty()) {
- return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::TodoObject, c);
- } else if (!calendar->journals().isEmpty()) {
- return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::JournalObject, c);
- }
- }
- if (c->contentType()->mimeType() == vcardType) {
- return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::ContactObject, c);
- }
- }
- return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::InvalidObject, 0);
+ return mFolderList;
}
-Kolab::FolderType ExchangeIMAPSourceAccount::getFolderType(const QString &folder)
+FetchObjectsJob* TestAccount::fetchObjects(const QString& sourceFolder)
{
- FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
- //Theoretically one would be enough, but in case we have a couple of invalid ones...
- fetchJob->setMaxNumberOfMessagesToFetch(10);
- fetchJob->exec();
- Debug() << fetchJob->getMessages().size();
- QList<Object> messages;
- foreach (const KMime::Message::Ptr &msg, fetchJob->getMessages()) {
- Kolab::ObjectType type = getObjectType(msg).first;
- if (type == Kolab::EventObject) {
- return Kolab::EventType;
- }
- if (type == Kolab::TodoObject) {
- return Kolab::TaskType;
- }
- if (type == Kolab::JournalObject) {
- return Kolab::JournalType;
- }
- if (type == Kolab::ContactObject) {
- return Kolab::ContactType;
- }
- }
- return Kolab::MailType;
+ Debug() << sourceFolder;
+ Q_ASSERT(mFolderList.removeAll(sourceFolder) == 1);
+ return 0;
}
-QPair<Kolab::FolderType, QString> ExchangeIMAPSourceAccount::translateFolder(const QString& folder)
+KJob* TestAccount::login()
{
- return QPair<Kolab::FolderType, QString>(getFolderType(folder), folder);
+ return new DummyJob;
}
-QList<Object> ExchangeIMAPSourceAccount::getObjects(const QString& folder)
-{
- Debug() << folder;
- FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
- fetchJob->exec();
- Debug() << fetchJob->getMessages().size();
- QList<Object> messages;
- foreach (const KMime::Message::Ptr &msg, fetchJob->getMessages()) {
- QPair<Kolab::ObjectType, KMime::Content*> type = getObjectType(msg);
- Debug() << type.first;
- if (type.first == Kolab::InvalidObject) {
- Object obj;
- obj.object = QVariant::fromValue(msg);
- obj.flags = fetchJob->getFlags(msg);
- messages.append(obj);
- } else if (type.first == Kolab::EventObject || type.first == Kolab::TodoObject || type.first == Kolab::JournalObject) {
- const QByteArray content = type.second->decodedContent();
- Debug() << "Found event object: " << content;
- KCalCore::ICalFormat format;
- KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
- format.fromRawString(calendar, content);
-
- //We're simply assuming here that we never have different incidence types mixed in a folder
- foreach (const KCalCore::Incidence::Ptr &inc, calendar->incidences()) {
- Object obj;
- obj.object = QVariant::fromValue(inc);
- obj.flags = fetchJob->getFlags(msg);
- if (!obj.object.isValid()) {
- Error() << "got empty message";
- continue;
- }
- messages.append(obj);
- }
- } else if (type.first == Kolab::ContactObject) {
- const QByteArray content = type.second->decodedContent();
- Debug() << "Found contact object: " << content;
- KABC::VCardConverter format;
- const KABC::Addressee addressee = format.parseVCard(content);
-
- Object obj;
- obj.object = QVariant::fromValue(addressee);
- obj.flags = fetchJob->getFlags(msg);
- if (!obj.object.isValid()) {
- Error() << "got empty message";
- continue;
- }
- messages.append(obj);
- }
-
- }
- return messages;
-}
diff --git a/migrationutility/sourceaccount.h b/migrationutility/sourceaccount.h
index 19ba4f7..db43062 100644
--- a/migrationutility/sourceaccount.h
+++ b/migrationutility/sourceaccount.h
@@ -29,29 +29,132 @@
#include "jobs/fetchmessagesjob.h"
#include "statefile.h"
+/**
+ * Job interface to retrieve objects from a folder.
+ */
+class FetchObjectsJob: public KJob
+{
+ Q_OBJECT
+public:
+ explicit FetchObjectsJob(QObject* parent = 0);
+Q_SIGNALS:
+ /**
+ * Emitted when objects are received from a folder.
+ * First arument is the sourcefolder that the objects where fetched from.
+ */
+ void objectsReceived(QString, QList<Object>);
+};
+
+/**
+ * Job interface to retrieve folder of an account.
+ */
+class FetchFoldersJob: public KJob
+{
+ Q_OBJECT
+public:
+ explicit FetchFoldersJob(QObject* parent = 0);
+Q_SIGNALS:
+ /**
+ * Emitted when objects are received from a folder.
+ * First arument is the sourcefolder that the objects where fetched from.
+ */
+ void foldersReceived(QStringList);
+};
+
+/**
+ * Represents a single users account on a server.
+ *
+ * This class is used as factory for the jobs to extract the necessary data that needs to be migrated.
+ *
+ * One account typically represents access via a single protocol (i.e. an imap account).
+ */
class SourceAccount: public QObject
{
Q_OBJECT
public:
explicit SourceAccount(QObject* parent = 0);
+ /**
+ * Login to the source account.
+ *
+ * If the job is sucessful, a session has been established and the source account can be used.
+ */
+ virtual KJob *login();
+
+ /*
+ * Synchronous lookup of folder list
+ */
virtual QStringList lookupFolderList();
- virtual QList<Object> getObjects(const QString &folder);
- virtual FetchMessagesJob *fetchObjects(const QString &folder);
- virtual Object convertObject(const Object &object, const QString& folder);
- virtual void logout();
- virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
+
+ /**
+ * Asynchronous lookup of folders
+ */
+ virtual FetchFoldersJob *fetchFolderList();
+
+ /**
+ * Synchronous wrapper around fetch objects + convertObject
+ *
+ * Use only for testing.
+ *
+ * Returns all objects of the source folder already converted using convertObject.
+ */
+ QList<Object> getObjects(const QString &sourceFolder);
+
+ /**
+ * Async method to retrieve objects
+ *
+ * used in combination with convertObject to stream objects.
+ *
+ * @param sourceFolder Folder on the source server to fetch objects from.
+ */
+ virtual FetchObjectsJob *fetchObjects(const QString &sourceFolder);
+
+ /**
+ * convert source object to target object.
+ * Used when streaming objects.
+ */
+ virtual Object convertObject(const Object &object, const QString& sourceFolder) const;
+
+ /**
+ * Close connection to source account;
+ */
+ virtual KJob *logout();
+
+ /**
+ * Translate source folder to target folder
+ */
+ virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& sourceFolder);
+
+ /**
+ * Set a statefile to record migration progress.
+ * This allows to resume the migration.
+ */
void setStatefile(const StateFile &);
+
+ /**
+ * Convenience method to record the migration of a single object.
+ */
void recordSuccessfulMigration(const Object &obj, const QString &folder);
- virtual void recordSuccessfulMigration(const QList<Object> &obj, const QString &folder);
-signals:
- void folderList(const QStringList &);
-// FindFoldersJob *getFolderList();
-// GetObjectsJob *getObjects(const QString &folder);
-// KolabObject convertObject();
-// QString getDestinationFolder(const QString &folder);
+
+ /**
+ * Record the sucessful migration of an object.
+ */
+ virtual void recordSuccessfulMigration(const QList<Object> &obj, const QString &sourceFolder);
+
+ /**
+ * Specify a list of regex to ignore source folders.
+ */
+ void setIgnoredFolders(const QStringList &);
+ virtual QStringList ignoredFolders() const;
+
protected:
StateFile mStatefile;
+private slots:
+ void onObjectsReceived(const QString &, const QList<Object> &);
+
+private:
+ QList<Object> mObjectList;
+ QStringList mIgnoredFolders;
};
class TestAccount: public SourceAccount
@@ -60,49 +163,14 @@ class TestAccount: public SourceAccount
public:
explicit TestAccount(QObject* parent = 0);
virtual QStringList lookupFolderList();
- virtual QList<Object> getObjects(const QString &folder);
+ virtual FetchObjectsJob *fetchObjects(const QString &sourceFolder);
+ virtual KJob *login();
QStringList mFolderList;
+private:
+ class DummyJob : public KJob {
+ virtual void start() {emitResult();}
+ };
};
-class KolabSourceAccount: public SourceAccount
-{
- Q_OBJECT
-public:
- explicit KolabSourceAccount(KIMAP::Session *session, QObject* parent = 0);
- virtual QStringList lookupFolderList();
- virtual QList<Object> getObjects(const QString &folder);
- QList<Object> getObjects(const QString& folder, const QList<qint64> &imapUids);
- virtual FetchMessagesJob *fetchObjects(const QString &folder);
- virtual Object convertObject(const Object &object, const QString& folder);
- QList<qint64> getImapUids(const QString &folder);
- virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
-
- void logout();
- virtual void recordSuccessfulMigration(const QList<Object> &obj, const QString &folder);
-
-private slots:
- void mailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList< QList< QByteArray > > &flags);
-protected:
- void init();
- Kolab::FolderType getFolderType(const QString &folder);
- KIMAP::Session *mSession;
- KIMAP::LoginJob::EncryptionMode mEncryptionMode;
- KIMAP::LoginJob::AuthenticationMode mAuthenticationMode;
- QList<KIMAP::MailBoxDescriptor> mMailboxes;
- QList<KIMAP::MailBoxDescriptor> mPersonalNamespaces;
- QMultiHash<QString, QString> mKolabFolders;
-};
-
-class ExchangeIMAPSourceAccount: public KolabSourceAccount
-{
- Q_OBJECT
-public:
- explicit ExchangeIMAPSourceAccount(KIMAP::Session *session, QObject* parent = 0);
- Kolab::FolderType getFolderType(const QString &folder);
- QPair<Kolab::ObjectType, KMime::Content*> getObjectType(const KMime::Message::Ptr &msg);
- virtual QList<Object> getObjects(const QString &folder);
- virtual QPair<Kolab::FolderType, QString> translateFolder(const QString& folder);
-};
-
#endif // SOURCEACCOUNT_H
diff --git a/migrationutility/sourceserver.cpp b/migrationutility/sourceserver.cpp
index 1b668e3..934ca6e 100644
--- a/migrationutility/sourceserver.cpp
+++ b/migrationutility/sourceserver.cpp
@@ -22,6 +22,8 @@
#include <kimap/logoutjob.h>
#include <commonconversion.h>
#include <errorhandler.h>
+#include "kolabsourceaccount.h"
+#include "exchangesourceaccount.h"
SourceServer::SourceServer(QObject* parent): QObject(parent)
@@ -29,12 +31,15 @@ SourceServer::SourceServer(QObject* parent): QObject(parent)
}
-SourceAccount* SourceServer::getSourceAccount(const QString& /* user */)
+QList<SourceAccount*> SourceServer::getSourceAccounts(const QString &user)
{
- return 0;
+ const QList<SourceAccount*> accounts = getSourceAccountsImpl(user);
+ foreach (SourceAccount * account, accounts) {
+ account->setIgnoredFolders(mIgnoredFolders);
+ }
+ return accounts;
}
-
QStringList SourceServer::getUserList()
{
if (!mExplicitUsers.isEmpty()) {
@@ -58,6 +63,18 @@ void SourceServer::setStatefile(const QString &statefile)
mStatefile = statefile;
}
+void SourceServer::setIgnoredFolders(const QStringList &ignoredFolders)
+{
+ Debug() << "Skipping source folders: " << ignoredFolders;
+ mIgnoredFolders = ignoredFolders;
+}
+
+QStringList SourceServer::ignoredFolders() const
+{
+ return mIgnoredFolders;
+}
+
+
TestServer::TestServer(QObject* parent)
: SourceServer(parent)
@@ -72,17 +89,16 @@ QStringList TestServer::retrieveUserList()
return mUsers;
}
-SourceAccount* TestServer::getSourceAccount(const QString& user)
+QList<SourceAccount*> TestServer::getSourceAccountsImpl(const QString& user)
{
Q_UNUSED(user);
Q_ASSERT(mUsers.removeAll(user) == 1);
- return new TestAccount(this);
+ return QList<SourceAccount*>() << new TestAccount(this);
}
-
//---------------------------------------------------------------------------
-KolabSourceServer::KolabSourceServer(QObject* parent)
+IMAPSourceServer::IMAPSourceServer(QObject* parent)
: SourceServer(parent),
mSession(0),
mEncryptionMode(KIMAP::LoginJob::TlsV1),
@@ -91,73 +107,55 @@ KolabSourceServer::KolabSourceServer(QObject* parent)
}
-void KolabSourceServer::setHost(const QString& host, qint16 port)
+void IMAPSourceServer::setHost(const QString& host, qint16 port)
{
mHost = host;
mPort = port;
}
-void KolabSourceServer::setAdminCredentials(const QString& username, const QString& pw)
+void IMAPSourceServer::setAdminCredentials(const QString& username, const QString& pw)
{
mUsername = username;
mPw = pw;
}
-void KolabSourceServer::setEncryption(KIMAP::LoginJob::EncryptionMode enc)
+void IMAPSourceServer::setEncryption(KIMAP::LoginJob::EncryptionMode enc)
{
mEncryptionMode = enc;
}
-void KolabSourceServer::setAuthentication(KIMAP::LoginJob::AuthenticationMode auth)
+void IMAPSourceServer::setAuthentication(KIMAP::LoginJob::AuthenticationMode auth)
{
mAuthenticationMode = auth;
}
-SourceAccount* KolabSourceServer::getSourceAccount(const QString& user)
+QList<SourceAccount*> IMAPSourceServer::getSourceAccountsImpl(const QString& user)
{
- KIMAP::Session *session = createSession(mHost, mPort, this);
- KIMAP::LoginJob *loginJob = new KIMAP::LoginJob( session );
- if (user != mUsername) {
- loginJob->setAuthorizationName(mUsername);
- }
- loginJob->setUserName( user );
- loginJob->setPassword( mPw );
- loginJob->setEncryptionMode( mEncryptionMode );
- loginJob->setAuthenticationMode( mAuthenticationMode );
- loginJob->exec();
-
- if ( loginJob->error() ) {
- Error() << "Failed to login: " << loginJob->errorString();
- session->deleteLater();
- return 0;
- } else {
- Debug() << "authentication successful";
- }
-
- KolabSourceAccount *account = new KolabSourceAccount(session, this);
+ IMAPSourceAccount *account = new IMAPSourceAccount(this);
+ account->prepareConnection(mHost, mPort, mUsername, user, mPw, mEncryptionMode, mAuthenticationMode);
if (!mStatefile.isEmpty()) {
account->setStatefile(StateFile(mStatefile, user));
}
- return account;
+ return QList<SourceAccount*>() << account;
}
-QStringList KolabSourceServer::retrieveUserList()
+QStringList IMAPSourceServer::retrieveUserList()
{
mSession = createSession(mHost, mPort, this);
-
+
KIMAP::LoginJob *loginJob = new KIMAP::LoginJob( mSession );
loginJob->setUserName( mUsername );
loginJob->setPassword( mPw );
loginJob->setEncryptionMode( mEncryptionMode );
loginJob->setAuthenticationMode( mAuthenticationMode );
loginJob->exec();
-
+
if ( loginJob->error() ) {
Warning() << "Failed to login: " << loginJob->errorString();
} else {
Debug() << "authentication successful";
}
-
+
GetUserListJob *userListJob = new GetUserListJob(mSession, this);
userListJob->exec();
const QStringList userList = userListJob->getUserList();
@@ -167,7 +165,7 @@ QStringList KolabSourceServer::retrieveUserList()
}
-void KolabSourceServer::logout()
+void IMAPSourceServer::logout()
{
Q_ASSERT(mSession);
KIMAP::LogoutJob *logoutJob = new KIMAP::LogoutJob(mSession);
@@ -178,34 +176,36 @@ void KolabSourceServer::logout()
Debug() << "logout done";
}
-//---------------------------------------------------------------------
-ExchangeIMAPSourceServer::ExchangeIMAPSourceServer(QObject* parent)
-: KolabSourceServer(parent)
+//---------------------------------------------------------------------------
+
+KolabSourceServer::KolabSourceServer(QObject* parent)
+: IMAPSourceServer(parent)
{
}
-SourceAccount* ExchangeIMAPSourceServer::getSourceAccount(const QString& user)
+QList<SourceAccount*> KolabSourceServer::getSourceAccountsImpl(const QString& user)
{
- KIMAP::Session *session = createSession(mHost, mPort, this);
- KIMAP::LoginJob *loginJob = new KIMAP::LoginJob( session );
- if (user != mUsername) {
- loginJob->setAuthorizationName(mUsername);
+ KolabSourceAccount *account = new KolabSourceAccount(this);
+ account->prepareConnection(mHost, mPort, mUsername, user, mPw, mEncryptionMode, mAuthenticationMode);
+ if (!mStatefile.isEmpty()) {
+ account->setStatefile(StateFile(mStatefile, user));
}
- loginJob->setUserName( user );
- loginJob->setPassword( mPw );
- loginJob->setEncryptionMode( mEncryptionMode );
- loginJob->setAuthenticationMode( mAuthenticationMode );
- loginJob->exec();
+ return QList<SourceAccount*>() << account;
+}
- if ( loginJob->error() ) {
- Error() << "Failed to login: " << loginJob->errorString();
- session->deleteLater();
- return 0;
- } else {
- Debug() << "authentication successful";
- }
-
- return new ExchangeIMAPSourceAccount(session, this);
+//---------------------------------------------------------------------
+
+ExchangeIMAPSourceServer::ExchangeIMAPSourceServer(QObject* parent)
+: IMAPSourceServer(parent)
+{
+
+}
+
+QList<SourceAccount*> ExchangeIMAPSourceServer::getSourceAccountsImpl(const QString& user)
+{
+ ExchangeIMAPSourceAccount *account = new ExchangeIMAPSourceAccount(this);
+ account->prepareConnection(mHost, mPort, mUsername, user, mPw, mEncryptionMode, mAuthenticationMode);
+ return QList<SourceAccount*>() << account;
}
diff --git a/migrationutility/sourceserver.h b/migrationutility/sourceserver.h
index e59c16a..08881d9 100644
--- a/migrationutility/sourceserver.h
+++ b/migrationutility/sourceserver.h
@@ -24,20 +24,37 @@
#include <QStringList>
#include "sourceaccount.h"
+/**
+ * The source server represents a server with user accounts that need to be migrated.
+ *
+ * The server can support multiple access protocols per user, that are each represented by a source account.
+ */
class SourceServer: public QObject
{
Q_OBJECT
public:
explicit SourceServer(QObject* parent = 0);
-// void setAdminCredentials(const QString &username, const QString &pw);
- virtual SourceAccount *getSourceAccount(const QString &user);
+ QList<SourceAccount*> getSourceAccounts(const QString &user);
QStringList getUserList();
- virtual QStringList retrieveUserList();
void setSingleUser(const QString &);
void setStatefile(const QString &);
+
+ /**
+ * Specify a list of regex to ignore source folders.
+ */
+ void setIgnoredFolders(const QStringList &);
+ QStringList ignoredFolders() const;
protected:
+ /**
+ * Reeimplement to retrieve a user list from the server.
+ * Note that the retrieved username is used to login to the users account on the source server.
+ */
+ virtual QStringList retrieveUserList();
+ virtual QList<SourceAccount*> getSourceAccountsImpl(const QString &user) = 0;
QStringList mExplicitUsers;
QString mStatefile;
+private:
+ QStringList mIgnoredFolders;
};
@@ -47,25 +64,25 @@ class TestServer: public SourceServer
public:
explicit TestServer(QObject* parent = 0);
- virtual SourceAccount *getSourceAccount(const QString &user);
- virtual QStringList retrieveUserList();
QStringList mUsers;
+protected:
+ virtual QStringList retrieveUserList();
+ virtual QList< SourceAccount* > getSourceAccountsImpl(const QString& user);
};
-class KolabSourceServer: public SourceServer
+class IMAPSourceServer: public SourceServer
{
Q_OBJECT
public:
- explicit KolabSourceServer(QObject* parent = 0);
-
- virtual SourceAccount *getSourceAccount(const QString &user);
- virtual QStringList retrieveUserList();
+ explicit IMAPSourceServer(QObject* parent = 0);
void setHost(const QString &host, qint16 port);
void setAdminCredentials(const QString &username, const QString &pw);
void setEncryption(KIMAP::LoginJob::EncryptionMode);
void setAuthentication(KIMAP::LoginJob::AuthenticationMode);
protected:
+ virtual QStringList retrieveUserList();
+ virtual QList< SourceAccount* > getSourceAccountsImpl(const QString& user);
void logout();
KIMAP::Session *mSession;
QString mHost;
@@ -76,13 +93,24 @@ protected:
KIMAP::LoginJob::AuthenticationMode mAuthenticationMode;
};
-class ExchangeIMAPSourceServer: public KolabSourceServer
+class KolabSourceServer: public IMAPSourceServer
+{
+ Q_OBJECT
+public:
+ explicit KolabSourceServer(QObject* parent = 0);
+
+protected:
+ virtual QList< SourceAccount* > getSourceAccountsImpl(const QString& user);
+};
+
+class ExchangeIMAPSourceServer: public IMAPSourceServer
{
Q_OBJECT
public:
explicit ExchangeIMAPSourceServer(QObject* parent = 0);
- virtual SourceAccount *getSourceAccount(const QString &user);
+protected:
+ virtual QList< SourceAccount* > getSourceAccountsImpl(const QString& user);
};
#endif // SOURCESERVER_H
diff --git a/migrationutility/tests/CMakeLists.txt b/migrationutility/tests/CMakeLists.txt
index da3e5a9..c9b49fc 100644
--- a/migrationutility/tests/CMakeLists.txt
+++ b/migrationutility/tests/CMakeLists.txt
@@ -1,41 +1,28 @@
if (NOT CMAKE_BUILD_TYPE MATCHES "debug*")
- message(SEND_ERROR "The tests require a debugbuild (for for enabled asserts), and will otherwise probably fail")
+ message(SEND_ERROR "The tests require a debugbuild (for enabled asserts), and will otherwise probably fail")
endif ()
-include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. )
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-# QT4_WRAP_CPP(MIGRATIONTEST_MOC
-# ${CMAKE_CURRENT_SOURCE_DIR}/migrationtest.cpp
-# )
-
-
-# QT4_AUTOMOC(
-# ${CMAKE_CURRENT_SOURCE_DIR}/migrationtest.cpp
-# )
-qt4_generate_moc(
- ${CMAKE_CURRENT_SOURCE_DIR}/migrationtest.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/migrationtest.moc
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_BINARY_DIR}
)
-# message("blasbblab ${kolabproxy_shared_relative_SRCS} : ${MIGRATION_SRCS}")
-# message("sdfsdf ${MIGRATIONTEST_MOC}")
+set(MIGRATIONTEST_DEPENDENCIES
+ migration_static
+ ${COMMON_DEPENDENCIES}
+ ${QT_QTTEST_LIBRARY}
+ ${MIGRATION_LIBRARIES}
+)
-add_executable(migrationtest ${MIGRATION_SRCS} ${MIGRATION_MOC} migrationtest.cpp migrationtest.moc)
-# set_target_properties(migrationtest PROPERTIES AUTOMOC TRUE)
-target_link_libraries(migrationtest ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils)
+qt4_automoc(migrationtest.cpp)
+add_executable(migrationtest migrationtest.cpp)
+target_link_libraries(migrationtest ${MIGRATIONTEST_DEPENDENCIES})
-qt4_generate_moc(
- ${CMAKE_CURRENT_SOURCE_DIR}/migrationscenariotest.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/migrationscenariotest.moc
-)
-add_executable(migrationscenariotest ${MIGRATION_SRCS} ${MIGRATION_MOC} migrationscenariotest.cpp migrationscenariotest.moc)
-target_link_libraries(migrationscenariotest ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils)
+qt4_automoc(migrationscenariotest.cpp)
+add_executable(migrationscenariotest migrationscenariotest.cpp)
+target_link_libraries(migrationscenariotest ${MIGRATIONTEST_DEPENDENCIES})
-qt4_generate_moc(
- ${CMAKE_CURRENT_SOURCE_DIR}/exchangeimaptest.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/exchangeimaptest.moc
-)
-add_executable(exchangeimaptest ${MIGRATION_SRCS} ${MIGRATION_MOC} exchangeimaptest.cpp exchangeimaptest.moc)
-target_link_libraries(exchangeimaptest ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils)
+qt4_automoc(exchangeimaptest.cpp)
+add_executable(exchangeimaptest exchangeimaptest.cpp)
+target_link_libraries(exchangeimaptest ${MIGRATIONTEST_DEPENDENCIES})
diff --git a/migrationutility/tests/exchangeimaptest.cpp b/migrationutility/tests/exchangeimaptest.cpp
index 281485c..cf83b66 100644
--- a/migrationutility/tests/exchangeimaptest.cpp
+++ b/migrationutility/tests/exchangeimaptest.cpp
@@ -14,8 +14,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "exchangeimaptest.h"
-#include <QObject>
#include <QTest>
#include <QDebug>
#include <kolabobject.h>
@@ -28,274 +28,258 @@
#include "lib/kolabaccount.h"
#include "lib/testlib/testutils.h"
+QPair<Object, Object> ExchangeIMAPTest::createEvent(const QString &uid)
+{
+ KMime::Message::Ptr msg(new KMime::Message);
+ msg->userAgent()->from7BitString( "exchangeimaptest" );
+ msg->contentType()->setMimeType( "multipart/mixed" );
+ msg->contentType()->setBoundary( KMime::multiPartBoundary() );
-/**
- * This test simulates an entier migration scenario.
- *
- * It requires two Kolab Servers, with all the required users already setup (ideally two local virtual machines, which are used for testing only)
- * So this is really a complex integration test, which involves all parts of the system, and not a unittest which has to be executed all the time.
- * On the other hand it should come quite close to a real world migration scenario and can also show problems with specific imap servers.
- *
- */
-class ExchangeIMAPTest: public QObject
+ KMime::Content* content = new KMime::Content();
+ content->contentType()->setMimeType( "text/calendar" );
+ content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
+ content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
+ KCalCore::Event::Ptr event(new KCalCore::Event());
+ event->setUid(uid);
+ event->setDtStart(KDateTime::currentUtcDateTime());
+ KCalCore::ICalFormat format;
+ KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
+ calendar->addEvent(event);
+ QByteArray decodedContent = format.toString(calendar, QString(), false).toLatin1();
+ content->setBody( decodedContent );
+
+ msg->addContent(content);
+ msg->assemble();
+
+ Object calObj1;
+ calObj1.object = QVariant::fromValue(msg);
+ calObj1.flags << QByteArray("\\Seen");
+
+ Object targetObject;
+ targetObject.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event));
+ targetObject.flags << QByteArray("\\Seen");
+ return QPair<Object,Object>(calObj1, targetObject);
+
+}
+
+QPair<Object, Object> ExchangeIMAPTest::createTodo(const QString &uid)
{
- Q_OBJECT
-
- QString sourcehost;
- QString targethost;
- QString user;
- QString admin;
- QString adminpw;
- qint16 port;
- QList<Folder> folders;
- QList<Folder> targetFolders;
-
- QPair<Object, Object> createEvent(const QString &uid)
- {
- KMime::Message::Ptr msg(new KMime::Message);
- msg->userAgent()->from7BitString( "exchangeimaptest" );
- msg->contentType()->setMimeType( "multipart/mixed" );
- msg->contentType()->setBoundary( KMime::multiPartBoundary() );
-
- KMime::Content* content = new KMime::Content();
- content->contentType()->setMimeType( "text/calendar" );
- content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
- content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
- KCalCore::Event::Ptr event(new KCalCore::Event());
- event->setUid(uid);
- event->setDtStart(KDateTime::currentUtcDateTime());
- KCalCore::ICalFormat format;
- KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
- calendar->addEvent(event);
- QByteArray decodedContent = format.toString(calendar, QString(), false).toLatin1();
- content->setBody( decodedContent );
-
- msg->addContent(content);
- msg->assemble();
-
- Object calObj1;
- calObj1.object = QVariant::fromValue(msg);
- calObj1.flags << QByteArray("\\Seen");
-
- Object targetObject;
- targetObject.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event));
- targetObject.flags << QByteArray("\\Seen");
- return QPair<Object,Object>(calObj1, targetObject);
+ KMime::Message::Ptr msg(new KMime::Message);
+ msg->userAgent()->from7BitString( "exchangeimaptest" );
+ msg->contentType()->setMimeType( "multipart/mixed" );
+ msg->contentType()->setBoundary( KMime::multiPartBoundary() );
- }
-
- QPair<Object, Object> createTodo(const QString &uid)
- {
- KMime::Message::Ptr msg(new KMime::Message);
- msg->userAgent()->from7BitString( "exchangeimaptest" );
- msg->contentType()->setMimeType( "multipart/mixed" );
- msg->contentType()->setBoundary( KMime::multiPartBoundary() );
-
- KMime::Content* content = new KMime::Content();
- content->contentType()->setMimeType( "text/calendar" );
- content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
- content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
- KCalCore::Todo::Ptr event(new KCalCore::Todo());
- event->setUid(uid);
- event->setDtStart(KDateTime::currentUtcDateTime());
- KCalCore::ICalFormat format;
- KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
- calendar->addTodo(event);
- QByteArray decodedContent = format.toString(calendar, QString(), false).toLatin1();
- content->setBody( decodedContent );
-
- msg->addContent(content);
- msg->assemble();
-
- Object calObj1;
- calObj1.object = QVariant::fromValue(msg);
- calObj1.flags << QByteArray("\\Seen");
-
- Object targetObject;
- targetObject.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeTodo(event));
- targetObject.flags << QByteArray("\\Seen");
- return QPair<Object,Object>(calObj1, targetObject);
+ KMime::Content* content = new KMime::Content();
+ content->contentType()->setMimeType( "text/calendar" );
+ content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
+ content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
+ KCalCore::Todo::Ptr event(new KCalCore::Todo());
+ event->setUid(uid);
+ event->setDtStart(KDateTime::currentUtcDateTime());
+ KCalCore::ICalFormat format;
+ KCalCore::MemoryCalendar::Ptr calendar(new KCalCore::MemoryCalendar(KDateTime::Spec::UTC()));
+ calendar->addTodo(event);
+ QByteArray decodedContent = format.toString(calendar, QString(), false).toLatin1();
+ content->setBody( decodedContent );
- }
-
- QPair<Object, Object> createContact(const QString &name)
- {
-
- KABC::Addressee addressee;
- addressee.setNameFromString(name);
-
- KMime::Message::Ptr msg(new KMime::Message);
- msg->userAgent()->from7BitString( "exchangeimaptest" );
- msg->contentType()->setMimeType( "multipart/mixed" );
- msg->contentType()->setBoundary( KMime::multiPartBoundary() );
-
- KMime::Content* content = new KMime::Content();
- content->contentType()->setMimeType( "text/vcard" );
- content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
- content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
- KABC::VCardConverter converter;
- QByteArray decodedContent = converter.createVCard(addressee);
- content->setBody( decodedContent );
-
- msg->addContent(content);
- msg->assemble();
-
- Object calObj1;
- calObj1.object = QVariant::fromValue(msg);
- calObj1.flags << QByteArray("\\Seen");
-
- Object targetObject;
- targetObject.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeContact(addressee));
- targetObject.flags << QByteArray("\\Seen");
- return QPair<Object,Object>(calObj1, targetObject);
- }
+ msg->addContent(content);
+ msg->assemble();
- Object createMail(const QString &subject)
- {
- KMime::Message::Ptr msg(new KMime::Message);
- msg->userAgent()->from7BitString( "exchangeimaptest" );
- msg->contentType()->setMimeType( "multipart/mixed" );
- msg->contentType()->setBoundary( KMime::multiPartBoundary() );
- msg->subject()->fromUnicodeString( subject, "utf-8" );
- msg->assemble();
- Object targetObject;
- targetObject.object = QVariant::fromValue(msg);
- targetObject.flags << QByteArray("\\Seen");
- return targetObject;
- }
+ Object calObj1;
+ calObj1.object = QVariant::fromValue(msg);
+ calObj1.flags << QByteArray("\\Seen");
+
+ Object targetObject;
+ targetObject.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeTodo(event));
+ targetObject.flags << QByteArray("\\Seen");
+ return QPair<Object,Object>(calObj1, targetObject);
-public:
- explicit ExchangeIMAPTest(QObject* parent = 0)
- : QObject(parent),
- sourcehost("192.168.122.104"),
- targethost("192.168.122.10"),
- user("john.doe@example.org"),
- admin("cyrus-admin"),
- adminpw("admin"),
- port(143)
- {
- folders << Folder("INBOX", Kolab::MailType, QList<Object>() << createMail("subject"));
- folders << Folder("Calendar", Kolab::MailType, QList<Object>() << createEvent("uid1").first);
- folders << Folder("Tasks", Kolab::MailType, QList<Object>() << createTodo("uid2").first);
- folders << Folder("Contacts", Kolab::MailType, QList<Object>() << createContact("John Doe").first);
- folders << Folder("Drafts", Kolab::MailType, QList<Object>() << createMail("subject2"));
- folders << Folder("Sent");
- folders << Folder("Trash");
-
- targetFolders << Folder("INBOX", Kolab::MailType, QList<Object>() << createMail("subject"));
- targetFolders << Folder("Calendar", Kolab::EventType, QList<Object>() << createEvent("uid1").second);
+}
+
+QPair<Object, Object> ExchangeIMAPTest::createContact(const QString &name)
+{
+
+ KABC::Addressee addressee;
+ addressee.setNameFromString(name);
+
+ KMime::Message::Ptr msg(new KMime::Message);
+ msg->userAgent()->from7BitString( "exchangeimaptest" );
+ msg->contentType()->setMimeType( "multipart/mixed" );
+ msg->contentType()->setBoundary( KMime::multiPartBoundary() );
+
+ KMime::Content* content = new KMime::Content();
+ content->contentType()->setMimeType( "text/vcard" );
+ content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
+ content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
+ KABC::VCardConverter converter;
+ QByteArray decodedContent = converter.createVCard(addressee);
+ content->setBody( decodedContent );
+
+ msg->addContent(content);
+ msg->assemble();
+
+ Object calObj1;
+ calObj1.object = QVariant::fromValue(msg);
+ calObj1.flags << QByteArray("\\Seen");
+
+ Object targetObject;
+ targetObject.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeContact(addressee));
+ targetObject.flags << QByteArray("\\Seen");
+ return QPair<Object,Object>(calObj1, targetObject);
+}
+
+Object ExchangeIMAPTest::createMail(const QString &subject)
+{
+ KMime::Message::Ptr msg(new KMime::Message);
+ msg->userAgent()->from7BitString( "exchangeimaptest" );
+ msg->contentType()->setMimeType( "multipart/mixed" );
+ msg->contentType()->setBoundary( KMime::multiPartBoundary() );
+ msg->subject()->fromUnicodeString( subject, "utf-8" );
+ msg->assemble();
+ Object targetObject;
+ targetObject.object = QVariant::fromValue(msg);
+ targetObject.flags << QByteArray("\\Seen");
+ return targetObject;
+}
+
+ExchangeIMAPTest::ExchangeIMAPTest(QObject* parent)
+ : QObject(parent),
+ sourcehost("192.168.122.104"),
+ targethost("192.168.122.10"),
+ user("john.doe@example.org"),
+ admin("cyrus-admin"),
+ adminpw("admin"),
+ port(143)
+{
+ folders << Folder("INBOX", Kolab::MailType, QList<Object>() << createMail("subject"));
+ folders << Folder("Calendar", Kolab::MailType, QList<Object>() << createEvent("uid1").first);
+ folders << Folder("Tasks", Kolab::MailType, QList<Object>() << createTodo("uid2").first);
+ folders << Folder("Contacts", Kolab::MailType, QList<Object>() << createContact("John Doe").first);
+ folders << Folder("Drafts", Kolab::MailType, QList<Object>() << createMail("subject2"));
+ folders << Folder("Sent");
+ folders << Folder("Trash");
+
+ targetFolders << Folder("INBOX", Kolab::MailType, QList<Object>() << createMail("subject"));
+ targetFolders << Folder("Calendar", Kolab::EventType, QList<Object>() << createEvent("uid1").second);
// targetFolders << Folder("Calendar/Personal Calendar", Kolab::EventType, QList<Object>() << createEvent("uid2"));
- targetFolders << Folder("Configuration", Kolab::ConfigurationType);
- targetFolders << Folder("Contacts", Kolab::ContactType, QList<Object>() << createContact("John Doe").second);
- targetFolders << Folder("Drafts", Kolab::MailType, QList<Object>() << createMail("subject2"));
- targetFolders << Folder("Journal", Kolab::JournalType);
- targetFolders << Folder("Notes", Kolab::NoteType);
- targetFolders << Folder("Sent");
- targetFolders << Folder("Tasks", Kolab::TaskType, QList<Object>() << createTodo("uid2").second);
- targetFolders << Folder("Trash");
- }
+ targetFolders << Folder("Configuration", Kolab::ConfigurationType);
+ targetFolders << Folder("Contacts", Kolab::ContactType, QList<Object>() << createContact("John Doe").second);
+ targetFolders << Folder("Drafts", Kolab::MailType, QList<Object>() << createMail("subject2"));
+ targetFolders << Folder("Journal", Kolab::JournalType);
+ targetFolders << Folder("Notes", Kolab::NoteType);
+ targetFolders << Folder("Sent");
+ targetFolders << Folder("Tasks", Kolab::TaskType, QList<Object>() << createTodo("uid2").second);
+ targetFolders << Folder("Trash");
+}
- virtual ~ExchangeIMAPTest(){};
-
-private:
- void setupSourceAccount()
- {
- KolabServer *kolabServer = new KolabServer(this);
- kolabServer->setHost(sourcehost, port);
- kolabServer->setAdminCredentials(admin, adminpw);
- KolabAccount *account = kolabServer->getAccount(user);
- account->cleanAccount();
- createFolders(account, folders);
- }
+ExchangeIMAPTest::~ExchangeIMAPTest(){};
- void setupTargetAccount()
- {
- //Depending on the test scenario, clear target account
- }
+void ExchangeIMAPTest::setupSourceAccount()
+{
+ KolabServer *kolabServer = new KolabServer(this);
+ kolabServer->setHost(sourcehost, port);
+ kolabServer->setAdminCredentials(admin, adminpw);
+ KolabAccount *account = kolabServer->getAccount(user);
+ account->setWipeTargetFolders(true);
+ account->cleanAccount();
+ createFolders(account, folders);
+ account->logout();
+}
- void executeMigration()
- {
- QObject obj;
- ExchangeIMAPSourceServer *sourceServer = new ExchangeIMAPSourceServer(&obj);
- sourceServer->setHost(sourcehost, port);
- sourceServer->setAdminCredentials(admin, adminpw);
- sourceServer->setSingleUser(user);
-
- KolabServer *kolabServer = new KolabServer(&obj);
+void ExchangeIMAPTest::setupTargetAccount()
+{
+ //Depending on the test scenario, clear target account
+ KolabServer *kolabServer = new KolabServer(this);
kolabServer->setHost(targethost, port);
kolabServer->setAdminCredentials(admin, adminpw);
-
- CoordinationJob *job = new CoordinationJob(sourceServer, kolabServer, &obj);
- job->exec();
- }
-
- void checkFolders(SourceAccount *account, const QList<Folder> &folders)
- {
- const QStringList &receivedFolders = account->lookupFolderList();
- qDebug() << "Received folders: ";
- qDebug() << receivedFolders;
- QStringList::const_iterator recIt = receivedFolders.constBegin();
- QList<Folder>::const_iterator foldersIt = folders.constBegin();
- QCOMPARE(receivedFolders.size(), folders.size());
- for (;foldersIt != folders.constEnd() && recIt != receivedFolders.constEnd(); ++foldersIt, ++recIt) {
- qDebug() << "Folder: " << *recIt;
- QCOMPARE(*recIt, foldersIt->name);
- //TODO Check folder annotations
-
- const QList<Object> &objects = account->getObjects(foldersIt->name);
- QCOMPARE(objects.size(), foldersIt->objects.size());
-
- QList<Object>::const_iterator recObjIt = objects.constBegin();
- QList<Object>::const_iterator objIt = foldersIt->objects.constBegin();
- for (;objIt != foldersIt->objects.constEnd() && recObjIt != objects.constEnd(); ++objIt, ++recObjIt) {
- Kolab::KolabObjectReader reader(objIt->object.value<KMime::Message::Ptr>());
- Kolab::ObjectType type = reader.getType();
- if (type == Kolab::EventObject) {
- QCOMPARE(*recObjIt->object.value<KCalCore::Incidence::Ptr>().dynamicCast<KCalCore::Event>(), *Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getEvent());
- } else if (type == Kolab::TodoObject) {
- QCOMPARE(*recObjIt->object.value<KCalCore::Incidence::Ptr>().dynamicCast<KCalCore::Todo>(), *Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getTodo());
- } else if (type == Kolab::ContactObject) {
- QCOMPARE(recObjIt->object.value<KABC::Addressee>().name(), Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getContact().name());
- } else {
+ KolabAccount *account = kolabServer->getAccount(user);
+ account->setWipeTargetFolders(true);
+ account->cleanAccount();
+ account->logout();
+}
+
+void ExchangeIMAPTest::executeMigration()
+{
+ QObject obj;
+ ExchangeIMAPSourceServer *sourceServer = new ExchangeIMAPSourceServer(&obj);
+ sourceServer->setHost(sourcehost, port);
+ sourceServer->setAdminCredentials(admin, adminpw);
+ sourceServer->setSingleUser(user);
+
+ KolabServer *kolabServer = new KolabServer(&obj);
+ kolabServer->setHost(targethost, port);
+ kolabServer->setAdminCredentials(admin, adminpw);
+
+ CoordinationJob *job = new CoordinationJob(sourceServer, kolabServer, &obj);
+ job->exec();
+}
+
+void ExchangeIMAPTest::checkFolders(SourceAccount *account, const QList<Folder> &folders)
+{
+ const QStringList &receivedFolders = account->lookupFolderList();
+ qDebug() << "Received folders: ";
+ qDebug() << receivedFolders;
+ QStringList::const_iterator recIt = receivedFolders.constBegin();
+ QList<Folder>::const_iterator foldersIt = folders.constBegin();
+ QCOMPARE(receivedFolders.size(), folders.size());
+ for (;foldersIt != folders.constEnd() && recIt != receivedFolders.constEnd(); ++foldersIt, ++recIt) {
+ qDebug() << "Folder: " << *recIt;
+ QCOMPARE(*recIt, foldersIt->name);
+ //TODO Check folder annotations
+
+ const QList<Object> &objects = account->getObjects(foldersIt->name);
+ QCOMPARE(objects.size(), foldersIt->objects.size());
+
+ QList<Object>::const_iterator recObjIt = objects.constBegin();
+ QList<Object>::const_iterator objIt = foldersIt->objects.constBegin();
+ for (;objIt != foldersIt->objects.constEnd() && recObjIt != objects.constEnd(); ++objIt, ++recObjIt) {
+ Kolab::KolabObjectReader reader(objIt->object.value<KMime::Message::Ptr>());
+ Kolab::ObjectType type = reader.getType();
+ if (type == Kolab::EventObject) {
+ QCOMPARE(*recObjIt->object.value<KCalCore::Incidence::Ptr>().dynamicCast<KCalCore::Event>(), *Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getEvent());
+ } else if (type == Kolab::TodoObject) {
+ QCOMPARE(*recObjIt->object.value<KCalCore::Incidence::Ptr>().dynamicCast<KCalCore::Todo>(), *Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getTodo());
+ } else if (type == Kolab::ContactObject) {
+ QCOMPARE(recObjIt->object.value<KABC::Addressee>().name(), Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getContact().name());
+ } else {
// QCOMPARE(Kolab::KolabObjectReader(recObjIt->message).getEvent(), *Kolab::KolabObjectReader(objIt->message).getEvent());
- }
- foreach (const QByteArray &flag, objIt->flags) {
- QVERIFY(recObjIt->flags.contains(flag));
- }
+ }
+ foreach (const QByteArray &flag, objIt->flags) {
+ QVERIFY(recObjIt->flags.contains(flag));
}
}
}
+}
- void checkTargetAccount()
- {
-
- QObject obj;
- KolabSourceServer *kolabSourceServer = new KolabSourceServer(&obj);
- kolabSourceServer->setHost(targethost, port);
- kolabSourceServer->setAdminCredentials(admin, adminpw);
- kolabSourceServer->setSingleUser(user);
-
- SourceAccount *account = kolabSourceServer->getSourceAccount(user);
- checkFolders(account, targetFolders);
- account->logout();
- }
+void ExchangeIMAPTest::checkTargetAccount()
+{
- void checkSourceAccount()
- {
- //If we start clearing the source server on successful migration, check that messages are really gone.
- }
-
-private slots:
- void testMigration()
- {
- setupSourceAccount();
- setupTargetAccount();
- executeMigration();
- checkTargetAccount();
- checkSourceAccount();
- }
+ QObject obj;
+ KolabSourceServer *kolabSourceServer = new KolabSourceServer(&obj);
+ kolabSourceServer->setHost(targethost, port);
+ kolabSourceServer->setAdminCredentials(admin, adminpw);
+ kolabSourceServer->setSingleUser(user);
+
+ SourceAccount *account = kolabSourceServer->getSourceAccounts(user).first();
+ QVERIFY(account->login()->exec());
+ checkFolders(account, targetFolders);
+ account->logout();
+}
+
+void ExchangeIMAPTest::checkSourceAccount()
+{
+ //If we start clearing the source server on successful migration, check that messages are really gone.
+}
+
+void ExchangeIMAPTest::testMigration()
+{
+ setupSourceAccount();
+ setupTargetAccount();
+ executeMigration();
+ checkTargetAccount();
+ checkSourceAccount();
+}
-};
QTEST_MAIN( ExchangeIMAPTest )
#include "exchangeimaptest.moc"
diff --git a/migrationutility/tests/exchangeimaptest.h b/migrationutility/tests/exchangeimaptest.h
new file mode 100644
index 0000000..47cc21e
--- /dev/null
+++ b/migrationutility/tests/exchangeimaptest.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EXCHANGEIMAPTEST_H
+#define EXCHANGEIMAPTEST_H
+
+#include <QObject>
+#include "testlib/testutils.h"
+
+class SourceAccount;
+
+/**
+ * This test simulates an entier migration scenario.
+ *
+ * It requires two Kolab Servers, with all the required users already setup (ideally two local virtual machines, which are used for testing only)
+ * So this is really a complex integration test, which involves all parts of the system, and not a unittest which has to be executed all the time.
+ * On the other hand it should come quite close to a real world migration scenario and can also show problems with specific imap servers.
+ */
+class ExchangeIMAPTest: public QObject
+{
+ Q_OBJECT
+public:
+ explicit ExchangeIMAPTest(QObject* parent = 0);
+ virtual ~ExchangeIMAPTest();
+
+private slots:
+ void testMigration();
+
+private:
+ void setupSourceAccount();
+ void setupTargetAccount();
+ void executeMigration();
+ void checkFolders(SourceAccount *account, const QList<Folder> &folders);
+ void checkTargetAccount();
+ void checkSourceAccount();
+
+ QPair<Object, Object> createEvent(const QString &uid);
+ QPair<Object, Object> createTodo(const QString &uid);
+ QPair<Object, Object> createContact(const QString &name);
+ Object createMail(const QString &subject);
+
+ QString sourcehost;
+ QString targethost;
+ QString user;
+ QString admin;
+ QString adminpw;
+ qint16 port;
+ QList<Folder> folders;
+ QList<Folder> targetFolders;
+};
+
+#endif
diff --git a/migrationutility/tests/migrationscenariotest.cpp b/migrationutility/tests/migrationscenariotest.cpp
index b659de8..1b7ec66 100644
--- a/migrationutility/tests/migrationscenariotest.cpp
+++ b/migrationutility/tests/migrationscenariotest.cpp
@@ -15,7 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <QObject>
+#include "migrationscenariotest.h"
+
#include <QTest>
#include <QDebug>
#include <QFile>
@@ -24,261 +25,236 @@
#include "migrationutility/kolabserver.h"
#include "migrationutility/sourceserver.h"
#include "lib/kolabaccount.h"
-#include "lib/testlib/testutils.h"
+MigrationScenarioTest::MigrationScenarioTest(QObject* parent)
+ : QObject(parent),
+ sourcehost("192.168.122.104"),
+ targethost("192.168.122.10"),
+ user("john.doe@example.org"),
+ admin("cyrus-admin"),
+ adminpw("admin"),
+ port(143),
+ statefilename("/tmp/migrationscenarioteststatefile")
+{
+}
-/**
- * This test simulates an entier migration scenario.
- *
- * It requires two Kolab Servers, with all the required users already setup (ideally two local virtual machines, which are used for testing only)
- * So this is really a complex integration test, which involves all parts of the system, and not a unittest which has to be executed all the time.
- * On the other hand it should come quite close to a real world migration scenario and can also show problems with specific imap servers.
- *
- */
-class MigrationScenarioTest: public QObject
+MigrationScenarioTest::~MigrationScenarioTest(){};
+
+Object MigrationScenarioTest::createEvent(const QString &uid)
{
- Q_OBJECT
-
- QString sourcehost;
- QString targethost;
- QString user;
- QString admin;
- QString adminpw;
- qint16 port;
- QList<Folder> folders;
- QString statefilename;
-
- Object createEvent(const QString &uid)
- {
- Object calObj1;
- KCalCore::Event::Ptr event(new KCalCore::Event());
- event->setUid(uid);
- event->setDtStart(KDateTime::currentUtcDateTime());
- calObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV2, "migrationtest"));
- calObj1.flags << QByteArray("\\Seen");
- return calObj1;
- }
+ Object calObj1;
+ KCalCore::Event::Ptr event(new KCalCore::Event());
+ event->setUid(uid);
+ event->setDtStart(KDateTime::currentUtcDateTime());
+ calObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV2, "migrationtest"));
+ calObj1.flags << QByteArray("\\Seen");
+ return calObj1;
+}
-public:
- explicit MigrationScenarioTest(QObject* parent = 0)
- : QObject(parent),
- sourcehost("192.168.122.104"),
- targethost("192.168.122.10"),
- user("john.doe@example.org"),
- admin("cyrus-admin"),
- adminpw("admin"),
- port(143),
- statefilename("/tmp/migrationscenarioteststatefile")
- {
- }
+KolabAccount *MigrationScenarioTest::getAccount(const QString &host)
+{
+ KolabServer *kolabServer = new KolabServer(this);
+ kolabServer->setHost(host, port);
+ kolabServer->setAdminCredentials(admin, adminpw);
+ kolabServer->setWipeTargetFolders(true);
+ KolabAccount *account = kolabServer->getAccount(user);
+ Q_ASSERT(account);
+ return account;
+}
- virtual ~MigrationScenarioTest(){};
-
-private:
- KolabAccount *getAccount(const QString &host)
- {
- KolabServer *kolabServer = new KolabServer(this);
- kolabServer->setHost(host, port);
- kolabServer->setAdminCredentials(admin, adminpw);
- kolabServer->setWipeTargetFolders(true);
- KolabAccount *account = kolabServer->getAccount(user);
- Q_ASSERT(account);
- return account;
- }
+void MigrationScenarioTest::setupSourceAccount()
+{
+ KolabAccount *account = getAccount(sourcehost);
+ account->cleanAccount();
+ fillDefaultFolders(folders);
+ createFolders(account, folders);
+}
- void setupSourceAccount()
- {
- KolabAccount *account = getAccount(sourcehost);
- account->cleanAccount();
- fillDefaultFolders(folders);
- createFolders(account, folders);
- }
+void MigrationScenarioTest::setupTargetAccount()
+{
+ KolabAccount *account = getAccount(targethost);
+ account->cleanAccount();
+}
- void setupTargetAccount()
- {
- KolabAccount *account = getAccount(targethost);
- account->cleanAccount();
+void MigrationScenarioTest::executeMigration(bool useStatefile)
+{
+ QObject obj;
+ //Copy main.cpp
+ KolabSourceServer *kolabSourceServer = new KolabSourceServer(&obj);
+ kolabSourceServer->setHost(sourcehost, port);
+ kolabSourceServer->setAdminCredentials(admin, adminpw);
+ kolabSourceServer->setSingleUser(user);
+ if (useStatefile) {
+ kolabSourceServer->setStatefile(statefilename);
}
- void executeMigration(bool useStatefile = false)
- {
- QObject obj;
- //Copy main.cpp
- KolabSourceServer *kolabSourceServer = new KolabSourceServer(&obj);
- kolabSourceServer->setHost(sourcehost, port);
- kolabSourceServer->setAdminCredentials(admin, adminpw);
- kolabSourceServer->setSingleUser(user);
- if (useStatefile) {
- kolabSourceServer->setStatefile(statefilename);
- }
-
- KolabServer *kolabServer = new KolabServer(&obj);
- kolabServer->setHost(targethost, port);
- kolabServer->setAdminCredentials(admin, adminpw);
-
- CoordinationJob *job = new CoordinationJob(kolabSourceServer, kolabServer, &obj);
- job->exec();
- }
-
- void checkFolders(SourceAccount *account, const QList<Folder> &folders)
- {
- Q_ASSERT(account);
- const QStringList &receivedFolders = account->lookupFolderList();
- QStringList::const_iterator recIt = receivedFolders.constBegin();
- QList<Folder>::const_iterator foldersIt = folders.constBegin();
- QCOMPARE(receivedFolders.size(), folders.size());
- for (;foldersIt != folders.constEnd() && recIt != receivedFolders.constEnd(); ++foldersIt, ++recIt) {
- qDebug() << "Folder: " << *recIt;
- QCOMPARE(*recIt, foldersIt->name);
- //TODO Check folder annotations
- const QList<Object> &objects = account->getObjects(foldersIt->name);
- QCOMPARE(objects.size(), foldersIt->objects.size());
-
- QList<Object>::const_iterator recObjIt = objects.constBegin();
- QList<Object>::const_iterator objIt = foldersIt->objects.constBegin();
- for (;objIt != foldersIt->objects.constEnd() && recObjIt != objects.constEnd(); ++objIt, ++recObjIt) {
- QCOMPARE(*recObjIt->object.value<KCalCore::Incidence::Ptr>().dynamicCast<KCalCore::Event>(), *Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getEvent());
- foreach (const QByteArray &flag, objIt->flags) {
- QVERIFY(recObjIt->flags.contains(flag));
- }
+ KolabServer *kolabServer = new KolabServer(&obj);
+ kolabServer->setHost(targethost, port);
+ kolabServer->setAdminCredentials(admin, adminpw);
+
+ CoordinationJob *job = new CoordinationJob(kolabSourceServer, kolabServer, &obj);
+ job->exec();
+}
+
+void MigrationScenarioTest::checkFolders(SourceAccount *account, const QList<Folder> &folders)
+{
+ Q_ASSERT(account);
+ const QStringList &receivedFolders = account->lookupFolderList();
+ QStringList::const_iterator recIt = receivedFolders.constBegin();
+ QList<Folder>::const_iterator foldersIt = folders.constBegin();
+ QCOMPARE(receivedFolders.size(), folders.size());
+ for (;foldersIt != folders.constEnd() && recIt != receivedFolders.constEnd(); ++foldersIt, ++recIt) {
+ qDebug() << "Folder: " << *recIt;
+ QCOMPARE(*recIt, foldersIt->name);
+ //TODO Check folder annotations
+ const QList<Object> &objects = account->getObjects(foldersIt->name);
+ QCOMPARE(objects.size(), foldersIt->objects.size());
+
+ QList<Object>::const_iterator recObjIt = objects.constBegin();
+ QList<Object>::const_iterator objIt = foldersIt->objects.constBegin();
+ for (;objIt != foldersIt->objects.constEnd() && recObjIt != objects.constEnd(); ++objIt, ++recObjIt) {
+ QVERIFY(recObjIt->object.canConvert<KCalCore::Incidence::Ptr>());
+ QVERIFY(objIt->object.canConvert<KMime::Message::Ptr>());
+ QCOMPARE(*recObjIt->object.value<KCalCore::Incidence::Ptr>().dynamicCast<KCalCore::Event>(), *Kolab::KolabObjectReader(objIt->object.value<KMime::Message::Ptr>()).getEvent());
+ foreach (const QByteArray &flag, objIt->flags) {
+ QVERIFY(recObjIt->flags.contains(flag));
}
}
}
+}
- void checkTargetAccount()
- {
- QObject obj;
- KolabSourceServer *kolabSourceServer = new KolabSourceServer(&obj);
- kolabSourceServer->setHost(targethost, port);
- kolabSourceServer->setAdminCredentials(admin, adminpw);
- kolabSourceServer->setSingleUser(user);
-
- SourceAccount *account = kolabSourceServer->getSourceAccount(user);
- checkFolders(account, folders);
- account->logout();
- }
+void MigrationScenarioTest::checkTargetAccount()
+{
+ QObject obj;
+ KolabSourceServer *kolabSourceServer = new KolabSourceServer(&obj);
+ kolabSourceServer->setHost(targethost, port);
+ kolabSourceServer->setAdminCredentials(admin, adminpw);
+ kolabSourceServer->setSingleUser(user);
- void checkSourceAccount()
- {
- //If we start clearing the source server on successful migration, check that messages are really gone.
- }
-
-private slots:
-
- void init()
- {
- QFile file(statefilename);
- file.remove();
- folders.clear();
- }
-
- void testMigration()
- {
- folders << Folder("Calendar", Kolab::EventType, QList<Object>() << createEvent("uid1"));
- folders << Folder("Calendar/Personal Calendar", Kolab::EventType, QList<Object>() << createEvent("uid2"));
- setupSourceAccount();
- setupTargetAccount();
- executeMigration();
- checkTargetAccount();
- checkSourceAccount();
- }
+ SourceAccount *account = kolabSourceServer->getSourceAccounts(user).first();
+ QVERIFY(account->login()->exec());
+ checkFolders(account, folders);
+ account->logout();
+}
- void testMassMigration()
- {
- QTime time;
- time.start();
- QList<Object> events;
- for(int i = 0; i < 1000; i++) {
- events << createEvent(QString("uid%1").arg(i));
- }
- folders << Folder("Calendar", Kolab::EventType, events);
- setupSourceAccount();
- qDebug() << "setup done " << time.elapsed()/1000.0;
- time.start();
- setupTargetAccount();
- executeMigration();
- qDebug() << "migration done " << time.elapsed()/1000.0;
- checkTargetAccount();
- checkSourceAccount();
- }
-
- void testLargeAttachments()
- {
- QTime time;
- time.start();
-
- QByteArray data;
- data.fill('x', 10000000);
- KCalCore::Attachment::Ptr attachment(new KCalCore::Attachment(data.toBase64(), "text/plain"));
-
- QList<Object> events;
- Object calObj1;
- KCalCore::Event::Ptr event(new KCalCore::Event());
- event->setUid("uid1");
- event->setDtStart(KDateTime::currentUtcDateTime());
- event->addAttachment(attachment);
- calObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV3, "migrationtest"));
- calObj1.flags << QByteArray("\\Seen");
- events << calObj1;
-
- Object calObj2;
- KCalCore::Event::Ptr event2(new KCalCore::Event());
- event2->setUid("uid2");
- event2->setDtStart(KDateTime::currentUtcDateTime());
- event2->addAttachment(attachment);
- calObj2.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event2, Kolab::KolabV3, "migrationtest"));
- calObj2.flags << QByteArray("\\Seen");
- events << calObj2;
-
-
- folders << Folder("Calendar", Kolab::EventType, events);
- setupSourceAccount();
- qDebug() << "setup done " << time.elapsed()/1000.0;
- time.start();
- setupTargetAccount();
- executeMigration();
- qDebug() << "migration done " << time.elapsed()/1000.0;
- checkTargetAccount();
- checkSourceAccount();
- }
-
- void testStatefile()
- {
- QList<Object> events;
- events << createEvent(QString("uid1"));
- events << createEvent(QString("uid2"));
- const Object event3 = createEvent(QString("uid3"));
- events << event3;
- folders << Folder("Calendar", Kolab::EventType, events);
- setupSourceAccount();
- setupTargetAccount();
- executeMigration(true);
-
- //Check statefile
- StateFile statefile(statefilename, user);
- QList<qint64> migratedUids = statefile.getMigratedUids("Calendar");
- QCOMPARE(migratedUids.size(), 3);
-
- //Remove one event from statefile
- qint64 toMigrate = migratedUids.takeLast();
- statefile.setMigratedUids("Calendar", migratedUids);
-
- //Redo migration, this time with the statefile
- setupTargetAccount();
- executeMigration(true);
- StateFile statefile2(statefilename, user);
- migratedUids = statefile2.getMigratedUids("Calendar");
- QCOMPARE(migratedUids.size(), 3);
- QVERIFY(migratedUids.contains(toMigrate));
-
- //onyl one event was migrated
- folders.clear();
- folders << Folder("Calendar", Kolab::EventType, QList<Object>() << event3);
- fillDefaultFolders(folders);
- checkTargetAccount();
+void MigrationScenarioTest::checkSourceAccount()
+{
+ //If we start clearing the source server on successful migration, check that messages are really gone.
+}
+
+void MigrationScenarioTest::init()
+{
+ QFile file(statefilename);
+ file.remove();
+ folders.clear();
+}
+
+void MigrationScenarioTest::testMigration()
+{
+ folders << Folder("Calendar", Kolab::EventType, QList<Object>() << createEvent("uid1"));
+ folders << Folder("Calendar/Personal Calendar", Kolab::EventType, QList<Object>() << createEvent("uid2"));
+ setupSourceAccount();
+ setupTargetAccount();
+ executeMigration();
+ checkTargetAccount();
+ checkSourceAccount();
+}
+
+void MigrationScenarioTest::testMassMigration()
+{
+ QTime time;
+ time.start();
+ QList<Object> events;
+ for(int i = 0; i < 1000; i++) {
+ events << createEvent(QString("uid%1").arg(i));
}
+ folders << Folder("Calendar", Kolab::EventType, events);
+ setupSourceAccount();
+ qDebug() << "setup done " << time.elapsed()/1000.0;
+ time.start();
+ setupTargetAccount();
+ executeMigration();
+ qDebug() << "migration done " << time.elapsed()/1000.0;
+ checkTargetAccount();
+ checkSourceAccount();
+}
+
+void MigrationScenarioTest::testLargeAttachments()
+{
+ QTime time;
+ time.start();
+
+ QByteArray data;
+ data.fill('x', 10000000);
+ KCalCore::Attachment::Ptr attachment(new KCalCore::Attachment(data.toBase64(), "text/plain"));
+
+ QList<Object> events;
+ Object calObj1;
+ KCalCore::Event::Ptr event(new KCalCore::Event());
+ event->setUid("uid1");
+ event->setDtStart(KDateTime::currentUtcDateTime());
+ event->addAttachment(attachment);
+ calObj1.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV3, "migrationtest"));
+ calObj1.flags << QByteArray("\\Seen");
+ events << calObj1;
+
+ Object calObj2;
+ KCalCore::Event::Ptr event2(new KCalCore::Event());
+ event2->setUid("uid2");
+ event2->setDtStart(KDateTime::currentUtcDateTime());
+ event2->addAttachment(attachment);
+ calObj2.object = QVariant::fromValue(Kolab::KolabObjectWriter::writeEvent(event2, Kolab::KolabV3, "migrationtest"));
+ calObj2.flags << QByteArray("\\Seen");
+ events << calObj2;
+
+
+ folders << Folder("Calendar", Kolab::EventType, events);
+ setupSourceAccount();
+ qDebug() << "setup done " << time.elapsed()/1000.0;
+ time.start();
+ setupTargetAccount();
+ executeMigration();
+ qDebug() << "migration done " << time.elapsed()/1000.0;
+ checkTargetAccount();
+ checkSourceAccount();
+}
+
+void MigrationScenarioTest::testStatefile()
+{
+ QList<Object> events;
+ events << createEvent(QString("uid1"));
+ events << createEvent(QString("uid2"));
+ const Object event3 = createEvent(QString("uid3"));
+ events << event3;
+ folders << Folder("Calendar", Kolab::EventType, events);
+ setupSourceAccount();
+ setupTargetAccount();
+ executeMigration(true);
+
+ //Check statefile
+ StateFile statefile(statefilename, user);
+ QList<qint64> migratedUids = statefile.getMigratedUids("Calendar");
+ QCOMPARE(migratedUids.size(), 3);
+
+ //Remove one event from statefile
+ qint64 toMigrate = migratedUids.takeLast();
+ statefile.setMigratedUids("Calendar", migratedUids);
+
+ //Redo migration, this time with the statefile
+ setupTargetAccount();
+ executeMigration(true);
+ StateFile statefile2(statefilename, user);
+ migratedUids = statefile2.getMigratedUids("Calendar");
+ QCOMPARE(migratedUids.size(), 3);
+ QVERIFY(migratedUids.contains(toMigrate));
+
+ //onyl one event was migrated
+ folders.clear();
+ folders << Folder("Calendar", Kolab::EventType, QList<Object>() << event3);
+ fillDefaultFolders(folders);
+ checkTargetAccount();
+}
-};
QTEST_MAIN( MigrationScenarioTest )
#include "migrationscenariotest.moc"
diff --git a/migrationutility/tests/migrationscenariotest.h b/migrationutility/tests/migrationscenariotest.h
new file mode 100644
index 0000000..fb23090
--- /dev/null
+++ b/migrationutility/tests/migrationscenariotest.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MIGRATIONSCENARIOTEST_H
+#define MIGRATIONSCENARIOTEST_H
+
+#include <QObject>
+#include "testlib/testutils.h"
+
+class SourceAccount;
+/**
+ * This test simulates an entier migration scenario.
+ *
+ * It requires two Kolab Servers, with all the required users already setup (ideally two local virtual machines, which are used for testing only)
+ * So this is really a complex integration test, which involves all parts of the system, and not a unittest which has to be executed all the time.
+ * On the other hand it should come quite close to a real world migration scenario and can also show problems with specific imap servers.
+ *
+ */
+class MigrationScenarioTest: public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit MigrationScenarioTest(QObject* parent = 0);
+ virtual ~MigrationScenarioTest();
+
+private slots:
+ void init();
+ void testMigration();
+ void testMassMigration();
+ void testLargeAttachments();
+ void testStatefile();
+
+private:
+ Object createEvent(const QString &uid);
+ KolabAccount *getAccount(const QString &host);
+ void setupSourceAccount();
+ void setupTargetAccount();
+ void executeMigration(bool useStatefile = false);
+ void checkFolders(SourceAccount *account, const QList<Folder> &folders);
+ void checkTargetAccount();
+ void checkSourceAccount();
+
+ QString sourcehost;
+ QString targethost;
+ QString user;
+ QString admin;
+ QString adminpw;
+ qint16 port;
+ QList<Folder> folders;
+ QString statefilename;
+};
+
+#endif
diff --git a/migrationutility/tests/migrationtest.cpp b/migrationutility/tests/migrationtest.cpp
index 933e39b..ffc8c7d 100644
--- a/migrationutility/tests/migrationtest.cpp
+++ b/migrationutility/tests/migrationtest.cpp
@@ -1,4 +1,21 @@
-#include <QObject>
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "migrationtest.h"
+
#include <QTest>
#include "coordinationjob.h"
#include "sourceserver.h"
@@ -6,30 +23,26 @@
#include "migrateuserjob.h"
#include <kolabaccount.h>
-class MigrationTest : public QObject
+void MigrationTest::testUsersProcessed()
+{
+ TestServer *server = new TestServer(this);
+ KolabServer *kolabServer = new KolabServer(this);
+ kolabServer->setDryRun(true);
+ CoordinationJob *job = new CoordinationJob(server, kolabServer, this);
+ job->exec();
+ QVERIFY(server->mUsers.isEmpty());
+}
+
+void MigrationTest::testFoldersProcessed()
{
- Q_OBJECT
- private slots:
- void testUsersProcessed()
- {
- TestServer *server = new TestServer(this);
- KolabServer *kolabServer = new KolabServer(this);
- CoordinationJob *job = new CoordinationJob(server, kolabServer, this);
- job->exec();
- QVERIFY(server->mUsers.isEmpty());
- }
-
- void testFoldersProcessed()
- {
- TestAccount *server = new TestAccount(this);
- KolabAccount *kolabServer = new KolabAccount(this);
- MigrateUserJob *job = new MigrateUserJob(server, kolabServer, this);
- job->exec();
- QVERIFY(server->mFolderList.isEmpty());
- }
-};
+ TestAccount *testSourceAccount = new TestAccount(this);
+ KolabAccount *kolabTargetAccount = new KolabAccount(this);
+ kolabTargetAccount->setDryRun(true);
+ MigrateUserJob *job = new MigrateUserJob(QList<SourceAccount*>() << testSourceAccount, kolabTargetAccount, this);
+ job->exec();
+ QVERIFY(testSourceAccount->mFolderList.isEmpty());
+}
QTEST_MAIN( MigrationTest )
-// #include "moc_migrationtest.cxx"
#include "migrationtest.moc" \ No newline at end of file
diff --git a/migrationutility/tests/migrationtest.h b/migrationutility/tests/migrationtest.h
new file mode 100644
index 0000000..f6e761d
--- /dev/null
+++ b/migrationutility/tests/migrationtest.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef MIGRATIONTEST_H
+#define MIGRATIONTEST_H
+
+#include <QObject>
+
+class MigrationTest : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testUsersProcessed();
+ void testFoldersProcessed();
+};
+
+#endif