Imported Upstream version 0.8~alpha1
[platform/upstream/syncevolution.git] / src / EvolutionCalendarSourceRegister.cpp
1 /*
2  * Copyright (C) 2008 Patrick Ohly
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include "EvolutionCalendarSource.h"
20 #include "EvolutionMemoSource.h"
21 #include "SyncEvolutionUtil.h"
22
23 #include <boost/algorithm/string.hpp>
24
25 static EvolutionSyncSource *createSource(const EvolutionSyncSourceParams &params)
26 {
27     pair <string, string> sourceType = EvolutionSyncSource::getSourceType(params.m_nodes);
28     bool isMe;
29
30     isMe = sourceType.first == "Evolution Task List";
31     if (isMe || sourceType.first == "todo") {
32         if (sourceType.second == "" || sourceType.second == "text/calendar") {
33 #ifdef ENABLE_ECAL
34             return new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_TODO, params);
35 #else
36             return isMe ? RegisterSyncSource::InactiveSource : NULL;
37 #endif
38         } else {
39             return NULL;
40         }
41     }
42
43     isMe = sourceType.first == "Evolution Memos";
44     if (isMe || sourceType.first == "memo") {
45         if (sourceType.second == "" || sourceType.second == "text/plain") {
46 #ifdef ENABLE_ECAL
47             return new EvolutionMemoSource(params);
48 #else
49             return isMe ? RegisterSyncSource::InactiveSource : NULL;
50 #endif
51         } else if (sourceType.second == "text/calendar") {
52 #ifdef ENABLE_ECAL
53             return new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_JOURNAL, params);
54 #else
55             return isMe ? RegisterSyncSource::InactiveSource : NULL;
56 #endif
57         } else {
58             return NULL;
59         }
60     }
61
62     isMe = sourceType.first == "Evolution Calendar";
63     if (isMe || sourceType.first == "calendar") {
64         if (sourceType.second == "" || sourceType.second == "text/calendar" ||
65             sourceType.second == "text/x-vcalendar" /* this is for backwards compatibility with broken configs */ ) {
66 #ifdef ENABLE_ECAL
67             return new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_EVENT, params);
68 #else
69             return isMe ? RegisterSyncSource::InactiveSource : NULL;
70 #endif
71         } else {
72             return NULL;
73         }
74     }
75
76     return NULL;
77 }
78
79 static RegisterSyncSource registerMe("Evolution Calendar/Task List/Memos",
80 #ifdef ENABLE_ECAL
81                                      true,
82 #else
83                                      false,
84 #endif
85                                      createSource,
86                                      "Evolution Calendar = calendar = events = evolution-events\n"
87                                      "   always uses iCalendar 2.0\n"
88                                      "Evolution Task List = Evolution Tasks = todo = tasks = evolution-tasks\n"
89                                      "   always uses iCalendar 2.0\n"
90                                      "Evolution Memos = memo = memos = evolution-memos\n"
91                                      "   plain text in UTF-8 (default) = text/plain\n"
92                                      "   iCalendar 2.0 = text/calendar\n"
93                                      "   The later format is not tested because none of the\n"
94                                      "   supported SyncML servers accepts it.\n",
95                                      Values() +
96                                      (Aliases("Evolution Calendar") + "evolution-calendar") +
97                                      (Aliases("Evolution Task List") + "Evolution Tasks" + "evolution-tasks") +
98                                      (Aliases("Evolution Memos") + "evolution-memos"));
99
100 #ifdef ENABLE_ECAL
101 #ifdef ENABLE_UNIT_TESTS
102
103 class EvolutionCalendarTest : public CppUnit::TestFixture {
104     CPPUNIT_TEST_SUITE(EvolutionCalendarTest);
105     CPPUNIT_TEST(testInstantiate);
106     CPPUNIT_TEST(testOpenDefaultCalendar);
107     CPPUNIT_TEST(testOpenDefaultTodo);
108     CPPUNIT_TEST(testOpenDefaultMemo);
109     CPPUNIT_TEST(testTimezones);
110     CPPUNIT_TEST_SUITE_END();
111
112 protected:
113     static string addItem(boost::shared_ptr<EvolutionSyncSource> source,
114                           string &data) {
115         SyncItem item;
116
117         item.setData(data.c_str(), data.size());
118         source->addItemThrow(item);
119         CPPUNIT_ASSERT(item.getKey());
120         return item.getKey();
121     }
122
123     void testInstantiate() {
124         boost::shared_ptr<EvolutionSyncSource> source;
125         source.reset(EvolutionSyncSource::createTestingSource("calendar", "calendar", true));
126         source.reset(EvolutionSyncSource::createTestingSource("calendar", "evolution-calendar", true));
127         source.reset(EvolutionSyncSource::createTestingSource("calendar", "Evolution Calendar:text/calendar", true));
128
129         source.reset(EvolutionSyncSource::createTestingSource("calendar", "tasks", true));
130         source.reset(EvolutionSyncSource::createTestingSource("calendar", "evolution-tasks", true));
131         source.reset(EvolutionSyncSource::createTestingSource("calendar", "Evolution Tasks", true));
132         source.reset(EvolutionSyncSource::createTestingSource("calendar", "Evolution Task List:text/calendar", true));
133
134         source.reset(EvolutionSyncSource::createTestingSource("calendar", "memos", true));
135         source.reset(EvolutionSyncSource::createTestingSource("calendar", "evolution-memos", true));
136         source.reset(EvolutionSyncSource::createTestingSource("calendar", "Evolution Memos:text/plain", true));
137         source.reset(EvolutionSyncSource::createTestingSource("calendar", "Evolution Memos:text/calendar", true));
138     }
139
140     void testOpenDefaultCalendar() {
141         boost::shared_ptr<EvolutionSyncSource> source;
142         source.reset(EvolutionSyncSource::createTestingSource("calendar", "evolution-calendar", true, NULL));
143         CPPUNIT_ASSERT_NO_THROW(source->open());
144     }
145
146     void testOpenDefaultTodo() {
147         boost::shared_ptr<EvolutionSyncSource> source;
148         source.reset(EvolutionSyncSource::createTestingSource("calendar", "evolution-tasks", true, NULL));
149         CPPUNIT_ASSERT_NO_THROW(source->open());
150     }
151
152     void testOpenDefaultMemo() {
153         boost::shared_ptr<EvolutionSyncSource> source;
154         source.reset(EvolutionSyncSource::createTestingSource("calendar", "evolution-memos", true, NULL));
155         CPPUNIT_ASSERT_NO_THROW(source->open());
156     }
157
158     void testTimezones() {
159         const char *prefix = getenv("CLIENT_TEST_EVOLUTION_PREFIX");
160         if (!prefix) {
161             prefix = "SyncEvolution_Test_";
162         }
163
164         boost::shared_ptr<EvolutionSyncSource> source;
165         source.reset(EvolutionSyncSource::createTestingSource("ical20", "evolution-calendar", true, prefix));
166         CPPUNIT_ASSERT_NO_THROW(source->open());
167
168         string newyork = 
169             "BEGIN:VCALENDAR\n"
170             "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
171             "VERSION:2.0\n"
172             "BEGIN:VTIMEZONE\n"
173             "TZID:America/New_York\n"
174             "BEGIN:STANDARD\n"
175             "TZOFFSETFROM:-0400\n"
176             "TZOFFSETTO:-0500\n"
177             "TZNAME:EST\n"
178             "DTSTART:19701025T020000\n"
179             "RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10\n"
180             "END:STANDARD\n"
181             "BEGIN:DAYLIGHT\n"
182             "TZOFFSETFROM:-0500\n"
183             "TZOFFSETTO:-0400\n"
184             "TZNAME:EDT\n"
185             "DTSTART:19700405T020000\n"
186             "RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=4\n"
187             "END:DAYLIGHT\n"
188             "END:VTIMEZONE\n"
189             "BEGIN:VEVENT\n"
190             "UID:artificial\n"
191             "DTSTAMP:20060416T205224Z\n"
192             "DTSTART;TZID=America/New_York:20060406T140000\n"
193             "DTEND;TZID=America/New_York:20060406T143000\n"
194             "TRANSP:OPAQUE\n"
195             "SEQUENCE:2\n"
196             "SUMMARY:timezone New York with custom definition\n"
197             "DESCRIPTION:timezone New York with custom definition\n"
198             "CLASS:PUBLIC\n"
199             "CREATED:20060416T205301Z\n"
200             "LAST-MODIFIED:20060416T205301Z\n"
201             "END:VEVENT\n"
202             "END:VCALENDAR\n";
203
204         string luid;
205         CPPUNIT_ASSERT_NO_THROW(luid = addItem(source, newyork));
206
207         string newyork_suffix = newyork;
208         boost::replace_first(newyork_suffix,
209                              "UID:artificial",
210                              "UID:artificial-2");
211         boost::replace_all(newyork_suffix,
212                            "TZID:America/New_York",
213                            "TZID://FOOBAR/America/New_York-SUFFIX");
214         CPPUNIT_ASSERT_NO_THROW(luid = addItem(source, newyork_suffix));
215
216         
217         string notimezone = 
218             "BEGIN:VCALENDAR\n"
219             "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
220             "VERSION:2.0\n"
221             "BEGIN:VEVENT\n"
222             "UID:artificial-3\n"
223             "DTSTAMP:20060416T205224Z\n"
224             "DTSTART;TZID=America/New_York:20060406T140000\n"
225             "DTEND;TZID=America/New_York:20060406T143000\n"
226             "TRANSP:OPAQUE\n"
227             "SEQUENCE:2\n"
228             "SUMMARY:timezone New York without custom definition\n"
229             "DESCRIPTION:timezone New York without custom definition\n"
230             "CLASS:PUBLIC\n"
231             "CREATED:20060416T205301Z\n"
232             "LAST-MODIFIED:20060416T205301Z\n"
233             "END:VEVENT\n"
234             "END:VCALENDAR\n";
235         CPPUNIT_ASSERT_NO_THROW(luid = addItem(source, notimezone));
236
237         // fake VTIMEZONE where daylight saving starts on first Sunday in March
238         string fake_march = 
239             "BEGIN:VCALENDAR\n"
240             "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
241             "VERSION:2.0\n"
242             "BEGIN:VTIMEZONE\n"
243             "TZID:FAKE\n"
244             "BEGIN:STANDARD\n"
245             "TZOFFSETFROM:-0400\n"
246             "TZOFFSETTO:-0500\n"
247             "TZNAME:EST MARCH\n"
248             "DTSTART:19701025T020000\n"
249             "RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10\n"
250             "END:STANDARD\n"
251             "BEGIN:DAYLIGHT\n"
252             "TZOFFSETFROM:-0500\n"
253             "TZOFFSETTO:-0400\n"
254             "TZNAME:EDT\n"
255             "DTSTART:19700405T020000\n"
256             "RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=3\n"
257             "END:DAYLIGHT\n"
258             "END:VTIMEZONE\n"
259             "BEGIN:VEVENT\n"
260             "UID:artificial-4\n"
261             "DTSTAMP:20060416T205224Z\n"
262             "DTSTART;TZID=FAKE:20060406T140000\n"
263             "DTEND;TZID=FAKE:20060406T143000\n"
264             "TRANSP:OPAQUE\n"
265             "SEQUENCE:2\n"
266             "SUMMARY:fake timezone with daylight starting in March\n"
267             "CLASS:PUBLIC\n"
268             "CREATED:20060416T205301Z\n"
269             "LAST-MODIFIED:20060416T205301Z\n"
270             "END:VEVENT\n"
271             "END:VCALENDAR\n";
272         CPPUNIT_ASSERT_NO_THROW(luid = addItem(source, fake_march));
273
274         string fake_may = fake_march;
275         boost::replace_first(fake_may,
276                              "UID:artificial-4",
277                              "UID:artificial-5");
278         boost::replace_first(fake_may,
279                              "RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=3",
280                              "RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=5");
281         boost::replace_first(fake_may,
282                              "starting in March",
283                              "starting in May");
284         boost::replace_first(fake_may,
285                              "TZNAME:EST MARCH",
286                              "TZNAME:EST MAY");
287         CPPUNIT_ASSERT_NO_THROW(luid = addItem(source, fake_may));
288
289         // insert again, shouldn't re-add timezone
290         CPPUNIT_ASSERT_NO_THROW(luid = addItem(source, fake_may));
291     }
292 };
293
294 SYNCEVOLUTION_TEST_SUITE_REGISTRATION(EvolutionCalendarTest);
295
296 #endif // ENABLE_UNIT_TESTS
297 #endif // ENABLE_ECAL