2 * Funambol is a mobile platform developed by Funambol, Inc.
3 * Copyright (C) 2003 - 2007 Funambol, Inc.
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Affero General Public License version 3 as published by
7 * the Free Software Foundation with the addition of the following permission
8 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
9 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
10 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program; if not, see http://www.gnu.org/licenses or write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
23 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
25 * The interactive user interfaces in modified source and object code versions
26 * of this program must display Appropriate Legal Notices, as required under
27 * Section 5 of the GNU Affero General Public License version 3.
29 * In accordance with Section 7(b) of the GNU Affero General Public License
30 * version 3, these Appropriate Legal Notices must retain the display of the
31 * "Powered by Funambol" logo. If the display of the logo is not reasonably
32 * feasible for technical reasons, the Appropriate Legal Notices must display
33 * the words "Powered by Funambol".
36 #include "vocl/WinEventSIF.h"
37 #include "vocl/VConverter.h"
38 #include "vocl/constants.h"
39 #include "base/stringUtils.h"
40 #include "vocl/sifUtils.h"
41 #include "base/globalsdef.h"
49 WinEventSIF::WinEventSIF() {
54 // Constructor: fills propertyMap parsing the passed SIF string
55 WinEventSIF::WinEventSIF(const wstring dataString, const wchar_t** fields, const wchar_t** recFields) {
59 recPatternSIF.setSifFields(recFields);
65 WinEventSIF::~WinEventSIF() {
70 wstring& WinEventSIF::toString() {
72 wstring propertyValue;
73 sif = L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
74 sif += L"<appointment>\n";
76 sif += L"<SIFVersion>";
78 sif += L"</SIFVersion>\n";
81 // Add all appointment properties
83 map<wstring,wstring>::iterator it = propertyMap.begin();
84 while (it != propertyMap.end()) {
85 propertyValue = it->second;
86 propertyValue = adaptToSIFSpecs(it->first, propertyValue);
87 addPropertyToSIF(sif, it->first, propertyValue);
92 // Append recurrence properties
95 if (getProperty(L"IsRecurring", element)) {
96 wstring recurrenceSIF = recPatternSIF.toString();
97 if(recurrenceSIF != L"") {
102 // If recurring, append events exceptions
104 bool isRec = (element != TEXT("0"));
106 list<wstring>::iterator it;
108 if (!excludeDate.size() && !includeDate.size()) {
109 sif += L"<Exceptions/>\n";
112 sif += L"<Exceptions>\n";
114 // Exceptions: ExcludeDate
115 if (excludeDate.size() > 0) {
116 for (it = excludeDate.begin(); it != excludeDate.end(); it++) {
117 wstring exDate = adaptToSIFSpecs(L"ExcludeDate", *it);
118 addPropertyToSIF(sif, L"ExcludeDate", exDate);
121 // Exceptions: IncludeDate (should be empty for Outlook and WM)
122 if (includeDate.size() > 0) {
123 for (it = includeDate.begin(); it != includeDate.end(); it++) {
124 wstring rDate = adaptToSIFSpecs(L"IncludeDate", *it);
125 addPropertyToSIF(sif, L"IncludeDate", rDate);
129 sif += L"</Exceptions>\n";
133 // TIMEZONE (only if recurring and tzInfo is used).
142 // TODO: format recipients
145 sif += L"</appointment>";
152 int WinEventSIF::parse(const wstring data) {
155 LOG.error(ERR_SIFFIELDS_NULL);
160 // Check if <appointment> tag is present...
161 wstring::size_type pos = 0;
162 wstring itemTypeTag = L"<appointment>";
163 pos = data.find(itemTypeTag, 0);
164 if (pos == wstring::npos) {
165 LOG.error("Tag '%ls' not found", itemTypeTag.c_str());
168 wstring propertyValue;
171 // Set appointment properties
173 for (int i=0; sifFields[i]; i++) {
174 // Set only properties found!
175 if (!getElementContent(data, sifFields[i], propertyValue, 0)) {
177 replaceAll(L"<", L"<", propertyValue);
178 replaceAll(L">", L">", propertyValue);
179 replaceAll(L"&", L"&", propertyValue);
181 propertyValue = adaptFromSIFSpecs(sifFields[i], propertyValue);
182 setProperty(sifFields[i], propertyValue);
187 // Set recurrence properties
190 if (getProperty(L"IsRecurring", element)) {
191 bool isRec = (element != TEXT("0"));
194 // Fill recPatternSIF propertyMap.
195 recPatternSIF.parse(data);
197 // Fill exceptions lists.
198 parseExceptions(data);
201 bool tzFound = parseTimezone(data);
202 useTimezone = tzFound;
203 getRecPattern()->setUseTimezone(tzFound);
208 // TODO: parse recipients and fill recipients list
215 WinRecurrenceSIF* WinEventSIF::getRecPattern() {
216 return &recPatternSIF;
221 wstring WinEventSIF::adaptToSIFSpecs(const wstring& propName, const wstring& propValue) {
223 wstring propertyValue = L"";
225 if (propValue.length() == 8) {
226 if ( propName == L"Start" ||
227 propName == L"ExcludeDate" ||
228 propName == L"IncludeDate" ) {
229 propertyValue = formatDateWithMinus(propValue);
231 else if (propName == L"End") {
232 // the End value must be decremented of a day in allDayEvent appointment
234 stringTimeToDouble(propValue, &d);
236 doubleToStringTime(propertyValue, d, true);
237 propertyValue = formatDateWithMinus(propertyValue);
241 if (propertyValue != L"") {
242 return propertyValue;
249 wstring WinEventSIF::adaptFromSIFSpecs(const wstring& propName, const wstring& propValue) {
251 wstring propertyValue = L"";
253 // the End value must be incremented of a day in allDayEvent appointment
254 if ( propName == L"End" &&
255 (propValue.size() == 8 || propValue.size() == 10)) { // both format yyyyMMdd and yyyy-MM-dd
257 stringTimeToDouble(propValue, &d);
259 doubleToStringTime(propertyValue, d, true);
263 if (propertyValue != L"") {
264 return propertyValue;
271 void WinEventSIF::parseExceptions(const wstring& sifString) {
275 if (getElementContent(sifString, L"Exceptions", exString)) {
276 // Not found: nothing to do.
280 // <Exceptions> not empty -> parse all exceptions
281 if (exString.size() > 0) {
282 wstring exDate, rDate;
283 wstring::size_type pos, start, end;
285 // Parse all <ExcludeDate>
287 while ( !getElementContent(exString, L"ExcludeDate", exDate, pos, start, end) ) {
289 if (exDate.size() > 0) {
290 excludeDate.push_back(exDate);
294 // Parse all <IncludeDate>
295 pos = start = end = 0;
296 while ( !getElementContent(exString, L"IncludeDate", rDate, pos, start, end) ) {
298 if (rDate.size() > 0) {
299 includeDate.push_back(rDate);
306 void WinEventSIF::addTimezone(wstring& sif) {
308 sif += L"<Timezone>\n";
311 // <BasicOffset> = - (Bias + StandardBias) [StandardBias is usually = 0]
313 sif += L"<BasicOffset>";
314 sif += formatBias(tzInfo.Bias + tzInfo.StandardBias);
315 sif += L"</BasicOffset>\n";
318 // <DayLight> = list of tag for every year that this appointment occurr.
322 getIntervalOfRecurrence(&yearBegin, &yearEnd);
325 // DSTOffset = - (Bias + StandardBias + DaylightBias)
326 // [StandardBias is usually = 0]
328 int diffBias = tzInfo.Bias + + tzInfo.StandardBias + tzInfo.DaylightBias;
329 wstring daylightBias;
332 daylightBias = formatBias(diffBias);
335 // Max 6 iterations (for infinite recurrences).
336 if (yearEnd - yearBegin > MAX_DAYLIGHT_PROPS) {
337 yearEnd = yearBegin + MAX_DAYLIGHT_PROPS;
341 // Add a DayLight tag for every year that this appointment occurr. (max = 6)
342 for (int year = yearBegin; year < yearEnd; year++) {
344 wstring daylightDate = getDateFromTzRule(year, tzInfo.DaylightDate);
345 wstring standardDate = getDateFromTzRule(year, tzInfo.StandardDate);
347 sif += L"<DayLight>\n";
348 sif += L"<DSTOffset>" ; sif += daylightBias; sif += L"</DSTOffset>";
349 sif += L"<DSTStart>" ; sif += daylightDate; sif += L"</DSTStart>" ;
350 sif += L"<DSTEnd>" ; sif += standardDate; sif += L"</DSTEnd>" ;
351 if (wcslen(tzInfo.StandardName) > 0) {
352 sif += L"<StandardName>"; sif += tzInfo.StandardName; sif += L"</StandardName>";
355 sif += L"<StandardName/>";
357 if (wcslen(tzInfo.StandardName) > 0) {
358 sif += L"<DSTName>"; sif += tzInfo.DaylightName; sif += L"</DSTName>\n";
361 sif += L"<DSTName/>";
363 sif += L"</DayLight>\n";
367 // No daylight for this timezone
368 sif += L"<DayLight/>\n";
371 sif += L"</Timezone>\n";
375 bool WinEventSIF::parseTimezone(const wstring& data) {
378 if (getElementContent(data, L"Timezone", timezone, 0)) {
381 if (timezone.size() == 0) {
387 if ( !getElementContent(timezone, L"BasicOffset", element, 0) && element.size() ) {
389 int bias = parseBias(element.c_str());
391 wstring dstOffset, standardName, daylightName;
392 list<wstring> daylightDates;
393 list<wstring> standardDates;
396 // Search all <DayLight> inside <Timezone> (one for every year)
398 wstring::size_type start = 0, end = 0;
399 bool dstFlag = false;
401 while (!getElementContent(timezone, L"DayLight", daylight, end, start, end)) {
402 if (daylight.size()) {
403 // Found a DayLight tag. Many props are redundant, now are overwritten.
405 getElementContent(daylight, L"DSTOffset", dstOffset);
406 getElementContent(daylight, L"DSTStart", element);
407 daylightDates.push_back(element);
408 getElementContent(daylight, L"DSTEnd", element);
409 standardDates.push_back(element);
410 getElementContent(daylight, L"StandardName", standardName);
411 getElementContent(daylight, L"DSTName", daylightName);
414 // Empty <DayLight/> = no daylight for this timezone
422 // If we have all required data, fill the tzInfo structure.
424 if (dstFlag == false) {
425 // Easy timezone, no DST
428 tzInfo.StandardBias = 0; // Cannot retrieve it, assume = 0 (usually is 0)
429 tzInfo.DaylightBias = 0;
430 //tzInfo.DaylightDate = 0;
431 //tzInfo.StandardDate = 0;
432 wcsncpy(tzInfo.StandardName, standardName.c_str(), 32);
433 wcsncpy(tzInfo.DaylightName, daylightName.c_str(), 32);
435 else if (dstOffset.size() && daylightDates.size() && standardDates.size() ) {
436 // Standard timezone, the DST rules are extracted from list of dates
438 // >> StandardBias = 0 (Cannot retrieve it, assume = 0 as usually is 0)
439 // >> DaylightBias = - (DSTOffset + Bias)
442 tzInfo.StandardBias = 0;
443 tzInfo.DaylightBias = parseBias(dstOffset.c_str()) - bias;
444 tzInfo.DaylightDate = getTzRuleFromDates(daylightDates);
445 tzInfo.StandardDate = getTzRuleFromDates(standardDates);
446 wcsncpy(tzInfo.StandardName, standardName.c_str(), 32);
447 wcsncpy(tzInfo.DaylightName, daylightName.c_str(), 32);
451 // <BasicOffset> missing (it's mandatory)