summaryrefslogtreecommitdiffabout
path: root/libkcal/vcalformat.cpp
authorzautrix <zautrix>2004-06-26 19:01:18 (UTC)
committer zautrix <zautrix>2004-06-26 19:01:18 (UTC)
commitb9aad1f15dc600e4dbe4c62d3fcced6363188ba3 (patch) (unidiff)
tree2c3d4004fb21c72cba65793859f9bcd8ffd3a49c /libkcal/vcalformat.cpp
downloadkdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.zip
kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.gz
kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.bz2
Initial revision
Diffstat (limited to 'libkcal/vcalformat.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libkcal/vcalformat.cpp1678
1 files changed, 1678 insertions, 0 deletions
diff --git a/libkcal/vcalformat.cpp b/libkcal/vcalformat.cpp
new file mode 100644
index 0000000..59030d5
--- a/dev/null
+++ b/libkcal/vcalformat.cpp
@@ -0,0 +1,1678 @@
1/*
2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brwon
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20*/
21
22#include <qapplication.h>
23#include <qdatetime.h>
24#include <qstring.h>
25#include <qptrlist.h>
26#include <qregexp.h>
27#include <qclipboard.h>
28#include <qdialog.h>
29#include <qfile.h>
30
31#include <kdebug.h>
32#include <kmessagebox.h>
33#include <kiconloader.h>
34#include <klocale.h>
35
36#include "vcc.h"
37#include "vobject.h"
38
39#include "vcaldrag.h"
40#include "calendar.h"
41
42#include "vcalformat.h"
43
44using namespace KCal;
45
46VCalFormat::VCalFormat()
47{
48}
49
50VCalFormat::~VCalFormat()
51{
52}
53
54bool VCalFormat::load(Calendar *calendar, const QString &fileName)
55{
56 mCalendar = calendar;
57
58 clearException();
59
60 kdDebug(5800) << "VCalFormat::load() " << fileName << endl;
61
62 VObject *vcal = 0;
63
64 // this is not necessarily only 1 vcal. Could be many vcals, or include
65 // a vcard...
66 vcal = Parse_MIME_FromFileName(const_cast<char *>(QFile::encodeName(fileName).data()));
67
68 if (!vcal) {
69 setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
70 return FALSE;
71 }
72
73 // any other top-level calendar stuff should be added/initialized here
74
75 // put all vobjects into their proper places
76 populate(vcal);
77
78 // clean up from vcal API stuff
79 cleanVObjects(vcal);
80 cleanStrTbl();
81
82 return true;
83}
84
85
86bool VCalFormat::save(Calendar *calendar, const QString &fileName)
87{
88 mCalendar = calendar;
89
90 QString tmpStr;
91 VObject *vcal, *vo;
92
93 kdDebug(5800) << "VCalFormat::save(): " << fileName << endl;
94
95 vcal = newVObject(VCCalProp);
96
97 // addPropValue(vcal,VCLocationProp, "0.0");
98 addPropValue(vcal,VCProdIdProp, productId());
99 tmpStr = mCalendar->getTimeZoneStr();
100 //qDebug("mCalendar->getTimeZoneStr() %s",tmpStr.latin1() );
101 addPropValue(vcal,VCTimeZoneProp, tmpStr.local8Bit());
102 addPropValue(vcal,VCVersionProp, _VCAL_VERSION);
103
104 // TODO STUFF
105 QPtrList<Todo> todoList = mCalendar->rawTodos();
106 QPtrListIterator<Todo> qlt(todoList);
107 for (; qlt.current(); ++qlt) {
108 vo = eventToVTodo(qlt.current());
109 addVObjectProp(vcal, vo);
110 }
111
112 // EVENT STUFF
113 QPtrList<Event> events = mCalendar->rawEvents();
114 Event *ev;
115 for(ev=events.first();ev;ev=events.next()) {
116 vo = eventToVEvent(ev);
117 addVObjectProp(vcal, vo);
118 }
119
120 writeVObjectToFile(QFile::encodeName(fileName).data() ,vcal);
121 cleanVObjects(vcal);
122 cleanStrTbl();
123
124 if (QFile::exists(fileName)) {
125 kdDebug(5800) << "No error" << endl;
126 return true;
127 } else {
128 kdDebug(5800) << "Error" << endl;
129 return false; // error
130 }
131}
132
133bool VCalFormat::fromString( Calendar *calendar, const QString &text )
134{
135 // TODO: Factor out VCalFormat::fromString()
136
137 QCString data = text.utf8();
138
139 if ( !data.size() ) return false;
140
141 VObject *vcal = Parse_MIME( data.data(), data.size());
142 if ( !vcal ) return false;
143
144 VObjectIterator i;
145 VObject *curvo;
146 initPropIterator( &i, vcal );
147
148 // we only take the first object. TODO: parse all incidences.
149 do {
150 curvo = nextVObject( &i );
151 } while ( strcmp( vObjectName( curvo ), VCEventProp ) &&
152 strcmp( vObjectName( curvo ), VCTodoProp ) );
153
154 if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) {
155 Event *event = VEventToEvent( curvo );
156 calendar->addEvent( event );
157 } else {
158 kdDebug(5800) << "VCalFormat::fromString(): Unknown object type." << endl;
159 deleteVObject( vcal );
160 return false;
161 }
162
163 deleteVObject( vcal );
164
165 return true;
166}
167
168QString VCalFormat::toString( Calendar *calendar )
169{
170 // TODO: Factor out VCalFormat::asString()
171
172 VObject *vcal = newVObject(VCCalProp);
173
174 addPropValue( vcal, VCProdIdProp, CalFormat::productId() );
175 QString tmpStr = mCalendar->getTimeZoneStr();
176 addPropValue( vcal, VCTimeZoneProp, tmpStr.local8Bit() );
177 addPropValue( vcal, VCVersionProp, _VCAL_VERSION );
178
179 // TODO: Use all data.
180 QPtrList<Event> events = calendar->events();
181 Event *event = events.first();
182 if ( !event ) return QString::null;
183
184 VObject *vevent = eventToVEvent( event );
185
186 addVObjectProp( vcal, vevent );
187
188 char *buf = writeMemVObject( 0, 0, vcal );
189
190 QString result( buf );
191
192 cleanVObject( vcal );
193
194 return result;
195}
196
197VObject *VCalFormat::eventToVTodo(const Todo *anEvent)
198{
199 VObject *vtodo;
200 QString tmpStr;
201 QStringList tmpStrList;
202
203 vtodo = newVObject(VCTodoProp);
204
205 // due date
206 if (anEvent->hasDueDate()) {
207 tmpStr = qDateTimeToISO(anEvent->dtDue(),
208 !anEvent->doesFloat());
209 addPropValue(vtodo, VCDueProp, tmpStr.local8Bit());
210 }
211
212 // start date
213 if (anEvent->hasStartDate()) {
214 tmpStr = qDateTimeToISO(anEvent->dtStart(),
215 !anEvent->doesFloat());
216 addPropValue(vtodo, VCDTstartProp, tmpStr.local8Bit());
217 }
218
219 // creation date
220 tmpStr = qDateTimeToISO(anEvent->created());
221 addPropValue(vtodo, VCDCreatedProp, tmpStr.local8Bit());
222
223 // unique id
224 addPropValue(vtodo, VCUniqueStringProp,
225 anEvent->uid().local8Bit());
226
227 // revision
228 tmpStr.sprintf("%i", anEvent->revision());
229 addPropValue(vtodo, VCSequenceProp, tmpStr.local8Bit());
230
231 // last modification date
232 tmpStr = qDateTimeToISO(anEvent->lastModified());
233 addPropValue(vtodo, VCLastModifiedProp, tmpStr.local8Bit());
234
235 // organizer stuff
236 tmpStr = "MAILTO:" + anEvent->organizer();
237 addPropValue(vtodo, ICOrganizerProp, tmpStr.local8Bit());
238
239 // attendees
240 if (anEvent->attendeeCount() != 0) {
241 QPtrList<Attendee> al = anEvent->attendees();
242 QPtrListIterator<Attendee> ai(al);
243 Attendee *curAttendee;
244
245 for (; ai.current(); ++ai) {
246 curAttendee = ai.current();
247 if (!curAttendee->email().isEmpty() &&
248 !curAttendee->name().isEmpty())
249 tmpStr = "MAILTO:" + curAttendee->name() + " <" +
250 curAttendee->email() + ">";
251 else if (curAttendee->name().isEmpty())
252 tmpStr = "MAILTO: " + curAttendee->email();
253 else if (curAttendee->email().isEmpty())
254 tmpStr = "MAILTO: " + curAttendee->name();
255 else if (curAttendee->name().isEmpty() &&
256 curAttendee->email().isEmpty())
257 kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl;
258 VObject *aProp = addPropValue(vtodo, VCAttendeeProp, tmpStr.local8Bit());
259 addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");
260 addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status()));
261 }
262 }
263
264 // description BL:
265 if (!anEvent->description().isEmpty()) {
266 VObject *d = addPropValue(vtodo, VCDescriptionProp,
267 anEvent->description().local8Bit());
268 if (anEvent->description().find('\n') != -1)
269 addProp(d, VCQuotedPrintableProp);
270 }
271
272 // summary
273 if (!anEvent->summary().isEmpty())
274 addPropValue(vtodo, VCSummaryProp, anEvent->summary().local8Bit());
275
276 if (!anEvent->location().isEmpty())
277 addPropValue(vtodo, VCLocationProp, anEvent->location().local8Bit());
278
279 // completed
280 // status
281 // backward compatibility, KOrganizer used to interpret only these two values
282 addPropValue(vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" :
283 "NEEDS_ACTION");
284 // completion date
285 if (anEvent->hasCompletedDate()) {
286 tmpStr = qDateTimeToISO(anEvent->completed());
287 addPropValue(vtodo, VCCompletedProp, tmpStr.local8Bit());
288 }
289
290 // priority
291 tmpStr.sprintf("%i",anEvent->priority());
292 addPropValue(vtodo, VCPriorityProp, tmpStr.local8Bit());
293
294 // related event
295 if (anEvent->relatedTo()) {
296 addPropValue(vtodo, VCRelatedToProp,
297 anEvent->relatedTo()->uid().local8Bit());
298 }
299
300 // categories
301 tmpStrList = anEvent->categories();
302 tmpStr = "";
303 QString catStr;
304 for ( QStringList::Iterator it = tmpStrList.begin();
305 it != tmpStrList.end();
306 ++it ) {
307 catStr = *it;
308 if (catStr[0] == ' ')
309 tmpStr += catStr.mid(1);
310 else
311 tmpStr += catStr;
312 // this must be a ';' character as the vCalendar specification requires!
313 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
314 // read in.
315 tmpStr += ";";
316 }
317 if (!tmpStr.isEmpty()) {
318 tmpStr.truncate(tmpStr.length()-1);
319 addPropValue(vtodo, VCCategoriesProp, tmpStr.local8Bit());
320 }
321
322 // alarm stuff
323 kdDebug(5800) << "vcalformat::eventToVTodo was called" << endl;
324 QPtrList<Alarm> alarms = anEvent->alarms();
325 Alarm* alarm;
326 for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
327 if (alarm->enabled()) {
328 VObject *a = addProp(vtodo, VCDAlarmProp);
329 tmpStr = qDateTimeToISO(alarm->time());
330 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
331 addPropValue(a, VCRepeatCountProp, "1");
332 addPropValue(a, VCDisplayStringProp, "beep!");
333 if (alarm->type() == Alarm::Audio) {
334 a = addProp(vtodo, VCAAlarmProp);
335 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
336 addPropValue(a, VCRepeatCountProp, "1");
337 addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile()));
338 }
339 else if (alarm->type() == Alarm::Procedure) {
340 a = addProp(vtodo, VCPAlarmProp);
341 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
342 addPropValue(a, VCRepeatCountProp, "1");
343 addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile()));
344 }
345 }
346 }
347
348 if (anEvent->pilotId()) {
349 // pilot sync stuff
350 tmpStr.sprintf("%i",anEvent->pilotId());
351 addPropValue(vtodo, KPilotIdProp, tmpStr.local8Bit());
352 tmpStr.sprintf("%i",anEvent->syncStatus());
353 addPropValue(vtodo, KPilotStatusProp, tmpStr.local8Bit());
354 }
355
356 return vtodo;
357}
358
359VObject* VCalFormat::eventToVEvent(const Event *anEvent)
360{
361 VObject *vevent;
362 QString tmpStr;
363 QStringList tmpStrList;
364
365 vevent = newVObject(VCEventProp);
366
367 // start and end time
368 tmpStr = qDateTimeToISO(anEvent->dtStart(),
369 !anEvent->doesFloat());
370 addPropValue(vevent, VCDTstartProp, tmpStr.local8Bit());
371
372 // events that have time associated but take up no time should
373 // not have both DTSTART and DTEND.
374 if (anEvent->dtStart() != anEvent->dtEnd()) {
375 tmpStr = qDateTimeToISO(anEvent->dtEnd(),
376 !anEvent->doesFloat());
377 addPropValue(vevent, VCDTendProp, tmpStr.local8Bit());
378 }
379
380 // creation date
381 tmpStr = qDateTimeToISO(anEvent->created());
382 addPropValue(vevent, VCDCreatedProp, tmpStr.local8Bit());
383
384 // unique id
385 addPropValue(vevent, VCUniqueStringProp,
386 anEvent->uid().local8Bit());
387
388 // revision
389 tmpStr.sprintf("%i", anEvent->revision());
390 addPropValue(vevent, VCSequenceProp, tmpStr.local8Bit());
391
392 // last modification date
393 tmpStr = qDateTimeToISO(anEvent->lastModified());
394 addPropValue(vevent, VCLastModifiedProp, tmpStr.local8Bit());
395
396 // attendee and organizer stuff
397 tmpStr = "MAILTO:" + anEvent->organizer();
398 addPropValue(vevent, ICOrganizerProp, tmpStr.local8Bit());
399
400 if (anEvent->attendeeCount() != 0) {
401 QPtrList<Attendee> al = anEvent->attendees();
402 QPtrListIterator<Attendee> ai(al);
403 Attendee *curAttendee;
404
405 // TODO: Put this functionality into Attendee class
406 for (; ai.current(); ++ai) {
407 curAttendee = ai.current();
408 if (!curAttendee->email().isEmpty() &&
409 !curAttendee->name().isEmpty())
410 tmpStr = "MAILTO:" + curAttendee->name() + " <" +
411 curAttendee->email() + ">";
412 else if (curAttendee->name().isEmpty())
413 tmpStr = "MAILTO: " + curAttendee->email();
414 else if (curAttendee->email().isEmpty())
415 tmpStr = "MAILTO: " + curAttendee->name();
416 else if (curAttendee->name().isEmpty() &&
417 curAttendee->email().isEmpty())
418 kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl;
419 VObject *aProp = addPropValue(vevent, VCAttendeeProp, tmpStr.local8Bit());
420 addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");;
421 addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status()));
422 }
423 }
424
425 // recurrence rule stuff
426 if (anEvent->recurrence()->doesRecur()) {
427 // some more variables
428 QPtrList<Recurrence::rMonthPos> tmpPositions;
429 QPtrList<int> tmpDays;
430 int *tmpDay;
431 Recurrence::rMonthPos *tmpPos;
432 QString tmpStr2;
433 int i;
434
435 switch(anEvent->recurrence()->doesRecur()) {
436 case Recurrence::rDaily:
437 tmpStr.sprintf("D%i ",anEvent->recurrence()->frequency());
438// if (anEvent->rDuration > 0)
439 //tmpStr += "#";
440 break;
441 case Recurrence::rWeekly:
442 tmpStr.sprintf("W%i ",anEvent->recurrence()->frequency());
443 for (i = 0; i < 7; i++) {
444 if (anEvent->recurrence()->days().testBit(i))
445 tmpStr += dayFromNum(i);
446 }
447 break;
448 case Recurrence::rMonthlyPos:
449 tmpStr.sprintf("MP%i ", anEvent->recurrence()->frequency());
450 // write out all rMonthPos's
451 tmpPositions = anEvent->recurrence()->monthPositions();
452 for (tmpPos = tmpPositions.first();
453 tmpPos;
454 tmpPos = tmpPositions.next()) {
455
456 tmpStr2.sprintf("%i", tmpPos->rPos);
457 if (tmpPos->negative)
458 tmpStr2 += "- ";
459 else
460 tmpStr2 += "+ ";
461 tmpStr += tmpStr2;
462 for (i = 0; i < 7; i++) {
463 if (tmpPos->rDays.testBit(i))
464 tmpStr += dayFromNum(i);
465 }
466 } // loop for all rMonthPos's
467 break;
468 case Recurrence::rMonthlyDay:
469 tmpStr.sprintf("MD%i ", anEvent->recurrence()->frequency());
470 // write out all rMonthDays;
471 tmpDays = anEvent->recurrence()->monthDays();
472 for (tmpDay = tmpDays.first();
473 tmpDay;
474 tmpDay = tmpDays.next()) {
475 tmpStr2.sprintf("%i ", *tmpDay);
476 tmpStr += tmpStr2;
477 }
478 break;
479 case Recurrence::rYearlyMonth:
480 tmpStr.sprintf("YM%i ", anEvent->recurrence()->frequency());
481 // write out all the rYearNums;
482 tmpDays = anEvent->recurrence()->yearNums();
483 for (tmpDay = tmpDays.first();
484 tmpDay;
485 tmpDay = tmpDays.next()) {
486 tmpStr2.sprintf("%i ", *tmpDay);
487 tmpStr += tmpStr2;
488 }
489 break;
490 case Recurrence::rYearlyDay:
491 tmpStr.sprintf("YD%i ", anEvent->recurrence()->frequency());
492 // write out all the rYearNums;
493 tmpDays = anEvent->recurrence()->yearNums();
494 for (tmpDay = tmpDays.first();
495 tmpDay;
496 tmpDay = tmpDays.next()) {
497 tmpStr2.sprintf("%i ", *tmpDay);
498 tmpStr += tmpStr2;
499 }
500 break;
501 default:
502 kdDebug(5800) << "ERROR, it should never get here in eventToVEvent!" << endl;
503 break;
504 } // switch
505
506 if (anEvent->recurrence()->duration() > 0) {
507 tmpStr2.sprintf("#%i",anEvent->recurrence()->duration());
508 tmpStr += tmpStr2;
509 } else if (anEvent->recurrence()->duration() == -1) {
510 tmpStr += "#0"; // defined as repeat forever
511 } else {
512 tmpStr += qDateTimeToISO(anEvent->recurrence()->endDate(), FALSE);
513 }
514 addPropValue(vevent,VCRRuleProp, tmpStr.local8Bit());
515
516 } // event repeats
517
518 // exceptions to recurrence
519 DateList dateList = anEvent->exDates();
520 DateList::ConstIterator it;
521 QString tmpStr2;
522
523 for (it = dateList.begin(); it != dateList.end(); ++it) {
524 tmpStr = qDateToISO(*it) + ";";
525 tmpStr2 += tmpStr;
526 }
527 if (!tmpStr2.isEmpty()) {
528 tmpStr2.truncate(tmpStr2.length()-1);
529 addPropValue(vevent, VCExDateProp, tmpStr2.local8Bit());
530 }
531
532 // description
533 if (!anEvent->description().isEmpty()) {
534 VObject *d = addPropValue(vevent, VCDescriptionProp,
535 anEvent->description().local8Bit());
536 if (anEvent->description().find('\n') != -1)
537 addProp(d, VCQuotedPrintableProp);
538 }
539
540 // summary
541 if (!anEvent->summary().isEmpty())
542 addPropValue(vevent, VCSummaryProp, anEvent->summary().local8Bit());
543
544 if (!anEvent->location().isEmpty())
545 addPropValue(vevent, VCLocationProp, anEvent->location().local8Bit());
546
547 // status
548// TODO: define Event status
549// addPropValue(vevent, VCStatusProp, anEvent->statusStr().local8Bit());
550
551 // secrecy
552 const char *text = 0;
553 switch (anEvent->secrecy()) {
554 case Incidence::SecrecyPublic:
555 text = "PUBLIC";
556 break;
557 case Incidence::SecrecyPrivate:
558 text = "PRIVATE";
559 break;
560 case Incidence::SecrecyConfidential:
561 text = "CONFIDENTIAL";
562 break;
563 }
564 if (text) {
565 addPropValue(vevent, VCClassProp, text);
566 }
567
568 // categories
569 tmpStrList = anEvent->categories();
570 tmpStr = "";
571 QString catStr;
572 for ( QStringList::Iterator it = tmpStrList.begin();
573 it != tmpStrList.end();
574 ++it ) {
575 catStr = *it;
576 if (catStr[0] == ' ')
577 tmpStr += catStr.mid(1);
578 else
579 tmpStr += catStr;
580 // this must be a ';' character as the vCalendar specification requires!
581 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
582 // read in.
583 tmpStr += ";";
584 }
585 if (!tmpStr.isEmpty()) {
586 tmpStr.truncate(tmpStr.length()-1);
587 addPropValue(vevent, VCCategoriesProp, tmpStr.local8Bit());
588 }
589
590 // attachments
591 // TODO: handle binary attachments!
592 QPtrList<Attachment> attachments = anEvent->attachments();
593 for ( Attachment *at = attachments.first(); at; at = attachments.next() )
594 addPropValue(vevent, VCAttachProp, at->uri().local8Bit());
595
596 // resources
597 tmpStrList = anEvent->resources();
598 tmpStr = tmpStrList.join(";");
599 if (!tmpStr.isEmpty())
600 addPropValue(vevent, VCResourcesProp, tmpStr.local8Bit());
601
602 // alarm stuff
603 QPtrList<Alarm> alarms = anEvent->alarms();
604 Alarm* alarm;
605 for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
606 if (alarm->enabled()) {
607 VObject *a = addProp(vevent, VCDAlarmProp);
608 tmpStr = qDateTimeToISO(alarm->time());
609 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
610 addPropValue(a, VCRepeatCountProp, "1");
611 addPropValue(a, VCDisplayStringProp, "beep!");
612 if (alarm->type() == Alarm::Audio) {
613 a = addProp(vevent, VCAAlarmProp);
614 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
615 addPropValue(a, VCRepeatCountProp, "1");
616 addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile()));
617 }
618 if (alarm->type() == Alarm::Procedure) {
619 a = addProp(vevent, VCPAlarmProp);
620 addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
621 addPropValue(a, VCRepeatCountProp, "1");
622 addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile()));
623 }
624 }
625 }
626
627 // priority
628 tmpStr.sprintf("%i",anEvent->priority());
629 addPropValue(vevent, VCPriorityProp, tmpStr.local8Bit());
630
631 // transparency
632 tmpStr.sprintf("%i",anEvent->transparency());
633 addPropValue(vevent, VCTranspProp, tmpStr.local8Bit());
634
635 // related event
636 if (anEvent->relatedTo()) {
637 addPropValue(vevent, VCRelatedToProp,
638 anEvent->relatedTo()->uid().local8Bit());
639 }
640
641 if (anEvent->pilotId()) {
642 // pilot sync stuff
643 tmpStr.sprintf("%i",anEvent->pilotId());
644 addPropValue(vevent, KPilotIdProp, tmpStr.local8Bit());
645 tmpStr.sprintf("%i",anEvent->syncStatus());
646 addPropValue(vevent, KPilotStatusProp, tmpStr.local8Bit());
647 }
648
649 return vevent;
650}
651
652Todo *VCalFormat::VTodoToEvent(VObject *vtodo)
653{
654 VObject *vo;
655 VObjectIterator voi;
656 char *s;
657
658 Todo *anEvent = new Todo;
659
660 // creation date
661 if ((vo = isAPropertyOf(vtodo, VCDCreatedProp)) != 0) {
662 anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
663 deleteStr(s);
664 }
665
666 // unique id
667 vo = isAPropertyOf(vtodo, VCUniqueStringProp);
668 // while the UID property is preferred, it is not required. We'll use the
669 // default Event UID if none is given.
670 if (vo) {
671 anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo)));
672 deleteStr(s);
673 }
674
675 // last modification date
676 if ((vo = isAPropertyOf(vtodo, VCLastModifiedProp)) != 0) {
677 anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
678 deleteStr(s);
679 }
680 else
681 anEvent->setLastModified(QDateTime(QDate::currentDate(),
682 QTime::currentTime()));
683
684 // organizer
685 // if our extension property for the event's ORGANIZER exists, add it.
686 if ((vo = isAPropertyOf(vtodo, ICOrganizerProp)) != 0) {
687 anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo)));
688 deleteStr(s);
689 } else {
690 anEvent->setOrganizer(mCalendar->getEmail());
691 }
692
693 // attendees.
694 initPropIterator(&voi, vtodo);
695 while (moreIteration(&voi)) {
696 vo = nextVObject(&voi);
697 if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) {
698 Attendee *a;
699 VObject *vp;
700 s = fakeCString(vObjectUStringZValue(vo));
701 QString tmpStr = QString::fromLocal8Bit(s);
702 deleteStr(s);
703 tmpStr = tmpStr.simplifyWhiteSpace();
704 int emailPos1, emailPos2;
705 if ((emailPos1 = tmpStr.find('<')) > 0) {
706 // both email address and name
707 emailPos2 = tmpStr.findRev('>');
708 a = new Attendee(tmpStr.left(emailPos1 - 1),
709 tmpStr.mid(emailPos1 + 1,
710 emailPos2 - (emailPos1 + 1)));
711 } else if (tmpStr.find('@') > 0) {
712 // just an email address
713 a = new Attendee(0, tmpStr);
714 } else {
715 // just a name
716 QString email = tmpStr.replace( QRegExp(" "), "." );
717 a = new Attendee(tmpStr,email);
718 }
719
720 // is there an RSVP property?
721 if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0)
722 a->setRSVP(vObjectStringZValue(vp));
723 // is there a status property?
724 if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0)
725 a->setStatus(readStatus(vObjectStringZValue(vp)));
726 // add the attendee
727 anEvent->addAttendee(a);
728 }
729 }
730
731 // description for todo
732 if ((vo = isAPropertyOf(vtodo, VCDescriptionProp)) != 0) {
733 s = fakeCString(vObjectUStringZValue(vo));
734 anEvent->setDescription(QString::fromLocal8Bit(s));
735 deleteStr(s);
736 }
737
738 // summary
739 if ((vo = isAPropertyOf(vtodo, VCSummaryProp))) {
740 s = fakeCString(vObjectUStringZValue(vo));
741 anEvent->setSummary(QString::fromLocal8Bit(s));
742 deleteStr(s);
743 }
744 if ((vo = isAPropertyOf(vtodo, VCLocationProp))) {
745 s = fakeCString(vObjectUStringZValue(vo));
746 anEvent->setLocation(QString::fromLocal8Bit(s));
747 deleteStr(s);
748 }
749
750
751 // completed
752 // was: status
753 if ((vo = isAPropertyOf(vtodo, VCStatusProp)) != 0) {
754 s = fakeCString(vObjectUStringZValue(vo));
755 if (strcmp(s,"COMPLETED") == 0) {
756 anEvent->setCompleted(true);
757 } else {
758 anEvent->setCompleted(false);
759 }
760 deleteStr(s);
761 }
762 else
763 anEvent->setCompleted(false);
764
765 // completion date
766 if ((vo = isAPropertyOf(vtodo, VCCompletedProp)) != 0) {
767 anEvent->setCompleted(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
768 deleteStr(s);
769 }
770
771 // priority
772 if ((vo = isAPropertyOf(vtodo, VCPriorityProp))) {
773 anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo))));
774 deleteStr(s);
775 }
776
777 // due date
778 if ((vo = isAPropertyOf(vtodo, VCDueProp)) != 0) {
779 anEvent->setDtDue(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
780 deleteStr(s);
781 anEvent->setHasDueDate(true);
782 } else {
783 anEvent->setHasDueDate(false);
784 }
785
786 // start time
787 if ((vo = isAPropertyOf(vtodo, VCDTstartProp)) != 0) {
788 anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
789 // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl;
790 deleteStr(s);
791 anEvent->setHasStartDate(true);
792 } else {
793 anEvent->setHasStartDate(false);
794 }
795
796 /* alarm stuff */
797 //kdDebug(5800) << "vcalformat::VTodoToEvent called" << endl;
798 if ((vo = isAPropertyOf(vtodo, VCDAlarmProp))) {
799 Alarm* alarm = anEvent->newAlarm();
800 VObject *a;
801 if ((a = isAPropertyOf(vo, VCRunTimeProp))) {
802 alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a))));
803 deleteStr(s);
804 }
805 alarm->setEnabled(true);
806 if ((vo = isAPropertyOf(vtodo, VCPAlarmProp))) {
807 if ((a = isAPropertyOf(vo, VCProcedureNameProp))) {
808 s = fakeCString(vObjectUStringZValue(a));
809 alarm->setProcedureAlarm(QFile::decodeName(s));
810 deleteStr(s);
811 }
812 }
813 if ((vo = isAPropertyOf(vtodo, VCAAlarmProp))) {
814 if ((a = isAPropertyOf(vo, VCAudioContentProp))) {
815 s = fakeCString(vObjectUStringZValue(a));
816 alarm->setAudioAlarm(QFile::decodeName(s));
817 deleteStr(s);
818 }
819 }
820 }
821
822 // related todo
823 if ((vo = isAPropertyOf(vtodo, VCRelatedToProp)) != 0) {
824 anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo)));
825 deleteStr(s);
826 mTodosRelate.append(anEvent);
827 }
828
829 // categories
830 QStringList tmpStrList;
831 int index1 = 0;
832 int index2 = 0;
833 if ((vo = isAPropertyOf(vtodo, VCCategoriesProp)) != 0) {
834 s = fakeCString(vObjectUStringZValue(vo));
835 QString categories = QString::fromLocal8Bit(s);
836 deleteStr(s);
837 //const char* category;
838 QString category;
839 while ((index2 = categories.find(',', index1)) != -1) {
840 //category = (const char *) categories.mid(index1, (index2 - index1));
841 category = categories.mid(index1, (index2 - index1));
842 tmpStrList.append(category);
843 index1 = index2+1;
844 }
845 // get last category
846 category = categories.mid(index1, (categories.length()-index1));
847 tmpStrList.append(category);
848 anEvent->setCategories(tmpStrList);
849 }
850
851 /* PILOT SYNC STUFF */
852 if ((vo = isAPropertyOf(vtodo, KPilotIdProp))) {
853 anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo))));
854 deleteStr(s);
855 }
856 else
857 anEvent->setPilotId(0);
858
859 if ((vo = isAPropertyOf(vtodo, KPilotStatusProp))) {
860 anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo))));
861 deleteStr(s);
862 }
863 else
864 anEvent->setSyncStatus(Event::SYNCMOD);
865
866 return anEvent;
867}
868
869Event* VCalFormat::VEventToEvent(VObject *vevent)
870{
871 VObject *vo;
872 VObjectIterator voi;
873 char *s;
874
875 Event *anEvent = new Event;
876
877 // creation date
878 if ((vo = isAPropertyOf(vevent, VCDCreatedProp)) != 0) {
879 anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
880 deleteStr(s);
881 }
882
883 // unique id
884 vo = isAPropertyOf(vevent, VCUniqueStringProp);
885 // while the UID property is preferred, it is not required. We'll use the
886 // default Event UID if none is given.
887 if (vo) {
888 anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo)));
889 deleteStr(s);
890 }
891
892 // revision
893 // again NSCAL doesn't give us much to work with, so we improvise...
894 if ((vo = isAPropertyOf(vevent, VCSequenceProp)) != 0) {
895 anEvent->setRevision(atoi(s = fakeCString(vObjectUStringZValue(vo))));
896 deleteStr(s);
897 }
898 else
899 anEvent->setRevision(0);
900
901 // last modification date
902 if ((vo = isAPropertyOf(vevent, VCLastModifiedProp)) != 0) {
903 anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
904 deleteStr(s);
905 }
906 else
907 anEvent->setLastModified(QDateTime(QDate::currentDate(),
908 QTime::currentTime()));
909
910 // organizer
911 // if our extension property for the event's ORGANIZER exists, add it.
912 if ((vo = isAPropertyOf(vevent, ICOrganizerProp)) != 0) {
913 anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo)));
914 deleteStr(s);
915 } else {
916 anEvent->setOrganizer(mCalendar->getEmail());
917 }
918
919 // deal with attendees.
920 initPropIterator(&voi, vevent);
921 while (moreIteration(&voi)) {
922 vo = nextVObject(&voi);
923 if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) {
924 Attendee *a;
925 VObject *vp;
926 s = fakeCString(vObjectUStringZValue(vo));
927 QString tmpStr = QString::fromLocal8Bit(s);
928 deleteStr(s);
929 tmpStr = tmpStr.simplifyWhiteSpace();
930 int emailPos1, emailPos2;
931 if ((emailPos1 = tmpStr.find('<')) > 0) {
932 // both email address and name
933 emailPos2 = tmpStr.findRev('>');
934 a = new Attendee(tmpStr.left(emailPos1 - 1),
935 tmpStr.mid(emailPos1 + 1,
936 emailPos2 - (emailPos1 + 1)));
937 } else if (tmpStr.find('@') > 0) {
938 // just an email address
939 a = new Attendee(0, tmpStr);
940 } else {
941 // just a name
942 QString email = tmpStr.replace( QRegExp(" "), "." );
943 a = new Attendee(tmpStr,email);
944 }
945
946 // is there an RSVP property?
947 if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0)
948 a->setRSVP(vObjectStringZValue(vp));
949 // is there a status property?
950 if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0)
951 a->setStatus(readStatus(vObjectStringZValue(vp)));
952 // add the attendee
953 anEvent->addAttendee(a);
954 }
955 }
956
957 // This isn't strictly true. An event that doesn't have a start time
958 // or an end time doesn't "float", it has an anchor in time but it doesn't
959 // "take up" any time.
960 /*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) ||
961 (isAPropertyOf(vevent, VCDTendProp) == 0)) {
962 anEvent->setFloats(TRUE);
963 } else {
964 }*/
965
966 anEvent->setFloats(FALSE);
967
968 // start time
969 if ((vo = isAPropertyOf(vevent, VCDTstartProp)) != 0) {
970 anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
971 // kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl;
972 deleteStr(s);
973 if (anEvent->dtStart().time().isNull())
974 anEvent->setFloats(TRUE);
975 }
976
977 // stop time
978 if ((vo = isAPropertyOf(vevent, VCDTendProp)) != 0) {
979 anEvent->setDtEnd(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
980 deleteStr(s);
981 if (anEvent->dtEnd().time().isNull())
982 anEvent->setFloats(TRUE);
983 }
984
985 // at this point, there should be at least a start or end time.
986 // fix up for events that take up no time but have a time associated
987 if (!(vo = isAPropertyOf(vevent, VCDTstartProp)))
988 anEvent->setDtStart(anEvent->dtEnd());
989 if (!(vo = isAPropertyOf(vevent, VCDTendProp)))
990 anEvent->setDtEnd(anEvent->dtStart());
991
992 ///////////////////////////////////////////////////////////////////////////
993
994 // repeat stuff
995 if ((vo = isAPropertyOf(vevent, VCRRuleProp)) != 0) {
996 QString tmpStr = (s = fakeCString(vObjectUStringZValue(vo)));
997 deleteStr(s);
998 tmpStr.simplifyWhiteSpace();
999 tmpStr = tmpStr.upper();
1000
1001 /********************************* DAILY ******************************/
1002 if (tmpStr.left(1) == "D") {
1003 int index = tmpStr.find(' ');
1004 int rFreq = tmpStr.mid(1, (index-1)).toInt();
1005 index = tmpStr.findRev(' ') + 1; // advance to last field
1006 if (tmpStr.mid(index,1) == "#") index++;
1007 if (tmpStr.find('T', index) != -1) {
1008 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1009 anEvent->recurrence()->setDaily(rFreq, rEndDate);
1010 } else {
1011 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1012 if (rDuration == 0) // VEvents set this to 0 forever, we use -1
1013 anEvent->recurrence()->setDaily(rFreq, -1);
1014 else
1015 anEvent->recurrence()->setDaily(rFreq, rDuration);
1016 }
1017 }
1018 /********************************* WEEKLY ******************************/
1019 else if (tmpStr.left(1) == "W") {
1020 int index = tmpStr.find(' ');
1021 int last = tmpStr.findRev(' ') + 1;
1022 int rFreq = tmpStr.mid(1, (index-1)).toInt();
1023 index += 1; // advance to beginning of stuff after freq
1024 QBitArray qba(7);
1025 QString dayStr;
1026 if( index == last ) {
1027 // e.g. W1 #0
1028 qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1);
1029 }
1030 else {
1031 // e.g. W1 SU #0
1032 while (index < last) {
1033 dayStr = tmpStr.mid(index, 3);
1034 int dayNum = numFromDay(dayStr);
1035 qba.setBit(dayNum);
1036 index += 3; // advance to next day, or possibly "#"
1037 }
1038 }
1039 index = last; if (tmpStr.mid(index,1) == "#") index++;
1040 if (tmpStr.find('T', index) != -1) {
1041 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1042 anEvent->recurrence()->setWeekly(rFreq, qba, rEndDate);
1043 } else {
1044 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1045 if (rDuration == 0)
1046 anEvent->recurrence()->setWeekly(rFreq, qba, -1);
1047 else
1048 anEvent->recurrence()->setWeekly(rFreq, qba, rDuration);
1049 }
1050 }
1051 /**************************** MONTHLY-BY-POS ***************************/
1052 else if (tmpStr.left(2) == "MP") {
1053 int index = tmpStr.find(' ');
1054 int last = tmpStr.findRev(' ') + 1;
1055 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1056 index += 1; // advance to beginning of stuff after freq
1057 QBitArray qba(7);
1058 short tmpPos;
1059 if( index == last ) {
1060 // e.g. MP1 #0
1061 tmpPos = anEvent->dtStart().date().day()/7 + 1;
1062 if( tmpPos == 5 )
1063 tmpPos = -1;
1064 qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1);
1065 anEvent->recurrence()->addMonthlyPos(tmpPos, qba);
1066 }
1067 else {
1068 // e.g. MP1 1+ SU #0
1069 while (index < last) {
1070 tmpPos = tmpStr.mid(index,1).toShort();
1071 index += 1;
1072 if (tmpStr.mid(index,1) == "-")
1073 // convert tmpPos to negative
1074 tmpPos = 0 - tmpPos;
1075 index += 2; // advance to day(s)
1076 while (numFromDay(tmpStr.mid(index,3)) >= 0) {
1077 int dayNum = numFromDay(tmpStr.mid(index,3));
1078 qba.setBit(dayNum);
1079 index += 3; // advance to next day, or possibly pos or "#"
1080 }
1081 anEvent->recurrence()->addMonthlyPos(tmpPos, qba);
1082 qba.detach();
1083 qba.fill(FALSE); // clear out
1084 } // while != "#"
1085 }
1086 index = last; if (tmpStr.mid(index,1) == "#") index++;
1087 if (tmpStr.find('T', index) != -1) {
1088 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length() -
1089 index))).date();
1090 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rEndDate);
1091 } else {
1092 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1093 if (rDuration == 0)
1094 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, -1);
1095 else
1096 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rDuration);
1097 }
1098 }
1099
1100 /**************************** MONTHLY-BY-DAY ***************************/
1101 else if (tmpStr.left(2) == "MD") {
1102 int index = tmpStr.find(' ');
1103 int last = tmpStr.findRev(' ') + 1;
1104 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1105 index += 1;
1106 short tmpDay;
1107 if( index == last ) {
1108 // e.g. MD1 #0
1109 tmpDay = anEvent->dtStart().date().day();
1110 anEvent->recurrence()->addMonthlyDay(tmpDay);
1111 }
1112 else {
1113 // e.g. MD1 3 #0
1114 while (index < last) {
1115 int index2 = tmpStr.find(' ', index);
1116 tmpDay = tmpStr.mid(index, (index2-index)).toShort();
1117 index = index2-1;
1118 if (tmpStr.mid(index, 1) == "-")
1119 tmpDay = 0 - tmpDay;
1120 index += 2; // advance the index;
1121 anEvent->recurrence()->addMonthlyDay(tmpDay);
1122 } // while != #
1123 }
1124 index = last; if (tmpStr.mid(index,1) == "#") index++;
1125 if (tmpStr.find('T', index) != -1) {
1126 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1127 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rEndDate);
1128 } else {
1129 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1130 if (rDuration == 0)
1131 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, -1);
1132 else
1133 anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rDuration);
1134 }
1135 }
1136
1137 /*********************** YEARLY-BY-MONTH *******************************/
1138 else if (tmpStr.left(2) == "YM") {
1139 int index = tmpStr.find(' ');
1140 int last = tmpStr.findRev(' ') + 1;
1141 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1142 index += 1;
1143 short tmpMonth;
1144 if( index == last ) {
1145 // e.g. YM1 #0
1146 tmpMonth = anEvent->dtStart().date().month();
1147 anEvent->recurrence()->addYearlyNum(tmpMonth);
1148 }
1149 else {
1150 // e.g. YM1 3 #0
1151 while (index < last) {
1152 int index2 = tmpStr.find(' ', index);
1153 tmpMonth = tmpStr.mid(index, (index2-index)).toShort();
1154 index = index2+1;
1155 anEvent->recurrence()->addYearlyNum(tmpMonth);
1156 } // while != #
1157 }
1158 index = last; if (tmpStr.mid(index,1) == "#") index++;
1159 if (tmpStr.find('T', index) != -1) {
1160 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1161 anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rEndDate);
1162 } else {
1163 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1164 if (rDuration == 0)
1165 anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, -1);
1166 else
1167 anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rDuration);
1168 }
1169 }
1170
1171 /*********************** YEARLY-BY-DAY *********************************/
1172 else if (tmpStr.left(2) == "YD") {
1173 int index = tmpStr.find(' ');
1174 int last = tmpStr.findRev(' ') + 1;
1175 int rFreq = tmpStr.mid(2, (index-1)).toInt();
1176 index += 1;
1177 short tmpDay;
1178 if( index == last ) {
1179 // e.g. YD1 #0
1180 tmpDay = anEvent->dtStart().date().dayOfYear();
1181 anEvent->recurrence()->addYearlyNum(tmpDay);
1182 }
1183 else {
1184 // e.g. YD1 123 #0
1185 while (index < last) {
1186 int index2 = tmpStr.find(' ', index);
1187 tmpDay = tmpStr.mid(index, (index2-index)).toShort();
1188 index = index2+1;
1189 anEvent->recurrence()->addYearlyNum(tmpDay);
1190 } // while != #
1191 }
1192 index = last; if (tmpStr.mid(index,1) == "#") index++;
1193 if (tmpStr.find('T', index) != -1) {
1194 QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
1195 anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rEndDate);
1196 } else {
1197 int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
1198 if (rDuration == 0)
1199 anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, -1);
1200 else
1201 anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, rFreq, rDuration);
1202 }
1203 } else {
1204 kdDebug(5800) << "we don't understand this type of recurrence!" << endl;
1205 } // if
1206 } // repeats
1207
1208
1209 // recurrence exceptions
1210 if ((vo = isAPropertyOf(vevent, VCExDateProp)) != 0) {
1211 s = fakeCString(vObjectUStringZValue(vo));
1212 QStringList exDates = QStringList::split(",",s);
1213 QStringList::ConstIterator it;
1214 for(it = exDates.begin(); it != exDates.end(); ++it ) {
1215 anEvent->addExDate(ISOToQDate(*it));
1216 }
1217 deleteStr(s);
1218 }
1219
1220 // summary
1221 if ((vo = isAPropertyOf(vevent, VCSummaryProp))) {
1222 s = fakeCString(vObjectUStringZValue(vo));
1223 anEvent->setSummary(QString::fromLocal8Bit(s));
1224 deleteStr(s);
1225 }
1226 if ((vo = isAPropertyOf(vevent, VCLocationProp))) {
1227 s = fakeCString(vObjectUStringZValue(vo));
1228 anEvent->setLocation(QString::fromLocal8Bit(s));
1229 deleteStr(s);
1230 }
1231
1232 // description
1233 if ((vo = isAPropertyOf(vevent, VCDescriptionProp)) != 0) {
1234 s = fakeCString(vObjectUStringZValue(vo));
1235 if (!anEvent->description().isEmpty()) {
1236 anEvent->setDescription(anEvent->description() + "\n" +
1237 QString::fromLocal8Bit(s));
1238 } else {
1239 anEvent->setDescription(QString::fromLocal8Bit(s));
1240 }
1241 deleteStr(s);
1242 }
1243
1244 // some stupid vCal exporters ignore the standard and use Description
1245 // instead of Summary for the default field. Correct for this.
1246 if (anEvent->summary().isEmpty() &&
1247 !(anEvent->description().isEmpty())) {
1248 QString tmpStr = anEvent->description().simplifyWhiteSpace();
1249 anEvent->setDescription("");
1250 anEvent->setSummary(tmpStr);
1251 }
1252
1253#if 0
1254 // status
1255 if ((vo = isAPropertyOf(vevent, VCStatusProp)) != 0) {
1256 QString tmpStr(s = fakeCString(vObjectUStringZValue(vo)));
1257 deleteStr(s);
1258// TODO: Define Event status
1259// anEvent->setStatus(tmpStr);
1260 }
1261 else
1262// anEvent->setStatus("NEEDS ACTION");
1263#endif
1264
1265 // secrecy
1266 int secrecy = Incidence::SecrecyPublic;
1267 if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) {
1268 s = fakeCString(vObjectUStringZValue(vo));
1269 if (strcmp(s,"PRIVATE") == 0) {
1270 secrecy = Incidence::SecrecyPrivate;
1271 } else if (strcmp(s,"CONFIDENTIAL") == 0) {
1272 secrecy = Incidence::SecrecyConfidential;
1273 }
1274 deleteStr(s);
1275 }
1276 anEvent->setSecrecy(secrecy);
1277
1278 // categories
1279 QStringList tmpStrList;
1280 int index1 = 0;
1281 int index2 = 0;
1282 if ((vo = isAPropertyOf(vevent, VCCategoriesProp)) != 0) {
1283 s = fakeCString(vObjectUStringZValue(vo));
1284 QString categories = QString::fromLocal8Bit(s);
1285 deleteStr(s);
1286 //const char* category;
1287 QString category;
1288 while ((index2 = categories.find(',', index1)) != -1) {
1289 //category = (const char *) categories.mid(index1, (index2 - index1));
1290 category = categories.mid(index1, (index2 - index1));
1291 tmpStrList.append(category);
1292 index1 = index2+1;
1293 }
1294 // get last category
1295 category = categories.mid(index1, (categories.length()-index1));
1296 tmpStrList.append(category);
1297 anEvent->setCategories(tmpStrList);
1298 }
1299
1300 // attachments
1301 tmpStrList.clear();
1302 initPropIterator(&voi, vevent);
1303 while (moreIteration(&voi)) {
1304 vo = nextVObject(&voi);
1305 if (strcmp(vObjectName(vo), VCAttachProp) == 0) {
1306 s = fakeCString(vObjectUStringZValue(vo));
1307 anEvent->addAttachment(new Attachment(QString(s)));
1308 deleteStr(s);
1309 }
1310 }
1311
1312 // resources
1313 if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) {
1314 QString resources = (s = fakeCString(vObjectUStringZValue(vo)));
1315 deleteStr(s);
1316 tmpStrList.clear();
1317 index1 = 0;
1318 index2 = 0;
1319 QString resource;
1320 while ((index2 = resources.find(';', index1)) != -1) {
1321 resource = resources.mid(index1, (index2 - index1));
1322 tmpStrList.append(resource);
1323 index1 = index2;
1324 }
1325 anEvent->setResources(tmpStrList);
1326 }
1327
1328 /* alarm stuff */
1329 if ((vo = isAPropertyOf(vevent, VCDAlarmProp))) {
1330 Alarm* alarm = anEvent->newAlarm();
1331 VObject *a;
1332 if ((a = isAPropertyOf(vo, VCRunTimeProp))) {
1333 alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a))));
1334 deleteStr(s);
1335 }
1336 alarm->setEnabled(true);
1337 if ((vo = isAPropertyOf(vevent, VCPAlarmProp))) {
1338 if ((a = isAPropertyOf(vo, VCProcedureNameProp))) {
1339 s = fakeCString(vObjectUStringZValue(a));
1340 alarm->setProcedureAlarm(QFile::decodeName(s));
1341 deleteStr(s);
1342 }
1343 }
1344 if ((vo = isAPropertyOf(vevent, VCAAlarmProp))) {
1345 if ((a = isAPropertyOf(vo, VCAudioContentProp))) {
1346 s = fakeCString(vObjectUStringZValue(a));
1347 alarm->setAudioAlarm(QFile::decodeName(s));
1348 deleteStr(s);
1349 }
1350 }
1351 }
1352
1353 // priority
1354 if ((vo = isAPropertyOf(vevent, VCPriorityProp))) {
1355 anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo))));
1356 deleteStr(s);
1357 }
1358
1359 // transparency
1360 if ((vo = isAPropertyOf(vevent, VCTranspProp)) != 0) {
1361 int i = atoi(s = fakeCString(vObjectUStringZValue(vo)));
1362 anEvent->setTransparency( i == 1 ? Event::Transparent : Event::Opaque );
1363 deleteStr(s);
1364 }
1365
1366 // related event
1367 if ((vo = isAPropertyOf(vevent, VCRelatedToProp)) != 0) {
1368 anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo)));
1369 deleteStr(s);
1370 mEventsRelate.append(anEvent);
1371 }
1372
1373 /* PILOT SYNC STUFF */
1374 if ((vo = isAPropertyOf(vevent, KPilotIdProp))) {
1375 anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo))));
1376 deleteStr(s);
1377 }
1378 else
1379 anEvent->setPilotId(0);
1380
1381 if ((vo = isAPropertyOf(vevent, KPilotStatusProp))) {
1382 anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo))));
1383 deleteStr(s);
1384 }
1385 else
1386 anEvent->setSyncStatus(Event::SYNCMOD);
1387
1388 return anEvent;
1389}
1390
1391
1392QString VCalFormat::qDateToISO(const QDate &qd)
1393{
1394 QString tmpStr;
1395
1396 ASSERT(qd.isValid());
1397
1398 tmpStr.sprintf("%.2d%.2d%.2d",
1399 qd.year(), qd.month(), qd.day());
1400 return tmpStr;
1401
1402}
1403
1404QString VCalFormat::qDateTimeToISO(const QDateTime &qdt, bool zulu)
1405{
1406 QString tmpStr;
1407
1408 ASSERT(qdt.date().isValid());
1409 ASSERT(qdt.time().isValid());
1410 if (zulu) {
1411 QDateTime tmpDT(qdt);
1412 tmpDT = tmpDT.addSecs(60*(-mCalendar->getTimeZone())); // correct to GMT.
1413 tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2dZ",
1414 tmpDT.date().year(), tmpDT.date().month(),
1415 tmpDT.date().day(), tmpDT.time().hour(),
1416 tmpDT.time().minute(), tmpDT.time().second());
1417 } else {
1418 tmpStr.sprintf("%.2d%.2d%.2dT%.2d%.2d%.2d",
1419 qdt.date().year(), qdt.date().month(),
1420 qdt.date().day(), qdt.time().hour(),
1421 qdt.time().minute(), qdt.time().second());
1422 }
1423 return tmpStr;
1424}
1425
1426QDateTime VCalFormat::ISOToQDateTime(const QString & dtStr)
1427{
1428 QDate tmpDate;
1429 QTime tmpTime;
1430 QString tmpStr;
1431 int year, month, day, hour, minute, second;
1432
1433 tmpStr = dtStr;
1434 year = tmpStr.left(4).toInt();
1435 month = tmpStr.mid(4,2).toInt();
1436 day = tmpStr.mid(6,2).toInt();
1437 hour = tmpStr.mid(9,2).toInt();
1438 minute = tmpStr.mid(11,2).toInt();
1439 second = tmpStr.mid(13,2).toInt();
1440 tmpDate.setYMD(year, month, day);
1441 tmpTime.setHMS(hour, minute, second);
1442
1443 ASSERT(tmpDate.isValid());
1444 ASSERT(tmpTime.isValid());
1445 QDateTime tmpDT(tmpDate, tmpTime);
1446 // correct for GMT if string is in Zulu format
1447 if (dtStr.at(dtStr.length()-1) == 'Z')
1448 tmpDT = tmpDT.addSecs(60*mCalendar->getTimeZone());
1449 return tmpDT;
1450}
1451
1452QDate VCalFormat::ISOToQDate(const QString &dateStr)
1453{
1454 int year, month, day;
1455
1456 year = dateStr.left(4).toInt();
1457 month = dateStr.mid(4,2).toInt();
1458 day = dateStr.mid(6,2).toInt();
1459
1460 return(QDate(year, month, day));
1461}
1462
1463// take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
1464// and break it down from it's tree-like format into the dictionary format
1465// that is used internally in the VCalFormat.
1466void VCalFormat::populate(VObject *vcal)
1467{
1468 // this function will populate the caldict dictionary and other event
1469 // lists. It turns vevents into Events and then inserts them.
1470
1471 VObjectIterator i;
1472 VObject *curVO, *curVOProp;
1473 Event *anEvent;
1474
1475 if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) {
1476 char *methodType = 0;
1477 methodType = fakeCString(vObjectUStringZValue(curVO));
1478 kdDebug() << "This calendar is an iTIP transaction of type '"
1479 << methodType << "'" << endl;
1480 delete methodType;
1481 }
1482
1483 // warn the user that we might have trouble reading non-known calendar.
1484 if ((curVO = isAPropertyOf(vcal, VCProdIdProp)) != 0) {
1485 char *s = fakeCString(vObjectUStringZValue(curVO));
1486 if (strcmp(productId().local8Bit(), s) != 0)
1487 kdDebug() << "This vCalendar file was not created by KOrganizer "
1488 "or any other product we support. Loading anyway..." << endl;
1489 mLoadedProductId = s;
1490 deleteStr(s);
1491 }
1492
1493 // warn the user we might have trouble reading this unknown version.
1494 if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) {
1495 char *s = fakeCString(vObjectUStringZValue(curVO));
1496 if (strcmp(_VCAL_VERSION, s) != 0)
1497 kdDebug() << "This vCalendar file has version " << s
1498 << "We only support " << _VCAL_VERSION << endl;
1499 deleteStr(s);
1500 }
1501
1502 // set the time zone
1503 if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) {
1504 char *s = fakeCString(vObjectUStringZValue(curVO));
1505 mCalendar->setTimeZone(s);
1506 deleteStr(s);
1507 }
1508
1509
1510 // Store all events with a relatedTo property in a list for post-processing
1511 mEventsRelate.clear();
1512 mTodosRelate.clear();
1513
1514 initPropIterator(&i, vcal);
1515
1516 // go through all the vobjects in the vcal
1517 while (moreIteration(&i)) {
1518 curVO = nextVObject(&i);
1519
1520 /************************************************************************/
1521
1522 // now, check to see that the object is an event or todo.
1523 if (strcmp(vObjectName(curVO), VCEventProp) == 0) {
1524
1525 if ((curVOProp = isAPropertyOf(curVO, KPilotStatusProp)) != 0) {
1526 char *s;
1527 s = fakeCString(vObjectUStringZValue(curVOProp));
1528 // check to see if event was deleted by the kpilot conduit
1529 if (atoi(s) == Event::SYNCDEL) {
1530 deleteStr(s);
1531 kdDebug(5800) << "skipping pilot-deleted event" << endl;
1532 goto SKIP;
1533 }
1534 deleteStr(s);
1535 }
1536
1537 // this code checks to see if we are trying to read in an event
1538 // that we already find to be in the calendar. If we find this
1539 // to be the case, we skip the event.
1540 if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) {
1541 char *s = fakeCString(vObjectUStringZValue(curVOProp));
1542 QString tmpStr(s);
1543 deleteStr(s);
1544
1545 if (mCalendar->event(tmpStr)) {
1546 goto SKIP;
1547 }
1548 if (mCalendar->todo(tmpStr)) {
1549 goto SKIP;
1550 }
1551 }
1552
1553 if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) &&
1554 (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) {
1555 kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl;
1556 goto SKIP;
1557 }
1558
1559 anEvent = VEventToEvent(curVO);
1560 // we now use addEvent instead of insertEvent so that the
1561 // signal/slot get connected.
1562 if (anEvent) {
1563 if ( !anEvent->dtStart().isValid() || !anEvent->dtEnd().isValid() ) {
1564 kdDebug() << "VCalFormat::populate(): Event has invalid dates."
1565 << endl;
1566 } else {
1567 mCalendar->addEvent(anEvent);
1568 }
1569 } else {
1570 // some sort of error must have occurred while in translation.
1571 goto SKIP;
1572 }
1573 } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) {
1574 Todo *aTodo = VTodoToEvent(curVO);
1575 mCalendar->addTodo(aTodo);
1576 } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) ||
1577 (strcmp(vObjectName(curVO), VCProdIdProp) == 0) ||
1578 (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) {
1579 // do nothing, we know these properties and we want to skip them.
1580 // we have either already processed them or are ignoring them.
1581 ;
1582 } else {
1583 kdDebug(5800) << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"" << endl;
1584 }
1585 SKIP:
1586 ;
1587 } // while
1588
1589 // Post-Process list of events with relations, put Event objects in relation
1590 Event *ev;
1591 for ( ev=mEventsRelate.first(); ev != 0; ev=mEventsRelate.next() ) {
1592 ev->setRelatedTo(mCalendar->event(ev->relatedToUid()));
1593 }
1594 Todo *todo;
1595 for ( todo=mTodosRelate.first(); todo != 0; todo=mTodosRelate.next() ) {
1596 todo->setRelatedTo(mCalendar->todo(todo->relatedToUid()));
1597 }
1598}
1599
1600const char *VCalFormat::dayFromNum(int day)
1601{
1602 const char *days[7] = { "MO ", "TU ", "WE ", "TH ", "FR ", "SA ", "SU " };
1603
1604 return days[day];
1605}
1606
1607int VCalFormat::numFromDay(const QString &day)
1608{
1609 if (day == "MO ") return 0;
1610 if (day == "TU ") return 1;
1611 if (day == "WE ") return 2;
1612 if (day == "TH ") return 3;
1613 if (day == "FR ") return 4;
1614 if (day == "SA ") return 5;
1615 if (day == "SU ") return 6;
1616
1617 return -1; // something bad happened. :)
1618}
1619
1620Attendee::PartStat VCalFormat::readStatus(const char *s) const
1621{
1622 QString statStr = s;
1623 statStr = statStr.upper();
1624 Attendee::PartStat status;
1625
1626 if (statStr == "X-ACTION")
1627 status = Attendee::NeedsAction;
1628 else if (statStr == "NEEDS ACTION")
1629 status = Attendee::NeedsAction;
1630 else if (statStr== "ACCEPTED")
1631 status = Attendee::Accepted;
1632 else if (statStr== "SENT")
1633 status = Attendee::NeedsAction;
1634 else if (statStr== "TENTATIVE")
1635 status = Attendee::Tentative;
1636 else if (statStr== "CONFIRMED")
1637 status = Attendee::Accepted;
1638 else if (statStr== "DECLINED")
1639 status = Attendee::Declined;
1640 else if (statStr== "COMPLETED")
1641 status = Attendee::Completed;
1642 else if (statStr== "DELEGATED")
1643 status = Attendee::Delegated;
1644 else {
1645 kdDebug(5800) << "error setting attendee mStatus, unknown mStatus!" << endl;
1646 status = Attendee::NeedsAction;
1647 }
1648
1649 return status;
1650}
1651
1652QCString VCalFormat::writeStatus(Attendee::PartStat status) const
1653{
1654 switch(status) {
1655 default:
1656 case Attendee::NeedsAction:
1657 return "NEEDS ACTION";
1658 break;
1659 case Attendee::Accepted:
1660 return "ACCEPTED";
1661 break;
1662 case Attendee::Declined:
1663 return "DECLINED";
1664 break;
1665 case Attendee::Tentative:
1666 return "TENTATIVE";
1667 break;
1668 case Attendee::Delegated:
1669 return "DELEGATED";
1670 break;
1671 case Attendee::Completed:
1672 return "COMPLETED";
1673 break;
1674 case Attendee::InProcess:
1675 return "NEEDS ACTION";
1676 break;
1677 }
1678}