• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 API Reference
  • KDE Home
  • Contact Us
 

KCal Library

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

KDE's Doxygen guidelines are available online.

KCal Library

Skip menu "KCal Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal