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

KCalCore Library

  • kcalcore
vcalformat.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcalcore 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 */
37 #include "vcalformat.h"
38 #include "calendar.h"
39 #include "event.h"
40 #include "exceptions.h"
41 #include "icaltimezones.h"
42 #include "todo.h"
43 #include "versit/vcc.h"
44 #include "versit/vobject.h"
45 
46 #include <KCodecs>
47 #include <KDebug>
48 
49 #include <QtCore/QBitArray>
50 #include <QtCore/QFile>
51 #include <QTextDocument> // for Qt::escape() and Qt::mightBeRichText()
52 
53 using namespace KCalCore;
54 
59 //@cond PRIVATE
60 template <typename K>
61 void removeAllVCal( QVector< QSharedPointer<K> > &c, const QSharedPointer<K> &x )
62 {
63  if ( c.count() < 1 ) {
64  return;
65  }
66 
67  int cnt = c.count( x );
68  if ( cnt != 1 ) {
69  qCritical() << "There number of relatedTos for this incidence is "
70  << cnt << " (there must be 1 relatedTo only)";
71  Q_ASSERT_X( false, "removeAllVCal", "Count is not 1." );
72  return;
73  }
74 
75  c.remove( c.indexOf( x ) );
76 }
77 
78 class KCalCore::VCalFormat::Private
79 {
80  public:
81  Calendar::Ptr mCalendar;
82  Event::List mEventsRelate; // Events with relations
83  Todo::List mTodosRelate; // To-dos with relations
84  QSet<QByteArray> mManuallyWrittenExtensionFields; // X- fields that are manually dumped
85 };
86 //@endcond
87 
88 VCalFormat::VCalFormat() : d( new KCalCore::VCalFormat::Private )
89 {
90 #if defined(KCALCORE_FOR_SYMBIAN)
91  d->mManuallyWrittenExtensionFields << VCRecurrenceIdProp;
92  d->mManuallyWrittenExtensionFields << EPOCAgendaEntryTypeProp;
93 #endif
94  d->mManuallyWrittenExtensionFields << KPilotIdProp;
95  d->mManuallyWrittenExtensionFields << KPilotStatusProp;
96 }
97 
98 VCalFormat::~VCalFormat()
99 {
100  delete d;
101 }
102 
103 bool VCalFormat::load( const Calendar::Ptr &calendar, const QString &fileName )
104 {
105  d->mCalendar = calendar;
106 
107  clearException();
108 
109  VObject *vcal = 0;
110 
111  // this is not necessarily only 1 vcal. Could be many vcals, or include
112  // a vcard...
113  vcal = Parse_MIME_FromFileName( const_cast<char *>( QFile::encodeName( fileName ).data() ) );
114 
115  if ( !vcal ) {
116  setException( new Exception( Exception::CalVersionUnknown ) );
117  return false;
118  }
119 
120  // any other top-level calendar stuff should be added/initialized here
121 
122  // put all vobjects into their proper places
123  QString savedTimeZoneId = d->mCalendar->timeZoneId();
124  populate( vcal, false, fileName );
125  d->mCalendar->setTimeZoneId( savedTimeZoneId );
126 
127  // clean up from vcal API stuff
128  cleanVObjects( vcal );
129  cleanStrTbl();
130 
131  return true;
132 }
133 
134 bool VCalFormat::save( const Calendar::Ptr &calendar, const QString &fileName )
135 {
136  d->mCalendar = calendar;
137 
138  ICalTimeZones *tzlist = d->mCalendar->timeZones();
139 
140  QString tmpStr;
141  VObject *vcal, *vo;
142 
143  vcal = newVObject( VCCalProp );
144 
145  // addPropValue(vcal,VCLocationProp, "0.0");
146  addPropValue( vcal, VCProdIdProp, productId().toLatin1() );
147  addPropValue( vcal, VCVersionProp, _VCAL_VERSION );
148 
149  // TODO STUFF
150  Todo::List todoList = d->mCalendar->rawTodos();
151  Todo::List::ConstIterator it;
152  for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) {
153  if ( ( *it )->dtStart().timeZone().name().mid( 0, 4 ) == "VCAL" ) {
154  ICalTimeZone zone = tzlist->zone( ( *it )->dtStart().timeZone().name() );
155  if ( zone.isValid() ) {
156  QByteArray timezone = zone.vtimezone();
157  addPropValue( vcal, VCTimeZoneProp, parseTZ( timezone ).toLocal8Bit() );
158  QString dst = parseDst( timezone );
159  while ( !dst.isEmpty() ) {
160  addPropValue( vcal, VCDayLightProp, dst.toLocal8Bit() );
161  dst = parseDst( timezone );
162  }
163  }
164  }
165  vo = eventToVTodo( *it );
166  addVObjectProp( vcal, vo );
167  }
168  // EVENT STUFF
169  Event::List events = d->mCalendar->rawEvents();
170  Event::List::ConstIterator it2;
171  for ( it2 = events.constBegin(); it2 != events.constEnd(); ++it2 ) {
172  if ( ( *it2 )->dtStart().timeZone().name().mid( 0, 4 ) == "VCAL" ) {
173  ICalTimeZone zone = tzlist->zone( ( *it2 )->dtStart().timeZone().name() );
174  if ( zone.isValid() ) {
175  QByteArray timezone = zone.vtimezone();
176  addPropValue( vcal, VCTimeZoneProp, parseTZ( timezone ).toLocal8Bit() );
177  QString dst = parseDst( timezone );
178  while ( !dst.isEmpty() ) {
179  addPropValue( vcal, VCDayLightProp, dst.toLocal8Bit() );
180  dst = parseDst( timezone );
181  }
182  }
183  }
184  vo = eventToVEvent( *it2 );
185  addVObjectProp( vcal, vo );
186  }
187  writeVObjectToFile( QFile::encodeName( fileName ).data(), vcal );
188  cleanVObjects( vcal );
189  cleanStrTbl();
190 
191  if ( QFile::exists( fileName ) ) {
192  return true;
193  } else {
194  return false; // error
195  }
196 
197  return false;
198 }
199 
200 bool VCalFormat::fromString( const Calendar::Ptr &calendar, const QString &string,
201  bool deleted, const QString &notebook )
202 {
203  return fromRawString( calendar, string.toUtf8(), deleted, notebook );
204 }
205 
206 bool VCalFormat::fromRawString( const Calendar::Ptr &calendar, const QByteArray &string,
207  bool deleted, const QString &notebook )
208 {
209  d->mCalendar = calendar;
210 
211  if ( !string.size() ) {
212  return false;
213  }
214 
215  VObject *vcal = Parse_MIME( string.data(), string.size() );
216  if ( !vcal ) {
217  return false;
218  }
219 
220  VObjectIterator i;
221  initPropIterator( &i, vcal );
222 
223  // put all vobjects into their proper places
224  QString savedTimeZoneId = d->mCalendar->timeZoneId();
225  populate( vcal, deleted, notebook );
226  d->mCalendar->setTimeZoneId( savedTimeZoneId );
227 
228  // clean up from vcal API stuff
229  cleanVObjects( vcal );
230  cleanStrTbl();
231 
232  return true;
233 }
234 
235 QString VCalFormat::toString( const Calendar::Ptr &calendar,
236  const QString &notebook, bool deleted )
237 {
238  // TODO: Factor out VCalFormat::asString()
239  d->mCalendar = calendar;
240 
241  ICalTimeZones *tzlist = d->mCalendar->timeZones();
242 
243  VObject *vo;
244  VObject *vcal = newVObject( VCCalProp );
245 
246  addPropValue( vcal, VCProdIdProp, CalFormat::productId().toLatin1() );
247  addPropValue( vcal, VCVersionProp, _VCAL_VERSION );
248 
249  // TODO STUFF
250  Todo::List todoList = deleted ? d->mCalendar->deletedTodos() : d->mCalendar->rawTodos();
251  Todo::List::ConstIterator it;
252  for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) {
253  if ( !deleted || !d->mCalendar->todo( ( *it )->uid(), ( *it )->recurrenceId() ) ) {
254  // use existing ones, or really deleted ones
255  if ( notebook.isEmpty() ||
256  ( !calendar->notebook( *it ).isEmpty() &&
257  notebook.endsWith( calendar->notebook( *it ) ) ) ) {
258  if ( ( *it )->dtStart().timeZone().name().mid( 0, 4 ) == "VCAL" ) {
259  ICalTimeZone zone = tzlist->zone( ( *it )->dtStart().timeZone().name() );
260  if ( zone.isValid() ) {
261  QByteArray timezone = zone.vtimezone();
262  addPropValue( vcal, VCTimeZoneProp, parseTZ( timezone ).toUtf8() );
263  QString dst = parseDst( timezone );
264  while ( !dst.isEmpty() ) {
265  addPropValue( vcal, VCDayLightProp, dst.toUtf8() );
266  dst = parseDst( timezone );
267  }
268  }
269  }
270  vo = eventToVTodo( *it );
271  addVObjectProp( vcal, vo );
272  }
273  }
274  }
275 
276  // EVENT STUFF
277  Event::List events = deleted ? d->mCalendar->deletedEvents() : d->mCalendar->rawEvents();
278  Event::List::ConstIterator it2;
279  for ( it2 = events.constBegin(); it2 != events.constEnd(); ++it2 ) {
280  if ( !deleted || !d->mCalendar->event( ( *it2 )->uid(), ( *it2 )->recurrenceId() ) ) {
281  // use existing ones, or really deleted ones
282  if ( notebook.isEmpty() ||
283  ( !calendar->notebook( *it2 ).isEmpty() &&
284  notebook.endsWith( calendar->notebook( *it2 ) ) ) ) {
285  if ( ( *it2 )->dtStart().timeZone().name().mid( 0, 4 ) == "VCAL" ) {
286  ICalTimeZone zone = tzlist->zone( ( *it2 )->dtStart().timeZone().name() );
287  if ( zone.isValid() ) {
288  QByteArray timezone = zone.vtimezone();
289  addPropValue( vcal, VCTimeZoneProp, parseTZ( timezone ).toUtf8() );
290  QString dst = parseDst( timezone );
291  while ( !dst.isEmpty() ) {
292  addPropValue( vcal, VCDayLightProp, dst.toUtf8() );
293  dst = parseDst( timezone );
294  }
295  }
296  }
297  vo = eventToVEvent( *it2 );
298  addVObjectProp( vcal, vo );
299  }
300  }
301  }
302 
303  char *buf = writeMemVObject( 0, 0, vcal );
304 
305  QString result( QString::fromUtf8( buf ) );
306 
307  deleteStr( buf );
308 
309  cleanVObject( vcal );
310 
311  return result;
312 }
313 
314 VObject *VCalFormat::eventToVTodo( const Todo::Ptr &anEvent )
315 {
316  VObject *vtodo;
317  QString tmpStr;
318 
319  vtodo = newVObject( VCTodoProp );
320 
321  // due date
322  if ( anEvent->hasDueDate() ) {
323  tmpStr = kDateTimeToISO( anEvent->dtDue(), !anEvent->allDay() );
324  addPropValue( vtodo, VCDueProp, tmpStr.toUtf8() );
325  }
326 
327  // start date
328  if ( anEvent->hasStartDate() ) {
329  tmpStr = kDateTimeToISO( anEvent->dtStart(), !anEvent->allDay() );
330  addPropValue( vtodo, VCDTstartProp, tmpStr.toUtf8() );
331  }
332 
333  // creation date
334  tmpStr = kDateTimeToISO( anEvent->created() );
335  addPropValue( vtodo, VCDCreatedProp, tmpStr.toUtf8() );
336 
337  // unique id
338  addPropValue( vtodo, VCUniqueStringProp,
339  anEvent->uid().toUtf8() );
340 
341  // revision
342  tmpStr.sprintf( "%i", anEvent->revision() );
343  addPropValue( vtodo, VCSequenceProp, tmpStr.toUtf8() );
344 
345  // last modification date
346  tmpStr = kDateTimeToISO( anEvent->lastModified() );
347  addPropValue( vtodo, VCLastModifiedProp, tmpStr.toUtf8() );
348 
349  // organizer stuff
350  // @TODO: How about the common name?
351  if ( !anEvent->organizer()->email().isEmpty() ) {
352  tmpStr = "MAILTO:" + anEvent->organizer()->email();
353  addPropValue( vtodo, ICOrganizerProp, tmpStr.toUtf8() );
354  }
355 
356  // attendees
357  if ( anEvent->attendeeCount() > 0 ) {
358  Attendee::List::ConstIterator it;
359  Attendee::Ptr curAttendee;
360  for ( it = anEvent->attendees().constBegin(); it != anEvent->attendees().constEnd();
361  ++it ) {
362  curAttendee = *it;
363  if ( !curAttendee->email().isEmpty() && !curAttendee->name().isEmpty() ) {
364  tmpStr = "MAILTO:" + curAttendee->name() + " <" + curAttendee->email() + '>';
365  } else if ( curAttendee->name().isEmpty() && curAttendee->email().isEmpty() ) {
366  tmpStr = "MAILTO: ";
367  kDebug() << "warning! this Event has an attendee w/o name or email!";
368  } else if ( curAttendee->name().isEmpty() ) {
369  tmpStr = "MAILTO: " + curAttendee->email();
370  } else {
371  tmpStr = "MAILTO: " + curAttendee->name();
372  }
373  VObject *aProp = addPropValue( vtodo, VCAttendeeProp, tmpStr.toUtf8() );
374  addPropValue( aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE" );
375  addPropValue( aProp, VCStatusProp, writeStatus( curAttendee->status() ) );
376  }
377  }
378 
379  // recurrence rule stuff
380  const Recurrence *recur = anEvent->recurrence();
381  if ( recur->recurs() ) {
382  bool validRecur = true;
383  QString tmpStr2;
384  switch ( recur->recurrenceType() ) {
385  case Recurrence::rDaily:
386  tmpStr.sprintf( "D%i ", recur->frequency() );
387  break;
388  case Recurrence::rWeekly:
389  tmpStr.sprintf( "W%i ", recur->frequency() );
390  for ( int i = 0; i < 7; ++i ) {
391  QBitArray days ( recur->days() );
392  if ( days.testBit( i ) ) {
393  tmpStr += dayFromNum( i );
394  }
395  }
396  break;
397  case Recurrence::rMonthlyPos:
398  {
399  tmpStr.sprintf( "MP%i ", recur->frequency() );
400  // write out all rMonthPos's
401  QList<RecurrenceRule::WDayPos> tmpPositions = recur->monthPositions();
402  for ( QList<RecurrenceRule::WDayPos>::ConstIterator posit = tmpPositions.constBegin();
403  posit != tmpPositions.constEnd(); ++posit ) {
404  int pos = (*posit).pos();
405  tmpStr2.sprintf( "%i", ( pos > 0 ) ? pos : (-pos) );
406  if ( pos < 0 ) {
407  tmpStr2 += "- ";
408  } else {
409  tmpStr2 += "+ ";
410  }
411  tmpStr += tmpStr2;
412  tmpStr += dayFromNum( ( *posit ).day() - 1 );
413  }
414  break;
415  }
416  case Recurrence::rMonthlyDay:
417  {
418  tmpStr.sprintf( "MD%i ", recur->frequency() );
419  // write out all rMonthDays;
420  const QList<int> tmpDays = recur->monthDays();
421  for ( QList<int>::ConstIterator tmpDay = tmpDays.constBegin();
422  tmpDay != tmpDays.constEnd(); ++tmpDay ) {
423  tmpStr2.sprintf( "%i ", *tmpDay );
424  tmpStr += tmpStr2;
425  }
426  break;
427  }
428  case Recurrence::rYearlyMonth:
429  {
430  tmpStr.sprintf( "YM%i ", recur->frequency() );
431  // write out all the months;'
432  // TODO: Any way to write out the day within the month???
433  const QList<int> months = recur->yearMonths();
434  for ( QList<int>::ConstIterator mit = months.constBegin();
435  mit != months.constEnd(); ++mit ) {
436  tmpStr2.sprintf( "%i ", *mit );
437  tmpStr += tmpStr2;
438  }
439  break;
440  }
441  case Recurrence::rYearlyDay:
442  {
443  tmpStr.sprintf( "YD%i ", recur->frequency() );
444  // write out all the rYearNums;
445  const QList<int> tmpDays = recur->yearDays();
446  for ( QList<int>::ConstIterator tmpDay = tmpDays.begin();
447  tmpDay != tmpDays.end(); ++tmpDay ) {
448  tmpStr2.sprintf( "%i ", *tmpDay );
449  tmpStr += tmpStr2;
450  }
451  break;
452  }
453  default:
454  // TODO: Write rYearlyPos and arbitrary rules!
455  kDebug() << "ERROR, it should never get here in eventToVTodo!";
456  validRecur = false;
457  break;
458  } // switch
459 
460  if ( recur->duration() > 0 ) {
461  tmpStr2.sprintf( "#%i", recur->duration() );
462  tmpStr += tmpStr2;
463  } else if ( recur->duration() == -1 ) {
464  tmpStr += "#0"; // defined as repeat forever
465  } else {
466  tmpStr += kDateTimeToISO( recur->endDateTime(), false );
467  }
468  // Only write out the rrule if we have a valid recurrence (i.e. a known
469  // type in thee switch above)
470  if ( validRecur ) {
471  addPropValue( vtodo, VCRRuleProp, tmpStr.toUtf8() );
472  }
473 
474  } // event repeats
475 
476  // exceptions dates to recurrence
477  DateList dateList = recur->exDates();
478  DateList::ConstIterator id;
479  QString tmpStr2;
480 
481  for ( id = dateList.constBegin(); id != dateList.constEnd(); ++id ) {
482  tmpStr = qDateToISO( *id ) + ';';
483  tmpStr2 += tmpStr;
484  }
485  if ( !tmpStr2.isEmpty() ) {
486  tmpStr2.truncate( tmpStr2.length() - 1 );
487  addPropValue( vtodo, VCExpDateProp, tmpStr2.toUtf8() );
488  }
489  // exceptions datetimes to recurrence
490  DateTimeList dateTimeList = recur->exDateTimes();
491  DateTimeList::ConstIterator idt;
492  tmpStr2.clear();
493 
494  for ( idt = dateTimeList.constBegin(); idt != dateTimeList.constEnd(); ++idt ) {
495  tmpStr = kDateTimeToISO( *idt ) + ';';
496  tmpStr2 += tmpStr;
497  }
498  if ( !tmpStr2.isEmpty() ) {
499  tmpStr2.truncate( tmpStr2.length() - 1 );
500  addPropValue( vtodo, VCExpDateProp, tmpStr2.toUtf8() );
501  }
502 
503  // description BL:
504  if ( !anEvent->description().isEmpty() ) {
505  QByteArray in = anEvent->description().toUtf8();
506  QByteArray out;
507  KCodecs::quotedPrintableEncode( in, out, true );
508  if ( out != in ) {
509  VObject *d = addPropValue( vtodo, VCDescriptionProp, out );
510  addPropValue( d, VCEncodingProp, VCQuotedPrintableProp );
511  addPropValue( d, VCCharSetProp, VCUtf8Prop );
512  } else {
513  addPropValue( vtodo, VCDescriptionProp, in );
514  }
515  }
516 
517  // summary
518  if ( !anEvent->summary().isEmpty() ) {
519  QByteArray in = anEvent->summary().toUtf8();
520  QByteArray out;
521  KCodecs::quotedPrintableEncode( in, out, true );
522  if ( out != in ) {
523  VObject *d = addPropValue( vtodo, VCSummaryProp, out );
524  addPropValue( d, VCEncodingProp, VCQuotedPrintableProp );
525  addPropValue( d, VCCharSetProp, VCUtf8Prop );
526  } else {
527  addPropValue( vtodo, VCSummaryProp, in );
528  }
529  }
530 
531  // location
532  if ( !anEvent->location().isEmpty() ) {
533  QByteArray in = anEvent->location().toUtf8();
534  QByteArray out;
535  KCodecs::quotedPrintableEncode( in, out, true );
536  if ( out != in ) {
537  VObject *d = addPropValue( vtodo, VCLocationProp, out );
538  addPropValue( d, VCEncodingProp, VCQuotedPrintableProp );
539  addPropValue( d, VCCharSetProp, VCUtf8Prop );
540  } else {
541  addPropValue( vtodo, VCLocationProp, in );
542  }
543  }
544 
545  // completed status
546  // backward compatibility, KOrganizer used to interpret only these two values
547  addPropValue( vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" : "NEEDS ACTION" );
548 
549  // completion date
550  if ( anEvent->hasCompletedDate() ) {
551  tmpStr = kDateTimeToISO( anEvent->completed() );
552  addPropValue( vtodo, VCCompletedProp, tmpStr.toUtf8() );
553  }
554 
555  // priority
556  tmpStr.sprintf( "%i", anEvent->priority() );
557  addPropValue( vtodo, VCPriorityProp, tmpStr.toUtf8() );
558 
559  // related event
560  if ( !anEvent->relatedTo().isEmpty() ) {
561  addPropValue( vtodo, VCRelatedToProp,
562  anEvent->relatedTo().toUtf8() );
563  }
564 
565  // secrecy
566  const char *text = 0;
567  switch ( anEvent->secrecy() ) {
568  case Incidence::SecrecyPublic:
569  text = "PUBLIC";
570  break;
571  case Incidence::SecrecyPrivate:
572  text = "PRIVATE";
573  break;
574  case Incidence::SecrecyConfidential:
575  text = "CONFIDENTIAL";
576  break;
577  }
578  if ( text ) {
579  addPropValue( vtodo, VCClassProp, text );
580  }
581 
582  // categories
583  const QStringList tmpStrList = anEvent->categories();
584  tmpStr = "";
585  QString catStr;
586  QStringList::const_iterator its;
587  for ( its = tmpStrList.constBegin(); its != tmpStrList.constEnd(); ++its ) {
588  catStr = *its;
589  if ( catStr[0] == ' ' ) {
590  tmpStr += catStr.mid( 1 );
591  } else {
592  tmpStr += catStr;
593  }
594  // this must be a ';' character as the vCalendar specification requires!
595  // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
596  // read in.
597  tmpStr += ';';
598  }
599  if ( !tmpStr.isEmpty() ) {
600  tmpStr.truncate( tmpStr.length() - 1 );
601  addPropValue( vtodo, VCCategoriesProp, tmpStr.toUtf8() );
602  }
603 
604  // alarm stuff
605  Alarm::List::ConstIterator it;
606  for ( it = anEvent->alarms().constBegin(); it != anEvent->alarms().constEnd(); ++it ) {
607  Alarm::Ptr alarm = *it;
608  if ( alarm->enabled() ) {
609  VObject *a;
610  if ( alarm->type() == Alarm::Display ) {
611  a = addProp( vtodo, VCDAlarmProp );
612  tmpStr = kDateTimeToISO( alarm->time() );
613  addPropValue( a, VCRunTimeProp, tmpStr.toUtf8() );
614  addPropValue( a, VCRepeatCountProp, "1" );
615  if ( alarm->text().isNull() ) {
616  addPropValue( a, VCDisplayStringProp, "beep!" );
617  } else {
618  addPropValue( a, VCDisplayStringProp, alarm->text().toLatin1().data() );
619  }
620  } else if ( alarm->type() == Alarm::Audio ) {
621  a = addProp( vtodo, VCAAlarmProp );
622  tmpStr = kDateTimeToISO( alarm->time() );
623  addPropValue( a, VCRunTimeProp, tmpStr.toUtf8() );
624  addPropValue( a, VCRepeatCountProp, "1" );
625  addPropValue( a, VCAudioContentProp, QFile::encodeName( alarm->audioFile() ) );
626  } else if ( alarm->type() == Alarm::Procedure ) {
627  a = addProp( vtodo, VCPAlarmProp );
628  tmpStr = kDateTimeToISO( alarm->time() );
629  addPropValue( a, VCRunTimeProp, tmpStr.toUtf8() );
630  addPropValue( a, VCRepeatCountProp, "1" );
631  addPropValue( a, VCProcedureNameProp, QFile::encodeName( alarm->programFile() ) );
632  }
633  }
634  }
635 
636  QString pilotId = anEvent->nonKDECustomProperty( KPilotIdProp );
637  if ( !pilotId.isEmpty() ) {
638  // pilot sync stuff
639  addPropValue( vtodo, KPilotIdProp, pilotId.toUtf8() );
640  addPropValue( vtodo, KPilotStatusProp,
641  anEvent->nonKDECustomProperty( KPilotStatusProp ).toUtf8() );
642  }
643 #if defined(KCALCORE_FOR_SYMBIAN)
644  if ( anEvent->nonKDECustomProperty( EPOCAgendaEntryTypeProp ).isEmpty() ) {
645  // Propagate braindeath by setting this property also so that
646  // S60 is happy
647  addPropValue( vtodo, EPOCAgendaEntryTypeProp, "TODO" );
648  }
649 
650  writeCustomProperties( vtodo, anEvent );
651 #endif
652 
653  return vtodo;
654 }
655 
656 VObject *VCalFormat::eventToVEvent( const Event::Ptr &anEvent )
657 {
658  VObject *vevent;
659  QString tmpStr;
660 
661  vevent = newVObject( VCEventProp );
662 
663  // start and end time
664  tmpStr = kDateTimeToISO( anEvent->dtStart(), !anEvent->allDay() );
665  addPropValue( vevent, VCDTstartProp, tmpStr.toUtf8() );
666 
667 #if !defined(KCALCORE_FOR_MEEGO)
668  // events that have time associated but take up no time should
669  // not have both DTSTART and DTEND.
670  if ( anEvent->dtStart() != anEvent->dtEnd() ) {
671  tmpStr = kDateTimeToISO( anEvent->dtEnd(), !anEvent->allDay() );
672  addPropValue( vevent, VCDTendProp, tmpStr.toUtf8() );
673  }
674 #else
675  // N900 and s60-phones need enddate
676  tmpStr = kDateTimeToISO( anEvent->dtEnd(), !anEvent->allDay() );
677  addPropValue( vevent, VCDTendProp, tmpStr.toUtf8() );
678 #endif
679 
680  // creation date
681  tmpStr = kDateTimeToISO( anEvent->created() );
682  addPropValue( vevent, VCDCreatedProp, tmpStr.toUtf8() );
683 
684  // unique id
685  addPropValue( vevent, VCUniqueStringProp,
686  anEvent->uid().toUtf8() );
687 
688  // revision
689  tmpStr.sprintf( "%i", anEvent->revision() );
690  addPropValue( vevent, VCSequenceProp, tmpStr.toUtf8() );
691 
692  // last modification date
693  tmpStr = kDateTimeToISO( anEvent->lastModified() );
694  addPropValue( vevent, VCLastModifiedProp, tmpStr.toUtf8() );
695 
696  // attendee and organizer stuff
697  // TODO: What to do with the common name?
698  if ( !anEvent->organizer()->email().isEmpty() ) {
699  tmpStr = "MAILTO:" + anEvent->organizer()->email();
700  addPropValue( vevent, ICOrganizerProp, tmpStr.toUtf8() );
701  }
702 
703  // TODO: Put this functionality into Attendee class
704  if ( anEvent->attendeeCount() > 0 ) {
705  Attendee::List::ConstIterator it;
706  for ( it = anEvent->attendees().constBegin(); it != anEvent->attendees().constEnd();
707  ++it ) {
708  Attendee::Ptr curAttendee = *it;
709  if ( !curAttendee->email().isEmpty() && !curAttendee->name().isEmpty() ) {
710  tmpStr = "MAILTO:" + curAttendee->name() + " <" + curAttendee->email() + '>';
711  } else if ( curAttendee->name().isEmpty() && curAttendee->email().isEmpty() ) {
712  tmpStr = "MAILTO: ";
713  kDebug() << "warning! this Event has an attendee w/o name or email!";
714  } else if ( curAttendee->name().isEmpty() ) {
715  tmpStr = "MAILTO: " + curAttendee->email();
716  } else {
717  tmpStr = "MAILTO: " + curAttendee->name();
718  }
719  VObject *aProp = addPropValue( vevent, VCAttendeeProp, tmpStr.toUtf8() );
720  addPropValue( aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE" );
721  addPropValue( aProp, VCStatusProp, writeStatus( curAttendee->status() ) );
722  }
723  }
724 
725  // recurrence rule stuff
726  const Recurrence *recur = anEvent->recurrence();
727  if ( recur->recurs() ) {
728  bool validRecur = true;
729  QString tmpStr2;
730  switch ( recur->recurrenceType() ) {
731  case Recurrence::rDaily:
732  tmpStr.sprintf( "D%i ", recur->frequency() );
733  break;
734  case Recurrence::rWeekly:
735  tmpStr.sprintf( "W%i ", recur->frequency() );
736  for ( int i = 0; i < 7; ++i ) {
737  QBitArray days ( recur->days() );
738  if ( days.testBit( i ) ) {
739  tmpStr += dayFromNum( i );
740  }
741  }
742  break;
743  case Recurrence::rMonthlyPos:
744  {
745  tmpStr.sprintf( "MP%i ", recur->frequency() );
746  // write out all rMonthPos's
747  QList<RecurrenceRule::WDayPos> tmpPositions = recur->monthPositions();
748  for ( QList<RecurrenceRule::WDayPos>::ConstIterator posit = tmpPositions.constBegin();
749  posit != tmpPositions.constEnd(); ++posit ) {
750  int pos = (*posit).pos();
751  tmpStr2.sprintf( "%i", ( pos > 0 ) ? pos : (-pos) );
752  if ( pos < 0 ) {
753  tmpStr2 += "- ";
754  } else {
755  tmpStr2 += "+ ";
756  }
757  tmpStr += tmpStr2;
758  tmpStr += dayFromNum( ( *posit ).day() - 1 );
759  }
760  break;
761  }
762  case Recurrence::rMonthlyDay:
763  {
764  tmpStr.sprintf( "MD%i ", recur->frequency() );
765  // write out all rMonthDays;
766  const QList<int> tmpDays = recur->monthDays();
767  for ( QList<int>::ConstIterator tmpDay = tmpDays.constBegin();
768  tmpDay != tmpDays.constEnd(); ++tmpDay ) {
769  tmpStr2.sprintf( "%i ", *tmpDay );
770  tmpStr += tmpStr2;
771  }
772  break;
773  }
774  case Recurrence::rYearlyMonth:
775  {
776  tmpStr.sprintf( "YM%i ", recur->frequency() );
777  // write out all the months;'
778  // TODO: Any way to write out the day within the month???
779  const QList<int> months = recur->yearMonths();
780  for ( QList<int>::ConstIterator mit = months.constBegin();
781  mit != months.constEnd(); ++mit ) {
782  tmpStr2.sprintf( "%i ", *mit );
783  tmpStr += tmpStr2;
784  }
785  break;
786  }
787  case Recurrence::rYearlyDay:
788  {
789  tmpStr.sprintf( "YD%i ", recur->frequency() );
790  // write out all the rYearNums;
791  const QList<int> tmpDays = recur->yearDays();
792  for ( QList<int>::ConstIterator tmpDay = tmpDays.begin();
793  tmpDay != tmpDays.end(); ++tmpDay ) {
794  tmpStr2.sprintf( "%i ", *tmpDay );
795  tmpStr += tmpStr2;
796  }
797  break;
798  }
799  default:
800  // TODO: Write rYearlyPos and arbitrary rules!
801  kDebug() << "ERROR, it should never get here in eventToVEvent!";
802  validRecur = false;
803  break;
804  } // switch
805 
806  if ( recur->duration() > 0 ) {
807  tmpStr2.sprintf( "#%i", recur->duration() );
808  tmpStr += tmpStr2;
809  } else if ( recur->duration() == -1 ) {
810  tmpStr += "#0"; // defined as repeat forever
811  } else {
812 #if !defined(KCALCORE_FOR_MEEGO)
813  tmpStr += kDateTimeToISO( recur->endDateTime(), false );
814 #else
815  tmpStr +=
816  kDateTimeToISO( recur->endDateTime().toTimeSpec( d->mCalendar->timeSpec() ), false );
817 #endif
818  }
819  // Only write out the rrule if we have a valid recurrence (i.e. a known
820  // type in thee switch above)
821  if ( validRecur ) {
822  addPropValue( vevent, VCRRuleProp, tmpStr.toUtf8() );
823  }
824 
825  } // event repeats
826 
827  // exceptions dates to recurrence
828  DateList dateList = recur->exDates();
829  DateList::ConstIterator it;
830  QString tmpStr2;
831 
832  for ( it = dateList.constBegin(); it != dateList.constEnd(); ++it ) {
833  tmpStr = qDateToISO( *it ) + ';';
834  tmpStr2 += tmpStr;
835  }
836  if ( !tmpStr2.isEmpty() ) {
837  tmpStr2.truncate( tmpStr2.length() - 1 );
838  addPropValue( vevent, VCExpDateProp, tmpStr2.toUtf8() );
839  }
840  // exceptions datetimes to recurrence
841  DateTimeList dateTimeList = recur->exDateTimes();
842  DateTimeList::ConstIterator idt;
843  tmpStr2.clear();
844 
845  for ( idt = dateTimeList.constBegin(); idt != dateTimeList.constEnd(); ++idt ) {
846  tmpStr = kDateTimeToISO( *idt ) + ';';
847  tmpStr2 += tmpStr;
848  }
849  if ( !tmpStr2.isEmpty() ) {
850  tmpStr2.truncate( tmpStr2.length() - 1 );
851  addPropValue( vevent, VCExpDateProp, tmpStr2.toUtf8() );
852  }
853 
854  // description
855  if ( !anEvent->description().isEmpty() ) {
856  QByteArray in = anEvent->description().toUtf8();
857  QByteArray out;
858  KCodecs::quotedPrintableEncode( in, out, true );
859  if ( out != in ) {
860  VObject *d = addPropValue( vevent, VCDescriptionProp, out );
861  addPropValue( d, VCEncodingProp, VCQuotedPrintableProp );
862  addPropValue( d, VCCharSetProp, VCUtf8Prop );
863  } else {
864  addPropValue( vevent, VCDescriptionProp, in );
865  }
866  }
867 
868  // summary
869  if ( !anEvent->summary().isEmpty() ) {
870  QByteArray in = anEvent->summary().toUtf8();
871  QByteArray out;
872  KCodecs::quotedPrintableEncode( in, out, true );
873  if ( out != in ) {
874  VObject *d = addPropValue( vevent, VCSummaryProp, out );
875  addPropValue( d, VCEncodingProp, VCQuotedPrintableProp );
876  addPropValue( d, VCCharSetProp, VCUtf8Prop );
877  } else {
878  addPropValue( vevent, VCSummaryProp, in );
879  }
880  }
881 
882  // location
883  if ( !anEvent->location().isEmpty() ) {
884  QByteArray in = anEvent->location().toUtf8();
885  QByteArray out;
886  KCodecs::quotedPrintableEncode( in, out, true );
887  if ( out != in ) {
888  VObject *d = addPropValue( vevent, VCLocationProp, out );
889  addPropValue( d, VCEncodingProp, VCQuotedPrintableProp );
890  addPropValue( d, VCCharSetProp, VCUtf8Prop );
891  } else {
892  addPropValue( vevent, VCLocationProp, in );
893  }
894  }
895 
896  // status
897 // TODO: define Event status
898 // addPropValue( vevent, VCStatusProp, anEvent->statusStr().toUtf8() );
899 
900  // secrecy
901  const char *text = 0;
902  switch ( anEvent->secrecy() ) {
903  case Incidence::SecrecyPublic:
904  text = "PUBLIC";
905  break;
906  case Incidence::SecrecyPrivate:
907  text = "PRIVATE";
908  break;
909  case Incidence::SecrecyConfidential:
910  text = "CONFIDENTIAL";
911  break;
912  }
913  if ( text ) {
914  addPropValue( vevent, VCClassProp, text );
915  }
916 
917  // categories
918  QStringList tmpStrList = anEvent->categories();
919  tmpStr = "";
920  QString catStr;
921  for ( QStringList::const_iterator it = tmpStrList.constBegin(); it != tmpStrList.constEnd();
922  ++it ) {
923  catStr = *it;
924  if ( catStr[0] == ' ' ) {
925  tmpStr += catStr.mid( 1 );
926  } else {
927  tmpStr += catStr;
928  }
929  // this must be a ';' character as the vCalendar specification requires!
930  // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
931  // read in.
932  tmpStr += ';';
933  }
934  if ( !tmpStr.isEmpty() ) {
935  tmpStr.truncate( tmpStr.length() - 1 );
936  addPropValue( vevent, VCCategoriesProp, tmpStr.toUtf8() );
937  }
938 
939  // attachments
940  // TODO: handle binary attachments!
941  Attachment::List attachments = anEvent->attachments();
942  Attachment::List::ConstIterator atIt;
943  for ( atIt = attachments.constBegin(); atIt != attachments.constEnd(); ++atIt ) {
944  addPropValue( vevent, VCAttachProp, ( *atIt )->uri().toUtf8() );
945  }
946 
947  // resources
948  tmpStrList = anEvent->resources();
949  tmpStr = tmpStrList.join( ";" );
950  if ( !tmpStr.isEmpty() ) {
951  addPropValue( vevent, VCResourcesProp, tmpStr.toUtf8() );
952  }
953 
954  // alarm stuff
955  Alarm::List::ConstIterator it2;
956  for ( it2 = anEvent->alarms().constBegin(); it2 != anEvent->alarms().constEnd(); ++it2 ) {
957  Alarm::Ptr alarm = *it2;
958  if ( alarm->enabled() ) {
959  VObject *a;
960  if ( alarm->type() == Alarm::Display ) {
961  a = addProp( vevent, VCDAlarmProp );
962  tmpStr = kDateTimeToISO( alarm->time() );
963  addPropValue( a, VCRunTimeProp, tmpStr.toUtf8() );
964  addPropValue( a, VCRepeatCountProp, "1" );
965  if ( alarm->text().isNull() ) {
966  addPropValue( a, VCDisplayStringProp, "beep!" );
967  } else {
968  addPropValue( a, VCDisplayStringProp, alarm->text().toLatin1().data() );
969  }
970  } else if ( alarm->type() == Alarm::Audio ) {
971  a = addProp( vevent, VCAAlarmProp );
972  tmpStr = kDateTimeToISO( alarm->time() );
973  addPropValue( a, VCRunTimeProp, tmpStr.toUtf8() );
974  addPropValue( a, VCRepeatCountProp, "1" );
975  addPropValue( a, VCAudioContentProp, QFile::encodeName( alarm->audioFile() ) );
976  }
977  if ( alarm->type() == Alarm::Procedure ) {
978  a = addProp( vevent, VCPAlarmProp );
979  tmpStr = kDateTimeToISO( alarm->time() );
980  addPropValue( a, VCRunTimeProp, tmpStr.toUtf8() );
981  addPropValue( a, VCRepeatCountProp, "1" );
982  addPropValue( a, VCProcedureNameProp, QFile::encodeName( alarm->programFile() ) );
983  }
984  }
985  }
986 
987  // priority
988  tmpStr.sprintf( "%i", anEvent->priority() );
989  addPropValue( vevent, VCPriorityProp, tmpStr.toUtf8() );
990 
991  // transparency
992  tmpStr.sprintf( "%i", anEvent->transparency() );
993  addPropValue( vevent, VCTranspProp, tmpStr.toUtf8() );
994 
995  // related event
996  if ( !anEvent->relatedTo().isEmpty() ) {
997  addPropValue( vevent, VCRelatedToProp, anEvent->relatedTo().toUtf8() );
998  }
999 
1000  QString pilotId = anEvent->nonKDECustomProperty( KPilotIdProp );
1001  if ( !pilotId.isEmpty() ) {
1002  // pilot sync stuff
1003  addPropValue( vevent, KPilotIdProp, pilotId.toUtf8() );
1004  addPropValue( vevent, KPilotStatusProp,
1005  anEvent->nonKDECustomProperty( KPilotStatusProp ).toUtf8() );
1006  }
1007 
1008 #if defined(KCALCORE_FOR_SYMBIAN)
1009  if ( anEvent->nonKDECustomProperty( EPOCAgendaEntryTypeProp ).isEmpty() ) {
1010  // Propagate braindeath by setting this property also so that
1011  // S60 is happy
1012  if ( anEvent->allDay() ) {
1013  addPropValue( vevent, EPOCAgendaEntryTypeProp, "EVENT" );
1014  } else {
1015  addPropValue( vevent, EPOCAgendaEntryTypeProp, "APPOINTMENT" );
1016  }
1017  }
1018 
1019  if ( anEvent->hasRecurrenceId() ) {
1020  tmpStr = kDateTimeToISO( anEvent->recurrenceId(), true );
1021  addPropValue( vevent, VCRecurrenceIdProp, tmpStr.toUtf8() );
1022  }
1023  writeCustomProperties( vevent, anEvent );
1024 #endif
1025 
1026  return vevent;
1027 }
1028 
1029 Todo::Ptr VCalFormat::VTodoToEvent( VObject *vtodo )
1030 {
1031  VObject *vo;
1032  VObjectIterator voi;
1033  char *s;
1034 
1035  Todo::Ptr anEvent( new Todo );
1036 
1037  // creation date
1038  if ( ( vo = isAPropertyOf( vtodo, VCDCreatedProp ) ) != 0 ) {
1039  anEvent->setCreated( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1040  deleteStr( s );
1041  }
1042 
1043  // unique id
1044  vo = isAPropertyOf( vtodo, VCUniqueStringProp );
1045  // while the UID property is preferred, it is not required. We'll use the
1046  // default Event UID if none is given.
1047  if ( vo ) {
1048  anEvent->setUid( s = fakeCString( vObjectUStringZValue( vo ) ) );
1049  deleteStr( s );
1050  }
1051 
1052  // last modification date
1053  if ( ( vo = isAPropertyOf( vtodo, VCLastModifiedProp ) ) != 0 ) {
1054  anEvent->setLastModified( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1055  deleteStr( s );
1056  } else {
1057  anEvent->setLastModified( KDateTime::currentUtcDateTime() );
1058  }
1059 
1060  // organizer
1061  // if our extension property for the event's ORGANIZER exists, add it.
1062  if ( ( vo = isAPropertyOf( vtodo, ICOrganizerProp ) ) != 0 ) {
1063  anEvent->setOrganizer( s = fakeCString( vObjectUStringZValue( vo ) ) );
1064  deleteStr( s );
1065  } else {
1066  if ( d->mCalendar->owner()->name() != "Unknown Name" ) {
1067  anEvent->setOrganizer( d->mCalendar->owner() );
1068  }
1069  }
1070 
1071  // attendees.
1072  initPropIterator( &voi, vtodo );
1073  while ( moreIteration( &voi ) ) {
1074  vo = nextVObject( &voi );
1075  if ( strcmp( vObjectName( vo ), VCAttendeeProp ) == 0 ) {
1076  Attendee::Ptr a;
1077  VObject *vp;
1078  s = fakeCString( vObjectUStringZValue( vo ) );
1079  QString tmpStr = QString::fromUtf8( s );
1080  deleteStr( s );
1081  tmpStr = tmpStr.simplified();
1082  int emailPos1, emailPos2;
1083  if ( ( emailPos1 = tmpStr.indexOf( '<' ) ) > 0 ) {
1084  // both email address and name
1085  emailPos2 = tmpStr.lastIndexOf( '>' );
1086  a = Attendee::Ptr( new Attendee( tmpStr.left( emailPos1 - 1 ),
1087  tmpStr.mid( emailPos1 + 1,
1088  emailPos2 - ( emailPos1 + 1 ) ) ) );
1089  } else if ( tmpStr.indexOf( '@' ) > 0 ) {
1090  // just an email address
1091  a = Attendee::Ptr( new Attendee( 0, tmpStr ) );
1092  } else {
1093  // just a name
1094  // WTF??? Replacing the spaces of a name and using this as email?
1095  QString email = tmpStr.replace( ' ', '.' );
1096  a = Attendee::Ptr( new Attendee( tmpStr, email ) );
1097  }
1098 
1099  // is there an RSVP property?
1100  if ( ( vp = isAPropertyOf( vo, VCRSVPProp ) ) != 0 ) {
1101  a->setRSVP( vObjectStringZValue( vp ) );
1102  }
1103  // is there a status property?
1104  if ( ( vp = isAPropertyOf( vo, VCStatusProp ) ) != 0 ) {
1105  a->setStatus( readStatus( vObjectStringZValue( vp ) ) );
1106  }
1107  // add the attendee
1108  anEvent->addAttendee( a );
1109  }
1110  }
1111 
1112  // description for todo
1113  if ( ( vo = isAPropertyOf( vtodo, VCDescriptionProp ) ) != 0 ) {
1114  s = fakeCString( vObjectUStringZValue( vo ) );
1115  anEvent->setDescription( QString::fromUtf8( s ), Qt::mightBeRichText( s ) );
1116  deleteStr( s );
1117  }
1118 
1119  // summary
1120  if ( ( vo = isAPropertyOf( vtodo, VCSummaryProp ) ) ) {
1121  s = fakeCString( vObjectUStringZValue( vo ) );
1122  anEvent->setSummary( QString::fromUtf8( s ), Qt::mightBeRichText( s ) );
1123  deleteStr( s );
1124  }
1125 
1126  // location
1127  if ( ( vo = isAPropertyOf( vtodo, VCLocationProp ) ) != 0 ) {
1128  s = fakeCString( vObjectUStringZValue( vo ) );
1129  anEvent->setLocation( QString::fromUtf8( s ), Qt::mightBeRichText( s ) );
1130  deleteStr( s );
1131  }
1132 
1133  // completed
1134  // was: status
1135  if ( ( vo = isAPropertyOf( vtodo, VCStatusProp ) ) != 0 ) {
1136  s = fakeCString( vObjectUStringZValue( vo ) );
1137  if ( s && strcmp( s, "COMPLETED" ) == 0 ) {
1138  anEvent->setCompleted( true );
1139  } else {
1140  anEvent->setCompleted( false );
1141  }
1142  deleteStr( s );
1143  } else {
1144  anEvent->setCompleted( false );
1145  }
1146 
1147  // completion date
1148  if ( ( vo = isAPropertyOf( vtodo, VCCompletedProp ) ) != 0 ) {
1149  anEvent->setCompleted( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1150  deleteStr( s );
1151  }
1152 
1153  // priority
1154  if ( ( vo = isAPropertyOf( vtodo, VCPriorityProp ) ) ) {
1155  s = fakeCString( vObjectUStringZValue( vo ) );
1156  if ( s ) {
1157  anEvent->setPriority( atoi( s ) );
1158  deleteStr( s );
1159  }
1160  }
1161 
1162  anEvent->setAllDay( false );
1163 
1164  // due date
1165  if ( ( vo = isAPropertyOf( vtodo, VCDueProp ) ) != 0 ) {
1166  anEvent->setDtDue( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1167  deleteStr( s );
1168  if ( anEvent->dtDue().time().hour() == 0 &&
1169  anEvent->dtDue().time().minute() == 0 &&
1170  anEvent->dtDue().time().second() == 0 ) {
1171 #if defined(KCALCORE_FOR_MEEGO)
1172  QDate dueDate = anEvent->dtDue().date();
1173  anEvent->setDtDue( KDateTime( dueDate, KDateTime::ClockTime ) );
1174 #endif
1175  anEvent->setAllDay( true );
1176  }
1177  } else {
1178  anEvent->setDtDue( KDateTime() );
1179  }
1180 
1181  // start time
1182  if ( ( vo = isAPropertyOf( vtodo, VCDTstartProp ) ) != 0 ) {
1183  anEvent->setDtStart( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1184  deleteStr( s );
1185  if ( anEvent->dtStart().time().hour() == 0 &&
1186  anEvent->dtStart().time().minute() == 0 &&
1187  anEvent->dtStart().time().second() == 0 ) {
1188 #if defined(KCALCORE_FOR_MEEGO)
1189  QDate startDate = anEvent->dtStart().date();
1190  anEvent->setDtStart( KDateTime( startDate, KDateTime::ClockTime ) );
1191 #endif
1192  anEvent->setAllDay( true );
1193  }
1194  } else {
1195  anEvent->setDtStart( KDateTime() );
1196  }
1197 
1198  // repeat stuff
1199  if ( ( vo = isAPropertyOf( vtodo, VCRRuleProp ) ) != 0 ) {
1200  QString tmpStr = ( s = fakeCString( vObjectUStringZValue( vo ) ) );
1201  deleteStr( s );
1202  tmpStr.simplified();
1203  tmpStr = tmpStr.toUpper();
1204  // first, read the type of the recurrence
1205  int typelen = 1;
1206  uint type = Recurrence::rNone;
1207  if ( tmpStr.left( 1 ) == "D" ) {
1208  type = Recurrence::rDaily;
1209  } else if ( tmpStr.left( 1 ) == "W" ) {
1210  type = Recurrence::rWeekly;
1211  } else {
1212  typelen = 2;
1213  if ( tmpStr.left( 2 ) == "MP" ) {
1214  type = Recurrence::rMonthlyPos;
1215  } else if ( tmpStr.left( 2 ) == "MD" ) {
1216  type = Recurrence::rMonthlyDay;
1217  } else if ( tmpStr.left( 2 ) == "YM" ) {
1218  type = Recurrence::rYearlyMonth;
1219  } else if ( tmpStr.left( 2 ) == "YD" ) {
1220  type = Recurrence::rYearlyDay;
1221  }
1222  }
1223 
1224  if ( type != Recurrence::rNone ) {
1225 
1226  // Immediately after the type is the frequency
1227  int index = tmpStr.indexOf( ' ' );
1228  int last = tmpStr.lastIndexOf( ' ' ) + 1; // find last entry
1229  int rFreq = tmpStr.mid( typelen, ( index - 1 ) ).toInt();
1230  ++index; // advance to beginning of stuff after freq
1231 
1232  // Read the type-specific settings
1233  switch ( type ) {
1234  case Recurrence::rDaily:
1235  anEvent->recurrence()->setDaily( rFreq );
1236  break;
1237 
1238  case Recurrence::rWeekly:
1239  {
1240  QBitArray qba( 7 );
1241  QString dayStr;
1242  if ( index == last ) {
1243  // e.g. W1 #0
1244  qba.setBit( anEvent->dtStart().date().dayOfWeek() - 1 );
1245  } else {
1246  // e.g. W1 SU #0
1247  while ( index < last ) {
1248  dayStr = tmpStr.mid( index, 3 );
1249  int dayNum = numFromDay( dayStr );
1250  if ( dayNum >= 0 ) {
1251  qba.setBit( dayNum );
1252  }
1253  index += 3; // advance to next day, or possibly "#"
1254  }
1255  }
1256  anEvent->recurrence()->setWeekly( rFreq, qba );
1257  break;
1258  }
1259 
1260  case Recurrence::rMonthlyPos:
1261  {
1262  anEvent->recurrence()->setMonthly( rFreq );
1263 
1264  QBitArray qba( 7 );
1265  short tmpPos;
1266  if ( index == last ) {
1267  // e.g. MP1 #0
1268  tmpPos = anEvent->dtStart().date().day() / 7 + 1;
1269  if ( tmpPos == 5 ) {
1270  tmpPos = -1;
1271  }
1272  qba.setBit( anEvent->dtStart().date().dayOfWeek() - 1 );
1273  anEvent->recurrence()->addMonthlyPos( tmpPos, qba );
1274  } else {
1275  // e.g. MP1 1+ SU #0
1276  while ( index < last ) {
1277  tmpPos = tmpStr.mid( index, 1 ).toShort();
1278  index += 1;
1279  if ( tmpStr.mid( index, 1 ) == "-" ) {
1280  // convert tmpPos to negative
1281  tmpPos = 0 - tmpPos;
1282  }
1283  index += 2; // advance to day(s)
1284  while ( numFromDay( tmpStr.mid( index, 3 ) ) >= 0 ) {
1285  int dayNum = numFromDay( tmpStr.mid( index, 3 ) );
1286  qba.setBit( dayNum );
1287  index += 3; // advance to next day, or possibly pos or "#"
1288  }
1289  anEvent->recurrence()->addMonthlyPos( tmpPos, qba );
1290  qba.detach();
1291  qba.fill( false ); // clear out
1292  } // while != "#"
1293  }
1294  break;
1295  }
1296 
1297  case Recurrence::rMonthlyDay:
1298  anEvent->recurrence()->setMonthly( rFreq );
1299  if ( index == last ) {
1300  // e.g. MD1 #0
1301  short tmpDay = anEvent->dtStart().date().day();
1302  anEvent->recurrence()->addMonthlyDate( tmpDay );
1303  } else {
1304  // e.g. MD1 3 #0
1305  while ( index < last ) {
1306  int index2 = tmpStr.indexOf( ' ', index );
1307  if ( ( tmpStr.mid( ( index2 - 1 ), 1 ) == "-" ) ||
1308  ( tmpStr.mid( ( index2 - 1 ), 1 ) == "+" ) ) {
1309  index2 = index2 - 1;
1310  }
1311  short tmpDay = tmpStr.mid( index, ( index2 - index ) ).toShort();
1312  index = index2;
1313  if ( tmpStr.mid( index, 1 ) == "-" ) {
1314  tmpDay = 0 - tmpDay;
1315  }
1316  index += 2; // advance the index;
1317  anEvent->recurrence()->addMonthlyDate( tmpDay );
1318  } // while != #
1319  }
1320  break;
1321 
1322  case Recurrence::rYearlyMonth:
1323  anEvent->recurrence()->setYearly( rFreq );
1324 
1325  if ( index == last ) {
1326  // e.g. YM1 #0
1327  short tmpMonth = anEvent->dtStart().date().month();
1328  anEvent->recurrence()->addYearlyMonth( tmpMonth );
1329  } else {
1330  // e.g. YM1 3 #0
1331  while ( index < last ) {
1332  int index2 = tmpStr.indexOf( ' ', index );
1333  short tmpMonth = tmpStr.mid( index, ( index2 - index ) ).toShort();
1334  index = index2 + 1;
1335  anEvent->recurrence()->addYearlyMonth( tmpMonth );
1336  } // while != #
1337  }
1338  break;
1339 
1340  case Recurrence::rYearlyDay:
1341  anEvent->recurrence()->setYearly( rFreq );
1342 
1343  if ( index == last ) {
1344  // e.g. YD1 #0
1345  short tmpDay = anEvent->dtStart().date().dayOfYear();
1346  anEvent->recurrence()->addYearlyDay( tmpDay );
1347  } else {
1348  // e.g. YD1 123 #0
1349  while ( index < last ) {
1350  int index2 = tmpStr.indexOf( ' ', index );
1351  short tmpDay = tmpStr.mid( index, ( index2 - index ) ).toShort();
1352  index = index2 + 1;
1353  anEvent->recurrence()->addYearlyDay( tmpDay );
1354  } // while != #
1355  }
1356  break;
1357 
1358  default:
1359  break;
1360  }
1361 
1362  // find the last field, which is either the duration or the end date
1363  index = last;
1364  if ( tmpStr.mid( index, 1 ) == "#" ) {
1365  // Nr of occurrences
1366  index++;
1367  int rDuration = tmpStr.mid( index, tmpStr.length() - index ).toInt();
1368  if ( rDuration > 0 ) {
1369  anEvent->recurrence()->setDuration( rDuration );
1370  }
1371  } else if ( tmpStr.indexOf( 'T', index ) != -1 ) {
1372  KDateTime rEndDate = ISOToKDateTime( tmpStr.mid( index, tmpStr.length() - index ) );
1373  anEvent->recurrence()->setEndDateTime( rEndDate );
1374  }
1375  } else {
1376  kDebug() << "we don't understand this type of recurrence!";
1377  } // if known recurrence type
1378  } // repeats
1379 
1380  // recurrence exceptions
1381  if ( ( vo = isAPropertyOf( vtodo, VCExpDateProp ) ) != 0 ) {
1382  s = fakeCString( vObjectUStringZValue( vo ) );
1383  QStringList exDates = QString::fromUtf8( s ).split( ',' );
1384  QStringList::ConstIterator it;
1385  for ( it = exDates.constBegin(); it != exDates.constEnd(); ++it ) {
1386  KDateTime exDate = ISOToKDateTime( *it );
1387  if ( exDate.time().hour() == 0 &&
1388  exDate.time().minute() == 0 &&
1389  exDate.time().second() == 0 ) {
1390  anEvent->recurrence()->addExDate( ISOToQDate( *it ) );
1391  } else {
1392  anEvent->recurrence()->addExDateTime( exDate );
1393  }
1394  }
1395  deleteStr( s );
1396  }
1397 
1398  // alarm stuff
1399  if ( ( vo = isAPropertyOf( vtodo, VCDAlarmProp ) ) ) {
1400  Alarm::Ptr alarm;
1401  VObject *a;
1402  VObject *b;
1403  a = isAPropertyOf( vo, VCRunTimeProp );
1404  b = isAPropertyOf( vo, VCDisplayStringProp );
1405 
1406  if ( a || b ) {
1407  alarm = anEvent->newAlarm();
1408  if ( a ) {
1409  alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) );
1410  deleteStr( s );
1411  }
1412  alarm->setEnabled( true );
1413  if ( b ) {
1414  s = fakeCString( vObjectUStringZValue( b ) );
1415  alarm->setDisplayAlarm( QString( s ) );
1416  deleteStr( s );
1417  } else {
1418  alarm->setDisplayAlarm( QString() );
1419  }
1420  }
1421  }
1422 
1423  if ( ( vo = isAPropertyOf( vtodo, VCAAlarmProp ) ) ) {
1424  Alarm::Ptr alarm;
1425  VObject *a;
1426  VObject *b;
1427  a = isAPropertyOf( vo, VCRunTimeProp );
1428  b = isAPropertyOf( vo, VCAudioContentProp );
1429 
1430  if ( a || b ) {
1431  alarm = anEvent->newAlarm();
1432  if ( a ) {
1433  alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) );
1434  deleteStr( s );
1435  }
1436  alarm->setEnabled( true );
1437  if ( b ) {
1438  s = fakeCString( vObjectUStringZValue( b ) );
1439  alarm->setAudioAlarm( QFile::decodeName( s ) );
1440  deleteStr( s );
1441  } else {
1442  alarm->setAudioAlarm( QString() );
1443  }
1444  }
1445  }
1446 
1447  if ( ( vo = isAPropertyOf( vtodo, VCPAlarmProp ) ) ) {
1448  Alarm::Ptr alarm;
1449  VObject *a;
1450  VObject *b;
1451  a = isAPropertyOf( vo, VCRunTimeProp );
1452  b = isAPropertyOf( vo, VCProcedureNameProp );
1453 
1454  if ( a || b ) {
1455  alarm = anEvent->newAlarm();
1456  if ( a ) {
1457  alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) );
1458  deleteStr( s );
1459  }
1460  alarm->setEnabled( true );
1461 
1462  if ( b ) {
1463  s = fakeCString( vObjectUStringZValue( b ) );
1464  alarm->setProcedureAlarm( QFile::decodeName( s ) );
1465  deleteStr( s );
1466  } else {
1467  alarm->setProcedureAlarm( QString() );
1468  }
1469  }
1470  }
1471 
1472  // related todo
1473  if ( ( vo = isAPropertyOf( vtodo, VCRelatedToProp ) ) != 0 ) {
1474  anEvent->setRelatedTo( s = fakeCString( vObjectUStringZValue( vo ) ) );
1475  deleteStr( s );
1476  d->mTodosRelate.append( anEvent );
1477  }
1478 
1479  // secrecy
1480  Incidence::Secrecy secrecy = Incidence::SecrecyPublic;
1481  if ( ( vo = isAPropertyOf( vtodo, VCClassProp ) ) != 0 ) {
1482  s = fakeCString( vObjectUStringZValue( vo ) );
1483  if ( s && strcmp( s, "PRIVATE" ) == 0 ) {
1484  secrecy = Incidence::SecrecyPrivate;
1485  } else if ( s && strcmp( s, "CONFIDENTIAL" ) == 0 ) {
1486  secrecy = Incidence::SecrecyConfidential;
1487  }
1488  deleteStr( s );
1489  }
1490  anEvent->setSecrecy( secrecy );
1491 
1492  // categories
1493  if ( ( vo = isAPropertyOf( vtodo, VCCategoriesProp ) ) != 0 ) {
1494  s = fakeCString( vObjectUStringZValue( vo ) );
1495  QString categories = QString::fromUtf8( s );
1496  deleteStr( s );
1497  QStringList tmpStrList = categories.split( ';' );
1498  anEvent->setCategories( tmpStrList );
1499  }
1500 
1501  /* PILOT SYNC STUFF */
1502  if ( ( vo = isAPropertyOf( vtodo, KPilotIdProp ) ) ) {
1503  anEvent->setNonKDECustomProperty(
1504  KPilotIdProp, QString::fromUtf8( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1505  deleteStr( s );
1506  if ( ( vo = isAPropertyOf( vtodo, KPilotStatusProp ) ) ) {
1507  anEvent->setNonKDECustomProperty(
1508  KPilotStatusProp, QString::fromUtf8( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1509  deleteStr( s );
1510  } else {
1511  anEvent->setNonKDECustomProperty( KPilotStatusProp, QString::number( int( SYNCMOD ) ) );
1512  }
1513  }
1514 
1515  return anEvent;
1516 }
1517 
1518 Event::Ptr VCalFormat::VEventToEvent( VObject *vevent )
1519 {
1520  VObject *vo;
1521  VObjectIterator voi;
1522  char *s;
1523 
1524  Event::Ptr anEvent( new Event );
1525 
1526  // creation date
1527  if ( ( vo = isAPropertyOf( vevent, VCDCreatedProp ) ) != 0 ) {
1528  anEvent->setCreated( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1529  deleteStr( s );
1530  }
1531 
1532  // unique id
1533  vo = isAPropertyOf( vevent, VCUniqueStringProp );
1534  // while the UID property is preferred, it is not required. We'll use the
1535  // default Event UID if none is given.
1536  if ( vo ) {
1537  anEvent->setUid( s = fakeCString( vObjectUStringZValue( vo ) ) );
1538  deleteStr( s );
1539  }
1540 
1541 #if defined(KCALCORE_FOR_SYMBIAN)
1542  // recurrence id
1543  vo = isAPropertyOf( vevent, VCRecurrenceIdProp );
1544  if ( vo ) {
1545  anEvent->setRecurrenceId( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1546  deleteStr( s );
1547  }
1548 #endif
1549 
1550  // revision
1551  // again NSCAL doesn't give us much to work with, so we improvise...
1552  anEvent->setRevision( 0 );
1553  if ( ( vo = isAPropertyOf( vevent, VCSequenceProp ) ) != 0 ) {
1554  s = fakeCString( vObjectUStringZValue( vo ) );
1555  if ( s ) {
1556  anEvent->setRevision( atoi( s ) );
1557  deleteStr( s );
1558  }
1559  }
1560 
1561  // last modification date
1562  if ( ( vo = isAPropertyOf( vevent, VCLastModifiedProp ) ) != 0 ) {
1563  anEvent->setLastModified( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1564  deleteStr( s );
1565  } else {
1566  anEvent->setLastModified( KDateTime::currentUtcDateTime() );
1567  }
1568 
1569  // organizer
1570  // if our extension property for the event's ORGANIZER exists, add it.
1571  if ( ( vo = isAPropertyOf( vevent, ICOrganizerProp ) ) != 0 ) {
1572  // FIXME: Also use the full name, not just the email address
1573  anEvent->setOrganizer( s = fakeCString( vObjectUStringZValue( vo ) ) );
1574  deleteStr( s );
1575  } else {
1576  if ( d->mCalendar->owner()->name() != "Unknown Name" ) {
1577  anEvent->setOrganizer( d->mCalendar->owner() );
1578  }
1579  }
1580 
1581  // deal with attendees.
1582  initPropIterator( &voi, vevent );
1583  while ( moreIteration( &voi ) ) {
1584  vo = nextVObject( &voi );
1585  if ( strcmp( vObjectName( vo ), VCAttendeeProp ) == 0 ) {
1586  Attendee::Ptr a;
1587  VObject *vp;
1588  s = fakeCString( vObjectUStringZValue( vo ) );
1589  QString tmpStr = QString::fromUtf8( s );
1590  deleteStr( s );
1591  tmpStr = tmpStr.simplified();
1592  int emailPos1, emailPos2;
1593  if ( ( emailPos1 = tmpStr.indexOf( '<' ) ) > 0 ) {
1594  // both email address and name
1595  emailPos2 = tmpStr.lastIndexOf( '>' );
1596  a = Attendee::Ptr( new Attendee( tmpStr.left( emailPos1 - 1 ),
1597  tmpStr.mid( emailPos1 + 1,
1598  emailPos2 - ( emailPos1 + 1 ) ) ) );
1599  } else if ( tmpStr.indexOf( '@' ) > 0 ) {
1600  // just an email address
1601  a = Attendee::Ptr( new Attendee( 0, tmpStr ) );
1602  } else {
1603  // just a name
1604  QString email = tmpStr.replace( ' ', '.' );
1605  a = Attendee::Ptr( new Attendee( tmpStr, email ) );
1606  }
1607 
1608  // is there an RSVP property?
1609  if ( ( vp = isAPropertyOf( vo, VCRSVPProp ) ) != 0 ) {
1610  a->setRSVP( vObjectStringZValue( vp ) );
1611  }
1612  // is there a status property?
1613  if ( ( vp = isAPropertyOf( vo, VCStatusProp ) ) != 0 ) {
1614  a->setStatus( readStatus( vObjectStringZValue( vp ) ) );
1615  }
1616  // add the attendee
1617  anEvent->addAttendee( a );
1618  }
1619  }
1620 
1621  // This isn't strictly true. An event that doesn't have a start time
1622  // or an end time isn't all-day, it has an anchor in time but it doesn't
1623  // "take up" any time.
1624  /*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) ||
1625  (isAPropertyOf(vevent, VCDTendProp) == 0)) {
1626  anEvent->setAllDay(true);
1627  } else {
1628  }*/
1629 
1630  anEvent->setAllDay( false );
1631 
1632  // start time
1633  if ( ( vo = isAPropertyOf( vevent, VCDTstartProp ) ) != 0 ) {
1634  anEvent->setDtStart( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1635  deleteStr( s );
1636 
1637  if ( anEvent->dtStart().time().hour() == 0 &&
1638  anEvent->dtStart().time().minute() == 0 &&
1639  anEvent->dtStart().time().second() == 0 ) {
1640 #if defined(KCALCORE_FOR_MEEGO)
1641  QDate startDate = anEvent->dtStart().date();
1642  anEvent->setDtStart( KDateTime( startDate, KDateTime::ClockTime ) );
1643 #endif
1644  anEvent->setAllDay( true );
1645  }
1646  }
1647 
1648  // stop time
1649  if ( ( vo = isAPropertyOf( vevent, VCDTendProp ) ) != 0 ) {
1650  anEvent->setDtEnd( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
1651  deleteStr( s );
1652 
1653  if ( anEvent->dtEnd().time().hour() == 0 &&
1654  anEvent->dtEnd().time().minute() == 0 &&
1655  anEvent->dtEnd().time().second() == 0 ) {
1656 #if defined(KCALCORE_FOR_MEEGO)
1657  QDate endDate = anEvent->dtEnd().date();
1658  anEvent->setDtEnd( KDateTime( endDate, KDateTime::ClockTime ) );
1659 #endif
1660  anEvent->setAllDay( true );
1661  }
1662  }
1663 #if defined(KCALCORE_FOR_MEEGO)
1664  if ( anEvent->allDay() ) {
1665  if ( anEvent->dtEnd() == anEvent->dtStart() ) {
1666  anEvent->setDtEnd( anEvent->dtEnd().addDays( 1 ) );
1667  }
1668  }
1669 #endif
1670 
1671  // at this point, there should be at least a start or end time.
1672  // fix up for events that take up no time but have a time associated
1673  if ( !isAPropertyOf( vevent, VCDTstartProp ) ) {
1674  anEvent->setDtStart( anEvent->dtEnd() );
1675  }
1676  if ( ! isAPropertyOf( vevent, VCDTendProp ) ) {
1677  anEvent->setDtEnd( anEvent->dtStart() );
1678  }
1679 
1681 
1682  // repeat stuff
1683  if ( ( vo = isAPropertyOf( vevent, VCRRuleProp ) ) != 0 ) {
1684  QString tmpStr = ( s = fakeCString( vObjectUStringZValue( vo ) ) );
1685  deleteStr( s );
1686  tmpStr.simplified();
1687  tmpStr = tmpStr.toUpper();
1688  // first, read the type of the recurrence
1689  int typelen = 1;
1690  uint type = Recurrence::rNone;
1691  if ( tmpStr.left( 1 ) == "D" ) {
1692  type = Recurrence::rDaily;
1693  } else if ( tmpStr.left( 1 ) == "W" ) {
1694  type = Recurrence::rWeekly;
1695  } else {
1696  typelen = 2;
1697  if ( tmpStr.left( 2 ) == "MP" ) {
1698  type = Recurrence::rMonthlyPos;
1699  } else if ( tmpStr.left( 2 ) == "MD" ) {
1700  type = Recurrence::rMonthlyDay;
1701  } else if ( tmpStr.left( 2 ) == "YM" ) {
1702  type = Recurrence::rYearlyMonth;
1703  } else if ( tmpStr.left( 2 ) == "YD" ) {
1704  type = Recurrence::rYearlyDay;
1705  }
1706  }
1707 
1708  if ( type != Recurrence::rNone ) {
1709 
1710  // Immediately after the type is the frequency
1711  int index = tmpStr.indexOf( ' ' );
1712  int last = tmpStr.lastIndexOf( ' ' ) + 1; // find last entry
1713  int rFreq = tmpStr.mid( typelen, ( index - 1 ) ).toInt();
1714  ++index; // advance to beginning of stuff after freq
1715 
1716  // Read the type-specific settings
1717  switch ( type ) {
1718  case Recurrence::rDaily:
1719  anEvent->recurrence()->setDaily( rFreq );
1720  break;
1721 
1722  case Recurrence::rWeekly:
1723  {
1724  QBitArray qba( 7 );
1725  QString dayStr;
1726  if ( index == last ) {
1727  // e.g. W1 #0
1728  qba.setBit( anEvent->dtStart().date().dayOfWeek() - 1 );
1729  } else {
1730  // e.g. W1 SU #0
1731  while ( index < last ) {
1732  dayStr = tmpStr.mid( index, 3 );
1733  int dayNum = numFromDay( dayStr );
1734  if ( dayNum >= 0 ) {
1735  qba.setBit( dayNum );
1736  }
1737  index += 3; // advance to next day, or possibly "#"
1738  }
1739  }
1740  anEvent->recurrence()->setWeekly( rFreq, qba );
1741  break;
1742  }
1743 
1744  case Recurrence::rMonthlyPos:
1745  {
1746  anEvent->recurrence()->setMonthly( rFreq );
1747 
1748  QBitArray qba( 7 );
1749  short tmpPos;
1750  if ( index == last ) {
1751  // e.g. MP1 #0
1752  tmpPos = anEvent->dtStart().date().day() / 7 + 1;
1753  if ( tmpPos == 5 ) {
1754  tmpPos = -1;
1755  }
1756  qba.setBit( anEvent->dtStart().date().dayOfWeek() - 1 );
1757  anEvent->recurrence()->addMonthlyPos( tmpPos, qba );
1758  } else {
1759  // e.g. MP1 1+ SU #0
1760  while ( index < last ) {
1761  tmpPos = tmpStr.mid( index, 1 ).toShort();
1762  index += 1;
1763  if ( tmpStr.mid( index, 1 ) == "-" ) {
1764  // convert tmpPos to negative
1765  tmpPos = 0 - tmpPos;
1766  }
1767  index += 2; // advance to day(s)
1768  while ( numFromDay( tmpStr.mid( index, 3 ) ) >= 0 ) {
1769  int dayNum = numFromDay( tmpStr.mid( index, 3 ) );
1770  qba.setBit( dayNum );
1771  index += 3; // advance to next day, or possibly pos or "#"
1772  }
1773  anEvent->recurrence()->addMonthlyPos( tmpPos, qba );
1774  qba.detach();
1775  qba.fill( false ); // clear out
1776  } // while != "#"
1777  }
1778  break;
1779  }
1780 
1781  case Recurrence::rMonthlyDay:
1782  anEvent->recurrence()->setMonthly( rFreq );
1783  if ( index == last ) {
1784  // e.g. MD1 #0
1785  short tmpDay = anEvent->dtStart().date().day();
1786  anEvent->recurrence()->addMonthlyDate( tmpDay );
1787  } else {
1788  // e.g. MD1 3 #0
1789  while ( index < last ) {
1790  int index2 = tmpStr.indexOf( ' ', index );
1791  if ( ( tmpStr.mid( ( index2 - 1 ), 1 ) == "-" ) ||
1792  ( tmpStr.mid( ( index2 - 1 ), 1 ) == "+" ) ) {
1793  index2 = index2 - 1;
1794  }
1795  short tmpDay = tmpStr.mid( index, ( index2 - index ) ).toShort();
1796  index = index2;
1797  if ( tmpStr.mid( index, 1 ) == "-" ) {
1798  tmpDay = 0 - tmpDay;
1799  }
1800  index += 2; // advance the index;
1801  anEvent->recurrence()->addMonthlyDate( tmpDay );
1802  } // while != #
1803  }
1804  break;
1805 
1806  case Recurrence::rYearlyMonth:
1807  anEvent->recurrence()->setYearly( rFreq );
1808 
1809  if ( index == last ) {
1810  // e.g. YM1 #0
1811  short tmpMonth = anEvent->dtStart().date().month();
1812  anEvent->recurrence()->addYearlyMonth( tmpMonth );
1813  } else {
1814  // e.g. YM1 3 #0
1815  while ( index < last ) {
1816  int index2 = tmpStr.indexOf( ' ', index );
1817  short tmpMonth = tmpStr.mid( index, ( index2 - index ) ).toShort();
1818  index = index2 + 1;
1819  anEvent->recurrence()->addYearlyMonth( tmpMonth );
1820  } // while != #
1821  }
1822  break;
1823 
1824  case Recurrence::rYearlyDay:
1825  anEvent->recurrence()->setYearly( rFreq );
1826 
1827  if ( index == last ) {
1828  // e.g. YD1 #0
1829  short tmpDay = anEvent->dtStart().date().dayOfYear();
1830  anEvent->recurrence()->addYearlyDay( tmpDay );
1831  } else {
1832  // e.g. YD1 123 #0
1833  while ( index < last ) {
1834  int index2 = tmpStr.indexOf( ' ', index );
1835  short tmpDay = tmpStr.mid( index, ( index2 - index ) ).toShort();
1836  index = index2 + 1;
1837  anEvent->recurrence()->addYearlyDay( tmpDay );
1838  } // while != #
1839  }
1840  break;
1841 
1842  default:
1843  break;
1844  }
1845 
1846  // find the last field, which is either the duration or the end date
1847  index = last;
1848  if ( tmpStr.mid( index, 1 ) == "#" ) {
1849  // Nr of occurrences
1850  index++;
1851  int rDuration = tmpStr.mid( index, tmpStr.length() - index ).toInt();
1852  if ( rDuration > 0 ) {
1853  anEvent->recurrence()->setDuration( rDuration );
1854  }
1855  } else if ( tmpStr.indexOf( 'T', index ) != -1 ) {
1856  KDateTime rEndDate = ISOToKDateTime( tmpStr.mid( index, tmpStr.length() - index ) );
1857  anEvent->recurrence()->setEndDateTime( rEndDate );
1858  }
1859 // anEvent->recurrence()->dump();
1860 
1861  } else {
1862  kDebug() << "we don't understand this type of recurrence!";
1863  } // if known recurrence type
1864  } // repeats
1865 
1866  // recurrence exceptions
1867  if ( ( vo = isAPropertyOf( vevent, VCExpDateProp ) ) != 0 ) {
1868  s = fakeCString( vObjectUStringZValue( vo ) );
1869  QStringList exDates = QString::fromUtf8( s ).split( ',' );
1870  QStringList::ConstIterator it;
1871  for ( it = exDates.constBegin(); it != exDates.constEnd(); ++it ) {
1872  KDateTime exDate = ISOToKDateTime( *it );
1873  if ( exDate.time().hour() == 0 &&
1874  exDate.time().minute() == 0 &&
1875  exDate.time().second() == 0 ) {
1876  anEvent->recurrence()->addExDate( ISOToQDate( *it ) );
1877  } else {
1878  anEvent->recurrence()->addExDateTime( exDate );
1879  }
1880  }
1881  deleteStr( s );
1882  }
1883 
1884  // summary
1885  if ( ( vo = isAPropertyOf( vevent, VCSummaryProp ) ) ) {
1886  s = fakeCString( vObjectUStringZValue( vo ) );
1887  anEvent->setSummary( QString::fromUtf8( s ), Qt::mightBeRichText( s ) );
1888  deleteStr( s );
1889  }
1890 
1891  // description
1892  if ( ( vo = isAPropertyOf( vevent, VCDescriptionProp ) ) != 0 ) {
1893  s = fakeCString( vObjectUStringZValue( vo ) );
1894  bool isRich = Qt::mightBeRichText( s );
1895  if ( !anEvent->description().isEmpty() ) {
1896  anEvent->setDescription(
1897  anEvent->description() + '\n' + QString::fromUtf8( s ), isRich );
1898  } else {
1899  anEvent->setDescription( QString::fromUtf8( s ), isRich );
1900  }
1901  deleteStr( s );
1902  }
1903 
1904  // location
1905  if ( ( vo = isAPropertyOf( vevent, VCLocationProp ) ) != 0 ) {
1906  s = fakeCString( vObjectUStringZValue( vo ) );
1907  anEvent->setLocation( QString::fromUtf8( s ), Qt::mightBeRichText( s ) );
1908  deleteStr( s );
1909  }
1910 
1911  // some stupid vCal exporters ignore the standard and use Description
1912  // instead of Summary for the default field. Correct for this.
1913  if ( anEvent->summary().isEmpty() && !( anEvent->description().isEmpty() ) ) {
1914  QString tmpStr = anEvent->description().simplified();
1915  anEvent->setDescription( "" );
1916  anEvent->setSummary( tmpStr );
1917  }
1918 
1919 #if 0
1920  // status
1921  if ( ( vo = isAPropertyOf( vevent, VCStatusProp ) ) != 0 ) {
1922  QString tmpStr( s = fakeCString( vObjectUStringZValue( vo ) ) );
1923  deleteStr( s );
1924 // TODO: Define Event status
1925 // anEvent->setStatus( tmpStr );
1926  } else {
1927 // anEvent->setStatus( "NEEDS ACTION" );
1928  }
1929 #endif
1930 
1931  // secrecy
1932  Incidence::Secrecy secrecy = Incidence::SecrecyPublic;
1933  if ( ( vo = isAPropertyOf( vevent, VCClassProp ) ) != 0 ) {
1934  s = fakeCString( vObjectUStringZValue( vo ) );
1935  if ( s && strcmp( s, "PRIVATE" ) == 0 ) {
1936  secrecy = Incidence::SecrecyPrivate;
1937  } else if ( s && strcmp( s, "CONFIDENTIAL" ) == 0 ) {
1938  secrecy = Incidence::SecrecyConfidential;
1939  }
1940  deleteStr( s );
1941  }
1942  anEvent->setSecrecy( secrecy );
1943 
1944  // categories
1945  if ( ( vo = isAPropertyOf( vevent, VCCategoriesProp ) ) != 0 ) {
1946  s = fakeCString( vObjectUStringZValue( vo ) );
1947  QString categories = QString::fromUtf8( s );
1948  deleteStr( s );
1949  QStringList tmpStrList = categories.split( ',' );
1950  anEvent->setCategories( tmpStrList );
1951  }
1952 
1953  // attachments
1954  initPropIterator( &voi, vevent );
1955  while ( moreIteration( &voi ) ) {
1956  vo = nextVObject( &voi );
1957  if ( strcmp( vObjectName( vo ), VCAttachProp ) == 0 ) {
1958  s = fakeCString( vObjectUStringZValue( vo ) );
1959  anEvent->addAttachment( Attachment::Ptr( new Attachment( QString( s ) ) ) );
1960  deleteStr( s );
1961  }
1962  }
1963 
1964  // resources
1965  if ( ( vo = isAPropertyOf( vevent, VCResourcesProp ) ) != 0 ) {
1966  QString resources = ( s = fakeCString( vObjectUStringZValue( vo ) ) );
1967  deleteStr( s );
1968  QStringList tmpStrList = resources.split( ';' );
1969  anEvent->setResources( tmpStrList );
1970  }
1971 
1972  // alarm stuff
1973  if ( ( vo = isAPropertyOf( vevent, VCDAlarmProp ) ) ) {
1974  Alarm::Ptr alarm;
1975  VObject *a;
1976  VObject *b;
1977  a = isAPropertyOf( vo, VCRunTimeProp );
1978  b = isAPropertyOf( vo, VCDisplayStringProp );
1979 
1980  if ( a || b ) {
1981  alarm = anEvent->newAlarm();
1982  if ( a ) {
1983  alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) );
1984  deleteStr( s );
1985  }
1986  alarm->setEnabled( true );
1987 
1988  if ( b ) {
1989  s = fakeCString( vObjectUStringZValue( b ) );
1990  alarm->setDisplayAlarm( QString( s ) );
1991  deleteStr( s );
1992  } else {
1993  alarm->setDisplayAlarm( QString() );
1994  }
1995  }
1996  }
1997 
1998  if ( ( vo = isAPropertyOf( vevent, VCAAlarmProp ) ) ) {
1999  Alarm::Ptr alarm;
2000  VObject *a;
2001  VObject *b;
2002  a = isAPropertyOf( vo, VCRunTimeProp );
2003  b = isAPropertyOf( vo, VCAudioContentProp );
2004 
2005  if ( a || b ) {
2006  alarm = anEvent->newAlarm();
2007  if ( a ) {
2008  alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) );
2009  deleteStr( s );
2010  }
2011  alarm->setEnabled( true );
2012 
2013  if ( b ) {
2014  s = fakeCString( vObjectUStringZValue( b ) );
2015  alarm->setAudioAlarm( QFile::decodeName( s ) );
2016  deleteStr( s );
2017  } else {
2018  alarm->setAudioAlarm( QString() );
2019  }
2020  }
2021  }
2022 
2023  if ( ( vo = isAPropertyOf( vevent, VCPAlarmProp ) ) ) {
2024  Alarm::Ptr alarm;
2025  VObject *a;
2026  VObject *b;
2027  a = isAPropertyOf( vo, VCRunTimeProp );
2028  b = isAPropertyOf( vo, VCProcedureNameProp );
2029 
2030  if ( a || b ) {
2031  alarm = anEvent->newAlarm();
2032  if ( a ) {
2033  alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) );
2034  deleteStr( s );
2035  }
2036  alarm->setEnabled( true );
2037 
2038  if ( b ) {
2039  s = fakeCString( vObjectUStringZValue( b ) );
2040  alarm->setProcedureAlarm( QFile::decodeName( s ) );
2041  deleteStr( s );
2042  } else {
2043  alarm->setProcedureAlarm( QString() );
2044  }
2045  }
2046  }
2047 
2048  // priority
2049  if ( ( vo = isAPropertyOf( vevent, VCPriorityProp ) ) ) {
2050  s = fakeCString( vObjectUStringZValue( vo ) );
2051  if ( s ) {
2052  anEvent->setPriority( atoi( s ) );
2053  deleteStr( s );
2054  }
2055  }
2056 
2057  // transparency
2058  if ( ( vo = isAPropertyOf( vevent, VCTranspProp ) ) != 0 ) {
2059  s = fakeCString( vObjectUStringZValue( vo ) );
2060  if ( s ) {
2061  int i = atoi( s );
2062  anEvent->setTransparency( i == 1 ? Event::Transparent : Event::Opaque );
2063  deleteStr( s );
2064  }
2065  }
2066 
2067  // related event
2068  if ( ( vo = isAPropertyOf( vevent, VCRelatedToProp ) ) != 0 ) {
2069  anEvent->setRelatedTo( s = fakeCString( vObjectUStringZValue( vo ) ) );
2070  deleteStr( s );
2071  d->mEventsRelate.append( anEvent );
2072  }
2073 
2074  /* PILOT SYNC STUFF */
2075  if ( ( vo = isAPropertyOf( vevent, KPilotIdProp ) ) ) {
2076  anEvent->setNonKDECustomProperty(
2077  KPilotIdProp, QString::fromUtf8( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
2078  deleteStr( s );
2079  if ( ( vo = isAPropertyOf( vevent, KPilotStatusProp ) ) ) {
2080  anEvent->setNonKDECustomProperty(
2081  KPilotStatusProp, QString::fromUtf8( s = fakeCString( vObjectUStringZValue( vo ) ) ) );
2082  deleteStr( s );
2083  } else {
2084  anEvent->setNonKDECustomProperty( KPilotStatusProp, QString::number( int( SYNCMOD ) ) );
2085  }
2086  }
2087 
2088  /* Rest of the custom properties */
2089  readCustomProperties( vevent, anEvent );
2090 
2091  return anEvent;
2092 }
2093 
2094 QString VCalFormat::parseTZ( const QByteArray &timezone ) const
2095 {
2096  // kDebug() << timezone;
2097  QString pZone = timezone.mid( timezone.indexOf( "TZID:VCAL" ) + 9 );
2098  return pZone.mid( 0, pZone.indexOf( QChar( QLatin1Char( '\n' ) ) ) );
2099 }
2100 
2101 QString VCalFormat::parseDst( QByteArray &timezone ) const
2102 {
2103  if ( !timezone.contains( "BEGIN:DAYLIGHT" ) ) {
2104  return QString();
2105  }
2106 
2107  timezone = timezone.mid( timezone.indexOf( "BEGIN:DAYLIGHT" ) );
2108  timezone = timezone.mid( timezone.indexOf( "TZNAME:" ) + 7 );
2109  QString sStart = timezone.mid( 0, ( timezone.indexOf( "COMMENT:" ) ) );
2110  sStart.chop( 2 );
2111  timezone = timezone.mid( timezone.indexOf( "TZOFFSETTO:" ) + 11 );
2112  QString sOffset = timezone.mid( 0, ( timezone.indexOf( "DTSTART:" ) ) );
2113  sOffset.chop( 2 );
2114  sOffset.insert( 3, QString( ":" ) );
2115  timezone = timezone.mid( timezone.indexOf( "TZNAME:" ) + 7 );
2116  QString sEnd = timezone.mid( 0, ( timezone.indexOf( "COMMENT:" ) ) );
2117  sEnd.chop( 2 );
2118 
2119  return "TRUE;" + sOffset + ';' + sStart + ';' + sEnd + ";;";
2120 }
2121 
2122 QString VCalFormat::qDateToISO( const QDate &qd )
2123 {
2124  QString tmpStr;
2125 
2126  if ( !qd.isValid() ) {
2127  return QString();
2128  }
2129 
2130  tmpStr.sprintf( "%.2d%.2d%.2d", qd.year(), qd.month(), qd.day() );
2131  return tmpStr;
2132 
2133 }
2134 
2135 QString VCalFormat::kDateTimeToISO( const KDateTime &dt, bool zulu )
2136 {
2137  QString tmpStr;
2138 
2139  if ( !dt.isValid() ) {
2140  return QString();
2141  }
2142 
2143  QDateTime tmpDT;
2144  if ( zulu ) {
2145  tmpDT = dt.toUtc().dateTime();
2146  } else {
2147 #if !defined(KCALCORE_FOR_MEEGO)
2148  tmpDT = dt.toTimeSpec( d->mCalendar->timeSpec() ).dateTime();
2149 #else
2150  tmpDT = dt.dateTime();
2151 #endif
2152  }
2153  tmpStr.sprintf( "%.2d%.2d%.2dT%.2d%.2d%.2d",
2154  tmpDT.date().year(), tmpDT.date().month(),
2155  tmpDT.date().day(), tmpDT.time().hour(),
2156  tmpDT.time().minute(), tmpDT.time().second() );
2157  if ( zulu || dt.isUtc() ) {
2158  tmpStr += 'Z';
2159  }
2160  return tmpStr;
2161 }
2162 
2163 KDateTime VCalFormat::ISOToKDateTime( const QString &dtStr )
2164 {
2165  QDate tmpDate;
2166  QTime tmpTime;
2167  QString tmpStr;
2168  int year, month, day, hour, minute, second;
2169 
2170  tmpStr = dtStr;
2171  year = tmpStr.left( 4 ).toInt();
2172  month = tmpStr.mid( 4, 2 ).toInt();
2173  day = tmpStr.mid( 6, 2 ).toInt();
2174  hour = tmpStr.mid( 9, 2 ).toInt();
2175  minute = tmpStr.mid( 11, 2 ).toInt();
2176  second = tmpStr.mid( 13, 2 ).toInt();
2177  tmpDate.setYMD( year, month, day );
2178  tmpTime.setHMS( hour, minute, second );
2179 
2180  if ( tmpDate.isValid() && tmpTime.isValid() ) {
2181  // correct for GMT if string is in Zulu format
2182  if ( dtStr.at( dtStr.length() - 1 ) == 'Z' ) {
2183  return KDateTime( tmpDate, tmpTime, KDateTime::UTC );
2184  } else {
2185  return KDateTime( tmpDate, tmpTime, d->mCalendar->timeSpec() );
2186  }
2187  } else {
2188  return KDateTime();
2189  }
2190 }
2191 
2192 QDate VCalFormat::ISOToQDate( const QString &dateStr )
2193 {
2194  int year, month, day;
2195 
2196  year = dateStr.left( 4 ).toInt();
2197  month = dateStr.mid( 4, 2 ).toInt();
2198  day = dateStr.mid( 6, 2 ).toInt();
2199 
2200  return QDate( year, month, day );
2201 }
2202 
2203 bool VCalFormat::parseTZOffsetISO8601( const QString &s, int &result )
2204 {
2205  // ISO8601 format(s):
2206  // +- hh : mm
2207  // +- hh mm
2208  // +- hh
2209 
2210  // We also accept broken one without +
2211  int mod = 1;
2212  int v = 0;
2213  QString str = s.trimmed();
2214  int ofs = 0;
2215  result = 0;
2216 
2217  // Check for end
2218  if ( str.size() <= ofs ) {
2219  return false;
2220  }
2221  if ( str[ofs] == '-' ) {
2222  mod = -1;
2223  ofs++;
2224  } else if ( str[ofs] == '+' ) {
2225  ofs++;
2226  }
2227  if ( str.size() <= ofs ) {
2228  return false;
2229  }
2230 
2231  // Make sure next two values are numbers
2232  bool ok;
2233 
2234  if ( str.size() < ( ofs + 2 ) ) {
2235  return false;
2236  }
2237 
2238  v = str.mid( ofs, 2 ).toInt( &ok ) * 60;
2239  if ( !ok ) {
2240  return false;
2241  }
2242  ofs += 2;
2243 
2244  if ( str.size() > ofs ) {
2245  if ( str[ofs] == ':' ) {
2246  ofs++;
2247  }
2248  if ( str.size() > ofs ) {
2249  if ( str.size() < ( ofs + 2 ) ) {
2250  return false;
2251  }
2252  v += str.mid( ofs, 2 ).toInt( &ok );
2253  if ( !ok ) {
2254  return false;
2255  }
2256  }
2257  }
2258  result = v * mod * 60;
2259  return true;
2260 }
2261 
2262 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
2263 // and break it down from it's tree-like format into the dictionary format
2264 // that is used internally in the VCalFormat.
2265 void VCalFormat::populate( VObject *vcal, bool deleted, const QString &notebook )
2266 {
2267  Q_UNUSED( notebook );
2268  // this function will populate the caldict dictionary and other event
2269  // lists. It turns vevents into Events and then inserts them.
2270 
2271  VObjectIterator i;
2272  VObject *curVO, *curVOProp;
2273  Event::Ptr anEvent;
2274  bool hasTimeZone = false; //The calendar came with a TZ and not UTC
2275  KDateTime::Spec previousSpec; //If we add a new TZ we should leave the spec as it was before
2276 
2277  if ( ( curVO = isAPropertyOf( vcal, ICMethodProp ) ) != 0 ) {
2278  char *methodType = 0;
2279  methodType = fakeCString( vObjectUStringZValue( curVO ) );
2280  // kDebug() << "This calendar is an iTIP transaction of type '" << methodType << "'";
2281  deleteStr( methodType );
2282  }
2283 
2284  // warn the user that we might have trouble reading non-known calendar.
2285  if ( ( curVO = isAPropertyOf( vcal, VCProdIdProp ) ) != 0 ) {
2286  char *s = fakeCString( vObjectUStringZValue( curVO ) );
2287  if ( !s || strcmp( productId().toUtf8(), s ) != 0 ) {
2288  kDebug() << "This vCalendar file was not created by KOrganizer or"
2289  << "any other product we support. Loading anyway...";
2290  }
2291  setLoadedProductId( s );
2292  deleteStr( s );
2293  }
2294 
2295  // warn the user we might have trouble reading this unknown version.
2296  if ( ( curVO = isAPropertyOf( vcal, VCVersionProp ) ) != 0 ) {
2297  char *s = fakeCString( vObjectUStringZValue( curVO ) );
2298  if ( !s || strcmp( _VCAL_VERSION, s ) != 0 ) {
2299  kDebug() << "This vCalendar file has version" << s
2300  << "We only support" << _VCAL_VERSION;
2301  }
2302  deleteStr( s );
2303  }
2304 
2305  // set the time zone (this is a property of the view, so just discard!)
2306  if ( ( curVO = isAPropertyOf( vcal, VCTimeZoneProp ) ) != 0 ) {
2307  char *s = fakeCString( vObjectUStringZValue( curVO ) );
2308  QString ts( s );
2309  QString name = "VCAL" + ts;
2310  deleteStr( s );
2311 
2312  // TODO: While using the timezone-offset + vcal as timezone is is
2313  // most likely unique, we should REALLY actually create something
2314  // like vcal-tzoffset-daylightoffsets, or better yet,
2315  // vcal-hash<the former>
2316 
2317  QStringList tzList;
2318  QString tz;
2319  int utcOffset;
2320  int utcOffsetDst;
2321  if ( parseTZOffsetISO8601( ts, utcOffset ) ) {
2322  // kDebug() << "got standard offset" << ts << utcOffset;
2323  // standard from tz
2324  // starting date for now 01011900
2325  KDateTime dt = KDateTime( QDateTime( QDate( 1900, 1, 1 ), QTime( 0, 0, 0 ) ) );
2326  tz = QString( "STD;%1;false;%2" ).arg( QString::number( utcOffset ) ).arg( dt.toString() );
2327  tzList.append( tz );
2328 
2329  // go through all the daylight tags
2330  initPropIterator( &i, vcal );
2331  while ( moreIteration( &i ) ) {
2332  curVO = nextVObject( &i );
2333  if ( strcmp( vObjectName( curVO ), VCDayLightProp ) == 0 ) {
2334  char *s = fakeCString( vObjectUStringZValue( curVO ) );
2335  QString dst = QString( s );
2336  QStringList argl = dst.split( ',' );
2337  deleteStr( s );
2338 
2339  // Too short -> not interesting
2340  if ( argl.size() < 4 ) {
2341  continue;
2342  }
2343 
2344  // We don't care about the non-DST periods
2345  if ( argl[0] != "TRUE" ) {
2346  continue;
2347  }
2348 
2349  if ( parseTZOffsetISO8601( argl[1], utcOffsetDst ) ) {
2350 
2351  // kDebug() << "got DST offset" << argl[1] << utcOffsetDst;
2352  // standard
2353  QString strEndDate = argl[3];
2354  KDateTime endDate = ISOToKDateTime( strEndDate );
2355  // daylight
2356  QString strStartDate = argl[2];
2357  KDateTime startDate = ISOToKDateTime( strStartDate );
2358 
2359  QString strRealEndDate = strEndDate;
2360  QString strRealStartDate = strStartDate;
2361  KDateTime realEndDate = endDate;
2362  KDateTime realStartDate = startDate;
2363  // if we get dates for some reason in wrong order, earlier is used for dst
2364  if ( endDate < startDate ) {
2365  strRealEndDate = strStartDate;
2366  strRealStartDate = strEndDate;
2367  realEndDate = startDate;
2368  realStartDate = endDate;
2369  }
2370  tz = QString( "%1;%2;false;%3" ).
2371  arg( strRealEndDate ).
2372  arg( QString::number( utcOffset ) ).
2373  arg( realEndDate.toString() );
2374  tzList.append( tz );
2375 
2376  tz = QString( "%1;%2;true;%3" ).
2377  arg( strRealStartDate ).
2378  arg( QString::number( utcOffsetDst ) ).
2379  arg( realStartDate.toString() );
2380  tzList.append( tz );
2381  } else {
2382  kDebug() << "unable to parse dst" << argl[1];
2383  }
2384  }
2385  }
2386  ICalTimeZones *tzlist = d->mCalendar->timeZones();
2387  ICalTimeZoneSource tzs;
2388  ICalTimeZone zone = tzs.parse( name, tzList, *tzlist );
2389  if ( !zone.isValid() ) {
2390  kDebug() << "zone is not valid, parsing error" << tzList;
2391  } else {
2392  previousSpec = d->mCalendar->timeSpec();
2393  d->mCalendar->setTimeZoneId( name );
2394  hasTimeZone = true;
2395  }
2396  } else {
2397  kDebug() << "unable to parse tzoffset" << ts;
2398  }
2399  }
2400 
2401  // Store all events with a relatedTo property in a list for post-processing
2402  d->mEventsRelate.clear();
2403  d->mTodosRelate.clear();
2404 
2405  initPropIterator( &i, vcal );
2406 
2407  // go through all the vobjects in the vcal
2408  while ( moreIteration( &i ) ) {
2409  curVO = nextVObject( &i );
2410 
2411  /************************************************************************/
2412 
2413  // now, check to see that the object is an event or todo.
2414  if ( strcmp( vObjectName( curVO ), VCEventProp ) == 0 ) {
2415 
2416  if ( ( curVOProp = isAPropertyOf( curVO, KPilotStatusProp ) ) != 0 ) {
2417  char *s;
2418  s = fakeCString( vObjectUStringZValue( curVOProp ) );
2419  // check to see if event was deleted by the kpilot conduit
2420  if ( s ) {
2421  if ( atoi( s ) == SYNCDEL ) {
2422  deleteStr( s );
2423  kDebug() << "skipping pilot-deleted event";
2424  goto SKIP;
2425  }
2426  deleteStr( s );
2427  }
2428  }
2429 
2430  if ( !isAPropertyOf( curVO, VCDTstartProp ) &&
2431  !isAPropertyOf( curVO, VCDTendProp ) ) {
2432  kDebug() << "found a VEvent with no DTSTART and no DTEND! Skipping...";
2433  goto SKIP;
2434  }
2435 
2436  anEvent = VEventToEvent( curVO );
2437  if ( anEvent ) {
2438  if ( hasTimeZone && !anEvent->allDay() && anEvent->dtStart().isUtc() ) {
2439  //This sounds stupid but is how others are doing it, so here
2440  //we go. If there is a TZ in the VCALENDAR even if the dtStart
2441  //and dtend are in UTC, clients interpret it using also the TZ defined
2442  //in the Calendar. I know it sounds braindead but oh well
2443  int utcOffSet = anEvent->dtStart().utcOffset();
2444  KDateTime dtStart( anEvent->dtStart().dateTime().addSecs( utcOffSet ),
2445  d->mCalendar->timeSpec() );
2446  KDateTime dtEnd( anEvent->dtEnd().dateTime().addSecs( utcOffSet ),
2447  d->mCalendar->timeSpec() );
2448  anEvent->setDtStart( dtStart );
2449  anEvent->setDtEnd( dtEnd );
2450  }
2451  Event::Ptr old = !anEvent->hasRecurrenceId() ?
2452  d->mCalendar->event( anEvent->uid() ) :
2453  d->mCalendar->event( anEvent->uid(), anEvent->recurrenceId() );
2454 
2455  if ( old ) {
2456  if ( deleted ) {
2457  d->mCalendar->deleteEvent( old ); // move old to deleted
2458  removeAllVCal( d->mEventsRelate, old );
2459  } else if ( anEvent->revision() > old->revision() ) {
2460  d->mCalendar->deleteEvent( old ); // move old to deleted
2461  removeAllVCal( d->mEventsRelate, old );
2462  d->mCalendar->addEvent( anEvent ); // and replace it with this one
2463  }
2464  } else if ( deleted ) {
2465  old = !anEvent->hasRecurrenceId() ?
2466  d->mCalendar->deletedEvent( anEvent->uid() ) :
2467  d->mCalendar->deletedEvent( anEvent->uid(), anEvent->recurrenceId() );
2468  if ( !old ) {
2469  d->mCalendar->addEvent( anEvent ); // add this one
2470  d->mCalendar->deleteEvent( anEvent ); // and move it to deleted
2471  }
2472  } else {
2473  d->mCalendar->addEvent( anEvent ); // just add this one
2474  }
2475  }
2476  } else if ( strcmp( vObjectName( curVO ), VCTodoProp ) == 0 ) {
2477  Todo::Ptr aTodo = VTodoToEvent( curVO );
2478  if ( aTodo ) {
2479  if ( hasTimeZone && !aTodo->allDay() && aTodo->dtStart().isUtc() ) {
2480  //This sounds stupid but is how others are doing it, so here
2481  //we go. If there is a TZ in the VCALENDAR even if the dtStart
2482  //and dtend are in UTC, clients interpret it usint alse the TZ defined
2483  //in the Calendar. I know it sounds braindead but oh well
2484  int utcOffSet = aTodo->dtStart().utcOffset();
2485  KDateTime dtStart( aTodo->dtStart().dateTime().addSecs( utcOffSet ),
2486  d->mCalendar->timeSpec() );
2487  aTodo->setDtStart( dtStart );
2488  if ( aTodo->hasDueDate() ) {
2489  KDateTime dtDue( aTodo->dtDue().dateTime().addSecs( utcOffSet ),
2490  d->mCalendar->timeSpec() );
2491  aTodo->setDtDue( dtDue );
2492  }
2493  }
2494  Todo::Ptr old = !aTodo->hasRecurrenceId() ?
2495  d->mCalendar->todo( aTodo->uid() ) :
2496  d->mCalendar->todo( aTodo->uid(), aTodo->recurrenceId() );
2497  if ( old ) {
2498  if ( deleted ) {
2499  d->mCalendar->deleteTodo( old ); // move old to deleted
2500  removeAllVCal( d->mTodosRelate, old );
2501  } else if ( aTodo->revision() > old->revision() ) {
2502  d->mCalendar->deleteTodo( old ); // move old to deleted
2503  removeAllVCal( d->mTodosRelate, old );
2504  d->mCalendar->addTodo( aTodo ); // and replace it with this one
2505  }
2506  } else if ( deleted ) {
2507  old = d->mCalendar->deletedTodo( aTodo->uid(), aTodo->recurrenceId() );
2508  if ( !old ) {
2509  d->mCalendar->addTodo( aTodo ); // add this one
2510  d->mCalendar->deleteTodo( aTodo ); // and move it to deleted
2511  }
2512  } else {
2513  d->mCalendar->addTodo( aTodo ); // just add this one
2514  }
2515  }
2516  } else if ( ( strcmp( vObjectName( curVO ), VCVersionProp ) == 0 ) ||
2517  ( strcmp( vObjectName( curVO ), VCProdIdProp ) == 0 ) ||
2518  ( strcmp( vObjectName( curVO ), VCTimeZoneProp ) == 0 ) ) {
2519  // do nothing, we know these properties and we want to skip them.
2520  // we have either already processed them or are ignoring them.
2521  ;
2522  } else if ( strcmp( vObjectName( curVO ), VCDayLightProp ) == 0 ) {
2523  // do nothing daylights are already processed
2524  ;
2525  } else {
2526  kDebug() << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"";
2527  }
2528  SKIP:
2529  ;
2530  } // while
2531 
2532  // Post-Process list of events with relations, put Event objects in relation
2533  Event::List::ConstIterator eIt;
2534  for ( eIt = d->mEventsRelate.constBegin(); eIt != d->mEventsRelate.constEnd(); ++eIt ) {
2535  (*eIt)->setRelatedTo( (*eIt)->relatedTo() );
2536  }
2537  Todo::List::ConstIterator tIt;
2538  for ( tIt = d->mTodosRelate.constBegin(); tIt != d->mTodosRelate.constEnd(); ++tIt ) {
2539  (*tIt)->setRelatedTo( (*tIt)->relatedTo() );
2540  }
2541 
2542  //Now lets put the TZ back as it was if we have changed it.
2543  if ( hasTimeZone ) {
2544  d->mCalendar->setTimeSpec(previousSpec);
2545  }
2546 
2547 }
2548 
2549 const char *VCalFormat::dayFromNum( int day )
2550 {
2551  const char *days[7] = { "MO ", "TU ", "WE ", "TH ", "FR ", "SA ", "SU " };
2552 
2553  return days[day];
2554 }
2555 
2556 int VCalFormat::numFromDay( const QString &day )
2557 {
2558  if ( day == "MO " ) {
2559  return 0;
2560  }
2561  if ( day == "TU " ) {
2562  return 1;
2563  }
2564  if ( day == "WE " ) {
2565  return 2;
2566  }
2567  if ( day == "TH " ) {
2568  return 3;
2569  }
2570  if ( day == "FR " ) {
2571  return 4;
2572  }
2573  if ( day == "SA " ) {
2574  return 5;
2575  }
2576  if ( day == "SU " ) {
2577  return 6;
2578  }
2579 
2580  return -1; // something bad happened. :)
2581 }
2582 
2583 Attendee::PartStat VCalFormat::readStatus( const char *s ) const
2584 {
2585  QString statStr = s;
2586  statStr = statStr.toUpper();
2587  Attendee::PartStat status;
2588 
2589  if ( statStr == "X-ACTION" ) {
2590  status = Attendee::NeedsAction;
2591  } else if ( statStr == "NEEDS ACTION" ) {
2592  status = Attendee::NeedsAction;
2593  } else if ( statStr == "ACCEPTED" ) {
2594  status = Attendee::Accepted;
2595  } else if ( statStr == "SENT" ) {
2596  status = Attendee::NeedsAction;
2597  } else if ( statStr == "TENTATIVE" ) {
2598  status = Attendee::Tentative;
2599  } else if ( statStr == "CONFIRMED" ) {
2600  status = Attendee::Accepted;
2601  } else if ( statStr == "DECLINED" ) {
2602  status = Attendee::Declined;
2603  } else if ( statStr == "COMPLETED" ) {
2604  status = Attendee::Completed;
2605  } else if ( statStr == "DELEGATED" ) {
2606  status = Attendee::Delegated;
2607  } else {
2608  kDebug() << "error setting attendee mStatus, unknown mStatus!";
2609  status = Attendee::NeedsAction;
2610  }
2611 
2612  return status;
2613 }
2614 
2615 QByteArray VCalFormat::writeStatus( Attendee::PartStat status ) const
2616 {
2617  switch( status ) {
2618  default:
2619  case Attendee::NeedsAction:
2620  return "NEEDS ACTION";
2621  break;
2622  case Attendee::Accepted:
2623  return "ACCEPTED";
2624  break;
2625  case Attendee::Declined:
2626  return "DECLINED";
2627  break;
2628  case Attendee::Tentative:
2629  return "TENTATIVE";
2630  break;
2631  case Attendee::Delegated:
2632  return "DELEGATED";
2633  break;
2634  case Attendee::Completed:
2635  return "COMPLETED";
2636  break;
2637  case Attendee::InProcess:
2638  return "NEEDS ACTION";
2639  break;
2640  }
2641 }
2642 
2643 void VCalFormat::readCustomProperties( VObject *o, const Incidence::Ptr &i )
2644 {
2645  VObjectIterator iter;
2646  VObject *cur;
2647  const char *curname;
2648  char *s;
2649 
2650  initPropIterator( &iter, o );
2651  while ( moreIteration( &iter ) ) {
2652  cur = nextVObject( &iter );
2653  curname = vObjectName( cur );
2654  Q_ASSERT( curname );
2655  if ( ( curname[0] == 'X' && curname[1] == '-' ) &&
2656  strcmp( curname, ICOrganizerProp ) != 0 ) {
2657  // TODO - for the time being, we ignore the parameters part
2658  // and just do the value handling here
2659  i->setNonKDECustomProperty(
2660  curname, QString::fromUtf8( s = fakeCString( vObjectUStringZValue( cur ) ) ) );
2661  deleteStr( s );
2662  }
2663  }
2664 }
2665 
2666 void VCalFormat::writeCustomProperties( VObject *o, const Incidence::Ptr &i )
2667 {
2668  const QMap<QByteArray, QString> custom = i->customProperties();
2669  for ( QMap<QByteArray, QString>::ConstIterator c = custom.begin();
2670  c != custom.end(); ++c ) {
2671  if ( d->mManuallyWrittenExtensionFields.contains( c.key() ) ||
2672  c.key().startsWith( "X-KDE-VOLATILE" ) ) {
2673  continue;
2674  }
2675 
2676  addPropValue( o, c.key(), c.value().toUtf8() );
2677  }
2678 }
2679 
2680 void VCalFormat::virtual_hook( int id, void *data )
2681 {
2682  Q_UNUSED( id );
2683  Q_UNUSED( data );
2684  Q_ASSERT( false );
2685 }
KCalCore::Exception
Exception base class, currently used as a fancy kind of error code and not as an C++ exception...
Definition: exceptions.h:50
KCalCore::VCalFormat::numFromDay
int numFromDay(const QString &day)
Converts a two letter representation of the day (i.e.
Definition: vcalformat.cpp:2556
KCalCore::Attachment::Ptr
QSharedPointer< Attachment > Ptr
A shared pointer to an Attachment object.
Definition: attachment.h:64
KCalCore::VCalFormat::save
bool save(const Calendar::Ptr &calendar, const QString &fileName)
Definition: vcalformat.cpp:134
KCalCore::CalFormat::productId
static const QString & productId()
Returns the our library&#39;s PRODID string to write into calendar files.
Definition: calformat.cpp:106
KCalCore::CalFormat::setException
void setException(Exception *error)
Sets an exception that is to be used by the functions of this class to report errors.
Definition: calformat.cpp:83
KCalCore::CalFormat::clearException
void clearException()
Clears the exception status.
Definition: calformat.cpp:77
KCalCore::Alarm::Ptr
QSharedPointer< Alarm > Ptr
A shared pointer to an Alarm object.
Definition: alarm.h:76
KCalCore::Incidence::SecrecyConfidential
Secret to the owner and some others.
Definition: incidence.h:96
KCalCore::VCalFormat::VCalFormat
VCalFormat()
Constructor a new vCalendar Format object.
Definition: vcalformat.cpp:88
KCalCore::Event::Ptr
QSharedPointer< Event > Ptr
A shared pointer to an Event object.
Definition: event.h:55
KCalCore::VCalFormat::parseDst
QString parseDst(QByteArray &timezone) const
Parse DAYLIGHT tag from vtimezone.
Definition: vcalformat.cpp:2101
KCalCore::VCalFormat::VEventToEvent
Event::Ptr VEventToEvent(VObject *vevent)
Translates a VObject into a Event and returns a pointer to it.
Definition: vcalformat.cpp:1518
KCalCore::ICalTimeZoneSource
A class which reads and parses iCalendar VTIMEZONE components, and accesses libical time zone data...
Definition: icaltimezones.h:405
KCalCore::Recurrence::yearDays
QList< int > yearDays() const
Returns the day numbers within a yearly recurrence.
Definition: recurrence.cpp:668
KCalCore::VCalFormat::toString
QString toString(const Calendar::Ptr &calendar, const QString &notebook=QString(), bool deleted=false)
Definition: vcalformat.cpp:235
KCalCore::Attachment::List
QVector< Ptr > List
List of attachments.
Definition: attachment.h:69
KCalCore::Incidence::Ptr
QSharedPointer< Incidence > Ptr
A shared pointer to an Incidence.
Definition: incidence.h:112
KCalCore::Recurrence::frequency
int frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
Definition: recurrence.cpp:600
KCalCore::Event::List
QVector< Ptr > List
List of events.
Definition: event.h:60
KCalCore::VCalFormat::writeStatus
QByteArray writeStatus(Attendee::PartStat status) const
Converts an Attendee::PartStat into a QByteArray string.
Definition: vcalformat.cpp:2615
KCalCore::Event::Opaque
Event appears in free/busy time.
Definition: event.h:48
KCalCore::Attendee::Delegated
Event or to-do delegated.
Definition: attendee.h:75
KCalCore::VCalFormat::parseTZOffsetISO8601
bool parseTZOffsetISO8601(const QString &s, int &result)
Parse one of the myriad of ISO8601 timezone offset formats, e.g.
Definition: vcalformat.cpp:2203
KCalCore::Event::Transparent
Event does not appear in free/busy time.
Definition: event.h:49
KCalCore::Recurrence
This class represents a recurrence rule for a calendar incidence.
Definition: recurrence.h:87
todo.h
This file is part of the API for handling calendar data and defines the Todo class.
KCalCore::Exception::CalVersionUnknown
Unknown calendar format detected.
Definition: exceptions.h:66
KCalCore::SortableList
A QList which can be sorted.
Definition: sortablelist.h:86
calendar.h
This file is part of the API for handling calendar data and defines the Calendar class.
KCalCore::VCalFormat::VTodoToEvent
Todo::Ptr VTodoToEvent(VObject *vtodo)
Translates a VObject of the TODO type into an Event.
Definition: vcalformat.cpp:1029
KCalCore::VCalFormat::eventToVTodo
VObject * eventToVTodo(const Todo::Ptr &todo)
Translates a Todo into a VTodo-type VObject and return pointer.
Definition: vcalformat.cpp:314
KCalCore::Attendee::PartStat
PartStat
The different types of participant status.
Definition: attendee.h:70
KCalCore::Recurrence::monthDays
QList< int > monthDays() const
Returns list of day numbers of a month.
Definition: recurrence.cpp:649
KCalCore::ICalTimeZoneSource::parse
ICalTimeZone parse(icalcomponent *vtimezone)
Creates an ICalTimeZone instance containing the detailed information parsed from an iCalendar VTIMEZO...
Definition: icaltimezones.cpp:910
KCalCore::Incidence::SecrecyPrivate
Secret to the owner.
Definition: incidence.h:95
exceptions.h
This file is part of the API for handling calendar data and defines the Exception class...
KCalCore::ICalTimeZone::vtimezone
QByteArray vtimezone() const
Returns the VTIMEZONE string which represents this time zone.
Definition: icaltimezones.cpp:321
KCalCore::VCalFormat::virtual_hook
virtual void virtual_hook(int id, void *data)
Definition: vcalformat.cpp:2680
KCalCore::VCalFormat::ISOToQDate
QDate ISOToQDate(const QString &dtStr)
Takes a string in the YYYYMMDD format and returns a valid QDate.
Definition: vcalformat.cpp:2192
KCalCore::VCalFormat::readStatus
Attendee::PartStat readStatus(const char *s) const
Converts a status string into an Attendee::PartStat.
Definition: vcalformat.cpp:2583
KCalCore::Alarm::Display
Display a dialog box.
Definition: alarm.h:67
KCalCore::Recurrence::duration
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
Definition: recurrence.cpp:482
KCalCore::Recurrence::yearMonths
QList< int > yearMonths() const
Returns the months within a yearly recurrence.
Definition: recurrence.cpp:679
KCalCore::CalFormat::setLoadedProductId
void setLoadedProductId(const QString &id)
Sets the PRODID string loaded from calendar file.
Definition: calformat.cpp:116
KCalCore::VCalFormat::load
bool load(const Calendar::Ptr &calendar, const QString &fileName)
Definition: vcalformat.cpp:103
KCalCore::VCalFormat::qDateToISO
QString qDateToISO(const QDate &date)
Takes a QDate and returns a string in the format YYYYMMDDTHHMMSS.
Definition: vcalformat.cpp:2122
KCalCore::Attendee::InProcess
To-do in process of being completed.
Definition: attendee.h:77
KCalCore::Calendar::Ptr
QSharedPointer< Calendar > Ptr
A shared pointer to a Calendar.
Definition: calendar.h:138
KCalCore::Todo::List
QVector< Ptr > List
List of to-dos.
Definition: todo.h:55
KCalCore::Attendee::NeedsAction
Event, to-do or journal needs action (default)
Definition: attendee.h:71
KCalCore::VCalFormat::fromRawString
bool fromRawString(const Calendar::Ptr &calendar, const QByteArray &string, bool deleted=false, const QString &notebook=QString())
Definition: vcalformat.cpp:206
KCalCore::VCalFormat::eventToVEvent
VObject * eventToVEvent(const Event::Ptr &event)
Translates an Event into a VEvent-type VObject and returns a pointer to it.
Definition: vcalformat.cpp:656
KCalCore::Attendee::Ptr
QSharedPointer< Attendee > Ptr
A shared pointer to an Attendee object.
Definition: attendee.h:94
KCalCore::Attendee::Completed
To-do completed.
Definition: attendee.h:76
KCalCore::VCalFormat::populate
void populate(VObject *vcal, bool deleted=false, const QString &notebook=QString())
Takes a vCalendar tree of VObjects, and puts all of them that have the &quot;event&quot; property into the dict...
Definition: vcalformat.cpp:2265
KCalCore::Alarm::Procedure
Call a script.
Definition: alarm.h:68
event.h
This file is part of the API for handling calendar data and defines the Event class.
KCalCore::Todo
Provides a To-do in the sense of RFC2445.
Definition: todo.h:44
KCalCore::Event
This class provides an Event in the sense of RFC2445.
Definition: event.h:41
KCalCore::Attachment
Represents information related to an attachment for a Calendar Incidence.
Definition: attachment.h:58
KCalCore::Incidence::Secrecy
Secrecy
The different types of incidence access classifications.
Definition: incidence.h:93
KCalCore::Alarm::Audio
Play an audio file.
Definition: alarm.h:70
KCalCore::ICalTimeZones
The ICalTimeZones class represents a time zone database which consists of a collection of individual ...
Definition: icaltimezones.h:65
KCalCore::Attendee::Tentative
Event or to-do tentatively accepted.
Definition: attendee.h:74
KCalCore::VCalFormat::~VCalFormat
virtual ~VCalFormat()
Destructor.
Definition: vcalformat.cpp:98
KCalCore::ICalTimeZone
The ICalTimeZone class represents an iCalendar VTIMEZONE component.
Definition: icaltimezones.h:176
KCalCore::Recurrence::recurrenceType
ushort recurrenceType() const
Returns the event&#39;s recurrence status.
Definition: recurrence.cpp:235
vcalformat.h
This file is part of the API for handling calendar data and defines the VCalFormat base class...
KCalCore::VCalFormat::parseTZ
QString parseTZ(const QByteArray &timezone) const
Parse TZ tag from vtimezone.
Definition: vcalformat.cpp:2094
KCalCore::VCalFormat
vCalendar format implementation.
Definition: vcalformat.h:69
KCalCore::Attendee
Represents information related to an attendee of an Calendar Incidence, typically a meeting or task (...
Definition: attendee.h:57
KCalCore::Todo::Ptr
QSharedPointer< Todo > Ptr
A shared pointer to a Todo object.
Definition: todo.h:50
KCalCore::Recurrence::days
QBitArray days() const
Returns week day mask (bit 0 = Monday).
Definition: recurrence.cpp:630
KCalCore::Recurrence::endDateTime
KDateTime endDateTime() const
Returns the date/time of the last recurrence.
Definition: recurrence.cpp:429
KCalCore::VCalFormat::ISOToKDateTime
KDateTime ISOToKDateTime(const QString &dtStr)
Takes a string in YYYYMMDDTHHMMSS format and returns a valid KDateTime.
Definition: vcalformat.cpp:2163
KCalCore::Attendee::Accepted
Event, to-do or journal accepted.
Definition: attendee.h:72
KCalCore::Recurrence::recurs
bool recurs() const
Returns whether the event recurs at all.
Definition: recurrence.cpp:230
KCalCore::Incidence::SecrecyPublic
Not secret (default)
Definition: incidence.h:94
KCalCore::Attendee::Declined
Event, to-do or journal declined.
Definition: attendee.h:73
KCalCore::VCalFormat::fromString
bool fromString(const Calendar::Ptr &calendar, const QString &string, bool deleted=false, const QString &notebook=QString())
Definition: vcalformat.cpp:200
KCalCore::ICalTimeZones::zone
ICalTimeZone zone(const QString &name) const
Returns the time zone with the given name.
Definition: icaltimezones.cpp:184
KCalCore::Recurrence::monthPositions
QList< RecurrenceRule::WDayPos > monthPositions() const
Returns list of day positions in months.
Definition: recurrence.cpp:660
KCalCore::VCalFormat::dayFromNum
const char * dayFromNum(int day)
Takes a number 0 - 6 and returns the two letter string of that day, i.e.
Definition: vcalformat.cpp:2549
KCalCore::VCalFormat::kDateTimeToISO
QString kDateTimeToISO(const KDateTime &date, bool zulu=true)
Takes a KDateTime and returns a string in format YYYYMMDDTHHMMSS.
Definition: vcalformat.cpp:2135
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Nov 26 2013 09:02:04 by doxygen 1.8.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KCalCore Library

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

kdepimlibs-4.11.3 API Reference

Skip menu "kdepimlibs-4.11.3 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