301 lines
10 KiB
C++
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 ¶ms)
|
|
{
|
|
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::unique_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
|