summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Mollekopf <mollekopf@kolabsys.com>2012-10-25 14:02:54 (GMT)
committerChristian Mollekopf <mollekopf@kolabsys.com>2012-10-25 14:02:54 (GMT)
commit11e85473757e4eb380a26ba82f92850a72b4e3bb (patch)
tree11d35ce24e78f6e5c562bc674a665b3bcddc02e8
parent2f544da3e3a76994d9388424ba523f54a3aeaacc (diff)
downloadkolab-utils-11e85473757e4eb380a26ba82f92850a72b4e3bb.tar.gz
We got a first event migrated.
-rw-r--r--migrationutility/sourceaccount.cpp88
-rw-r--r--migrationutility/sourceaccount.h14
-rw-r--r--migrationutility/sourceserver.cpp34
-rw-r--r--migrationutility/sourceserver.h11
-rw-r--r--migrationutility/tests/CMakeLists.txt7
-rw-r--r--migrationutility/tests/exchangeimaptest.cpp209
6 files changed, 357 insertions, 6 deletions
diff --git a/migrationutility/sourceaccount.cpp b/migrationutility/sourceaccount.cpp
index 8d61bfb..bfa4096 100644
--- a/migrationutility/sourceaccount.cpp
+++ b/migrationutility/sourceaccount.cpp
@@ -26,6 +26,8 @@
#include <kimap/namespacejob.h>
#include <kolab/errorhandler.h>
#include <kolab/kolabobject.h>
+#include <kcalcore/memorycalendar.h>
+#include <kcalcore/icalformat.h>
SourceAccount::SourceAccount(QObject* parent)
: QObject(parent)
@@ -177,7 +179,7 @@ QList<Object> KolabSourceAccount::getObjects(const QString& folder)
if (mKolabFolders.values().contains(folder)) {
isKolabType = true;
}
- Debug() << folder;
+// Debug() << folder;
FetchMessagesJob *fetchJob = new FetchMessagesJob(folder, mSession, this);
fetchJob->exec();
Debug() << fetchJob->getMessages().size();
@@ -211,4 +213,86 @@ void KolabSourceAccount::logout()
}
-// #include "sourceaccount.moc"
+//--------------------------------------------------------
+
+
+ExchangeIMAPSourceAccount::ExchangeIMAPSourceAccount(KIMAP::Session* session, QObject* parent)
+: KolabSourceAccount(session, parent)
+{
+
+}
+
+QPair<Kolab::ObjectType, KMime::Content*> ExchangeIMAPSourceAccount::getObjectType(const KMime::Message::Ptr &msg)
+{
+ QByteArray calendarType("text/calendar");
+ Q_FOREACH(KMime::Content *c, msg->contents()) {
+ Debug() << c->contentType()->mimeType();
+ if (c->contentType()->mimeType() == calendarType) {
+ //TODO maybe distinguish between todos, events, etc
+ return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::EventObject, c);
+ }
+ }
+ return QPair<Kolab::ObjectType, KMime::Content*>(Kolab::InvalidObject, 0);
+}
+
+Kolab::FolderType ExchangeIMAPSourceAccount::getFolderType(const QString &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()) {
+ Kolab::ObjectType type = getObjectType(msg).first;
+ if (type == Kolab::EventObject) {
+ return Kolab::EventType;
+ }
+ }
+ return Kolab::MailType;
+}
+
+QPair<Kolab::FolderType, QString> ExchangeIMAPSourceAccount::translateFolder(const QString& folder)
+{
+ //Fetch items and check first item for type
+ return QPair<Kolab::FolderType, QString>(getFolderType(folder), folder);
+}
+
+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::MailType) {
+ Object obj;
+ obj.message = msg;
+ obj.flags = fetchJob->getFlags(msg);
+ messages.append(obj);
+ } else if (type.first == Kolab::EventObject) {
+ 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);
+
+ qDebug() << calendar->rawIncidences().size() << calendar->incidences().size();
+ qDebug() << calendar->events().size();
+
+ foreach (const KCalCore::Event::Ptr &event, calendar->events()) {
+ Object obj;
+ obj.message = Kolab::KolabObjectWriter::writeEvent(event, Kolab::KolabV3, "kolab-migration");
+ obj.flags = fetchJob->getFlags(msg);
+ if (!obj.message) {
+ Error() << "got empty message";
+ continue;
+ }
+ messages.append(obj);
+ }
+ }
+
+ }
+ return messages;
+} \ No newline at end of file
diff --git a/migrationutility/sourceaccount.h b/migrationutility/sourceaccount.h
index bbe1a0b..b07df20 100644
--- a/migrationutility/sourceaccount.h
+++ b/migrationutility/sourceaccount.h
@@ -21,6 +21,7 @@
#include <QObject>
#include <QStringList>
#include <formathelpers.h>
+#include <kolabobject.h>
#include <kimap/loginjob.h>
#include <kimap/listjob.h>
#include <kmime/kmime_message.h>
@@ -68,7 +69,7 @@ public:
private slots:
void mailBoxesReceived(const QList<KIMAP::MailBoxDescriptor> &descriptors, const QList< QList< QByteArray > > &flags);
-private:
+protected:
void init();
Kolab::FolderType getFolderType(const QString &folder);
KIMAP::Session *mSession;
@@ -79,4 +80,15 @@ private:
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 012759d..b3383fd 100644
--- a/migrationutility/sourceserver.cpp
+++ b/migrationutility/sourceserver.cpp
@@ -160,5 +160,35 @@ void KolabSourceServer::logout()
mSession = 0;
Debug() << "logout done";
}
-// #include "moc_sourceserver.cxx"
-// #include "sourceserver.moc"
+
+//---------------------------------------------------------------------
+
+ExchangeIMAPSourceServer::ExchangeIMAPSourceServer(QObject* parent)
+: KolabSourceServer(parent)
+{
+
+}
+
+SourceAccount* ExchangeIMAPSourceServer::getSourceAccount(const QString& user)
+{
+ KIMAP::Session *session = new KIMAP::Session( mHost, mPort, this );
+ session->setUiProxy( KIMAP::SessionUiProxy::Ptr(new UiProxy()) );
+ 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();
+ return 0;
+ } else {
+ Debug() << "authentication successful";
+ }
+
+ return new ExchangeIMAPSourceAccount(session, this);
+} \ No newline at end of file
diff --git a/migrationutility/sourceserver.h b/migrationutility/sourceserver.h
index 8a484e5..ae88d91 100644
--- a/migrationutility/sourceserver.h
+++ b/migrationutility/sourceserver.h
@@ -61,7 +61,7 @@ public:
void setHost(const QString &host, qint16 port);
void setAdminCredentials(const QString &username, const QString &pw);
-private:
+protected:
void logout();
KIMAP::Session *mSession;
QString mHost;
@@ -72,4 +72,13 @@ private:
KIMAP::LoginJob::AuthenticationMode mAuthenticationMode;
};
+class ExchangeIMAPSourceServer: public KolabSourceServer
+{
+ Q_OBJECT
+public:
+ explicit ExchangeIMAPSourceServer(QObject* parent = 0);
+
+ virtual SourceAccount *getSourceAccount(const QString &user);
+};
+
#endif // SOURCESERVER_H
diff --git a/migrationutility/tests/CMakeLists.txt b/migrationutility/tests/CMakeLists.txt
index 257dd90..eeaf7ac 100644
--- a/migrationutility/tests/CMakeLists.txt
+++ b/migrationutility/tests/CMakeLists.txt
@@ -28,3 +28,10 @@ qt4_generate_moc(
)
add_executable(migrationscenariotest ${MIGRATION_SRCS} ${MIGRATION_MOC} migrationscenariotest.cpp)
target_link_libraries(migrationscenariotest ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils)
+
+qt4_generate_moc(
+ ${CMAKE_CURRENT_SOURCE_DIR}/exchangeimaptest.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/exchangeimaptest.moc
+)
+add_executable(exchangeimaptest ${MIGRATION_SRCS} ${MIGRATION_MOC} exchangeimaptest.cpp)
+target_link_libraries(exchangeimaptest ${COMMON_DEPENDENCIES} ${QT_QTTEST_LIBRARY} kolabutils)
diff --git a/migrationutility/tests/exchangeimaptest.cpp b/migrationutility/tests/exchangeimaptest.cpp
new file mode 100644
index 0000000..44fd097
--- /dev/null
+++ b/migrationutility/tests/exchangeimaptest.cpp
@@ -0,0 +1,209 @@
+/*
+ * 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 <QObject>
+#include <QTest>
+#include <QDebug>
+#include <kolabobject.h>
+#include <kcalcore/memorycalendar.h>
+#include <kcalcore/icalformat.h>
+#include "migrationutility/coordinationjob.h"
+#include "migrationutility/kolabserver.h"
+#include "migrationutility/sourceserver.h"
+#include "lib/kolabaccount.h"
+#include "lib/testlib/testutils.h"
+
+
+/**
+ * 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
+
+ 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.message = msg;
+ calObj1.flags << QByteArray("\\Seen");
+
+ Object targetObject;
+ targetObject.message = Kolab::KolabObjectWriter::writeEvent(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");
+ folders << Folder("Calendar", Kolab::MailType, QList<Object>() << createEvent("uid1").first);
+ folders << Folder("Contacts", Kolab::MailType);
+ folders << Folder("Drafts");
+ folders << Folder("Sent");
+ folders << Folder("Trash");
+
+ targetFolders << Folder("INBOX");
+ 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);
+ targetFolders << Folder("Drafts");
+ targetFolders << Folder("Journal", Kolab::JournalType);
+ targetFolders << Folder("Notes", Kolab::NoteType);
+ targetFolders << Folder("Sent");
+ targetFolders << Folder("Tasks", Kolab::TaskType);
+ 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);
+ }
+
+ void setupTargetAccount()
+ {
+ //Depending on the test scenario, clear target account
+ }
+
+ 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);
+ 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) {
+ QCOMPARE(*Kolab::KolabObjectReader(recObjIt->message).getEvent(), *Kolab::KolabObjectReader(objIt->message).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, targetFolders);
+ account->logout();
+ }
+
+ 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();
+ }
+
+};
+QTEST_MAIN( ExchangeIMAPTest )
+
+#include "exchangeimaptest.moc"