libkcal

icalformatimpl.cpp
1 /*
2  This file is part of libkcal.
3 
4  Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
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 */
22 
23 #include <tqdatetime.h>
24 #include <tqstring.h>
25 #include <tqptrlist.h>
26 #include <tqfile.h>
27 #include <cstdlib>
28 
29 #include <kdebug.h>
30 #include <tdelocale.h>
31 #include <kmdcodec.h>
32 
33 extern "C" {
34  #include <libical/ical.h>
35  #include <libical/icalparser.h>
36  #include <libical/icalrestriction.h>
37 }
38 
39 #include "calendar.h"
40 #include "journal.h"
41 #include "icalformat.h"
42 #include "icalformatimpl.h"
43 #include "compat.h"
44 
45 #include "config.h"
46 
47 #define _ICAL_VERSION "2.0"
48 
49 #if ICAL_CHECK_VERSION(4,0,0)
50  #define FIELD_BY_SECOND ICAL_BY_SECOND
51  #define FIELD_BY_MINUTE ICAL_BY_MINUTE
52  #define FIELD_BY_HOUR ICAL_BY_HOUR
53  #define FIELD_BY_DAY ICAL_BY_DAY
54  #define FIELD_BY_MONTH_DAY ICAL_BY_MONTH_DAY
55  #define FIELD_BY_YEAR_DAY ICAL_BY_YEAR_DAY
56  #define FIELD_BY_WEEK_NO ICAL_BY_WEEK_NO
57  #define FIELD_BY_MONTH ICAL_BY_MONTH
58  #define FIELD_BY_SET_POS ICAL_BY_SET_POS
59 #else
60  #define FIELD_BY_SECOND by_second
61  #define FIELD_BY_MINUTE by_minute
62  #define FIELD_BY_HOUR by_hour
63  #define FIELD_BY_DAY by_day
64  #define FIELD_BY_MONTH_DAY by_month_day
65  #define FIELD_BY_YEAR_DAY by_year_day
66  #define FIELD_BY_WEEK_NO by_week_no
67  #define FIELD_BY_MONTH by_month
68  #define FIELD_BY_SET_POS by_set_pos
69 #endif
70 
71 using namespace KCal;
72 
73 /* Static helpers */
74 static TQDateTime ICalDate2TQDate(const icaltimetype& t)
75 {
76  // Outlook sends dates starting from 1601-01-01, but TQDate()
77  // can only handle dates starting 1752-09-14.
78  const int year = (t.year>=1754) ? t.year : 1754;
79  return TQDateTime(TQDate(year,t.month,t.day), TQTime(t.hour,t.minute,t.second));
80 }
81 
82 /*
83 static void _dumpIcaltime( const icaltimetype& t)
84 {
85  kdDebug(5800) << "--- Y: " << t.year << " M: " << t.month << " D: " << t.day
86  << endl;
87  kdDebug(5800) << "--- H: " << t.hour << " M: " << t.minute << " S: " << t.second
88  << endl;
89  kdDebug(5800) << "--- isUtc: " << icaltime_is_utc( t )<< endl;
90  kdDebug(5800) << "--- zoneId: " << icaltimezone_get_tzid( const_cast<icaltimezone*>( t.zone ) )<< endl;
91 }
92 */
93 
94 const int gSecondsPerMinute = 60;
95 const int gSecondsPerHour = gSecondsPerMinute * 60;
96 const int gSecondsPerDay = gSecondsPerHour * 24;
97 const int gSecondsPerWeek = gSecondsPerDay * 7;
98 
99 ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) :
100  mParent( parent ), mCompat( new Compat )
101 {
102 }
103 
104 ICalFormatImpl::~ICalFormatImpl()
105 {
106  delete mCompat;
107 }
108 
109 class ICalFormatImpl::ToComponentVisitor : public IncidenceBase::Visitor
110 {
111  public:
112  ToComponentVisitor( ICalFormatImpl *impl, Scheduler::Method m ) : mImpl( impl ), mComponent( 0 ), mMethod( m ) {}
113 
114  bool visit( Event *e ) { mComponent = mImpl->writeEvent( e ); return true; }
115  bool visit( Todo *e ) { mComponent = mImpl->writeTodo( e ); return true; }
116  bool visit( Journal *e ) { mComponent = mImpl->writeJournal( e ); return true; }
117  bool visit( FreeBusy *fb ) { mComponent = mImpl->writeFreeBusy( fb, mMethod ); return true; }
118 
119  icalcomponent *component() { return mComponent; }
120 
121  private:
122  ICalFormatImpl *mImpl;
123  icalcomponent *mComponent;
124  Scheduler::Method mMethod;
125 };
126 
127 icalcomponent *ICalFormatImpl::writeIncidence( IncidenceBase *incidence, Scheduler::Method method )
128 {
129  ToComponentVisitor v( this, method );
130  if ( incidence->accept(v) )
131  return v.component();
132  else return 0;
133 }
134 
135 icalcomponent *ICalFormatImpl::writeTodo(Todo *todo)
136 {
137  TQString tmpStr;
138  TQStringList tmpStrList;
139 
140  icalcomponent *vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT);
141 
142  writeIncidence(vtodo,todo);
143 
144  // due date
145  if (todo->hasDueDate()) {
146  icaltimetype due;
147  if (todo->doesFloat()) {
148  due = writeICalDate(todo->dtDue(true).date());
149  } else {
150  due = writeICalDateTime(todo->dtDue(true));
151  }
152  icalcomponent_add_property(vtodo,icalproperty_new_due(due));
153  }
154 
155  // start time
156  if ( todo->hasStartDate() || todo->doesRecur() ) {
157  icaltimetype start;
158  if (todo->doesFloat()) {
159 // kdDebug(5800) << " Incidence " << todo->summary() << " floats." << endl;
160  start = writeICalDate(todo->dtStart(true).date());
161  } else {
162 // kdDebug(5800) << " incidence " << todo->summary() << " has time." << endl;
163  start = writeICalDateTime(todo->dtStart(true));
164  }
165  icalcomponent_add_property(vtodo,icalproperty_new_dtstart(start));
166  }
167 
168  // completion date
169  if (todo->isCompleted()) {
170  if (!todo->hasCompletedDate()) {
171  // If todo was created by KOrganizer <2.2 it has no correct completion
172  // date. Set it to now.
173  todo->setCompleted(TQDateTime::currentDateTime());
174  }
175  icaltimetype completed = writeICalDateTime(todo->completed());
176  icalcomponent_add_property(vtodo,icalproperty_new_completed(completed));
177  }
178 
179  icalcomponent_add_property(vtodo,
180  icalproperty_new_percentcomplete(todo->percentComplete()));
181 
182  if( todo->doesRecur() ) {
183  icalcomponent_add_property(vtodo,
184  icalproperty_new_recurrenceid( writeICalDateTime( todo->dtDue())));
185  }
186 
187  return vtodo;
188 }
189 
190 icalcomponent *ICalFormatImpl::writeEvent(Event *event)
191 {
192 #if 0
193  kdDebug(5800) << "Write Event '" << event->summary() << "' (" << event->uid()
194  << ")" << endl;
195 #endif
196 
197  TQString tmpStr;
198  TQStringList tmpStrList;
199 
200  icalcomponent *vevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
201 
202  writeIncidence(vevent,event);
203 
204  // start time
205  icaltimetype start;
206  if (event->doesFloat()) {
207 // kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl;
208  start = writeICalDate(event->dtStart().date());
209  } else {
210 // kdDebug(5800) << " incidence " << event->summary() << " has time." << endl;
211  start = writeICalDateTime(event->dtStart());
212  }
213  icalcomponent_add_property(vevent,icalproperty_new_dtstart(start));
214 
215  if (event->hasEndDate()) {
216  // End time.
217  // RFC2445 says that if DTEND is present, it has to be greater than DTSTART.
218  icaltimetype end;
219  if (event->doesFloat()) {
220 // kdDebug(5800) << " Event " << event->summary() << " floats." << endl;
221  // +1 day because end date is non-inclusive.
222  end = writeICalDate( event->dtEnd().date().addDays( 1 ) );
223  icalcomponent_add_property(vevent,icalproperty_new_dtend(end));
224  } else {
225 // kdDebug(5800) << " Event " << event->summary() << " has time." << endl;
226  if (event->dtEnd() != event->dtStart()) {
227  end = writeICalDateTime(event->dtEnd());
228  icalcomponent_add_property(vevent,icalproperty_new_dtend(end));
229  }
230  }
231  }
232 
233 // TODO: resources
234 #if 0
235  // resources
236  tmpStrList = anEvent->resources();
237  tmpStr = tmpStrList.join(";");
238  if (!tmpStr.isEmpty())
239  addPropValue(vevent, VCResourcesProp, tmpStr.utf8());
240 
241 #endif
242 
243  // Transparency
244  switch( event->transparency() ) {
245  case Event::Transparent:
246  icalcomponent_add_property(
247  vevent,
248  icalproperty_new_transp( ICAL_TRANSP_TRANSPARENT ) );
249  break;
250  case Event::Opaque:
251  icalcomponent_add_property(
252  vevent,
253  icalproperty_new_transp( ICAL_TRANSP_OPAQUE ) );
254  break;
255  }
256 
257  return vevent;
258 }
259 
260 icalcomponent *ICalFormatImpl::writeFreeBusy(FreeBusy *freebusy,
261  Scheduler::Method method)
262 {
263  kdDebug(5800) << "icalformatimpl: writeFreeBusy: startDate: "
264  << freebusy->dtStart().toString("ddd MMMM d yyyy: h:m:s ap") << " End Date: "
265  << freebusy->dtEnd().toString("ddd MMMM d yyyy: h:m:s ap") << endl;
266 
267  icalcomponent *vfreebusy = icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
268 
269  writeIncidenceBase(vfreebusy,freebusy);
270 
271  icalcomponent_add_property(vfreebusy, icalproperty_new_dtstart(
272  writeICalDateTime(freebusy->dtStart())));
273 
274  icalcomponent_add_property(vfreebusy, icalproperty_new_dtend(
275  writeICalDateTime(freebusy->dtEnd())));
276 
277  if (method == Scheduler::Request) {
278  icalcomponent_add_property(vfreebusy,icalproperty_new_uid(
279  freebusy->uid().utf8()));
280  }
281 
282  //Loops through all the periods in the freebusy object
283  TQValueList<Period> list = freebusy->busyPeriods();
284  TQValueList<Period>::Iterator it;
285  icalperiodtype period = icalperiodtype_null_period();
286  for (it = list.begin(); it!= list.end(); ++it) {
287  period.start = writeICalDateTime((*it).start());
288  if ( (*it).hasDuration() ) {
289  period.duration = writeICalDuration( (*it).duration().asSeconds() );
290  } else {
291  period.end = writeICalDateTime((*it).end());
292  }
293  icalcomponent_add_property(vfreebusy, icalproperty_new_freebusy(period) );
294  }
295 
296  return vfreebusy;
297 }
298 
299 icalcomponent *ICalFormatImpl::writeJournal(Journal *journal)
300 {
301  icalcomponent *vjournal = icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
302 
303  writeIncidence(vjournal,journal);
304 
305  // start time
306  if (journal->dtStart().isValid()) {
307  icaltimetype start;
308  if (journal->doesFloat()) {
309 // kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl;
310  start = writeICalDate(journal->dtStart().date());
311  } else {
312 // kdDebug(5800) << " incidence " << event->summary() << " has time." << endl;
313  start = writeICalDateTime(journal->dtStart());
314  }
315  icalcomponent_add_property(vjournal,icalproperty_new_dtstart(start));
316  }
317 
318  return vjournal;
319 }
320 
321 void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence)
322 {
323  // pilot sync stuff
324 // TODO: move this application-specific code to kpilot
325  if (incidence->pilotId()) {
326  // NOTE: we can't do setNonKDECustomProperty here because this changes
327  // data and triggers an updated() event...
328  // incidence->setNonKDECustomProperty("X-PILOTSTAT", TQString::number(incidence->syncStatus()));
329  // incidence->setNonKDECustomProperty("X-PILOTID", TQString::number(incidence->pilotId()));
330 
331  icalproperty *p = 0;
332  p = icalproperty_new_x(TQString::number(incidence->syncStatus()).utf8());
333  icalproperty_set_x_name(p,"X-PILOTSTAT");
334  icalcomponent_add_property(parent,p);
335 
336  p = icalproperty_new_x(TQString::number(incidence->pilotId()).utf8());
337  icalproperty_set_x_name(p,"X-PILOTID");
338  icalcomponent_add_property(parent,p);
339  }
340 
341  TQString modifiedUid;
342  if ( incidence->hasRecurrenceID() ) {
343  // Recurring incidences are special; they must match their parent's UID
344  // Each child has the parent set as the first item in the list
345  // So, get and set the UID...
346  IncidenceList il = incidence->childIncidences();
347  IncidenceListIterator it;
348  it = il.begin();
349  modifiedUid = (*it);
350  }
351  else {
352  modifiedUid = incidence->uid();
353  }
354 
355  if ( incidence->schedulingID() != modifiedUid )
356  // We need to store the UID in here. The rawSchedulingID will
357  // go into the iCal UID component
358  incidence->setCustomProperty( "LIBKCAL", "ID", modifiedUid );
359  else
360  incidence->removeCustomProperty( "LIBKCAL", "ID" );
361 
362  writeIncidenceBase(parent,incidence);
363 
364  // creation date
365  icalcomponent_add_property(parent,icalproperty_new_created(
366  writeICalDateTime(incidence->created())));
367 
368  // unique id
369  // If the scheduling ID is different from the real UID, the real
370  // one is stored on X-REALID above
371  if ( incidence->hasRecurrenceID() ) {
372  // Recurring incidences are special; they must match their parent's UID
373  icalcomponent_add_property(parent,icalproperty_new_uid(modifiedUid.utf8()));
374  }
375  else {
376  if ( !incidence->schedulingID().isEmpty() ) {
377  icalcomponent_add_property(parent,icalproperty_new_uid(
378  incidence->schedulingID().utf8()));
379  }
380  }
381 
382  // revision
383  if ( incidence->revision() > 0 ) { // 0 is default, so don't write that out
384  icalcomponent_add_property(parent,icalproperty_new_sequence(
385  incidence->revision()));
386  }
387 
388  // last modification date
389  if ( incidence->lastModified().isValid() ) {
390  icalcomponent_add_property(parent,icalproperty_new_lastmodified(
391  writeICalDateTime(incidence->lastModified())));
392  }
393 
394  // description
395  if (!incidence->description().isEmpty()) {
396  icalcomponent_add_property(parent,icalproperty_new_description(
397  incidence->description().utf8()));
398  }
399 
400  // summary
401  if (!incidence->summary().isEmpty()) {
402  icalcomponent_add_property(parent,icalproperty_new_summary(
403  incidence->summary().utf8()));
404  }
405 
406  // location
407  if (!incidence->location().isEmpty()) {
408  icalcomponent_add_property(parent,icalproperty_new_location(
409  incidence->location().utf8()));
410  }
411 
412  // status
413  icalproperty_status status = ICAL_STATUS_NONE;
414  switch (incidence->status()) {
415  case Incidence::StatusTentative: status = ICAL_STATUS_TENTATIVE; break;
416  case Incidence::StatusConfirmed: status = ICAL_STATUS_CONFIRMED; break;
417  case Incidence::StatusCompleted: status = ICAL_STATUS_COMPLETED; break;
418  case Incidence::StatusNeedsAction: status = ICAL_STATUS_NEEDSACTION; break;
419  case Incidence::StatusCanceled: status = ICAL_STATUS_CANCELLED; break;
420  case Incidence::StatusInProcess: status = ICAL_STATUS_INPROCESS; break;
421  case Incidence::StatusDraft: status = ICAL_STATUS_DRAFT; break;
422  case Incidence::StatusFinal: status = ICAL_STATUS_FINAL; break;
423  case Incidence::StatusX: {
424  icalproperty* p = icalproperty_new_status(ICAL_STATUS_X);
425  icalvalue_set_x(icalproperty_get_value(p), incidence->statusStr().utf8());
426  icalcomponent_add_property(parent, p);
427  break;
428  }
429  case Incidence::StatusNone:
430  default:
431  break;
432  }
433  if (status != ICAL_STATUS_NONE)
434  icalcomponent_add_property(parent, icalproperty_new_status(status));
435 
436  // secrecy
437  icalproperty_class secClass;
438  switch (incidence->secrecy()) {
439  case Incidence::SecrecyPublic:
440  secClass = ICAL_CLASS_PUBLIC;
441  break;
442  case Incidence::SecrecyConfidential:
443  secClass = ICAL_CLASS_CONFIDENTIAL;
444  break;
445  case Incidence::SecrecyPrivate:
446  default:
447  secClass = ICAL_CLASS_PRIVATE;
448  break;
449  }
450  if ( secClass != ICAL_CLASS_PUBLIC ) {
451  icalcomponent_add_property(parent,icalproperty_new_class(secClass));
452  }
453 
454  // priority
455  if ( incidence->priority() > 0 ) { // 0 is undefined priority
456  icalcomponent_add_property(parent,icalproperty_new_priority(
457  incidence->priority()));
458  }
459 
460  // categories
461  TQStringList categories = incidence->categories();
462  TQStringList::Iterator it;
463  for(it = categories.begin(); it != categories.end(); ++it ) {
464  icalcomponent_add_property(parent,icalproperty_new_categories((*it).utf8()));
465  }
466 
467  // related event
468  if ( !incidence->relatedToUid().isEmpty() ) {
469  icalcomponent_add_property(parent,icalproperty_new_relatedto(
470  incidence->relatedToUid().utf8()));
471  }
472 
473  // recurrenceid
474  if ( incidence->hasRecurrenceID() ) {
475  icalcomponent_add_property(parent, icalproperty_new_recurrenceid( writeICalDateTime( incidence->recurrenceID() ) ));
476  }
477 
478 // kdDebug(5800) << "Write recurrence for '" << incidence->summary() << "' (" << incidence->uid()
479 // << ")" << endl;
480 
481  RecurrenceRule::List rrules( incidence->recurrence()->rRules() );
482  RecurrenceRule::List::ConstIterator rit;
483  for ( rit = rrules.begin(); rit != rrules.end(); ++rit ) {
484  icalrecurrencetype *recur = writeRecurrenceRule( (*rit) );
485 #if ICAL_CHECK_VERSION(4,0,0)
486  icalcomponent_add_property( parent, icalproperty_new_rrule( recur ) );
487  icalrecurrencetype_unref( recur );
488 #else
489  icalcomponent_add_property( parent, icalproperty_new_rrule( *recur ) );
490  delete recur;
491 #endif
492  }
493 
494  RecurrenceRule::List exrules( incidence->recurrence()->exRules() );
495  RecurrenceRule::List::ConstIterator exit;
496  for ( exit = exrules.begin(); exit != exrules.end(); ++exit ) {
497  icalrecurrencetype *recur = writeRecurrenceRule( (*exit) );
498 #if ICAL_CHECK_VERSION(4,0,0)
499  icalcomponent_add_property( parent, icalproperty_new_rrule( recur ) );
500  icalrecurrencetype_unref( recur );
501 #else
502  icalcomponent_add_property( parent, icalproperty_new_rrule( *recur ) );
503  delete recur;
504 #endif
505  }
506 
507  DateList dateList = incidence->recurrence()->exDates();
508  DateList::ConstIterator exIt;
509  for(exIt = dateList.begin(); exIt != dateList.end(); ++exIt) {
510  icalcomponent_add_property(parent,icalproperty_new_exdate(
511  writeICalDate(*exIt)));
512  }
513  DateTimeList dateTimeList = incidence->recurrence()->exDateTimes();
514  DateTimeList::ConstIterator extIt;
515  for(extIt = dateTimeList.begin(); extIt != dateTimeList.end(); ++extIt) {
516  icalcomponent_add_property(parent,icalproperty_new_exdate(
517  writeICalDateTime(*extIt)));
518  }
519 
520 
521  dateList = incidence->recurrence()->rDates();
522  DateList::ConstIterator rdIt;
523  for( rdIt = dateList.begin(); rdIt != dateList.end(); ++rdIt) {
524  icalcomponent_add_property( parent, icalproperty_new_rdate(
525  writeICalDatePeriod(*rdIt) ) );
526  }
527  dateTimeList = incidence->recurrence()->rDateTimes();
528  DateTimeList::ConstIterator rdtIt;
529  for( rdtIt = dateTimeList.begin(); rdtIt != dateTimeList.end(); ++rdtIt) {
530  icalcomponent_add_property( parent, icalproperty_new_rdate(
531  writeICalDateTimePeriod(*rdtIt) ) );
532  }
533 
534  // attachments
535  Attachment::List attachments = incidence->attachments();
536  Attachment::List::ConstIterator atIt;
537  for ( atIt = attachments.begin(); atIt != attachments.end(); ++atIt ) {
538  icalcomponent_add_property( parent, writeAttachment( *atIt ) );
539  }
540 
541  // alarms
542  Alarm::List::ConstIterator alarmIt;
543  for ( alarmIt = incidence->alarms().begin();
544  alarmIt != incidence->alarms().end(); ++alarmIt ) {
545  if ( (*alarmIt)->enabled() ) {
546 // kdDebug(5800) << "Write alarm for " << incidence->summary() << endl;
547  icalcomponent_add_component( parent, writeAlarm( *alarmIt ) );
548  }
549  }
550 
551  // duration
552  if (incidence->hasDuration()) {
553  icaldurationtype duration;
554  duration = writeICalDuration( incidence->duration() );
555  icalcomponent_add_property(parent,icalproperty_new_duration(duration));
556  }
557 }
558 
559 void ICalFormatImpl::writeIncidenceBase( icalcomponent *parent,
560  IncidenceBase * incidenceBase )
561 {
562  icalcomponent_add_property( parent, icalproperty_new_dtstamp(
563  writeICalDateTime( TQDateTime::currentDateTime() ) ) );
564 
565  // organizer stuff
566  if ( !incidenceBase->organizer().isEmpty() ) {
567  icalcomponent_add_property( parent, writeOrganizer( incidenceBase->organizer() ) );
568  }
569 
570  // attendees
571  if ( incidenceBase->attendeeCount() > 0 ) {
572  Attendee::List::ConstIterator it;
573  for( it = incidenceBase->attendees().begin();
574  it != incidenceBase->attendees().end(); ++it ) {
575  icalcomponent_add_property( parent, writeAttendee( *it ) );
576  }
577  }
578 
579  // comments
580  TQStringList comments = incidenceBase->comments();
581  for (TQStringList::Iterator it=comments.begin(); it!=comments.end(); ++it) {
582  icalcomponent_add_property(parent, icalproperty_new_comment((*it).utf8()));
583  }
584 
585  // custom properties
586  writeCustomProperties( parent, incidenceBase );
587 }
588 
589 void ICalFormatImpl::writeCustomProperties(icalcomponent *parent,CustomProperties *properties)
590 {
591  TQMap<TQCString, TQString> custom = properties->customProperties();
592  for (TQMap<TQCString, TQString>::Iterator c = custom.begin(); c != custom.end(); ++c) {
593  icalproperty *p = icalproperty_new_x(c.data().utf8());
594  icalproperty_set_x_name(p,c.key());
595  icalcomponent_add_property(parent,p);
596  }
597 }
598 
599 icalproperty *ICalFormatImpl::writeOrganizer( const Person &organizer )
600 {
601  icalproperty *p = icalproperty_new_organizer("MAILTO:" + organizer.email().utf8());
602 
603  if (!organizer.name().isEmpty()) {
604  icalproperty_add_parameter( p, icalparameter_new_cn(organizer.name().utf8()) );
605  }
606  // TODO: Write dir, sent-by and language
607 
608  return p;
609 }
610 
611 
612 icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee)
613 {
614  icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8());
615 
616  if (!attendee->name().isEmpty()) {
617  icalproperty_add_parameter(p,icalparameter_new_cn(attendee->name().utf8()));
618  }
619 
620 
621  icalproperty_add_parameter(p,icalparameter_new_rsvp(
622  attendee->RSVP() ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE ));
623 
624  icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
625  switch (attendee->status()) {
626  default:
627  case Attendee::NeedsAction:
628  status = ICAL_PARTSTAT_NEEDSACTION;
629  break;
630  case Attendee::Accepted:
631  status = ICAL_PARTSTAT_ACCEPTED;
632  break;
633  case Attendee::Declined:
634  status = ICAL_PARTSTAT_DECLINED;
635  break;
636  case Attendee::Tentative:
637  status = ICAL_PARTSTAT_TENTATIVE;
638  break;
639  case Attendee::Delegated:
640  status = ICAL_PARTSTAT_DELEGATED;
641  break;
642  case Attendee::Completed:
643  status = ICAL_PARTSTAT_COMPLETED;
644  break;
645  case Attendee::InProcess:
646  status = ICAL_PARTSTAT_INPROCESS;
647  break;
648  }
649  icalproperty_add_parameter(p,icalparameter_new_partstat(status));
650 
651  icalparameter_role role = ICAL_ROLE_REQPARTICIPANT;
652  switch (attendee->role()) {
653  case Attendee::Chair:
654  role = ICAL_ROLE_CHAIR;
655  break;
656  default:
657  case Attendee::ReqParticipant:
658  role = ICAL_ROLE_REQPARTICIPANT;
659  break;
660  case Attendee::OptParticipant:
661  role = ICAL_ROLE_OPTPARTICIPANT;
662  break;
663  case Attendee::NonParticipant:
664  role = ICAL_ROLE_NONPARTICIPANT;
665  break;
666  }
667  icalproperty_add_parameter(p,icalparameter_new_role(role));
668 
669  if (!attendee->uid().isEmpty()) {
670  icalparameter* icalparameter_uid = icalparameter_new_x(attendee->uid().utf8());
671  icalparameter_set_xname(icalparameter_uid,"X-UID");
672  icalproperty_add_parameter(p,icalparameter_uid);
673  }
674 
675  if ( !attendee->delegate().isEmpty() ) {
676  icalparameter* icalparameter_delegate = icalparameter_new_delegatedto( attendee->delegate().utf8() );
677  icalproperty_add_parameter( p, icalparameter_delegate );
678  }
679 
680  if ( !attendee->delegator().isEmpty() ) {
681  icalparameter* icalparameter_delegator = icalparameter_new_delegatedfrom( attendee->delegator().utf8() );
682  icalproperty_add_parameter( p, icalparameter_delegator );
683  }
684 
685  return p;
686 }
687 
688 icalproperty *ICalFormatImpl::writeAttachment( Attachment *att )
689 {
690  icalattach *attach;
691  if ( att->isUri() ) {
692  attach = icalattach_new_from_url( att->uri().utf8().data() );
693  } else {
694  attach = icalattach_new_from_data ( (const char *)att->data(), 0, 0 );
695  }
696  icalproperty *p = icalproperty_new_attach( attach );
697 
698  if ( !att->mimeType().isEmpty() ) {
699  icalproperty_add_parameter( p,
700  icalparameter_new_fmttype( att->mimeType().utf8().data() ) );
701  }
702 
703  if ( att->isBinary() ) {
704  icalproperty_add_parameter( p,
705  icalparameter_new_value( ICAL_VALUE_BINARY ) );
706  icalproperty_add_parameter( p,
707  icalparameter_new_encoding( ICAL_ENCODING_BASE64 ) );
708  }
709 
710  if ( att->showInline() ) {
711  icalparameter* icalparameter_inline = icalparameter_new_x( "inline" );
712  icalparameter_set_xname( icalparameter_inline, "X-CONTENT-DISPOSITION" );
713  icalproperty_add_parameter( p, icalparameter_inline );
714  }
715 
716  if ( !att->label().isEmpty() ) {
717  icalparameter* icalparameter_label = icalparameter_new_x( att->label().utf8() );
718  icalparameter_set_xname( icalparameter_label, "X-LABEL" );
719  icalproperty_add_parameter( p, icalparameter_label );
720  }
721 
722  return p;
723 }
724 
725 #if ICAL_CHECK_VERSION(4,0,0)
726  #define writeByData(by_enum) \
727  if ( bys.count() > 0 ) { \
728  icalrecur_resize_by( &r->by[by_enum], bys.count() ); \
729  index = 0; \
730  for ( it = bys.begin(); it != bys.end(); ++it ) { \
731  r->by[by_enum].data[index++] = *it; \
732  } \
733  }
734 #else
735  #define writeByData(by_enum) \
736  index = 0; \
737  for ( it = bys.begin(); it != bys.end(); ++it ) { \
738  r->by_enum[index++] = *it; \
739  }
740 #endif
741 icalrecurrencetype *ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur )
742 {
743 // kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl;
744 
745 #if ICAL_CHECK_VERSION(4,0,0)
746  icalrecurrencetype *r = icalrecurrencetype_new();
747 #else
748  icalrecurrencetype *r = new icalrecurrencetype;
749  icalrecurrencetype_clear(r);
750 #endif
751  if ( !r ) return 0;
752 
753  switch( recur->recurrenceType() ) {
754  case RecurrenceRule::rSecondly:
755  r->freq = ICAL_SECONDLY_RECURRENCE;
756  break;
757  case RecurrenceRule::rMinutely:
758  r->freq = ICAL_MINUTELY_RECURRENCE;
759  break;
760  case RecurrenceRule::rHourly:
761  r->freq = ICAL_HOURLY_RECURRENCE;
762  break;
763  case RecurrenceRule::rDaily:
764  r->freq = ICAL_DAILY_RECURRENCE;
765  break;
766  case RecurrenceRule::rWeekly:
767  r->freq = ICAL_WEEKLY_RECURRENCE;
768  break;
769  case RecurrenceRule::rMonthly:
770  r->freq = ICAL_MONTHLY_RECURRENCE;
771  break;
772  case RecurrenceRule::rYearly:
773  r->freq = ICAL_YEARLY_RECURRENCE;
774  break;
775  default:
776  r->freq = ICAL_NO_RECURRENCE;
777  kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl;
778  break;
779  }
780 
781  int index = 0;
782  TQValueList<int> bys;
783  TQValueList<int>::ConstIterator it;
784 
785  // Now write out the BY* parts:
786  bys = recur->bySeconds();
787  writeByData(FIELD_BY_SECOND);
788 
789  bys = recur->byMinutes();
790  writeByData(FIELD_BY_MINUTE);
791 
792  bys = recur->byHours();
793  writeByData(FIELD_BY_HOUR);
794 
795  bys = recur->byMonthDays();
796 #if ICAL_CHECK_VERSION(4,0,0)
797  if ( bys.count() > 0 ) {
798  icalrecur_resize_by( &r->by[ICAL_BY_MONTH_DAY], bys.count() );
799  index = 0;
800  for ( it = bys.begin(); it != bys.end(); ++it ) {
801  r->by[ICAL_BY_MONTH_DAY].data[index++] = icalrecurrencetype_day_position( (*it) * 8 );
802  }
803  }
804 #else
805  index = 0;
806  for ( it = bys.begin(); it != bys.end(); ++it ) {
807  r->by_month_day[index++] = icalrecurrencetype_day_position( (*it) * 8 );
808  }
809 #endif
810 
811  bys = recur->byYearDays();
812  writeByData(FIELD_BY_YEAR_DAY);
813 
814  bys = recur->byWeekNumbers();
815  writeByData(FIELD_BY_WEEK_NO);
816 
817  bys = recur->byMonths();
818  writeByData(FIELD_BY_MONTH);
819 
820  bys = recur->bySetPos();
821  writeByData(FIELD_BY_SET_POS);
822 
823  TQValueList<RecurrenceRule::WDayPos> byd = recur->byDays();
824 #if ICAL_CHECK_VERSION(4,0,0)
825  if ( byd.count() > 0 )
826  {
827  icalrecur_resize_by( &r->by[ICAL_BY_DAY], byd.count() );
828  }
829 #endif
830  int day;
831  index = 0;
832  for ( TQValueList<RecurrenceRule::WDayPos>::ConstIterator dit = byd.begin();
833  dit != byd.end(); ++dit ) {
834  day = (*dit).day() % 7 + 1; // convert from Monday=1 to Sunday=1
835 #if ICAL_CHECK_VERSION(4,0,0)
836  r->by[ICAL_BY_DAY].data[index++] = icalrecurrencetype_encode_day(
837  static_cast<icalrecurrencetype_weekday>( day ),
838  (*dit).pos() );
839 #else
840  if ( (*dit).pos() < 0 ) {
841  day += (-(*dit).pos())*8;
842  day = -day;
843  } else {
844  day += (*dit).pos()*8;
845  }
846  r->by_day[index++] = day;
847 #endif
848  }
849 
850  r->week_start = static_cast<icalrecurrencetype_weekday>(
851  recur->weekStart()%7 + 1);
852 
853  if ( recur->frequency() > 1 ) {
854  // Dont' write out INTERVAL=1, because that's the default anyway
855  r->interval = recur->frequency();
856  }
857 
858  if ( recur->duration() > 0 ) {
859  r->count = recur->duration();
860  } else if ( recur->duration() == -1 ) {
861  r->count = 0;
862  } else {
863  if ( recur->doesFloat() )
864  r->until = writeICalDate(recur->endDt().date());
865  else
866  r->until = writeICalDateTime(recur->endDt());
867  }
868 
869 // Debug output
870 #if 0
871  const char *str = icalrecurrencetype_as_string(r);
872  if (str) {
873  kdDebug(5800) << " String: " << str << endl;
874  } else {
875  kdDebug(5800) << " No String" << endl;
876  }
877 #endif
878 
879  return r;
880 }
881 #undef writeByData
882 
883 icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
884 {
885 // kdDebug(5800) << " ICalFormatImpl::writeAlarm" << endl;
886  icalcomponent *a = icalcomponent_new(ICAL_VALARM_COMPONENT);
887 
888  icalproperty_action action;
889  icalattach *attach = 0;
890 
891  switch (alarm->type()) {
892  case Alarm::Procedure:
893  action = ICAL_ACTION_PROCEDURE;
894  attach = icalattach_new_from_url(TQFile::encodeName(alarm->programFile()).data());
895  icalcomponent_add_property(a,icalproperty_new_attach(attach));
896  if (!alarm->programArguments().isEmpty()) {
897  icalcomponent_add_property(a,icalproperty_new_description(alarm->programArguments().utf8()));
898  }
899  break;
900  case Alarm::Audio:
901  action = ICAL_ACTION_AUDIO;
902 // kdDebug(5800) << " It's an audio action, file: " << alarm->audioFile() << endl;
903  if (!alarm->audioFile().isEmpty()) {
904  attach = icalattach_new_from_url(TQFile::encodeName( alarm->audioFile() ).data());
905  icalcomponent_add_property(a,icalproperty_new_attach(attach));
906  }
907  break;
908  case Alarm::Email: {
909  action = ICAL_ACTION_EMAIL;
910  TQValueList<Person> addresses = alarm->mailAddresses();
911  for (TQValueList<Person>::Iterator ad = addresses.begin(); ad != addresses.end(); ++ad) {
912  icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8());
913  if (!(*ad).name().isEmpty()) {
914  icalproperty_add_parameter(p,icalparameter_new_cn((*ad).name().utf8()));
915  }
916  icalcomponent_add_property(a,p);
917  }
918  icalcomponent_add_property(a,icalproperty_new_summary(alarm->mailSubject().utf8()));
919  icalcomponent_add_property(a,icalproperty_new_description(alarm->mailText().utf8()));
920  TQStringList attachments = alarm->mailAttachments();
921  if (attachments.count() > 0) {
922  for (TQStringList::Iterator at = attachments.begin(); at != attachments.end(); ++at) {
923  attach = icalattach_new_from_url(TQFile::encodeName( *at ).data());
924  icalcomponent_add_property(a,icalproperty_new_attach(attach));
925  }
926  }
927  break;
928  }
929  case Alarm::Display:
930  action = ICAL_ACTION_DISPLAY;
931  icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8()));
932  break;
933  case Alarm::Invalid:
934  default:
935  kdDebug(5800) << "Unknown type of alarm" << endl;
936  action = ICAL_ACTION_NONE;
937  break;
938  }
939  icalcomponent_add_property(a,icalproperty_new_action(action));
940 
941  // Trigger time
942  icaltriggertype trigger;
943  if ( alarm->hasTime() ) {
944  trigger.time = writeICalDateTime(alarm->time());
945  trigger.duration = icaldurationtype_null_duration();
946  } else {
947  trigger.time = icaltime_null_time();
948  Duration offset;
949  if ( alarm->hasStartOffset() )
950  offset = alarm->startOffset();
951  else
952  offset = alarm->endOffset();
953  trigger.duration = writeICalDuration( offset.asSeconds() );
954  }
955  icalproperty *p = icalproperty_new_trigger(trigger);
956  if ( alarm->hasEndOffset() )
957  icalproperty_add_parameter(p,icalparameter_new_related(ICAL_RELATED_END));
958  icalcomponent_add_property(a,p);
959 
960  // Repeat count and duration
961  if (alarm->repeatCount()) {
962  icalcomponent_add_property(a,icalproperty_new_repeat(alarm->repeatCount()));
963  icalcomponent_add_property(a,icalproperty_new_duration(
964  writeICalDuration(alarm->snoozeTime().value())));
965  }
966 
967  // Custom properties
968  TQMap<TQCString, TQString> custom = alarm->customProperties();
969  for (TQMap<TQCString, TQString>::Iterator c = custom.begin(); c != custom.end(); ++c) {
970  icalproperty *p = icalproperty_new_x(c.data().utf8());
971  icalproperty_set_x_name(p,c.key());
972  icalcomponent_add_property(a,p);
973  }
974 
975  return a;
976 }
977 
978 Todo *ICalFormatImpl::readTodo(icalcomponent *vtodo)
979 {
980  Todo *todo = new Todo;
981 
982  readIncidence(vtodo, 0, todo); // FIXME timezone
983 
984  icalproperty *p = icalcomponent_get_first_property(vtodo,ICAL_ANY_PROPERTY);
985 
986 // int intvalue;
987  icaltimetype icaltime;
988 
989  TQStringList categories;
990 
991  while (p) {
992  icalproperty_kind kind = icalproperty_isa(p);
993  switch (kind) {
994 
995  case ICAL_DUE_PROPERTY: // due date
996  icaltime = icalproperty_get_due(p);
997  if (icaltime.is_date) {
998  todo->setDtDue(TQDateTime(readICalDate(icaltime),TQTime(0,0,0)),true);
999  } else {
1000  todo->setDtDue(readICalDateTime(p, icaltime),true);
1001  todo->setFloats(false);
1002  }
1003  todo->setHasDueDate(true);
1004  break;
1005 
1006  case ICAL_COMPLETED_PROPERTY: // completion date
1007  icaltime = icalproperty_get_completed(p);
1008  todo->setCompleted(readICalDateTime(p, icaltime));
1009  break;
1010 
1011  case ICAL_PERCENTCOMPLETE_PROPERTY: // Percent completed
1012  todo->setPercentComplete(icalproperty_get_percentcomplete(p));
1013  break;
1014 
1015  case ICAL_RELATEDTO_PROPERTY: // related todo (parent)
1016  todo->setRelatedToUid(TQString::fromUtf8(icalproperty_get_relatedto(p)));
1017  mTodosRelate.append(todo);
1018  break;
1019 
1020  case ICAL_DTSTART_PROPERTY: {
1021  // Flag that todo has start date. Value is read in by readIncidence().
1022  if ( todo->comments().grep("NoStartDate").count() )
1023  todo->setHasStartDate( false );
1024  else
1025  todo->setHasStartDate( true );
1026  break;
1027  }
1028 
1029  case ICAL_RECURRENCEID_PROPERTY:
1030  icaltime = icalproperty_get_recurrenceid(p);
1031  todo->setDtRecurrence( readICalDateTime(p, icaltime) );
1032  break;
1033 
1034  default:
1035 // kdDebug(5800) << "ICALFormat::readTodo(): Unknown property: " << kind
1036 // << endl;
1037  break;
1038  }
1039 
1040  p = icalcomponent_get_next_property(vtodo,ICAL_ANY_PROPERTY);
1041  }
1042 
1043  if (mCompat) mCompat->fixEmptySummary( todo );
1044 
1045  return todo;
1046 }
1047 
1048 Event *ICalFormatImpl::readEvent( icalcomponent *vevent, icalcomponent *vtimezone )
1049 {
1050  Event *event = new Event;
1051 
1052  // FIXME where is this freed?
1053  icaltimezone *tz = icaltimezone_new();
1054  if ( !icaltimezone_set_component( tz, vtimezone ) ) {
1055  icaltimezone_free( tz, 1 );
1056  tz = 0;
1057  }
1058 
1059  readIncidence( vevent, tz, event);
1060 
1061  icalproperty *p = icalcomponent_get_first_property( vevent, ICAL_ANY_PROPERTY );
1062 
1063  // int intvalue;
1064  icaltimetype icaltime;
1065 
1066  TQStringList categories;
1067  icalproperty_transp transparency;
1068 
1069  bool dtEndProcessed = false;
1070 
1071  while ( p ) {
1072  icalproperty_kind kind = icalproperty_isa( p );
1073  switch ( kind ) {
1074 
1075  case ICAL_DTEND_PROPERTY: // start date and time
1076  icaltime = icalproperty_get_dtend( p );
1077  if ( icaltime.is_date ) {
1078  // End date is non-inclusive
1079  TQDate endDate = readICalDate( icaltime ).addDays( -1 );
1080  if ( mCompat ) {
1081  mCompat->fixFloatingEnd( endDate );
1082  }
1083 
1084  if ( endDate < event->dtStart().date() ) {
1085  endDate = event->dtStart().date();
1086  }
1087  event->setDtEnd( TQDateTime( endDate, TQTime( 0, 0, 0 ) ) );
1088  } else {
1089  event->setDtEnd(readICalDateTime(p, icaltime, tz));
1090  event->setFloats( false );
1091  }
1092  dtEndProcessed = true;
1093  break;
1094 
1095  case ICAL_RELATEDTO_PROPERTY: // related event (parent)
1096  event->setRelatedToUid( TQString::fromUtf8( icalproperty_get_relatedto( p ) ) );
1097  mEventsRelate.append( event );
1098  break;
1099 
1100  case ICAL_TRANSP_PROPERTY: // Transparency
1101  transparency = icalproperty_get_transp( p );
1102  if ( transparency == ICAL_TRANSP_TRANSPARENT ) {
1103  event->setTransparency( Event::Transparent );
1104  } else {
1105  event->setTransparency( Event::Opaque );
1106  }
1107  break;
1108 
1109  default:
1110  // kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind
1111  // << endl;
1112  break;
1113  }
1114 
1115  p = icalcomponent_get_next_property( vevent, ICAL_ANY_PROPERTY );
1116  }
1117 
1118  // according to rfc2445 the dtend shouldn't be written when it equals
1119  // start date. so assign one equal to start date.
1120  if ( !dtEndProcessed && !event->hasDuration() ) {
1121  event->setDtEnd( event->dtStart() );
1122  }
1123 
1124  const TQString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT");
1125  if ( !msade.isEmpty() ) {
1126  const bool floats = ( msade == TQString::fromLatin1("TRUE") );
1127  event->setFloats(floats);
1128  }
1129 
1130  if ( mCompat ) {
1131  mCompat->fixEmptySummary( event );
1132  }
1133 
1134  return event;
1135 }
1136 
1137 FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
1138 {
1139  FreeBusy *freebusy = new FreeBusy;
1140 
1141  readIncidenceBase(vfreebusy, freebusy);
1142 
1143  icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY);
1144 
1145  icaltimetype icaltime;
1146  PeriodList periods;
1147 
1148  while (p) {
1149  icalproperty_kind kind = icalproperty_isa(p);
1150  switch (kind) {
1151 
1152  case ICAL_DTSTART_PROPERTY: // start date and time
1153  icaltime = icalproperty_get_dtstart(p);
1154  freebusy->setDtStart(readICalDateTime(p, icaltime));
1155  break;
1156 
1157  case ICAL_DTEND_PROPERTY: // end Date and Time
1158  icaltime = icalproperty_get_dtend(p);
1159  freebusy->setDtEnd(readICalDateTime(p, icaltime));
1160  break;
1161 
1162  case ICAL_FREEBUSY_PROPERTY: //Any FreeBusy Times
1163  {
1164  icalperiodtype icalperiod = icalproperty_get_freebusy(p);
1165  TQDateTime period_start = readICalDateTime(p, icalperiod.start);
1166  Period period;
1167  if ( !icaltime_is_null_time(icalperiod.end) ) {
1168  TQDateTime period_end = readICalDateTime(p, icalperiod.end);
1169  period = Period(period_start, period_end);
1170  } else {
1171  Duration duration = readICalDuration( icalperiod.duration );
1172  period = Period(period_start, duration);
1173  }
1174  icalparameter *param = icalproperty_get_first_parameter( p, ICAL_X_PARAMETER );
1175  while ( param ) {
1176  if ( strncmp( icalparameter_get_xname( param ), "X-SUMMARY", 9 ) == 0 ) {
1177  period.setSummary( TQString::fromUtf8(
1178  KCodecs::base64Decode( TQCString( icalparameter_get_xvalue( param ) ) ) ) );
1179  }
1180  if ( strncmp( icalparameter_get_xname( param ), "X-LOCATION", 10 ) == 0 ) {
1181  period.setLocation( TQString::fromUtf8(
1182  KCodecs::base64Decode( TQCString( icalparameter_get_xvalue( param ) ) ) ) );
1183  }
1184  param = icalproperty_get_next_parameter( p, ICAL_X_PARAMETER );
1185  }
1186  periods.append( period );
1187  break;
1188  }
1189 
1190  default:
1191 // kdDebug(5800) << "ICalFormatImpl::readFreeBusy(): Unknown property: "
1192 // << kind << endl;
1193  break;
1194  }
1195  p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY);
1196  }
1197  freebusy->addPeriods( periods );
1198 
1199  return freebusy;
1200 }
1201 
1202 Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal)
1203 {
1204  Journal *journal = new Journal;
1205 
1206  readIncidence(vjournal, 0, journal); // FIXME tz?
1207 
1208  return journal;
1209 }
1210 
1211 Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee)
1212 {
1213  icalparameter *p = 0;
1214 
1215  TQString email = TQString::fromUtf8(icalproperty_get_attendee(attendee));
1216  if ( email.startsWith( "mailto:", false ) ) {
1217  email = email.mid( 7 );
1218  }
1219 
1220  TQString name;
1221  TQString uid = TQString();
1222  p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER);
1223  if (p) {
1224  name = TQString::fromUtf8(icalparameter_get_cn(p));
1225  } else {
1226  }
1227 
1228  bool rsvp=false;
1229  p = icalproperty_get_first_parameter(attendee,ICAL_RSVP_PARAMETER);
1230  if (p) {
1231  icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp(p);
1232  if (rsvpParameter == ICAL_RSVP_TRUE) rsvp = true;
1233  }
1234 
1235  Attendee::PartStat status = Attendee::NeedsAction;
1236  p = icalproperty_get_first_parameter(attendee,ICAL_PARTSTAT_PARAMETER);
1237  if (p) {
1238  icalparameter_partstat partStatParameter = icalparameter_get_partstat(p);
1239  switch(partStatParameter) {
1240  default:
1241  case ICAL_PARTSTAT_NEEDSACTION:
1242  status = Attendee::NeedsAction;
1243  break;
1244  case ICAL_PARTSTAT_ACCEPTED:
1245  status = Attendee::Accepted;
1246  break;
1247  case ICAL_PARTSTAT_DECLINED:
1248  status = Attendee::Declined;
1249  break;
1250  case ICAL_PARTSTAT_TENTATIVE:
1251  status = Attendee::Tentative;
1252  break;
1253  case ICAL_PARTSTAT_DELEGATED:
1254  status = Attendee::Delegated;
1255  break;
1256  case ICAL_PARTSTAT_COMPLETED:
1257  status = Attendee::Completed;
1258  break;
1259  case ICAL_PARTSTAT_INPROCESS:
1260  status = Attendee::InProcess;
1261  break;
1262  }
1263  }
1264 
1265  Attendee::Role role = Attendee::ReqParticipant;
1266  p = icalproperty_get_first_parameter(attendee,ICAL_ROLE_PARAMETER);
1267  if (p) {
1268  icalparameter_role roleParameter = icalparameter_get_role(p);
1269  switch(roleParameter) {
1270  case ICAL_ROLE_CHAIR:
1271  role = Attendee::Chair;
1272  break;
1273  default:
1274  case ICAL_ROLE_REQPARTICIPANT:
1275  role = Attendee::ReqParticipant;
1276  break;
1277  case ICAL_ROLE_OPTPARTICIPANT:
1278  role = Attendee::OptParticipant;
1279  break;
1280  case ICAL_ROLE_NONPARTICIPANT:
1281  role = Attendee::NonParticipant;
1282  break;
1283  }
1284  }
1285 
1286  p = icalproperty_get_first_parameter(attendee,ICAL_X_PARAMETER);
1287  uid = icalparameter_get_xvalue(p);
1288  // This should be added, but there seems to be a libical bug here.
1289  // TODO: does this work now in libical-0.24 or greater?
1290  /*while (p) {
1291  // if (icalparameter_get_xname(p) == "X-UID") {
1292  uid = icalparameter_get_xvalue(p);
1293  p = icalproperty_get_next_parameter(attendee,ICAL_X_PARAMETER);
1294  } */
1295 
1296  Attendee *a = new Attendee( name, email, rsvp, status, role, uid );
1297 
1298  p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDTO_PARAMETER );
1299  if ( p )
1300  {
1301 #if ICAL_CHECK_VERSION(4,0,0)
1302  a->setDelegate( icalparameter_get_delegatedto_nth( p, 0 ) );
1303 #else
1304  a->setDelegate( icalparameter_get_delegatedto( p ) );
1305 #endif
1306  }
1307 
1308  p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDFROM_PARAMETER );
1309  if ( p )
1310  {
1311 #if ICAL_CHECK_VERSION(4,0,0)
1312  a->setDelegator( icalparameter_get_delegatedfrom_nth( p, 0 ) );
1313 #else
1314  a->setDelegator( icalparameter_get_delegatedfrom( p ) );
1315 #endif
1316  }
1317 
1318  return a;
1319 }
1320 
1321 Person ICalFormatImpl::readOrganizer( icalproperty *organizer )
1322 {
1323  TQString email = TQString::fromUtf8(icalproperty_get_organizer(organizer));
1324  if ( email.startsWith( "mailto:", false ) ) {
1325  email = email.mid( 7 );
1326  }
1327  TQString cn;
1328 
1329  icalparameter *p = icalproperty_get_first_parameter(
1330  organizer, ICAL_CN_PARAMETER );
1331 
1332  if ( p ) {
1333  cn = TQString::fromUtf8( icalparameter_get_cn( p ) );
1334  }
1335  Person org( cn, email );
1336  // TODO: Treat sent-by, dir and language here, too
1337  return org;
1338 }
1339 
1340 Attachment *ICalFormatImpl::readAttachment(icalproperty *attach)
1341 {
1342  Attachment *attachment = 0;
1343 
1344  const char *p;
1345  icalvalue *value = icalproperty_get_value( attach );
1346 
1347  switch( icalvalue_isa( value ) ) {
1348  case ICAL_ATTACH_VALUE:
1349  {
1350  icalattach *a = icalproperty_get_attach( attach );
1351  if ( !icalattach_get_is_url( a ) ) {
1352  p = (const char *)icalattach_get_data( a );
1353  if ( p ) {
1354  attachment = new Attachment( p );
1355  }
1356  } else {
1357  p = icalattach_get_url( a );
1358  if ( p ) {
1359  attachment = new Attachment( TQString::fromUtf8( p ) );
1360  }
1361  }
1362  break;
1363  }
1364  case ICAL_BINARY_VALUE:
1365  {
1366  icalattach *a = icalproperty_get_attach( attach );
1367  p = (const char *)icalattach_get_data( a );
1368  if ( p ) {
1369  attachment = new Attachment( p );
1370  }
1371  break;
1372  }
1373  case ICAL_URI_VALUE:
1374  p = icalvalue_get_uri( value );
1375  attachment = new Attachment( TQString::fromUtf8( p ) );
1376  break;
1377  default:
1378  break;
1379  }
1380 
1381  if ( attachment ) {
1382  icalparameter *p =
1383  icalproperty_get_first_parameter( attach, ICAL_FMTTYPE_PARAMETER );
1384  if ( p ) {
1385  attachment->setMimeType( TQString( icalparameter_get_fmttype( p ) ) );
1386  }
1387 
1388  p = icalproperty_get_first_parameter( attach, ICAL_X_PARAMETER );
1389  while ( p ) {
1390  TQString xname = TQString( icalparameter_get_xname( p ) ).upper();
1391  TQString xvalue = TQString::fromUtf8( icalparameter_get_xvalue( p ) );
1392  if ( xname == "X-CONTENT-DISPOSITION" ) {
1393  attachment->setShowInline( xvalue.lower() == "inline" );
1394  }
1395  if ( xname == "X-LABEL" ) {
1396  attachment->setLabel( xvalue );
1397  }
1398  p = icalproperty_get_next_parameter( attach, ICAL_X_PARAMETER );
1399  }
1400 
1401  p = icalproperty_get_first_parameter( attach, ICAL_X_PARAMETER );
1402  while ( p ) {
1403  if ( strncmp( icalparameter_get_xname( p ), "X-LABEL", 7 ) == 0 ) {
1404  attachment->setLabel( TQString::fromUtf8( icalparameter_get_xvalue( p ) ) );
1405  }
1406  p = icalproperty_get_next_parameter( attach, ICAL_X_PARAMETER );
1407  }
1408  }
1409 
1410  return attachment;
1411 }
1412 
1413 void ICalFormatImpl::readIncidence(icalcomponent *parent, icaltimezone *tz, Incidence *incidence)
1414 {
1415  readIncidenceBase(parent,incidence);
1416 
1417  icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
1418 
1419  const char *text;
1420  int intvalue, inttext;
1421  icaltimetype icaltime;
1422  icaldurationtype icalduration;
1423 
1424  TQStringList categories;
1425 
1426  while (p) {
1427  icalproperty_kind kind = icalproperty_isa(p);
1428  switch (kind) {
1429 
1430  case ICAL_CREATED_PROPERTY:
1431  icaltime = icalproperty_get_created(p);
1432  incidence->setCreated(readICalDateTime(p, icaltime, tz));
1433  break;
1434 
1435  case ICAL_SEQUENCE_PROPERTY: // sequence
1436  intvalue = icalproperty_get_sequence(p);
1437  incidence->setRevision(intvalue);
1438  break;
1439 
1440  case ICAL_LASTMODIFIED_PROPERTY: // last modification date
1441  icaltime = icalproperty_get_lastmodified(p);
1442  incidence->setLastModified(readICalDateTime(p, icaltime, tz));
1443  break;
1444 
1445  case ICAL_DTSTART_PROPERTY: // start date and time
1446  icaltime = icalproperty_get_dtstart(p);
1447  if (icaltime.is_date) {
1448  incidence->setDtStart(TQDateTime(readICalDate(icaltime),TQTime(0,0,0)));
1449  incidence->setFloats( true );
1450  } else {
1451  incidence->setDtStart(readICalDateTime(p, icaltime, tz));
1452  incidence->setFloats( false );
1453  }
1454  break;
1455 
1456  case ICAL_DURATION_PROPERTY: // start date and time
1457  icalduration = icalproperty_get_duration(p);
1458  incidence->setDuration(readICalDuration(icalduration));
1459  break;
1460 
1461  case ICAL_DESCRIPTION_PROPERTY: // description
1462  text = icalproperty_get_description(p);
1463  incidence->setDescription(TQString::fromUtf8(text));
1464  break;
1465 
1466  case ICAL_SUMMARY_PROPERTY: // summary
1467  text = icalproperty_get_summary(p);
1468  incidence->setSummary(TQString::fromUtf8(text));
1469  break;
1470 
1471  case ICAL_LOCATION_PROPERTY: // location
1472  text = icalproperty_get_location(p);
1473  incidence->setLocation(TQString::fromUtf8(text));
1474  break;
1475 
1476  case ICAL_STATUS_PROPERTY: { // status
1477  Incidence::Status stat;
1478  switch (icalproperty_get_status(p)) {
1479  case ICAL_STATUS_TENTATIVE: stat = Incidence::StatusTentative; break;
1480  case ICAL_STATUS_CONFIRMED: stat = Incidence::StatusConfirmed; break;
1481  case ICAL_STATUS_COMPLETED: stat = Incidence::StatusCompleted; break;
1482  case ICAL_STATUS_NEEDSACTION: stat = Incidence::StatusNeedsAction; break;
1483  case ICAL_STATUS_CANCELLED: stat = Incidence::StatusCanceled; break;
1484  case ICAL_STATUS_INPROCESS: stat = Incidence::StatusInProcess; break;
1485  case ICAL_STATUS_DRAFT: stat = Incidence::StatusDraft; break;
1486  case ICAL_STATUS_FINAL: stat = Incidence::StatusFinal; break;
1487  case ICAL_STATUS_X:
1488  incidence->setCustomStatus(TQString::fromUtf8(icalvalue_get_x(icalproperty_get_value(p))));
1489  stat = Incidence::StatusX;
1490  break;
1491  case ICAL_STATUS_NONE:
1492  default: stat = Incidence::StatusNone; break;
1493  }
1494  if (stat != Incidence::StatusX)
1495  incidence->setStatus(stat);
1496  break;
1497  }
1498 
1499  case ICAL_PRIORITY_PROPERTY: // priority
1500  intvalue = icalproperty_get_priority( p );
1501  if ( mCompat )
1502  intvalue = mCompat->fixPriority( intvalue );
1503  incidence->setPriority( intvalue );
1504  break;
1505 
1506  case ICAL_CATEGORIES_PROPERTY: // categories
1507  text = icalproperty_get_categories(p);
1508  categories.append(TQString::fromUtf8(text));
1509  break;
1510 
1511  case ICAL_RECURRENCEID_PROPERTY: // recurrenceID
1512  icaltime = icalproperty_get_recurrenceid(p);
1513  incidence->setRecurrenceID( readICalDateTime( p, icaltime ) );
1514  incidence->setHasRecurrenceID( true );
1515  break;
1516 
1517  case ICAL_RRULE_PROPERTY:
1518  readRecurrenceRule( p, incidence );
1519  break;
1520 
1521 // case ICAL_CONTACT_PROPERTY:
1522 // incidenceBase->addContact(
1523 // TQString::fromUtf8( icalproperty_get_contact( p ) ) );
1524 // break;
1525 
1526  case ICAL_RDATE_PROPERTY: {
1527  icaldatetimeperiodtype rd = icalproperty_get_rdate( p );
1528  if ( icaltime_is_valid_time( rd.time ) ) {
1529  if ( icaltime_is_date( rd.time ) ) {
1530  incidence->recurrence()->addRDate( readICalDate( rd.time ) );
1531  } else {
1532  incidence->recurrence()->addRDateTime( readICalDateTime(p, rd.time, tz ) );
1533  }
1534  } else {
1535  // TODO: RDates as period are not yet implemented!
1536  }
1537  break; }
1538 
1539  case ICAL_EXRULE_PROPERTY:
1540  readExceptionRule( p, incidence );
1541  break;
1542 
1543  case ICAL_EXDATE_PROPERTY:
1544  icaltime = icalproperty_get_exdate(p);
1545  if ( icaltime_is_date(icaltime) ) {
1546  incidence->recurrence()->addExDate( readICalDate(icaltime) );
1547  } else {
1548  incidence->recurrence()->addExDateTime( readICalDateTime(p, icaltime, tz) );
1549  }
1550  break;
1551 
1552  case ICAL_CLASS_PROPERTY:
1553  inttext = icalproperty_get_class(p);
1554  if (inttext == ICAL_CLASS_PUBLIC ) {
1555  incidence->setSecrecy(Incidence::SecrecyPublic);
1556  } else if (inttext == ICAL_CLASS_CONFIDENTIAL ) {
1557  incidence->setSecrecy(Incidence::SecrecyConfidential);
1558  } else {
1559  incidence->setSecrecy(Incidence::SecrecyPrivate);
1560  }
1561  break;
1562 
1563  case ICAL_ATTACH_PROPERTY: // attachments
1564  incidence->addAttachment(readAttachment(p));
1565  break;
1566 
1567  default:
1568 // kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
1569 // << endl;
1570  break;
1571  }
1572 
1573  p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
1574  }
1575 
1576  // Set the scheduling ID
1577  const TQString uid = incidence->customProperty( "LIBKCAL", "ID" );
1578  if ( !uid.isNull() ) {
1579  // The UID stored in incidencebase is actually the scheduling ID
1580  // It has to be stored in the iCal UID component for compatibility
1581  // with other iCal applications
1582  incidence->setSchedulingID( incidence->uid() );
1583  incidence->setUid( uid );
1584  }
1585 
1586  // Now that recurrence and exception stuff is completely set up,
1587  // do any backwards compatibility adjustments.
1588  if ( incidence->doesRecur() && mCompat )
1589  mCompat->fixRecurrence( incidence );
1590 
1591  // add categories
1592  incidence->setCategories(categories);
1593 
1594  // iterate through all alarms
1595  for (icalcomponent *alarm = icalcomponent_get_first_component(parent,ICAL_VALARM_COMPONENT);
1596  alarm;
1597  alarm = icalcomponent_get_next_component(parent,ICAL_VALARM_COMPONENT)) {
1598  readAlarm(alarm,incidence);
1599  }
1600  // Fix incorrect alarm settings by other applications (like outloook 9)
1601  if ( mCompat ) mCompat->fixAlarms( incidence );
1602 
1603 }
1604 
1605 void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
1606 {
1607  icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
1608 
1609  bool uidProcessed = false;
1610 
1611  while ( p ) {
1612  icalproperty_kind kind = icalproperty_isa( p );
1613  switch (kind) {
1614 
1615  case ICAL_UID_PROPERTY: // unique id
1616  uidProcessed = true;
1617  incidenceBase->setUid( TQString::fromUtf8(icalproperty_get_uid( p ) ) );
1618  break;
1619 
1620  case ICAL_ORGANIZER_PROPERTY: // organizer
1621  incidenceBase->setOrganizer( readOrganizer( p ) );
1622  break;
1623 
1624  case ICAL_ATTENDEE_PROPERTY: // attendee
1625  incidenceBase->addAttendee( readAttendee( p ) );
1626  break;
1627 
1628  case ICAL_COMMENT_PROPERTY:
1629  incidenceBase->addComment(
1630  TQString::fromUtf8( icalproperty_get_comment( p ) ) );
1631  break;
1632 
1633  default:
1634  break;
1635  }
1636 
1637  p = icalcomponent_get_next_property( parent, ICAL_ANY_PROPERTY );
1638  }
1639 
1640  if ( !uidProcessed ) {
1641  kdWarning() << "The incidence didn't have any UID! Report a bug "
1642  << "to the application that generated this file."
1643  << endl;
1644 
1645  // Our in-memory incidence has a random uid generated in Event's ctor.
1646  // Make it empty so it matches what's in the file:
1647  incidenceBase->setUid( TQString() );
1648 
1649  // Otherwise, next time we read the file, this function will return
1650  // an event with another random uid and we will have two events in the calendar.
1651  }
1652 
1653  // kpilot stuff
1654  // TODO: move this application-specific code to kpilot
1655  // need to get X-PILOT* attributes out, set correct properties, and get
1656  // rid of them...
1657  // Pointer fun, as per libical documentation
1658  // (documented in UsingLibical.txt)
1659  icalproperty *next =0;
1660 
1661  for ( p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
1662  p != 0;
1663  p = next )
1664  {
1665 
1666  next = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
1667 
1668  TQString value = TQString::fromUtf8(icalproperty_get_x(p));
1669  TQString name = icalproperty_get_x_name(p);
1670 
1671  if (name == "X-PILOTID" && !value.isEmpty()) {
1672  incidenceBase->setPilotId(value.toInt());
1673  icalcomponent_remove_property(parent,p);
1674  } else if (name == "X-PILOTSTAT" && !value.isEmpty()) {
1675  incidenceBase->setSyncStatus(value.toInt());
1676  icalcomponent_remove_property(parent,p);
1677  }
1678  }
1679 
1680  // custom properties
1681  readCustomProperties(parent, incidenceBase);
1682 }
1683 
1684 void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties)
1685 {
1686  TQMap<TQCString, TQString> customProperties;
1687  TQString lastProperty;
1688 
1689  icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
1690 
1691  while (p) {
1692 
1693  TQString value = TQString::fromUtf8(icalproperty_get_x(p));
1694  const char *name = icalproperty_get_x_name(p);
1695  if ( lastProperty != name ) {
1696  customProperties[name] = value;
1697  } else {
1698  customProperties[name] = customProperties[name].append( "," ).append( value );
1699  }
1700  // kdDebug(5800) << "Set custom property [" << name << '=' << value << ']' << endl;
1701  p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
1702  lastProperty = name;
1703  }
1704 
1705  properties->setCustomProperties(customProperties);
1706 }
1707 
1708 
1709 
1710 void ICalFormatImpl::readRecurrenceRule(icalproperty *rrule,Incidence *incidence )
1711 {
1712 // kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
1713 
1714  Recurrence *recur = incidence->recurrence();
1715 
1716 #if ICAL_CHECK_VERSION(4,0,0)
1717  struct icalrecurrencetype *r = icalproperty_get_rrule(rrule);
1718  if ( !r ) return;
1719 #else
1720  struct icalrecurrencetype _r = icalproperty_get_rrule(rrule);
1721  struct icalrecurrencetype *r = &_r;
1722 #endif
1723 // dumpIcalRecurrence(r);
1724 
1725  RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
1726  recurrule->setStartDt( incidence->dtStart() );
1727  readRecurrence( r, recurrule );
1728  recur->addRRule( recurrule );
1729 }
1730 
1731 void ICalFormatImpl::readExceptionRule( icalproperty *rrule, Incidence *incidence )
1732 {
1733 // kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
1734 
1735 #if ICAL_CHECK_VERSION(4,0,0)
1736  struct icalrecurrencetype *r = icalproperty_get_exrule(rrule);
1737  if ( !r ) return;
1738 #else
1739  struct icalrecurrencetype _r = icalproperty_get_exrule(rrule);
1740  struct icalrecurrencetype *r = &_r;
1741 #endif
1742 // dumpIcalRecurrence(r);
1743 
1744  RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
1745  recurrule->setStartDt( incidence->dtStart() );
1746  readRecurrence( r, recurrule );
1747 
1748  Recurrence *recur = incidence->recurrence();
1749  recur->addExRule( recurrule );
1750 }
1751 
1752 #if ICAL_CHECK_VERSION(4,0,0)
1753 #define readSetByList(by_enum,setfunc) \
1754  index = 0; \
1755  lst.clear(); \
1756  while ( index < r->by[by_enum].size ) { \
1757  i = r->by[by_enum].data[index++]; \
1758  lst.append( i ); \
1759  } \
1760  if ( !lst.isEmpty() ) recur->setfunc( lst );
1761 #else
1762 #define readSetByList(by_enum,setfunc) \
1763  index = 0; \
1764  lst.clear(); \
1765  while ( (i = r->by_enum[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) \
1766  lst.append( i ); \
1767  if ( !lst.isEmpty() ) recur->setfunc( lst );
1768 #endif
1769 void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype *r, RecurrenceRule* recur )
1770 {
1771  // Generate the RRULE string
1772  recur->mRRule = TQString( icalrecurrencetype_as_string( const_cast<struct icalrecurrencetype*>(r) ) );
1773  // Period
1774  switch ( r->freq ) {
1775  case ICAL_SECONDLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rSecondly ); break;
1776  case ICAL_MINUTELY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rMinutely ); break;
1777  case ICAL_HOURLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rHourly ); break;
1778  case ICAL_DAILY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rDaily ); break;
1779  case ICAL_WEEKLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rWeekly ); break;
1780  case ICAL_MONTHLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rMonthly ); break;
1781  case ICAL_YEARLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rYearly ); break;
1782  case ICAL_NO_RECURRENCE:
1783  default:
1784  recur->setRecurrenceType( RecurrenceRule::rNone );
1785  }
1786  // Frequency
1787  recur->setFrequency( r->interval );
1788 
1789  // Duration & End Date
1790  if ( !icaltime_is_null_time( r->until ) ) {
1791  icaltimetype t;
1792  t = r->until;
1793  // Convert to the correct time zone! it's in UTC by specification.
1794  TQDateTime endDate( readICalDateTime(0, t) );
1795  recur->setEndDt( endDate );
1796  } else {
1797  if (r->count == 0)
1798  recur->setDuration( -1 );
1799  else
1800  recur->setDuration( r->count );
1801  }
1802 
1803  // Week start setting
1804  int wkst = (r->week_start + 5)%7 + 1;
1805  recur->setWeekStart( wkst );
1806 
1807  // And now all BY*
1808  TQValueList<int> lst;
1809  int i;
1810  int index = 0;
1811 
1812  readSetByList( FIELD_BY_SECOND, setBySeconds );
1813  readSetByList( FIELD_BY_MINUTE, setByMinutes );
1814  readSetByList( FIELD_BY_HOUR, setByHours );
1815  readSetByList( FIELD_BY_MONTH_DAY, setByMonthDays );
1816  readSetByList( FIELD_BY_YEAR_DAY, setByYearDays );
1817  readSetByList( FIELD_BY_WEEK_NO, setByWeekNumbers );
1818  readSetByList( FIELD_BY_MONTH, setByMonths );
1819  readSetByList( FIELD_BY_SET_POS, setBySetPos );
1820 
1821  // BYDAY is a special case, since it's not an int list
1822  TQValueList<RecurrenceRule::WDayPos> wdlst;
1823  short day;
1824  index = 0;
1825 #if ICAL_CHECK_VERSION(4,0,0)
1826  while( index < r->by[ICAL_BY_DAY].size && (day = r->by[ICAL_BY_DAY].data[index++]) )
1827 #else
1828  while( (day = r->by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX )
1829 #endif
1830  {
1832  pos.setDay( ( icalrecurrencetype_day_day_of_week( day ) + 5 )%7 + 1 );
1833  pos.setPos( icalrecurrencetype_day_position( day ) );
1834  wdlst.append( pos );
1835  }
1836  if ( !wdlst.isEmpty() ) recur->setByDays( wdlst );
1837 
1838  // TODO Store all X- fields of the RRULE inside the recurrence (so they are
1839  // preserved
1840 }
1841 #undef readSetByList
1842 
1843 void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
1844 {
1845 // kdDebug(5800) << "Read alarm for " << incidence->summary() << endl;
1846 
1847  Alarm* ialarm = incidence->newAlarm();
1848  ialarm->setRepeatCount(0);
1849  ialarm->setEnabled(true);
1850 
1851  // Determine the alarm's action type
1852  icalproperty *p = icalcomponent_get_first_property(alarm,ICAL_ACTION_PROPERTY);
1853  Alarm::Type type = Alarm::Display;
1854  icalproperty_action action = ICAL_ACTION_DISPLAY;
1855  if ( !p ) {
1856  kdDebug(5800) << "Unknown type of alarm, using default" << endl;
1857 // return;
1858  } else {
1859 
1860  action = icalproperty_get_action(p);
1861  switch ( action ) {
1862  case ICAL_ACTION_DISPLAY: type = Alarm::Display; break;
1863  case ICAL_ACTION_AUDIO: type = Alarm::Audio; break;
1864  case ICAL_ACTION_PROCEDURE: type = Alarm::Procedure; break;
1865  case ICAL_ACTION_EMAIL: type = Alarm::Email; break;
1866  default:
1867  kdDebug(5800) << "Unknown type of alarm: " << action << endl;
1868 // type = Alarm::Invalid;
1869  }
1870  }
1871  ialarm->setType(type);
1872 // kdDebug(5800) << " alarm type =" << type << endl;
1873 
1874  p = icalcomponent_get_first_property(alarm,ICAL_ANY_PROPERTY);
1875  while (p) {
1876  icalproperty_kind kind = icalproperty_isa(p);
1877 
1878  switch (kind) {
1879 
1880  case ICAL_TRIGGER_PROPERTY: {
1881  icaltriggertype trigger = icalproperty_get_trigger(p);
1882  if (icaltime_is_null_time(trigger.time)) {
1883  if (icaldurationtype_is_null_duration(trigger.duration)) {
1884  kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl;
1885  } else {
1886  Duration duration =
1887 #if ICAL_CHECK_VERSION(4,0,0)
1888  icaldurationtype_as_utc_seconds( trigger.duration );
1889 #else
1890  icaldurationtype_as_int( trigger.duration );
1891 #endif
1892  icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER);
1893  if (param && icalparameter_get_related(param) == ICAL_RELATED_END)
1894  ialarm->setEndOffset(duration);
1895  else
1896  ialarm->setStartOffset(duration);
1897  }
1898  } else {
1899  ialarm->setTime(readICalDateTime(p, trigger.time));
1900  }
1901  break;
1902  }
1903  case ICAL_DURATION_PROPERTY: {
1904  icaldurationtype duration = icalproperty_get_duration(p);
1905  ialarm->setSnoozeTime( readICalDuration( duration ) );
1906  break;
1907  }
1908  case ICAL_REPEAT_PROPERTY:
1909  ialarm->setRepeatCount(icalproperty_get_repeat(p));
1910  break;
1911 
1912  // Only in DISPLAY and EMAIL and PROCEDURE alarms
1913  case ICAL_DESCRIPTION_PROPERTY: {
1914  TQString description = TQString::fromUtf8(icalproperty_get_description(p));
1915  switch ( action ) {
1916  case ICAL_ACTION_DISPLAY:
1917  ialarm->setText( description );
1918  break;
1919  case ICAL_ACTION_PROCEDURE:
1920  ialarm->setProgramArguments( description );
1921  break;
1922  case ICAL_ACTION_EMAIL:
1923  ialarm->setMailText( description );
1924  break;
1925  default:
1926  break;
1927  }
1928  break;
1929  }
1930  // Only in EMAIL alarm
1931  case ICAL_SUMMARY_PROPERTY:
1932  ialarm->setMailSubject(TQString::fromUtf8(icalproperty_get_summary(p)));
1933  break;
1934 
1935  // Only in EMAIL alarm
1936  case ICAL_ATTENDEE_PROPERTY: {
1937  TQString email = TQString::fromUtf8(icalproperty_get_attendee(p));
1938  if ( email.startsWith("mailto:", false ) ) {
1939  email = email.mid( 7 );
1940  }
1941  TQString name;
1942  icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER);
1943  if (param) {
1944  name = TQString::fromUtf8(icalparameter_get_cn(param));
1945  }
1946  ialarm->addMailAddress(Person(name, email));
1947  break;
1948  }
1949  // Only in AUDIO and EMAIL and PROCEDURE alarms
1950  case ICAL_ATTACH_PROPERTY: {
1951  Attachment *attach = readAttachment( p );
1952  if ( attach && attach->isUri() ) {
1953  switch ( action ) {
1954  case ICAL_ACTION_AUDIO:
1955  ialarm->setAudioFile( attach->uri() );
1956  break;
1957  case ICAL_ACTION_PROCEDURE:
1958  ialarm->setProgramFile( attach->uri() );
1959  break;
1960  case ICAL_ACTION_EMAIL:
1961  ialarm->addMailAttachment( attach->uri() );
1962  break;
1963  default:
1964  break;
1965  }
1966  } else {
1967  kdDebug() << "Alarm attachments currently only support URIs, but "
1968  "no binary data" << endl;
1969  }
1970  delete attach;
1971  break;
1972  }
1973  default:
1974  break;
1975  }
1976 
1977  p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY);
1978  }
1979 
1980  // custom properties
1981  readCustomProperties(alarm, ialarm);
1982 
1983  // TODO: check for consistency of alarm properties
1984 }
1985 
1986 icaldatetimeperiodtype ICalFormatImpl::writeICalDatePeriod( const TQDate &date )
1987 {
1988  icaldatetimeperiodtype t;
1989  t.time = writeICalDate( date );
1990  t.period = icalperiodtype_null_period();
1991  return t;
1992 }
1993 
1994 icaldatetimeperiodtype ICalFormatImpl::writeICalDateTimePeriod( const TQDateTime &date )
1995 {
1996  icaldatetimeperiodtype t;
1997  t.time = writeICalDateTime( date );
1998  t.period = icalperiodtype_null_period();
1999  return t;
2000 }
2001 
2002 icaltimetype ICalFormatImpl::writeICalDate(const TQDate &date)
2003 {
2004  icaltimetype t = icaltime_null_time();
2005 
2006  t.year = date.year();
2007  t.month = date.month();
2008  t.day = date.day();
2009 
2010  t.hour = 0;
2011  t.minute = 0;
2012  t.second = 0;
2013 
2014  t.is_date = 1;
2015 #if !ICAL_CHECK_VERSION(3,0,0)
2016  t.is_utc = 0;
2017 #endif
2018  t.zone = 0;
2019 
2020  return t;
2021 }
2022 
2023 icaltimetype ICalFormatImpl::writeICalDateTime(const TQDateTime &datetime)
2024 {
2025  icaltimetype t = icaltime_null_time();
2026 
2027  t.year = datetime.date().year();
2028  t.month = datetime.date().month();
2029  t.day = datetime.date().day();
2030 
2031  t.hour = datetime.time().hour();
2032  t.minute = datetime.time().minute();
2033  t.second = datetime.time().second();
2034 
2035  t.is_date = 0;
2036  t.zone = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
2037 #if !ICAL_CHECK_VERSION(3,0,0)
2038  t.is_utc = 0;
2039 #endif
2040 
2041  // _dumpIcaltime( t );
2042  /* The TQDateTime we get passed in is to be considered in the timezone of
2043  * the current calendar (mParent's), or, if there is none, to be floating.
2044  * In the later case store a floating time, in the former normalize to utc. */
2045  if (mParent->timeZoneId().isEmpty())
2046  t = icaltime_convert_to_zone( t, 0 ); //make floating timezone
2047  else {
2048  icaltimezone* tz = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
2049  icaltimezone* utc = icaltimezone_get_utc_timezone();
2050  if ( tz != utc ) {
2051  t.zone = tz;
2052  t = icaltime_convert_to_zone( t, utc );
2053  } else {
2054 #if !ICAL_CHECK_VERSION(3,0,0)
2055  t.is_utc = 1;
2056 #endif
2057  t.zone = utc;
2058  }
2059  }
2060 // _dumpIcaltime( t );
2061 
2062  return t;
2063 }
2064 
2065 TQDateTime ICalFormatImpl::readICalDateTime( icalproperty *p, icaltimetype& t, icaltimezone* tz )
2066 {
2067 // kdDebug(5800) << "ICalFormatImpl::readICalDateTime()" << endl;
2068 #if ICAL_CHECK_VERSION(3,0,0)
2069  bool time_is_utc = icaltime_is_utc(t);
2070 #else
2071  bool time_is_utc = t.is_utc;
2072 #endif
2073  if ( !time_is_utc ) { // Only use the TZ if time is not UTC.{
2074  // FIXME: We'll need to make sure to apply the appropriate TZ, not just
2075  // the first one found.
2076  icalparameter *param = p ? icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) : 0;
2077  const char *tzid = param ? icalparameter_get_tzid(param) : 0;
2078  if ( tzid ) {
2079  icaltimezone* icaltz;
2080  // Try to match the ID with the libical time zone's location property
2081  icaltz = icaltimezone_get_builtin_timezone( tzid );
2082  if ( icaltz ) {
2083  //kdDebug(5800) << "ICalFormatImpl::readICalDateTime(): time zone '" << tzid << "' read from libical database" << endl;
2084  }
2085  t.zone = icaltz;
2086  }
2087  else {
2088  if (tz && tz != icaltimezone_get_utc_timezone()) {
2089 #if !ICAL_CHECK_VERSION(3,0,0)
2090  t.is_utc = 0;
2091 #endif
2092  t.zone = tz;
2093  }
2094  else {
2095 #if !ICAL_CHECK_VERSION(3,0,0)
2096  t.is_utc = 1;
2097 #endif
2098  t.zone = icaltimezone_get_utc_timezone();
2099  }
2100  }
2101  } else {
2102  t.zone = icaltimezone_get_utc_timezone();
2103  }
2104  //_dumpIcaltime( t );
2105 
2106  // Convert to view time
2107  if ( !mParent->timeZoneId().isEmpty() && t.zone ) {
2108 // kdDebug(5800) << "--- Converting time from: " << icaltimezone_get_tzid( const_cast<icaltimezone*>( t.zone ) ) << " (" << ICalDate2TQDate(t) << ")." << endl;
2109  icaltimezone* viewTimeZone = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
2110  icaltimezone_convert_time( &t, const_cast<icaltimezone*>(t.zone), viewTimeZone );
2111 // kdDebug(5800) << "--- Converted to zone " << mParent->timeZoneId() << " (" << ICalDate2TQDate(t) << ")." << endl;
2112  }
2113 
2114  return ICalDate2TQDate(t);
2115 }
2116 
2117 TQDate ICalFormatImpl::readICalDate(icaltimetype t)
2118 {
2119  return ICalDate2TQDate(t).date();
2120 }
2121 
2122 icaldurationtype ICalFormatImpl::writeICalDuration(int seconds)
2123 {
2124  // should be able to use icaldurationtype_from_int(), except we know
2125  // that some older tools do not properly support weeks. So we never
2126  // set a week duration, only days
2127 
2128  icaldurationtype d;
2129 
2130  d.is_neg = (seconds<0)?1:0;
2131  if (seconds<0) seconds = -seconds;
2132 
2133  d.weeks = 0;
2134  d.days = seconds / gSecondsPerDay;
2135  seconds %= gSecondsPerDay;
2136  d.hours = seconds / gSecondsPerHour;
2137  seconds %= gSecondsPerHour;
2138  d.minutes = seconds / gSecondsPerMinute;
2139  seconds %= gSecondsPerMinute;
2140  d.seconds = seconds;
2141 
2142  return d;
2143 }
2144 
2145 int ICalFormatImpl::readICalDuration(icaldurationtype d)
2146 {
2147  int result = 0;
2148 
2149  result += d.weeks * gSecondsPerWeek;
2150  result += d.days * gSecondsPerDay;
2151  result += d.hours * gSecondsPerHour;
2152  result += d.minutes * gSecondsPerMinute;
2153  result += d.seconds;
2154 
2155  if (d.is_neg) result *= -1;
2156 
2157  return result;
2158 }
2159 
2160 icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal)
2161 {
2162  icalcomponent *calendar;
2163 
2164  // Root component
2165  calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
2166 
2167  icalproperty *p;
2168 
2169  // Product Identifier
2170  p = icalproperty_new_prodid(CalFormat::productId().utf8());
2171  icalcomponent_add_property(calendar,p);
2172 
2173  // TODO: Add time zone
2174 
2175  // iCalendar version (2.0)
2176  p = icalproperty_new_version(const_cast<char *>(_ICAL_VERSION));
2177  icalcomponent_add_property(calendar,p);
2178 
2179  // Custom properties
2180  if( cal != 0 )
2181  writeCustomProperties(calendar, cal);
2182 
2183  return calendar;
2184 }
2185 
2186 
2187 
2188 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
2189 // and break it down from its tree-like format into the dictionary format
2190 // that is used internally in the ICalFormatImpl.
2191 bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar )
2192 {
2193  // this function will populate the caldict dictionary and other event
2194  // lists. It turns vevents into Events and then inserts them.
2195 
2196  if (!calendar) return false;
2197 
2198 // TODO: check for METHOD
2199 
2200  icalproperty *p;
2201 
2202  p = icalcomponent_get_first_property(calendar,ICAL_PRODID_PROPERTY);
2203  if (!p) {
2204  kdDebug(5800) << "No PRODID property found" << endl;
2205  mLoadedProductId = "";
2206  } else {
2207  mLoadedProductId = TQString::fromUtf8(icalproperty_get_prodid(p));
2208 // kdDebug(5800) << "VCALENDAR prodid: '" << mLoadedProductId << "'" << endl;
2209 
2210  delete mCompat;
2211  mCompat = CompatFactory::createCompat( mLoadedProductId );
2212  }
2213 
2214  p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY);
2215  if (!p) {
2216  kdDebug(5800) << "No VERSION property found" << endl;
2217  mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
2218  return false;
2219  } else {
2220  const char *version = icalproperty_get_version(p);
2221  if ( !version ) {
2222  kdDebug(5800) << "No VERSION property found" << endl;
2223  mParent->setException( new ErrorFormat(
2224  ErrorFormat::CalVersionUnknown,
2225  i18n( "No VERSION property found" ) ) );
2226  return false;
2227  }
2228 
2229 // kdDebug(5800) << "VCALENDAR version: '" << version << "'" << endl;
2230 
2231  if (strcmp(version,"1.0") == 0) {
2232  kdDebug(5800) << "Expected iCalendar, got vCalendar" << endl;
2233  mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1,
2234  i18n("Expected iCalendar format")));
2235  return false;
2236  } else if (strcmp(version,"2.0") != 0) {
2237  kdDebug(5800) << "Expected iCalendar, got unknown format" << endl;
2238  mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
2239  return false;
2240  }
2241  }
2242 
2243  // custom properties
2244  readCustomProperties(calendar, cal);
2245 
2246 // TODO: set time zone
2247 
2248  // read a VTIMEZONE if there is one
2249  icalcomponent *ctz =
2250  icalcomponent_get_first_component( calendar, ICAL_VTIMEZONE_COMPONENT );
2251 
2252  // Store all events with a relatedTo property in a list for post-processing
2253  mEventsRelate.clear();
2254  mTodosRelate.clear();
2255  // TODO: make sure that only actually added events go to this lists.
2256 
2257  icalcomponent *c;
2258 
2259  // Iterate through all todos
2260  c = icalcomponent_get_first_component(calendar,ICAL_VTODO_COMPONENT);
2261  while (c) {
2262 // kdDebug(5800) << "----Todo found" << endl;
2263  Todo *todo = readTodo(c);
2264  if (todo) {
2265  if (todo->hasRecurrenceID()) {
2266  TQString originalUid = todo->uid();
2267  todo->setUid(originalUid + TQString("-recur-%1").arg(todo->recurrenceID().toTime_t()));
2268  if (!cal->todo(todo->uid())) {
2269  if ( !cal->addTodo( todo ) ) {
2270  cal->endBatchAdding();
2271  // If the user pressed cancel, return true, it's not an error.
2272  return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
2273  }
2274  if (!cal->event(originalUid)) {
2275  printf("FIXME! [WARNING] Parent for child event does not yet exist!\n");
2276  }
2277  else {
2278  // Add this todo to its parent
2279  cal->todo(originalUid)->addChildIncidence(todo->uid());
2280  // And the parent to the child
2281  todo->addChildIncidence(cal->todo(originalUid)->uid());
2282  }
2283  }
2284  }
2285  else {
2286  if (!cal->todo(todo->uid())) {
2287  if ( !cal->addTodo( todo ) ) {
2288  cal->endBatchAdding();
2289  // If the user pressed cancel, return true, it's not an error.
2290  return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
2291  }
2292  } else {
2293  delete todo;
2294  mTodosRelate.remove( todo );
2295  }
2296  }
2297  }
2298  c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT);
2299  }
2300 
2301  // Iterate through all events
2302  c = icalcomponent_get_first_component(calendar,ICAL_VEVENT_COMPONENT);
2303  while (c) {
2304 // kdDebug(5800) << "----Event found" << endl;
2305  Event *event = readEvent(c, ctz);
2306  if (event) {
2307  if (event->hasRecurrenceID()) {
2308  TQString originalUid = event->uid();
2309  event->setUid(originalUid + TQString("-recur-%1").arg(event->recurrenceID().toTime_t()));
2310  if (!cal->event(event->uid())) {
2311  cal->addEvent(event);
2312  if (!cal->event(originalUid)) {
2313  printf("FIXME! [WARNING] Parent for child event does not yet exist!\n");
2314  }
2315  else {
2316  // Add this event to its parent
2317  cal->event(originalUid)->addChildIncidence(event->uid());
2318  // And the parent to the child
2319  event->addChildIncidence(cal->event(originalUid)->uid());
2320  }
2321  }
2322  }
2323  else {
2324  if (!cal->event(event->uid())) {
2325  if ( !cal->addEvent( event ) ) {
2326  cal->endBatchAdding();
2327  // If the user pressed cancel, return true, it's not an error.
2328  return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
2329  }
2330  } else {
2331  delete event;
2332  mEventsRelate.remove( event );
2333  }
2334  }
2335  }
2336  c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT);
2337  }
2338 
2339  // Iterate through all journals
2340  c = icalcomponent_get_first_component(calendar,ICAL_VJOURNAL_COMPONENT);
2341  while (c) {
2342 // kdDebug(5800) << "----Journal found" << endl;
2343  Journal *journal = readJournal(c);
2344  if (journal) {
2345  if (journal->hasRecurrenceID()) {
2346  TQString originalUid = journal->uid();
2347  journal->setUid(originalUid + TQString("-recur-%1").arg(journal->recurrenceID().toTime_t()));
2348  if (!cal->journal(journal->uid())) {
2349  cal->addJournal(journal);
2350  if (!cal->event(originalUid)) {
2351  printf("FIXME! [WARNING] Parent for child event does not yet exist!\n");
2352  }
2353  else {
2354  // Add this journal to its parent
2355  cal->journal(originalUid)->addChildIncidence(journal->uid());
2356  // And the parent to the child
2357  journal->addChildIncidence(cal->journal(originalUid)->uid());
2358  }
2359  }
2360  }
2361  else {
2362  if (!cal->journal(journal->uid())) {
2363  if ( !cal->addJournal(journal) ) {
2364  cal->endBatchAdding();
2365  // If the user pressed cancel, return true, it's not an error.
2366  return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
2367  }
2368  } else {
2369  delete journal;
2370  }
2371  }
2372  }
2373  c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT);
2374  }
2375 
2376  cal->endBatchAdding();
2377 
2378  // Post-Process list of events with relations, put Event objects in relation
2379  Event::List::ConstIterator eIt;
2380  for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) {
2381  (*eIt)->setRelatedTo( cal->incidence( (*eIt)->relatedToUid() ) );
2382  }
2383  Todo::List::ConstIterator tIt;
2384  for ( tIt = mTodosRelate.begin(); tIt != mTodosRelate.end(); ++tIt ) {
2385  (*tIt)->setRelatedTo( cal->incidence( (*tIt)->relatedToUid() ) );
2386  }
2387 
2388  return true;
2389 }
2390 
2391 TQString ICalFormatImpl::extractErrorProperty(icalcomponent *c)
2392 {
2393 // kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: "
2394 // << icalcomponent_as_ical_string(c) << endl;
2395 
2396  TQString errorMessage;
2397 
2398  icalproperty *error;
2399  error = icalcomponent_get_first_property(c,ICAL_XLICERROR_PROPERTY);
2400  while(error) {
2401  errorMessage += icalproperty_get_xlicerror(error);
2402  errorMessage += "\n";
2403  error = icalcomponent_get_next_property(c,ICAL_XLICERROR_PROPERTY);
2404  }
2405 
2406 // kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " << errorMessage << endl;
2407 
2408  return errorMessage;
2409 }
2410 
2411 #if ICAL_CHECK_VERSION(4,0,0)
2412  #define dumpByData(by_enum,by_string) \
2413  if (r->by[by_enum].size > 0) { \
2414  int index = 0; \
2415  TQString out = by_string; \
2416  while( index < r->by[by_enum].size ) { \
2417  out.append(TQString::number(r->by[by_enum].data[index++]) + " "); \
2418  } \
2419  kdDebug(5800) << out << endl; \
2420  }
2421 #else
2422  #define dumpByData(by_enum,by_string) \
2423  if (r->by_enum[0] != ICAL_RECURRENCE_ARRAY_MAX) { \
2424  int index = 0; \
2425  int i; \
2426  TQString out = by_string; \
2427  while((i = r->by_enum[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { \
2428  out.append(TQString::number(i) + " "); \
2429  } \
2430  kdDebug(5800) << out << endl; \
2431  }
2432 #endif
2433 void ICalFormatImpl::dumpIcalRecurrence(const icalrecurrencetype *r)
2434 {
2435  if (!r)
2436  {
2437  return;
2438  }
2439 
2440  kdDebug(5800) << " Freq: " << r->freq << endl;
2441  kdDebug(5800) << " Until: " << icaltime_as_ical_string(r->until) << endl;
2442  kdDebug(5800) << " Count: " << r->count << endl;
2443 
2444  dumpByData(FIELD_BY_DAY, " By Day: ");
2445  dumpByData(FIELD_BY_MONTH_DAY, " By Month Day: ");
2446  dumpByData(FIELD_BY_YEAR_DAY, " By Year Day: ");
2447  dumpByData(FIELD_BY_MONTH, " By Month: ");
2448  dumpByData(FIELD_BY_SET_POS, " By Set Pos: ");
2449 }
2450 #undef dumpByData
2451 
2452 icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence,
2453  Scheduler::Method method)
2454 {
2455  icalcomponent *message = createCalendarComponent();
2456 
2457  icalproperty_method icalmethod = ICAL_METHOD_NONE;
2458 
2459  switch (method) {
2460  case Scheduler::Publish:
2461  icalmethod = ICAL_METHOD_PUBLISH;
2462  break;
2463  case Scheduler::Request:
2464  icalmethod = ICAL_METHOD_REQUEST;
2465  break;
2466  case Scheduler::Refresh:
2467  icalmethod = ICAL_METHOD_REFRESH;
2468  break;
2469  case Scheduler::Cancel:
2470  icalmethod = ICAL_METHOD_CANCEL;
2471  break;
2472  case Scheduler::Add:
2473  icalmethod = ICAL_METHOD_ADD;
2474  break;
2475  case Scheduler::Reply:
2476  icalmethod = ICAL_METHOD_REPLY;
2477  break;
2478  case Scheduler::Counter:
2479  icalmethod = ICAL_METHOD_COUNTER;
2480  break;
2481  case Scheduler::Declinecounter:
2482  icalmethod = ICAL_METHOD_DECLINECOUNTER;
2483  break;
2484  default:
2485  kdDebug(5800) << "ICalFormat::createScheduleMessage(): Unknow method" << endl;
2486  return message;
2487  }
2488 
2489  icalcomponent_add_property(message,icalproperty_new_method(icalmethod));
2490 
2491  icalcomponent *inc = writeIncidence( incidence, method );
2492  /*
2493  * RFC 2446 states in section 3.4.3 ( REPLY to a VTODO ), that
2494  * a REQUEST-STATUS property has to be present. For the other two, event and
2495  * free busy, it can be there, but is optional. Until we do more
2496  * fine grained handling, assume all is well. Note that this is the
2497  * status of the _request_, not the attendee. Just to avoid confusion.
2498  * - till
2499  */
2500  if ( icalmethod == ICAL_METHOD_REPLY ) {
2501  struct icalreqstattype rst;
2502  rst.code = ICAL_2_0_SUCCESS_STATUS;
2503  rst.desc = 0;
2504  rst.debug = 0;
2505  icalcomponent_add_property( inc, icalproperty_new_requeststatus( rst ) );
2506  }
2507  icalcomponent_add_component( message, inc );
2508 
2509  return message;
2510 }
Provides the main "calendar" object class.
This class represents an alarm notification.
Definition: alarm.h:46
bool hasStartOffset() const
Return whether the alarm is defined in terms of an offset relative to the start of the event.
Definition: alarm.cpp:456
TQString audioFile() const
Return the name of the audio file for the alarm.
Definition: alarm.cpp:164
Duration snoozeTime() const
Get how long the alarm snooze interval is.
Definition: alarm.cpp:362
void setMailSubject(const TQString &mailAlarmSubject)
Set the subject line of the mail.
Definition: alarm.cpp:244
TQString programFile() const
Return the name of the program file to execute when the alarm is triggered.
Definition: alarm.cpp:185
void addMailAttachment(const TQString &mailAttachFile)
Add this filename to the list of files to attach to the email.
Definition: alarm.cpp:274
void setRepeatCount(int alarmRepeatCount)
Set how many times an alarm is to repeat itself after its initial occurrence (w/snoozes).
Definition: alarm.cpp:367
TQString mailSubject() const
Return the subject line of the mail.
Definition: alarm.cpp:252
TQDateTime time() const
Return the date/time when an alarm goes off.
Definition: alarm.cpp:329
TQString text() const
Return the text string that displays when the alarm is triggered.
Definition: alarm.cpp:316
void setEnabled(bool enable)
Set the alarm enabled status.
Definition: alarm.cpp:432
void addMailAddress(const Person &mailAlarmAddress)
Add this address to the list of addresses to send mail to when the alarm is triggered.
Definition: alarm.cpp:231
Duration endOffset() const
Return offset of alarm in time relative to the end of the event.
Definition: alarm.cpp:474
bool hasEndOffset() const
Return whether the alarm is defined in terms of an offset relative to the end of the event.
Definition: alarm.cpp:461
Duration startOffset() const
Return offset of alarm in time relative to the start of the event.
Definition: alarm.cpp:451
void setSnoozeTime(const Duration &alarmSnoozeTime)
Set the interval between snoozes for the alarm.
Definition: alarm.cpp:354
TQString programArguments() const
Return the arguments to the program to run when the alarm is triggered.
Definition: alarm.cpp:198
void setEndOffset(const Duration &)
Set offset of alarm in time relative to the end of the event.
Definition: alarm.cpp:466
void setText(const TQString &text)
Set the text to be displayed when the alarm is triggered.
Definition: alarm.cpp:308
void setProgramArguments(const TQString &arguments)
Set the arguments to the program to execute when the alarm is triggered.
Definition: alarm.cpp:190
TQString mailText() const
Return the email body text.
Definition: alarm.cpp:295
bool hasTime() const
Return true, if the alarm has an explicit date/time.
Definition: alarm.cpp:349
void setStartOffset(const Duration &)
Set offset of alarm in time relative to the start of the event.
Definition: alarm.cpp:443
TQValueList< Person > mailAddresses() const
Return the addresses to send mail to when an alarm goes off.
Definition: alarm.cpp:239
void setTime(const TQDateTime &alarmTime)
Set the time to trigger an alarm.
Definition: alarm.cpp:321
Type type() const
Return the type of the alarm.
Definition: alarm.cpp:144
void setAudioFile(const TQString &audioFile)
Set the file to play when the audio alarm is triggered.
Definition: alarm.cpp:156
void setMailText(const TQString &text)
Set the email body text.
Definition: alarm.cpp:287
void setType(Type type)
Set the type of the alarm.
Definition: alarm.cpp:115
void setProgramFile(const TQString &programFile)
Set the program file to execute when the alarm is triggered.
Definition: alarm.cpp:177
int repeatCount() const
Get how many times an alarm repeats, after its initial occurrence.
Definition: alarm.cpp:373
TQStringList mailAttachments() const
Return the filenames to attach to the email.
Definition: alarm.cpp:282
This class represents information related to an attachment.
Definition: attachment.h:35
This class represents information related to an attendee of an event.
Definition: attendee.h:37
void setDelegator(const TQString &delegator)
Sets the delegator.
Definition: attendee.h:140
void setDelegate(const TQString &delegate)
Sets the delegate.
Definition: attendee.h:131
TQString uid() const
Return unique id of the attendee.
Definition: attendee.cpp:137
TQString delegate() const
Returns the delegate.
Definition: attendee.h:135
Role role() const
Return role of Attendee.
Definition: attendee.cpp:122
TQString delegator() const
Returns the delegator.
Definition: attendee.h:144
bool RSVP() const
Return, if Attendee is asked to reply.
Definition: attendee.h:126
PartStat status() const
Return status.
Definition: attendee.cpp:61
This is the main "calendar" object class.
Definition: calendar.h:171
virtual bool addJournal(Journal *journal)=0
Insert a Journal into the Calendar.
virtual Todo * todo(const TQString &uid)=0
Returns the Todo associated with the given unique identifier.
virtual Event * event(const TQString &uid)=0
Returns the Event associated with the given unique identifier.
virtual bool addEvent(Event *event)=0
Insert an Event into the Calendar.
ErrorFormat * exception() const
Returns an exception, if there is any, containing information about the last error that occurred.
Definition: calendar.cpp:80
virtual Journal * journal(const TQString &uid)=0
Returns the Journal associated with the given unique identifier.
virtual bool addTodo(Todo *todo)=0
Insert a Todo into the Calendar.
Incidence * incidence(const TQString &uid)
Returns the Incidence associated with the given unique identifier.
Definition: calendar.cpp:576
void endBatchAdding()
Emits the endBatchAdding() signal.
Definition: calendar.cpp:149
This class provides compatibility to older (broken) versions of KOrganizer.
Definition: compat.h:46
This class represents custom calendar properties.
void setCustomProperties(const TQMap< TQCString, TQString > &properties)
Initialise the alarm's custom calendar properties to the specified key/value pairs.
TQMap< TQCString, TQString > customProperties() const
Return all custom calendar property key/value pairs.
void setCustomProperty(const TQCString &app, const TQCString &key, const TQString &value)
Create or modify a custom calendar property.
TQString customProperty(const TQCString &app, const TQCString &key) const
Return the value of a custom calendar property.
void removeCustomProperty(const TQCString &app, const TQCString &key)
Delete a custom calendar property.
This class represents a duration.
Definition: duration.h:34
int value() const
Returns the length of the duration in seconds or days.
Definition: duration.cpp:175
int asSeconds() const
Returns the length of the duration in seconds.
Definition: duration.cpp:165
Calendar format related error class.
Definition: exceptions.h:65
ErrorCodeFormat errorCode()
Return format error code.
Definition: exceptions.cpp:101
This class provides an Event in the sense of RFC2445.
Definition: event.h:33
virtual TQDateTime dtEnd() const
Return end date and time.
Definition: event.cpp:85
Transparency transparency() const
Return the event's time transparency level.
Definition: event.cpp:145
bool hasEndDate() const
Return whether the event has an end date/time.
Definition: event.cpp:121
This class provides information about free/busy time of a calendar user.
Definition: freebusy.h:41
void addPeriods(const PeriodList &)
Adds a list of periods to the freebusy object and then sorts that list.
Definition: freebusy.cpp:194
This class implements the iCalendar format.
Definition: icalformat.h:44
This class provides the interface for a visitor of calendar components.
Definition: incidencebase.h:55
virtual bool visit(Event *)
Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on a...
Definition: incidencebase.h:64
This class provides the base class common to all calendar components.
Definition: incidencebase.h:46
void setOrganizer(const Person &o)
sets the organizer for the event
int attendeeCount() const
Return number of attendees.
void setPilotId(unsigned long id)
Set Pilot Id.
unsigned long pilotId() const
Return Pilot Id.
TQStringList comments() const
Return all comments associated with this incidence.
bool doesFloat() const
Return true or false depending on whether the incidence "floats," i.e.
const Attendee::List & attendees() const
Return list of attendees.
TQString uid() const
Return the unique id for the event.
void addComment(const TQString &comment)
Add a comment to this incidence.
void setUid(const TQString &)
Set the unique id for the event.
int syncStatus() const
Return synchronisation status.
virtual TQDateTime dtStart() const
returns an event's starting date/time as a TQDateTime.
virtual bool accept(Visitor &)
Accept IncidenceVisitor.
virtual void setDtStart(const TQDateTime &dtStart)
for setting the event's starting date/time with a TQDateTime.
TQDateTime lastModified() const
Return the time the incidence was last modified.
void setSyncStatus(int status)
Set synchronisation satus.
void setLastModified(const TQDateTime &lm)
Sets the time the incidence was last modified.
void addAttendee(Attendee *attendee, bool doUpdate=true)
Add Attendee to this incidence.
This class provides the base class common to all calendar components.
Definition: incidence.h:48
TQString statusStr() const
Return the event's status string.
Definition: incidence.cpp:762
void addAttachment(Attachment *attachment)
Add attachment.
Definition: incidence.cpp:674
TQString relatedToUid() const
What event does this one relate to? This function should only be used when constructing a calendar be...
Definition: incidence.cpp:340
void setLocation(const TQString &location)
Set the event's/todo's location.
Definition: incidence.cpp:868
const Alarm::List & alarms() const
All alarms that are associated with this incidence.
Definition: incidence.cpp:828
void setSummary(const TQString &summary)
Set short summary.
Definition: incidence.cpp:286
void setCustomStatus(const TQString &status)
Sets the incidence status to a non-standard status value.
Definition: incidence.cpp:749
void setSchedulingID(const TQString &sid)
Set the event's/todo's scheduling ID.
Definition: incidence.cpp:880
Alarm * newAlarm()
Create a new alarm which is associated with this incidence.
Definition: incidence.cpp:833
TQDateTime created() const
Return time and date of creation.
Definition: incidence.cpp:246
int revision() const
Return the number of revisions this event has seen.
Definition: incidence.cpp:259
void setPriority(int priority)
Set the incidences priority.
Definition: incidence.cpp:729
void setSecrecy(int)
Sets secrecy status.
Definition: incidence.cpp:786
int secrecy() const
Return the event's secrecy.
Definition: incidence.cpp:793
IncidenceList childIncidences() const
Returns an EventList of all child incidences.
Definition: incidence.cpp:934
TQString description() const
Return long description.
Definition: incidence.cpp:280
Status
Enumeration for describing an event's status.
Definition: incidence.h:117
TQStringList categories() const
Return categories as a list of strings.
Definition: incidence.cpp:323
void setStatus(Status status)
Sets the incidence status to a standard status value.
Definition: incidence.cpp:741
void setDescription(const TQString &description)
Set the long description.
Definition: incidence.cpp:273
int priority() const
Return priority.
Definition: incidence.cpp:736
Status status() const
Return the event's status.
Definition: incidence.cpp:757
void setFloats(bool f)
Set whether the incidence floats, i.e.
Definition: incidence.cpp:229
void setRelatedToUid(const TQString &)
Point at some other event to which the event relates.
Definition: incidence.cpp:333
bool doesRecur() const
Forward to Recurrence::doesRecur().
Definition: incidence.cpp:416
virtual void setDtStart(const TQDateTime &dtStart)
Set starting date/time.
Definition: incidence.cpp:264
TQString schedulingID() const
Return the event's/todo's scheduling ID.
Definition: incidence.cpp:885
bool hasRecurrenceID() const
Returns true if the incidence has recurrenceID, otherwise return false.
Definition: incidence.cpp:893
TQDateTime recurrenceID() const
Returns the incidence recurrenceID.
Definition: incidence.cpp:908
void setCategories(const TQStringList &categories)
Set categories.
Definition: incidence.cpp:298
TQString location() const
Return the event's/todo's location.
Definition: incidence.cpp:875
Attachment::List attachments() const
Return list of all associated attachments.
Definition: incidence.cpp:695
TQString summary() const
Return short summary.
Definition: incidence.cpp:293
Recurrence * recurrence() const
Return the recurrence rule associated with this incidence.
Definition: incidence.cpp:390
void setRevision(int rev)
Set the number of revisions this event has seen.
Definition: incidence.cpp:251
void addChildIncidence(TQString childIncidence)
Attach a child incidence to a parent incidence.
Definition: incidence.cpp:924
void setCreated(const TQDateTime &)
Set creation date.
Definition: incidence.cpp:237
void setHasRecurrenceID(bool hasRecurrenceID)
Sets if the incidence has recurrenceID.
Definition: incidence.cpp:898
void setRecurrenceID(const TQDateTime &recurrenceID)
Set the incidences recurrenceID.
Definition: incidence.cpp:913
This class provides a Journal in the sense of RFC2445.
Definition: journal.h:34
This class represents a period of time.
Definition: period.h:36
This class represents a person.
Definition: person.h:35
structure for describing the n-th weekday of the month/year.
This class represents a recurrence rule for a calendar incidence.
TQDateTime endDt(bool *result=0) const
Returns the date and time of the last recurrence.
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last.
void setFrequency(int freq)
Sets the frequency of recurrence, in terms of the recurrence time period type.
void setEndDt(const TQDateTime &endDateTime)
Sets the date and time of the last recurrence.
uint frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
bool doesFloat() const
Returns whether the start date has no time associated.
void setStartDt(const TQDateTime &start)
Set start of recurrence, as a date and time.
This class represents a recurrence rule for a calendar incidence.
Definition: recurrence.h:90
Method
iTIP methods.
Definition: scheduler.h:103
This class provides a Todo in the sense of RFC2445.
Definition: todo.h:32
bool hasDueDate() const
Returns true if the todo has a due date, otherwise return false.
Definition: todo.cpp:144
bool isCompleted() const
Returns true if the todo is 100% completed, otherwise return false.
Definition: todo.cpp:217
void setDtRecurrence(const TQDateTime &dt)
Sets the due date/time of the current occurrence if recurrent.
Definition: todo.cpp:279
bool hasStartDate() const
Returns true if the todo has a start date, otherwise return false.
Definition: todo.cpp:157
void setDtDue(const TQDateTime &dtDue, bool first=false)
Sets due date and time.
Definition: todo.cpp:85
void setCompleted(bool completed)
Set completed state.
Definition: todo.cpp:223
TQDateTime dtStart(bool first=false) const
Returns the startdate of the todo.
Definition: todo.cpp:177
TQDateTime completed() const
Returns date and time when todo was completed.
Definition: todo.cpp:235
void setHasStartDate(bool hasStartDate)
Set if the todo has a start date.
Definition: todo.cpp:162
int percentComplete() const
Returns how many percent of the task are completed.
Definition: todo.cpp:263
bool hasCompletedDate() const
Returns true, if todo has a date associated with completion, otherwise return false.
Definition: todo.cpp:258
TQDateTime dtDue(bool first=false) const
Returns due date and time.
Definition: todo.cpp:117
void setHasDueDate(bool hasDueDate)
Set if the todo has a due date.
Definition: todo.cpp:149
void setPercentComplete(int)
Set how many percent of the task are completed.
Definition: todo.cpp:268
Namespace KCal is for global classes, objects and/or functions in libkcal.
Definition: alarm.h:38