syncevolution/src/backends/activesync/ActiveSyncSourceRegister.cpp

301 lines
10 KiB
C++

/*
* Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
* Copyright (C) 2009 Intel Corporation
*
* This library 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 2.1 of the License, or (at your option) version 3.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "ActiveSyncSource.h"
#include "ActiveSyncCalendarSource.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef ENABLE_UNIT_TESTS
# include <cppunit/extensions/TestFactoryRegistry.h>
# include <cppunit/extensions/HelperMacros.h>
#endif
#include <fstream>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
static SyncSource *createSource(const SyncSourceParams &params)
{
SourceType sourceType = SyncSource::getSourceType(params.m_nodes);
bool isMe;
isMe = sourceType.m_backend == "ActiveSync Address Book";
if (isMe) {
return
#ifdef ENABLE_ACTIVESYNC
new ActiveSyncContactSource(params)
#else
RegisterSyncSource::InactiveSource(params)
#endif
;
}
isMe = sourceType.m_backend == "ActiveSync Events";
if (isMe) {
return
#ifdef ENABLE_ACTIVESYNC
new ActiveSyncCalendarSource(params, EAS_ITEM_CALENDAR)
#else
RegisterSyncSource::InactiveSource(params)
#endif
;
}
isMe = sourceType.m_backend == "ActiveSync Todos";
if (isMe) {
return
#ifdef ENABLE_ACTIVESYNC
new ActiveSyncCalFormatSource(params, EAS_ITEM_TODO)
#else
RegisterSyncSource::InactiveSource(params)
#endif
;
}
isMe = sourceType.m_backend == "ActiveSync Memos";
if (isMe) {
return
#ifdef ENABLE_ACTIVESYNC
new ActiveSyncCalFormatSource(params, EAS_ITEM_JOURNAL)
#else
RegisterSyncSource::InactiveSource(params)
#endif
;
}
return NULL;
}
static RegisterSyncSource registerMe("ActiveSync",
#ifdef ENABLE_ACTIVESYNC
true,
#else
false,
#endif
createSource,
"ActiveSync Address Book = eas-contacts\n"
"ActiveSync Events = eas-events\n"
"ActiveSync Todos = eas-todos\n"
"ActiveSync Memos = eas-memos",
Values() +
(Aliases("ActiveSync Address Book") + "eas-contacts") +
(Aliases("ActiveSync Events") + "eas-events") +
(Aliases("ActiveSync Todos") + "eas-todos") +
(Aliases("ActiveSync Memos") + "eas-memos"));
#ifdef ENABLE_ACTIVESYNC
#ifdef ENABLE_UNIT_TESTS
class ActiveSyncsTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ActiveSyncsTest);
CPPUNIT_TEST(testInstantiate);
CPPUNIT_TEST_SUITE_END();
protected:
void testInstantiate() {
boost::shared_ptr<SyncSource> source;
source.reset(SyncSource::createTestingSource("contacts", "ActiveSync Address Book", true));
source.reset(SyncSource::createTestingSource("events", "ActiveSync Events", true));
source.reset(SyncSource::createTestingSource("todos", "ActiveSync Todos", true));
source.reset(SyncSource::createTestingSource("memos", "ActiveSync Memos", true));
}
};
SYNCEVOLUTION_TEST_SUITE_REGISTRATION(ActiveSyncsTest);
#endif // ENABLE_UNIT_TESTS
namespace {
#if 0
}
#endif
/**
* Takes all existing items in the source and writes them into the file,
* separated by a blank line. beginSync() with the previous sync key was
* already called.
*
* Used for testing and thus should better not rely on cached information,
* but ActiveSync doesn't offer an independent "list and/or retrieve all items"
* operation. Using the cached information implies that we won't find bugs in
* the handling of that information.
*/
static int DumpItems(ClientTest &client, TestingSyncSource &source, const std::string &file,
bool forceBaseReadItem)
{
ActiveSyncSource &eassource = static_cast<ActiveSyncSource &>(source);
ofstream out(file.c_str());
// find all ActiveSync server IDs: in ActiveSyncCalendarSource,
// each server ID might appear multiple times, once for each
// recurrence associated with it
std::set<std::string> easids;
BOOST_FOREACH (const std::string &luid, eassource.getAllItems()) {
// slight hack: we know that luids in ActiveSyncSource base
// class pass through this method unmodified, so no need to
// avoid it
StringPair ids = ActiveSyncCalendarSource::splitLUID(luid);
easids.insert(ids.first);
}
BOOST_FOREACH(const std::string &easid, easids) {
std::string item;
if (forceBaseReadItem) {
// This bypasses the more specialized
// ActiveSyncCalendarSource::readItem(), which helps
// reveal potential bugs in it. However, it depends on a
// working Fetch operation in the ActiveSync server, which
// Google doesn't seem to provide (404 error).
eassource.ActiveSyncSource::readItem(easid, item);
} else {
// Normal readItem() works with Google by using the cached
// item. However, the source must have done a beginSync()
// with empty sync key, because otherwise the cache is
// not guaranteed to be complete.
eassource.readItem(easid, item);
}
out << item << '\n';
if (!boost::ends_with(item, "\n")) {
out << '\n';
}
}
return 0;
}
static TestingSyncSource *createEASSource(const ClientTestConfig::createsource_t &create,
ClientTest &client,
const std::string &clientID,
int source, bool isSourceA)
{
std::auto_ptr<TestingSyncSource> res(create(client, clientID, source, isSourceA));
// Mangle username: if the base username in the config is account
// "foo", then source B uses "foo_B", because otherwise it'll end
// up sharing change tracking with source A.
if (!isSourceA) {
ActiveSyncSource *eassource = static_cast<ActiveSyncSource *>(res.get());
std::string account = eassource->getSyncConfig().getSyncUser().toString();
account += "_B";
eassource->getSyncConfig().setSyncUsername(account, true);
}
if (res->getDatabaseID().empty()) {
return res.release();
} else {
// sorry, no database
SE_LOG_ERROR(NULL, "cannot create EAS datastore for database %s, check config",
res->getDatabaseID().c_str());
return NULL;
}
}
// common settings for all kinds of data
static void updateConfigEAS(const RegisterSyncSourceTest */* me */,
ClientTestConfig &config,
EasItemType type)
{
// cannot run tests involving a second database:
// wrap orginal source creation, set default database for
// database #0 and refuse to return a source for database #1
config.m_createSourceA = boost::bind(createEASSource, config.m_createSourceA,
_1, _2, _3, _4);
config.m_createSourceB = boost::bind(createEASSource, config.m_createSourceB,
_1, _2, _3, _4);
config.m_dump = boost::bind(DumpItems, _1, _2, _3,
type == EAS_ITEM_CONTACT ||
// need to read from our cache for Google Calendar,
// because it does not support Fetch
strcmp(getEnv("CLIENT_TEST_SERVER", ""), "googleeas")
);
config.m_sourceLUIDsAreVolatile = true;
// TODO: find out how ActiveSync/Exchange handle children without parent;
// at the moment, the child is stored as if it was a stand-alone event
// and the RECURRENCE-ID is lost (BMC #22831).
config.m_linkedItemsRelaxedSemantic = false;
}
static class ActiveSyncContactTest : public RegisterSyncSourceTest {
public:
ActiveSyncContactTest() :
RegisterSyncSourceTest("eas_contact", // name of test => Client::Source::eas_contact"
"eds_contact" // name of test cases: inherit from EDS, override below
) {}
virtual void updateConfig(ClientTestConfig &config) const
{
// override default eds_contact test config
config.m_type = "eas-contacts";
// TODO: provide comprehensive set of vCard 3.0 contacts as they are understood by the ActiveSync library
// config.testcases = "testcases/eas_contact.vcf";
updateConfigEAS(this, config, EAS_ITEM_CONTACT);
}
} ActiveSyncContactTest;
static class ActiveSyncEventTest : public RegisterSyncSourceTest {
public:
ActiveSyncEventTest() :
RegisterSyncSourceTest("eas_event", "eds_event")
{}
virtual void updateConfig(ClientTestConfig &config) const
{
config.m_type = "eas-events";
updateConfigEAS(this, config, EAS_ITEM_CALENDAR);
}
} ActiveSyncEventTest;
static class ActiveSyncTodoTest : public RegisterSyncSourceTest {
public:
ActiveSyncTodoTest() :
RegisterSyncSourceTest("eas_task", "eds_task")
{}
virtual void updateConfig(ClientTestConfig &config) const
{
config.m_type = "eas-todos";
updateConfigEAS(this, config, EAS_ITEM_TODO);
}
} ActiveSyncTodoTest;
static class ActiveSyncMemoTest : public RegisterSyncSourceTest {
public:
ActiveSyncMemoTest() :
RegisterSyncSourceTest("eas_memo", "eds_memo")
{}
virtual void updateConfig(ClientTestConfig &config) const
{
config.m_type = "eas-memos";
updateConfigEAS(this, config, EAS_ITEM_JOURNAL);
}
} ActiveSyncMemoTest;
} // anonymous namespace
#endif // ENABLE_ACTIVESYNC
SE_END_CXX