Imported Upstream version 0.8~alpha1
[platform/upstream/syncevolution.git] / src / client-api / src / c++ / common / vocl / iCalendar / iCalConverter.cpp
1 /*
2  * Funambol is a mobile platform developed by Funambol, Inc. 
3  * Copyright (C) 2003 - 2007 Funambol, Inc.
4  * 
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.
11  * 
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
15  * details.
16  * 
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,
20  * MA 02110-1301 USA.
21  * 
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.
24  * 
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.
28  * 
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".
34  */
35
36
37 #include "vocl/iCalendar/iCalConverter.h"
38 #include "base/util/WString.h"
39 #include "base/globalsdef.h"
40
41 USE_NAMESPACE
42
43
44 iCalConverter::iCalConverter() {
45     iCalendar = NULL;
46     calendar = NULL;
47 }
48
49 iCalConverter::~iCalConverter() {
50     if (iCalendar) {
51         delete [] iCalendar; iCalendar = NULL;
52     }
53     if (calendar) {
54         delete calendar; calendar = NULL;
55     }
56 }
57
58 void iCalConverter::setSource(WCHAR* inputICalendar) {
59     if(iCalendar) {
60         delete[] iCalendar;
61         iCalendar = NULL;
62     }
63     if(inputICalendar) {
64         iCalendar = new WCHAR[wcslen(inputICalendar) + 1];
65         wcscpy(iCalendar, inputICalendar);
66     }
67     if(calendar) {
68         delete calendar; calendar = NULL;
69     }
70 }
71
72 void iCalConverter::setSource(Calendar& inputCalendar) {
73     if(calendar)
74         delete calendar;
75     calendar = (Calendar *)inputCalendar.clone();
76     if(iCalendar) {
77         delete [] iCalendar; iCalendar = NULL;
78     }
79 }
80
81 void iCalConverter::getICalendar(WCHAR* ouputICalendar) {
82     if(iCalendar) {
83         if(!ouputICalendar)
84             return;
85         wcscpy(ouputICalendar, iCalendar);
86     }
87     else
88         ouputICalendar = NULL;
89 }
90
91 void iCalConverter::getCalendar(Calendar** outputCalendar) {
92     if(calendar) {
93         *outputCalendar = (Calendar *)calendar->clone();
94     }
95     else
96         *outputCalendar = NULL;
97 }
98
99 bool iCalConverter::convert(WString& errorDescription, long* errorCode) {
100     errorDescription = TEXT("");
101     *errorCode = ERROR_SUCCESS;
102
103     if(!calendar && !iCalendar)
104         return false;
105     if(calendar && iCalendar)
106         return true;
107     if(calendar) {
108
109         iCalendar = calendar->toString();
110
111         if(!calendar->getProdID() || !calendar->getProdID()->getValue()) {
112             *errorCode = ERROR_KEY_PROPERTY_MISSING;
113             errorDescription = TEXT("'PRODID' property is missing");
114             delete [] iCalendar; iCalendar = NULL;
115             return false;
116         }
117
118         if(!calendar->getVersion() || !calendar->getVersion()->getValue()) {
119             *errorCode = ERROR_KEY_PROPERTY_MISSING;
120             errorDescription = TEXT("'VERSION' property is missing");
121             delete [] iCalendar; iCalendar = NULL;
122             return false;
123         }
124         if(calendar->getEvents())
125             for(int i=0; i<calendar->getEvents()->size(); i++)
126                 if(!validateEvent(((Event*)calendar->getEvents()->get(i)), errorDescription, errorCode)) {
127                     delete [] iCalendar; iCalendar = NULL;
128                     return false;
129             }
130         if(calendar->getToDos())
131             for(int i=0; i<calendar->getToDos()->size(); i++)
132                 if(!validateTodo(((ToDo*)calendar->getToDos()->get(i)), errorDescription, errorCode)) {
133                     delete [] iCalendar; iCalendar = NULL;
134                     return false;
135                 }
136
137         return true;
138    }
139     if (iCalendar) {
140
141         calendar = new Calendar();
142         VObject* vo = VConverter::parse(iCalendar);
143         if(!vo) {
144             *errorCode = ERROR_PARSING_ERROR;
145             errorDescription = TEXT("Invalid VObject returned");
146             return false;
147         }
148
149         int n = vo->propertiesCount();
150
151         if(wcscmp(vo->getProperty(0)->getName(), TEXT("BEGIN")) ||
152             !vo->getProperty(0)->getValue() ||
153             wcscmp(vo->getProperty(0)->getValue(), TEXT("VCALENDAR"))) {
154                 *errorCode = ERROR_KEY_PROPERTY_MISSING;
155                 errorDescription = TEXT("'BEGIN:VCALENDAR' property is missing");
156                 return false;
157             }
158
159         if(wcscmp(vo->getProperty(n-1)->getName(), TEXT("END")) ||
160             !vo->getProperty(n-1)->getValue() ||
161             wcscmp(vo->getProperty(n-1)->getValue(), TEXT("VCALENDAR"))) {
162                 *errorCode = ERROR_KEY_PROPERTY_MISSING;
163                 errorDescription = TEXT("'END:VCALENDAR' property is missing");
164                 return false;
165             }
166
167         if(!vo->containsProperty(TEXT("VERSION"))) {
168             *errorCode = ERROR_KEY_PROPERTY_MISSING;
169             errorDescription = TEXT("'VERSION' property is missing");
170             return false;
171         }
172
173         if(vo->containsProperty(TEXT("VERSION")) &&
174             (!vo->getProperty(TEXT("VERSION")) || wcscmp(vo->getProperty(TEXT("VERSION"))->getValue(), TEXT("2.0")))) {
175                 *errorCode = ERROR_ILLEGAL_VERSION_NUMBER;
176                 if(vo->getProperty(TEXT("VERSION"))) {
177                     errorDescription = TEXT("Illegal version number : ");
178                     errorDescription += vo->getProperty(TEXT("VERSION"))->getValue();
179                 }
180                 else {
181                     errorDescription = TEXT("Illegal version number");
182                 }
183                 return false;
184             }
185         else {
186             iCalProperty* prop = new iCalProperty(vo->getProperty(TEXT("VERSION"))->getValue());
187             calendar->setVersion(*prop);
188             vo->removeProperty(TEXT("VERSION"));
189             delete prop;
190         }
191
192         if(!vo->containsProperty(TEXT("PRODID")) || !vo->getProperty(TEXT("PRODID"))) {
193             *errorCode = ERROR_KEY_PROPERTY_MISSING;
194             errorDescription = TEXT("'PRODID' property is missing");
195             return false;
196         }
197         else {
198             iCalProperty* prop = new iCalProperty(vo->getProperty(TEXT("PRODID"))->getValue());
199             calendar->setProdID(*prop);
200             vo->removeProperty(TEXT("PRODID"));
201             delete prop;
202         }
203
204         if(vo->containsProperty(TEXT("CALSCALE")) ||
205             vo->getProperty(TEXT("CALSCALE"))) {
206                 iCalProperty* prop = new iCalProperty(vo->getProperty(TEXT("CALSCALE"))->getValue());
207                 calendar->setCalScale(*prop);
208                 vo->removeProperty(TEXT("CALSCALE"));
209                 delete prop;
210             }
211
212         if(vo->containsProperty(TEXT("METHOD")) ||
213             vo->getProperty(TEXT("METHOD"))) {
214                 iCalProperty* prop = new iCalProperty(vo->getProperty(TEXT("METHOD"))->getValue());
215                 calendar->setMethod(*prop);
216                 vo->removeProperty(TEXT("METHOD"));
217                 delete prop;
218             }
219
220         //extract VEVENTs from vo
221         Event* ev;
222         while(ev = extractEvent(vo, errorDescription, errorCode)) {
223             if (!validateEvent(ev, errorDescription, errorCode)) {
224                 delete ev; ev = NULL;
225                 return false;
226             }
227             calendar->addEvent(ev);
228             delete ev; ev = NULL;
229         }
230
231         //extract VTODOs from vo
232         ToDo* task;
233         while(task = extractTask(vo, errorDescription, errorCode)) {
234             if (!validateTodo(task, errorDescription, errorCode)) {
235                 delete task; task = NULL;
236                 return false;
237             }
238             calendar->addToDo(task);
239             delete task; task = NULL;
240         }
241     }
242
243     return true;
244 }
245
246 Event* iCalConverter::extractEvent(VObject* vo, WString& errorDescription, long* errorCode) {
247     int i,m;
248         int beginEvent = -1;
249     int endEvent = -1;
250     for(i = 0, m = vo->propertiesCount(); i < m ; i++) {
251         if(beginEvent == -1 && !wcscmp(vo->getProperty(i)->getName(), TEXT("BEGIN")) &&
252             vo->getProperty(i)->getValue() &&
253             !wcscmp(vo->getProperty(i)->getValue(), TEXT("VEVENT")))
254             beginEvent = i;
255         if(endEvent == -1 && !wcscmp(vo->getProperty(i)->getName(),TEXT("END")) &&
256             vo->getProperty(i)->getValue() &&
257             !wcscmp(vo->getProperty(i)->getValue(),TEXT("VEVENT"))) {
258                 endEvent = i;
259                 break;
260             }
261     }
262
263     if(beginEvent == -1)
264         return NULL;
265
266     if(beginEvent > endEvent) {
267         *errorCode = ERROR_INVALID_EVENT_BLOCK;
268         errorDescription = TEXT("BEGIN:VEVENT property found, but END:VEVENT is missing");
269         return NULL;
270     }
271
272     Event* ret = new Event();
273     for(i = beginEvent; i <= endEvent; i++) {
274         ret->addProperty(vo->getProperty(i));
275         vo->removeProperty(i);
276         --i;
277         --endEvent;
278     }
279
280     extractAlarm((VObject*) ret);
281
282     return ret;
283 }
284
285 ToDo* iCalConverter::extractTask(VObject* vo, WString& errorDescription, long* errorCode) {
286     int i,m;
287         int beginTask = -1;
288     int endTask = -1;
289     for(i = 0, m = vo->propertiesCount(); i < m ; i++) {
290         if(beginTask == -1 && !wcscmp(vo->getProperty(i)->getName(), TEXT("BEGIN")) &&
291             vo->getProperty(i)->getValue() &&
292             !wcscmp(vo->getProperty(i)->getValue(), TEXT("VTODO")))
293             beginTask = i;
294         if(endTask == -1 && !wcscmp(vo->getProperty(i)->getName(),TEXT("END")) &&
295             vo->getProperty(i)->getValue() &&
296             !wcscmp(vo->getProperty(i)->getValue(),TEXT("VTODO"))) {
297                 endTask = i;
298                 break;
299             }
300     }
301
302     if(beginTask == -1)
303         return NULL;
304
305     if(beginTask > endTask) {
306         *errorCode = ERROR_INVALID_TODO_BLOCK;
307         errorDescription = TEXT("BEGIN:VTODO property found, but END:VTODO is missing");
308         return NULL;
309     }
310
311     ToDo* ret = new ToDo();
312     for(i = beginTask; i <= endTask; i++) {
313         ret->addProperty(vo->getProperty(i));
314         vo->removeProperty(i);
315         --i;
316         --endTask;
317     }
318
319     extractAlarm((VObject*) ret);
320
321     return ret;
322 }
323
324 void iCalConverter::extractAlarm(VObject* vo){
325     int beginAlarm = -1;
326     int endAlarm = -1;
327     for(int i = 0, m = vo->propertiesCount(); i < m ; i++) {
328         if(beginAlarm== -1 && !wcscmp(vo->getProperty(i)->getName(), TEXT("BEGIN")) &&
329             vo->getProperty(i)->getValue() &&
330             !wcscmp(vo->getProperty(i)->getValue(), TEXT("VALARM")))
331             beginAlarm = i;
332         if(endAlarm == -1 && !wcscmp(vo->getProperty(i)->getName(),TEXT("END")) &&
333             vo->getProperty(i)->getValue() &&
334             !wcscmp(vo->getProperty(i)->getValue(),TEXT("VALARM"))) {
335                 endAlarm = i;
336                 break;
337             }
338     }
339
340     if(beginAlarm != -1 && endAlarm > beginAlarm)
341         for(int i = beginAlarm; i <= endAlarm; i++) {
342             vo->removeProperty(i);
343             --i;
344             --endAlarm;
345         }
346 }
347
348 bool iCalConverter::validateEvent(Event* ev, WString& errorDescription, long* errorCode) {
349   //validate BEGIN, END, UID
350     if(wcscmp(ev->getProperty(0)->getName(), TEXT("BEGIN")) ||
351         wcscmp(ev->getProperty(0)->getValue(), TEXT("VEVENT"))) {
352             *errorCode = ERROR_KEY_PROPERTY_MISSING;
353             errorDescription = TEXT("Invalid EVENT: 'BEGIN' property is missing");
354             return false;
355         }
356     if(wcscmp(ev->getProperty(ev->propertiesCount()-1)->getName(), TEXT("END")) ||
357         wcscmp(ev->getProperty(ev->propertiesCount()-1)->getValue(), TEXT("VEVENT"))) {
358             *errorCode = ERROR_KEY_PROPERTY_MISSING;
359             errorDescription = TEXT("Invalid EVENT: 'END' property is missing");
360             return false;
361         }
362     if(!ev->containsProperty(TEXT("UID"))) {
363         *errorCode = ERROR_KEY_PROPERTY_MISSING;
364         errorDescription = TEXT("Invalid EVENT: 'UID' property is missing");
365         return false;
366     }
367     for(int i = 0; i < ev->propertiesCount(); i++) {
368         if(!wcsstr(EVENT_PROPERTIES_LIST, ev->getProperty(i)->getName()) &&
369             wcsstr(ev->getProperty(i)->getName(),TEXT("X-")) != ev->getProperty(i)->getName()) {
370                 *errorCode = ERROR_ILLEGAL_PROPERTY_NAME;
371                 errorDescription = TEXT("EVENT - Illegal property name : %s");
372                 errorDescription += ev->getProperty(i)->getName();
373                 return false;
374             }
375         if(ev->getProperty(i)->getValue() && !validatePropery(ev->getProperty(i), errorDescription, errorCode))
376             return false;
377     }
378     return true;
379 }
380 bool iCalConverter::validateTodo(ToDo* task, WString& errorDescription, long* errorCode) {
381     //validate BEGIN, END, UID
382     if(wcscmp(task->getProperty(0)->getName(), TEXT("BEGIN")) ||
383         wcscmp(task->getProperty(0)->getValue(), TEXT("VTODO"))) {
384             *errorCode = ERROR_KEY_PROPERTY_MISSING;
385             errorDescription = TEXT("Invalid TODO: 'BEGIN' property is missing");
386             return false;
387         }
388     if(wcscmp(task->getProperty(task->propertiesCount()-1)->getName(), TEXT("END")) ||
389         wcscmp(task->getProperty(task->propertiesCount()-1)->getValue(), TEXT("VTODO"))) {
390             *errorCode = ERROR_KEY_PROPERTY_MISSING;
391             errorDescription = TEXT("Invalid TODO: 'END' property is missing");
392             return false;
393         }
394     if(!task->containsProperty(TEXT("UID"))) {
395         *errorCode = ERROR_KEY_PROPERTY_MISSING;
396         errorDescription = TEXT("Invalid TODO: 'UID' property is missing");
397         return false;
398     }
399     for(int i = 0; i < task->propertiesCount(); i++) {
400         if(!wcsstr(TODO_PROPERTIES_LIST, task->getProperty(i)->getName()) &&
401             wcsstr(task->getProperty(i)->getName(),TEXT("X-")) != task->getProperty(i)->getName()) {
402                 *errorCode = ERROR_ILLEGAL_PROPERTY_NAME;
403                 errorDescription = TEXT("TODO - Illegal property name : ");
404                 errorDescription += task->getProperty(i)->getName();
405                 return false;
406             }
407             if(task->getProperty(i)->getValue() && !validatePropery(task->getProperty(i), errorDescription, errorCode))
408                 return false;
409     }
410     return true;
411 }
412 bool iCalConverter::validatePropery(VProperty* vp, WString& errorDescription, long* errorCode) {
413
414     if(!wcscmp(vp->getName(), TEXT("CLASS"))) {
415         if(!wcsstr(CLASS_PROPERTY_VALUE, vp->getValue()) &&
416             wcsstr(vp->getValue(),TEXT("X-")) != vp->getValue()) {
417                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
418                 errorDescription = TEXT("Property CLASS, Invalid value : ");
419                 errorDescription += vp->getValue();
420                 return false;
421             }
422     }
423     else if(!wcscmp(vp->getName(), TEXT("CREATED"))) {
424         if(!validateDT(vp->getValue())) {
425             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
426             errorDescription = TEXT("Property CREATED, Invalid value : ");
427             errorDescription += vp->getValue();
428             return false;
429         }
430     }
431     else if(!wcscmp(vp->getName(), TEXT("DESCRIPTION"))) {
432         for(int i = 0; i < vp->parameterCount(); i++)
433             if(!wcsstr(COMMENT_PARAM_LIST, vp->getParameter(i)) &&
434                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
435                     *errorCode = ERROR_ILLEGAL_PARAMETER;
436                     errorDescription = TEXT("Property DESCRIPTION, Invalid parameter : ");
437                     errorDescription += vp->getParameter(i);
438                     return false;
439                 }
440     }
441     else if(!wcscmp(vp->getName(), TEXT("DTSTART"))) {
442         for(int i = 0; i < vp->parameterCount(); i++) {
443             if(!wcsstr(DT_PARAM_LIST, vp->getParameter(i)) &&
444                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
445                     *errorCode = ERROR_ILLEGAL_PARAMETER;
446                     errorDescription = TEXT("Property DTSTART, Invalid parameter : ");
447                     errorDescription += vp->getParameter(i);
448                     return false;
449                 }
450         }
451         if(vp->containsParameter(TEXT("VALUE")) && !wcscmp(vp->getParameterValue(TEXT("VALUE")), TEXT("DATE"))) {
452             if(!validateDate(vp->getValue())) {
453                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
454                 errorDescription = TEXT("Property DTSTART, Invalid value : ");
455                 errorDescription += vp->getValue();
456                 return false;
457             }
458         }
459         else if(!validateDT(vp->getValue()) && !validateDate(vp->getValue())) {
460             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
461             errorDescription = TEXT("Property DTSTART, Invalid value : ");
462             errorDescription += vp->getValue();
463             return false;
464         }
465     }
466     else if(!wcscmp(vp->getName(), TEXT("GEO"))) {
467         if(!validateGeo(vp->getValue())) {
468             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
469             errorDescription = TEXT("Property GEO, Invalid value format : ");
470             errorDescription += vp->getValue();
471             return false;
472         }
473     }
474     else if(!wcscmp(vp->getName(), TEXT("LAST-MODIFIED"))) {
475         if(!validateDT(vp->getValue())) {
476             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
477             errorDescription = TEXT("Property LAST-MODIFIED, Invalid value : ");
478             errorDescription += vp->getValue();
479             return false;
480         }
481     }
482     else if(!wcscmp(vp->getName(), TEXT("LOCATION"))) {
483         for(int i = 0; i < vp->parameterCount(); i++)
484             if(!wcsstr(COMMENT_PARAM_LIST, vp->getParameter(i)) &&
485                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
486                     *errorCode = ERROR_ILLEGAL_PARAMETER;
487                     errorDescription = TEXT("Property LOCATION, Invalid parameter : ");
488                     errorDescription += vp->getParameter(i);
489                     return false;
490                 }
491     }
492     else if(!wcscmp(vp->getName(), TEXT("ORGANIZER"))) {
493         for(int i = 0; i < vp->parameterCount(); i++)
494             if(!wcsstr(ORGANIZER_PARAM_LIST, vp->getParameter(i)) &&
495                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
496                     *errorCode = ERROR_ILLEGAL_PARAMETER;
497                     errorDescription = TEXT("Property ORGANIZER, Invalid parameter : ");
498                     errorDescription += vp->getParameter(i);
499                     return false;
500                 }
501     }
502     else if(!wcscmp(vp->getName(), TEXT("PRIORITY"))) {
503         if(vp->getValue()) {
504             if(wcslen(vp->getValue()) > 1 || !isdigit(vp->getValue()[0])) {
505                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
506                 errorDescription = TEXT("Property PRIORITY, Invalid value : ");
507                 errorDescription += vp->getValue();
508                 return false;
509             }
510         }
511     }
512     else if(!wcscmp(vp->getName(), TEXT("DTSTAMP"))) {
513         if(!validateDT(vp->getValue())) {
514             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
515             errorDescription = TEXT("Property DTSTAMP, Invalid value : ");
516             errorDescription += vp->getValue();
517             return false;
518         }
519     }
520     else if(!wcscmp(vp->getName(), TEXT("SUMMARY"))) {
521         for(int i = 0; i < vp->parameterCount(); i++)
522             if(!wcsstr(COMMENT_PARAM_LIST, vp->getParameter(i)) &&
523                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
524                     *errorCode = ERROR_ILLEGAL_PARAMETER;
525                     errorDescription = TEXT("Property SUMMARY, Invalid parameter : ");
526                     errorDescription += vp->getParameter(i);
527                     return false;
528                 }
529     }
530     else if(!wcscmp(vp->getName(), TEXT("TRANSP"))) {
531         if(wcscmp(vp->getName(), TEXT("OPAQUE")) && wcscmp(vp->getName(), TEXT("TRANSPARENT"))) {
532             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
533             errorDescription = TEXT("Property TRANSP, Invalid value : ");
534             errorDescription += vp->getValue();
535             return false;
536         }
537     }
538
539     else if(!wcscmp(vp->getName(), TEXT("RECURRENCE-ID"))) {
540         for(int i = 0; i < vp->parameterCount(); i++) {
541             if(!wcsstr(DT_PARAM_LIST, vp->getParameter(i)) &&
542                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i) &&
543                 wcscmp(vp->getParameter(i), TEXT("RANGE"))) {
544                     *errorCode = ERROR_ILLEGAL_PARAMETER;
545                     errorDescription = TEXT("Property RECURRENCE-ID, Invalid parameter : ");
546                     errorDescription += vp->getParameter(i);
547                     return false;
548                 }
549         }
550         if(vp->containsParameter(TEXT("VALUE")) && !wcscmp(vp->getParameterValue(TEXT("VALUE")), TEXT("DATE"))) {
551             if(!validateDate(vp->getValue())) {
552                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
553                 errorDescription = TEXT("Property RECURRENCE-ID, Invalid value : ");
554                 errorDescription += vp->getValue();
555                 return false;
556             }
557         }
558         else if(!validateDT(vp->getValue())) {
559             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
560             errorDescription = TEXT("Property RECURRENCE-ID, Invalid value : ");
561             errorDescription += vp->getValue();
562             return false;
563         }
564     }
565     else if(!wcscmp(vp->getName(), TEXT("DTEND"))) {
566         for(int i = 0; i < vp->parameterCount(); i++) {
567             if(!wcsstr(DT_PARAM_LIST, vp->getParameter(i)) &&
568                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
569                     *errorCode = ERROR_ILLEGAL_PARAMETER;
570                     errorDescription = TEXT("Property DTEND, Invalid parameter: ");
571                     errorDescription += vp->getParameter(i);
572                     return false;
573                 }
574         }
575         if(vp->containsParameter(TEXT("VALUE")) && !wcscmp(vp->getParameterValue(TEXT("VALUE")), TEXT("DATE"))) {
576             if(!validateDate(vp->getValue())) {
577                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
578                 errorDescription = TEXT("Property DTEND, Invalid value : ");
579                 errorDescription += vp->getValue();
580                 return false;
581             }
582         }
583         else if(!validateDT(vp->getValue()) && !validateDate(vp->getValue())) {
584             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
585             errorDescription = TEXT("Property DTEND, Invalid value : ");
586             errorDescription += vp->getValue();
587             return false;
588         }
589     }
590     else if(!wcscmp(vp->getName(), TEXT("DUE"))) {
591         for(int i = 0; i < vp->parameterCount(); i++) {
592             if(!wcsstr(DT_PARAM_LIST, vp->getParameter(i)) &&
593                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
594                     *errorCode = ERROR_ILLEGAL_PARAMETER;
595                     errorDescription = TEXT("Property DUE, Invalid parameter : ");
596                     errorDescription += vp->getParameter(i);
597                     return false;
598                 }
599         }
600         if(vp->containsParameter(TEXT("VALUE")) && !wcscmp(vp->getParameterValue(TEXT("VALUE")), TEXT("DATE"))) {
601             if(!validateDate(vp->getValue())) {
602                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
603                 errorDescription = TEXT("Property DUE, Invalid value : ");
604                 errorDescription += vp->getValue();
605                 return false;
606             }
607         }
608         else if(!validateDT(vp->getValue())) {
609             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
610             errorDescription = TEXT("Property DUE, Invalid value : ");
611             errorDescription += vp->getValue();
612             return false;
613         }
614     }
615     else if(!wcscmp(vp->getName(), TEXT("COMPLETED"))) {
616         if(!validateDT(vp->getValue())) {
617             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
618             errorDescription = TEXT("Property COMPLETED, Invalid value : ");
619             errorDescription += vp->getValue();
620             return false;
621         }
622     }
623     else if(!wcscmp(vp->getName(), TEXT("PERCENT-COMPLETE"))) {
624         if(wcslen(vp->getValue()) > 2 ||
625             (wcslen(vp->getValue()) == 1 && !isdigit(vp->getValue()[0])) ||
626             (wcslen(vp->getValue()) == 2 && (!isdigit(vp->getValue()[0]) || !isdigit(vp->getValue()[1])))) {
627             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
628             errorDescription = TEXT("Property PERCENT, Invalid value : ");
629             errorDescription += vp->getValue();
630             return false;
631             }
632     }
633     else if(!wcscmp(vp->getName(), TEXT("ATTACH"))) {
634         for(int i = 0; i < vp->parameterCount(); i++) {
635             if(!wcsstr(ATTACH_PARAM_LIST, vp->getParameter(i)) &&
636                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
637                     *errorCode = ERROR_ILLEGAL_PARAMETER;
638                     errorDescription = TEXT("Property ATTACH, Invalid parameter : ");
639                     errorDescription += vp->getParameter(i);
640                     return false;
641                 }
642             if(!wcscmp(vp->getParameter(i), TEXT("ENCODING"))
643                 && wcscmp(vp->getParameterValue(TEXT("ENCODING")), TEXT("BASE64"))) {
644                     *errorCode = ERROR_UNSUPPORTED_ENCODING;
645                     errorDescription = TEXT("Property ATTACH, unsupported encoding : ");
646                     errorDescription += vp->getParameterValue(TEXT("ENCODING"));
647                     return false;
648                 }
649         }
650     }
651     else if(!wcscmp(vp->getName(), TEXT("ATTENDEE"))) {
652         for(int i = 0; i < vp->parameterCount(); i++) {
653             if(!wcsstr(ATTENDEE_PARAM_LIST, vp->getParameter(i)) &&
654                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
655                     *errorCode = ERROR_ILLEGAL_PARAMETER;
656                     errorDescription = TEXT("Property ATTENDEE, Invalid parameter : ");
657                     errorDescription += vp->getParameter(i);
658                     return false;
659                 }
660         }
661     }
662     else if(!wcscmp(vp->getName(), TEXT("COMMENT"))) {
663         for(int i = 0; i < vp->parameterCount(); i++)
664             if(!wcsstr(COMMENT_PARAM_LIST, vp->getParameter(i)) &&
665                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
666                     *errorCode = ERROR_ILLEGAL_PARAMETER;
667                     errorDescription = TEXT("Property COMMENT, Invalid parameter : ");
668                     errorDescription += vp->getParameter(i);
669                     return false;
670                 }
671     }
672     else if(!wcscmp(vp->getName(), TEXT("CONTACT"))) {
673         for(int i = 0; i < vp->parameterCount(); i++)
674             if(!wcsstr(COMMENT_PARAM_LIST, vp->getParameter(i)) &&
675                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
676                     *errorCode = ERROR_ILLEGAL_PARAMETER;
677                     errorDescription = TEXT("Property CONTACT, Invalid parameter : ");
678                     errorDescription += vp->getParameter(i);
679                     return false;
680                 }
681     }
682     else if(!wcscmp(vp->getName(), TEXT("EXDATE"))) {
683         for(int i = 0; i < vp->parameterCount(); i++) {
684             if(!wcsstr(DT_PARAM_LIST, vp->getParameter(i)) &&
685                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
686                     *errorCode = ERROR_ILLEGAL_PARAMETER;
687                     errorDescription = TEXT("Property EXDATE, Invalid parameter : ");
688                     errorDescription += vp->getParameter(i);
689                     return false;
690                 }
691         }
692         if(vp->containsParameter(TEXT("VALUE")) && !wcscmp(vp->getParameterValue(TEXT("VALUE")), TEXT("DATE"))) {
693             WCHAR seps[] = TEXT(",");
694             WCHAR *token;
695             token = wcstok( vp->getValue(), seps );
696             while( token != NULL ) {
697                 if(!validateDate(token)) {
698                     *errorCode = ERROR_INVALID_PROPERTY_VALUE;
699                     errorDescription = TEXT("Property EXDATE, Invalid value : ");
700                     errorDescription += vp->getValue();
701                     return false;
702                 }
703                 token = wcstok( NULL, seps );
704             }
705         }
706         else if(!validateDT(vp->getValue())) {
707             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
708             errorDescription = TEXT("Property EXDATE, Invalid value : ");
709             errorDescription += vp->getValue();
710             return false;
711         }
712     }
713     else if(!wcscmp(vp->getName(), TEXT("EXRULE"))) {
714         if(!validateRecur(vp->getValue())) {
715             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
716             errorDescription = TEXT("Property EXRULE, Invalid value : ");
717             errorDescription += vp->getValue();
718             return false;
719         }
720     }
721     else if(!wcscmp(vp->getName(), TEXT("REQUEST-STATUS"))) {
722         //statcode ";" statdesc [";" extdata]
723         WCHAR* value = new WCHAR[wcslen(vp->getName())+1];
724         wcscpy(value, vp->getName());
725         if(!isdigit(value[0]) || value[1] != '.' || !wcschr(value, ';')) {
726             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
727             errorDescription = TEXT("Property REQUEST-STATUS, Invalid value : ");
728             errorDescription += vp->getValue();
729             delete [] value;
730             return false;
731         }
732         delete [] value;
733     }
734     else if(!wcscmp(vp->getName(), TEXT("RELATED-TO"))) {
735         for(int i = 0; i < vp->parameterCount(); i++)
736             if(wcscmp(TEXT("RELTYPE"), vp->getParameter(i)) &&
737                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
738                     *errorCode = ERROR_ILLEGAL_PARAMETER;
739                     errorDescription = TEXT("Property RELATED-TO, Invalid parameter : ");
740                     errorDescription += vp->getParameter(i);
741                     return false;
742                 }
743     }
744     else if(!wcscmp(vp->getName(), TEXT("RESOURCES"))) {
745         for(int i = 0; i < vp->parameterCount(); i++)
746             if(!wcsstr(COMMENT_PARAM_LIST, vp->getParameter(i)) &&
747                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
748                     *errorCode = ERROR_ILLEGAL_PARAMETER;
749                     errorDescription = TEXT("Property RESOURCES, Invalid parameter : ");
750                     errorDescription += vp->getParameter(i);
751                     return false;
752                 }
753     }
754     else if(!wcscmp(vp->getName(), TEXT("RDATE"))) {
755         for(int i = 0; i < vp->parameterCount(); i++) {
756             if(!wcsstr(RDATE_PARAM_LIST, vp->getParameter(i)) &&
757                 wcsstr(vp->getValue(),TEXT("X-")) != vp->getParameter(i)) {
758                     *errorCode = ERROR_ILLEGAL_PARAMETER;
759                     errorDescription = TEXT("Property RDATE, Invalid parameter : ");
760                     errorDescription += vp->getParameter(i);
761                     return false;
762                 }
763         }
764         if(vp->containsParameter(TEXT("VALUE")) && !wcscmp(vp->getParameterValue(TEXT("VALUE")), TEXT("DATE"))) {
765             if(!validateDate(vp->getValue())) {
766                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
767                 errorDescription = TEXT("Property RDATE, Invalid value : ");
768                 errorDescription += vp->getValue();
769                 return false;
770             }
771         }
772         else if(vp->containsParameter(TEXT("VALUE")) && !wcscmp(vp->getParameterValue(TEXT("VALUE")), TEXT("PERIOD"))) {
773             WCHAR* delimiter;
774             delimiter = wcschr(vp->getValue(), '/');
775             if(!delimiter) {
776                 *errorCode = ERROR_INVALID_PROPERTY_VALUE;
777                 errorDescription = TEXT("Property RDATE, Invalid value : ");
778                 errorDescription += vp->getValue();
779                 return false;
780             }
781         }
782         else if(!validateDT(vp->getValue())) {
783             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
784             errorDescription = TEXT("Property RDATE, Invalid value : ");
785             errorDescription += vp->getValue();
786             return false;
787         }
788     }
789     else if(!wcscmp(vp->getName(), TEXT("RRULE"))) {
790         if(!validateRecur(vp->getValue())) {
791             *errorCode = ERROR_INVALID_PROPERTY_VALUE;
792             errorDescription = TEXT("Property RRULE, Invalid value : ");
793             errorDescription += vp->getValue();
794             return false;
795         }
796     }
797     return true;
798 }
799
800 bool iCalConverter::validateGeo(WCHAR* geo) {
801     if(!geo)
802         return false;
803
804     //expected format: longitude;latitude
805     WCHAR* pDest = NULL;
806     pDest = wcschr(geo, ';');
807
808     if(!pDest)
809         return false;
810
811     WCHAR* longitude = new WCHAR[wcslen(geo)+1];
812     wcsncpy(longitude, geo, pDest-geo);
813
814     WCHAR* latitude = new WCHAR[wcslen(geo)+1];
815     if(++pDest)
816         wcscpy(latitude, pDest);
817     else
818         return false;
819
820         WCHAR* stopstring;
821    // double lon = _wtof(longitude);
822    // double lat = _wtof(latitude);
823
824         double lon = wcstod(longitude, &stopstring);
825         double lat = wcstod(latitude, &stopstring);
826
827     if(lon == 0.0 || lat == 0.0)
828         return false;
829
830     return true;
831 }
832
833 bool iCalConverter::validateDT(WCHAR* dt) {
834     //1997 06 30 T 23 59 60 Z
835     int len = int(wcslen(dt));
836     if(len != 15 && len != 16)
837         return false;
838
839     if(len == 16) {
840         if(dt[15] != 'Z')
841             return false;
842     }
843
844     if(dt[8] != 'T')
845         return false;
846
847     WCHAR* date;
848     date = new WCHAR[9];
849     wcsncpy(date, dt, 8);
850     date[8] = 0;
851     if(!validateDate(date)) {
852         delete [] date;
853         return false;
854     }
855     delete [] date;
856
857     WCHAR hour[2];
858     hour[0] = dt[9];
859     hour[1] = dt[10];
860     int h = _wtoi(hour);
861     if(h < 0 || h > 23)
862         return false;
863
864     WCHAR min[2];
865     min[0] = dt[11];
866     min[1] = dt[12];
867     int m = _wtoi(min);
868     if(m < 0 || m > 59)
869         return false;
870
871     WCHAR sec[2];
872     sec[0] = dt[13];
873     sec[1] = dt[14];
874     int s = _wtoi(sec);
875     if(s < 0 || s > 59)
876         return false;
877
878     return true;
879
880 }
881
882 bool iCalConverter::validateDate(WCHAR* date) {
883     if(wcslen(date) != 8)
884         return false;
885
886     WCHAR month[2];
887     month[0] = date[4];
888     month[1] = date[5];
889     int mo = _wtoi(month);
890
891     if(mo > 12 || mo < 1)
892         return false;
893
894     WCHAR day[2];
895     day[0] = date[6];
896     day[1] = date[7];
897
898     int d = _wtoi(day);
899     if(d > 31 || d < 1)
900         return false;
901
902     return true;
903 }
904
905 bool iCalConverter::validateRecur(WCHAR* recur) {
906
907     if(wcsstr(recur, TEXT("FREQ")) != recur)
908         return false;
909
910     WCHAR seps[] = TEXT(";");
911     WCHAR* token;
912     WCHAR* delimiter;
913
914     token = wcstok( recur, seps );
915     while( token != NULL ) {
916         delimiter = wcschr(token, '=');
917         if(!delimiter)
918             return false;
919         int len = int(wcslen(token));
920         WCHAR* item = new WCHAR[len + 1];
921         wcsncpy(item, token, delimiter - token);
922         item[delimiter - token] = 0;
923
924         if(!wcsstr(RECRUL_ITEMS_LIST, item) && wcsstr(item,TEXT("X-")) != item) {
925             delete [] item; item = NULL;
926             return false;
927         }
928
929         if(!wcscmp(item, TEXT("FREQ"))) {
930             WCHAR* value = new WCHAR[len + 1];
931             wcscpy(value, ++delimiter);
932             if(!wcsstr(FREQUENCY_VALUES_LIST, value)) {
933                 delete [] value; value = NULL;
934                 return false;
935             }
936             delete [] value; value = NULL;
937         }
938
939         delete [] item; item = NULL;
940
941         token = wcstok( NULL, seps );
942     }
943     return true;
944 }