Imported Upstream version 1.3.99.3~20130529~SE~b989f69~SYSYNC~3366831
[platform/upstream/syncevolution.git] / src / backends / activesync / ActiveSyncSourceRegister.cpp
1 /*
2  * Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
3  * Copyright (C) 2009 Intel Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) version 3.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301  USA
19  */
20
21 #include "ActiveSyncSource.h"
22 #include "ActiveSyncCalendarSource.h"
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #ifdef ENABLE_UNIT_TESTS
29 # include <cppunit/extensions/TestFactoryRegistry.h>
30 # include <cppunit/extensions/HelperMacros.h>
31 #endif
32
33 #include <fstream>
34
35 #include <syncevo/declarations.h>
36 SE_BEGIN_CXX
37
38 static SyncSource *createSource(const SyncSourceParams &params)
39 {
40     SourceType sourceType = SyncSource::getSourceType(params.m_nodes);
41     bool isMe;
42
43     isMe = sourceType.m_backend == "ActiveSync Address Book";
44     if (isMe) {
45         return
46 #ifdef ENABLE_ACTIVESYNC
47             new ActiveSyncContactSource(params)
48 #else
49             RegisterSyncSource::InactiveSource(params)
50 #endif
51             ;
52     }
53
54     isMe = sourceType.m_backend == "ActiveSync Events";
55     if (isMe) {
56         return
57 #ifdef ENABLE_ACTIVESYNC
58             new ActiveSyncCalendarSource(params, EAS_ITEM_CALENDAR)
59 #else
60             RegisterSyncSource::InactiveSource(params)
61 #endif
62             ;
63     }
64
65     isMe = sourceType.m_backend == "ActiveSync Todos";
66     if (isMe) {
67         return
68 #ifdef ENABLE_ACTIVESYNC
69             new ActiveSyncCalFormatSource(params, EAS_ITEM_TODO)
70 #else
71             RegisterSyncSource::InactiveSource(params)
72 #endif
73             ;
74     }
75
76     isMe = sourceType.m_backend == "ActiveSync Memos";
77     if (isMe) {
78         return
79 #ifdef ENABLE_ACTIVESYNC
80             new ActiveSyncCalFormatSource(params, EAS_ITEM_JOURNAL)
81 #else
82             RegisterSyncSource::InactiveSource(params)
83 #endif
84             ;
85     }
86
87     return NULL;
88 }
89
90 static RegisterSyncSource registerMe("ActiveSync",
91 #ifdef ENABLE_ACTIVESYNC
92                                      true,
93 #else
94                                      false,
95 #endif
96                                      createSource,
97                                      "ActiveSync Address Book = eas-contacts\n"
98                                      "ActiveSync Events = eas-events\n"
99                                      "ActiveSync Todos = eas-todos\n"
100                                      "ActiveSync Memos = eas-memos",
101                                      Values() +
102                                      (Aliases("ActiveSync Address Book") + "eas-contacts") +
103                                      (Aliases("ActiveSync Events") + "eas-events") +
104                                      (Aliases("ActiveSync Todos") + "eas-todos") +
105                                      (Aliases("ActiveSync Memos") + "eas-memos"));
106
107 #ifdef ENABLE_ACTIVESYNC
108 #ifdef ENABLE_UNIT_TESTS
109
110 class ActiveSyncsTest : public CppUnit::TestFixture {
111     CPPUNIT_TEST_SUITE(ActiveSyncsTest);
112     CPPUNIT_TEST(testInstantiate);
113     CPPUNIT_TEST_SUITE_END();
114
115 protected:
116     void testInstantiate() {
117         boost::shared_ptr<SyncSource> source;
118         source.reset(SyncSource::createTestingSource("contacts", "ActiveSync Address Book", true));
119         source.reset(SyncSource::createTestingSource("events", "ActiveSync Events", true));
120         source.reset(SyncSource::createTestingSource("todos", "ActiveSync Todos", true));
121         source.reset(SyncSource::createTestingSource("memos", "ActiveSync Memos", true));
122     }
123 };
124
125 SYNCEVOLUTION_TEST_SUITE_REGISTRATION(ActiveSyncsTest);
126
127 #endif // ENABLE_UNIT_TESTS
128
129 namespace {
130 #if 0
131 }
132 #endif
133
134 /**
135  * Takes all existing items in the source and writes them into the file,
136  * separated by a blank line. beginSync() with the previous sync key was
137  * already called.
138  *
139  * Used for testing and thus should better not rely on cached information,
140  * but ActiveSync doesn't offer an independent "list and/or retrieve all items"
141  * operation. Using the cached information implies that we won't find bugs in
142  * the handling of that information.
143  */
144 static int DumpItems(ClientTest &client, TestingSyncSource &source, const std::string &file,
145                      bool forceBaseReadItem)
146 {
147     ActiveSyncSource &eassource = static_cast<ActiveSyncSource &>(source);
148     ofstream out(file.c_str());
149
150     // find all ActiveSync server IDs: in ActiveSyncCalendarSource,
151     // each server ID might appear multiple times, once for each
152     // recurrence associated with it
153     std::set<std::string> easids;
154     BOOST_FOREACH (const std::string &luid, eassource.getAllItems()) {
155         // slight hack: we know that luids in ActiveSyncSource base
156         // class pass through this method unmodified, so no need to
157         // avoid it
158         StringPair ids = ActiveSyncCalendarSource::splitLUID(luid);
159         easids.insert(ids.first);
160     }
161
162     BOOST_FOREACH(const std::string &easid, easids) {
163         std::string item;
164         if (forceBaseReadItem) {
165             // This bypasses the more specialized
166             // ActiveSyncCalendarSource::readItem(), which helps
167             // reveal potential bugs in it. However, it depends on a
168             // working Fetch operation in the ActiveSync server, which
169             // Google doesn't seem to provide (404 error).
170             eassource.ActiveSyncSource::readItem(easid, item);
171         } else {
172             // Normal readItem() works with Google by using the cached
173             // item. However, the source must have done a beginSync()
174             // with empty sync key, because otherwise the cache is
175             // not guaranteed to be complete.
176             eassource.readItem(easid, item);
177         }
178         out << item << '\n';
179         if (!boost::ends_with(item, "\n")) {
180             out << '\n';
181         }
182     }
183     return 0;
184 }
185
186 static TestingSyncSource *createEASSource(const ClientTestConfig::createsource_t &create,
187                                           ClientTest &client,
188                                           const std::string &clientID,
189                                           int source, bool isSourceA)
190 {
191     std::auto_ptr<TestingSyncSource> res(create(client, clientID, source, isSourceA));
192
193     // Mangle username: if the base username in the config is account
194     // "foo", then source B uses "foo_B", because otherwise it'll end
195     // up sharing change tracking with source A.
196     if (!isSourceA) {
197         ActiveSyncSource *eassource = static_cast<ActiveSyncSource *>(res.get());
198         std::string account = eassource->getSyncConfig().getSyncUsername();
199         account += "_B";
200         eassource->getSyncConfig().setSyncUsername(account, true);
201     }
202
203     if (res->getDatabaseID().empty()) {
204         return res.release();
205     } else {
206         // sorry, no database
207         SE_LOG_ERROR(NULL, "cannot create EAS source for database %s, check config",
208                      res->getDatabaseID().c_str());
209         return NULL;
210     }
211 }
212
213 // common settings for all kinds of data
214 static void updateConfigEAS(const RegisterSyncSourceTest */* me */,
215                             ClientTestConfig &config,
216                             EasItemType type)
217 {
218         // cannot run tests involving a second database:
219         // wrap orginal source creation, set default database for
220         // database #0 and refuse to return a source for database #1
221         config.m_createSourceA = boost::bind(createEASSource, config.m_createSourceA,
222                                              _1, _2, _3, _4);
223         config.m_createSourceB = boost::bind(createEASSource, config.m_createSourceB,
224                                              _1, _2, _3, _4);
225
226         config.m_dump = boost::bind(DumpItems, _1, _2, _3,
227                                     type == EAS_ITEM_CONTACT ||
228                                     // need to read from our cache for Google Calendar,
229                                     // because it does not support Fetch
230                                     strcmp(getEnv("CLIENT_TEST_SERVER", ""), "googleeas")
231                                     );
232         config.m_sourceLUIDsAreVolatile = true;
233         // TODO: find out how ActiveSync/Exchange handle children without parent;
234         // at the moment, the child is stored as if it was a stand-alone event
235         // and the RECURRENCE-ID is lost (BMC #22831).
236         config.m_linkedItemsRelaxedSemantic = false;
237 }
238
239 static class ActiveSyncContactTest : public RegisterSyncSourceTest {
240 public:
241     ActiveSyncContactTest() :
242         RegisterSyncSourceTest("eas_contact", // name of test => Client::Source::eas_contact"
243                                "eds_contact"  // name of test cases: inherit from EDS, override below
244                                ) {}
245
246     virtual void updateConfig(ClientTestConfig &config) const
247     {
248         // override default eds_contact test config
249         config.m_type = "eas-contacts";
250         // TODO: provide comprehensive set of vCard 3.0 contacts as they are understood by the ActiveSync library
251         // config.testcases = "testcases/eas_contact.vcf";
252
253         updateConfigEAS(this, config, EAS_ITEM_CONTACT);
254     }
255 } ActiveSyncContactTest;
256
257 static class ActiveSyncEventTest : public RegisterSyncSourceTest {
258 public:
259     ActiveSyncEventTest() :
260         RegisterSyncSourceTest("eas_event", "eds_event")
261     {}
262
263     virtual void updateConfig(ClientTestConfig &config) const
264     {
265         config.m_type = "eas-events";
266         updateConfigEAS(this, config, EAS_ITEM_CALENDAR);
267     }
268 } ActiveSyncEventTest;
269
270 static class ActiveSyncTodoTest : public RegisterSyncSourceTest {
271 public:
272     ActiveSyncTodoTest() :
273         RegisterSyncSourceTest("eas_task", "eds_task")
274     {}
275
276     virtual void updateConfig(ClientTestConfig &config) const
277     {
278         config.m_type = "eas-todos";
279         updateConfigEAS(this, config, EAS_ITEM_TODO);
280     }
281 } ActiveSyncTodoTest;
282
283 static class ActiveSyncMemoTest : public RegisterSyncSourceTest {
284 public:
285     ActiveSyncMemoTest() :
286         RegisterSyncSourceTest("eas_memo", "eds_memo")
287     {}
288
289     virtual void updateConfig(ClientTestConfig &config) const
290     {
291         config.m_type = "eas-memos";
292         updateConfigEAS(this, config, EAS_ITEM_JOURNAL);
293     }
294 } ActiveSyncMemoTest;
295
296 } // anonymous namespace
297
298 #endif // ENABLE_ACTIVESYNC
299
300 SE_END_CXX