libkcal

icalformatimpl.cpp

00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020     Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <qdatetime.h>
00024 #include <qstring.h>
00025 #include <qptrlist.h>
00026 #include <qfile.h>
00027 #include <cstdlib>
00028 
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031 
00032 extern "C" {
00033   #include <ical.h>
00034   #include <icalparser.h>
00035   #include <icalrestriction.h>
00036 }
00037 
00038 #include "calendar.h"
00039 #include "journal.h"
00040 #include "icalformat.h"
00041 #include "icalformatimpl.h"
00042 #include "compat.h"
00043 
00044 #define _ICAL_VERSION "2.0"
00045 
00046 using namespace KCal;
00047 
00048 /* Static helpers */
00049 static QDateTime ICalDate2QDate(const icaltimetype& t)
00050 {
00051   // Outlook sends dates starting from 1601-01-01, but QDate()
00052   // can only handle dates starting 1752-09-14.
00053   const int year = (t.year>=1754) ? t.year : 1754;
00054   return QDateTime(QDate(year,t.month,t.day), QTime(t.hour,t.minute,t.second));
00055 }
00056 
00057 static void _dumpIcaltime( const icaltimetype& t)
00058 {
00059   kdDebug(5800) << "--- Y: " << t.year << " M: " << t.month << " D: " << t.day
00060       << endl;
00061   kdDebug(5800) << "--- H: " << t.hour << " M: " << t.minute << " S: " << t.second
00062       << endl;
00063   kdDebug(5800) << "--- isUtc: " << icaltime_is_utc( t )<< endl;
00064   kdDebug(5800) << "--- zoneId: " << icaltimezone_get_tzid( const_cast<icaltimezone*>( t.zone ) )<< endl;
00065 }
00066 
00067 const int gSecondsPerMinute = 60;
00068 const int gSecondsPerHour   = gSecondsPerMinute * 60;
00069 const int gSecondsPerDay    = gSecondsPerHour   * 24;
00070 const int gSecondsPerWeek   = gSecondsPerDay    * 7;
00071 
00072 ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) :
00073   mParent( parent ), mCompat( new Compat )
00074 {
00075 }
00076 
00077 ICalFormatImpl::~ICalFormatImpl()
00078 {
00079   delete mCompat;
00080 }
00081 
00082 class ICalFormatImpl::ToComponentVisitor : public IncidenceBase::Visitor
00083 {
00084   public:
00085     ToComponentVisitor( ICalFormatImpl *impl, Scheduler::Method m ) : mImpl( impl ), mComponent( 0 ), mMethod( m ) {}
00086 
00087     bool visit( Event *e ) { mComponent = mImpl->writeEvent( e ); return true; }
00088     bool visit( Todo *e ) { mComponent = mImpl->writeTodo( e ); return true; }
00089     bool visit( Journal *e ) { mComponent = mImpl->writeJournal( e ); return true; }
00090     bool visit( FreeBusy *fb ) { mComponent = mImpl->writeFreeBusy( fb, mMethod ); return true; }
00091 
00092     icalcomponent *component() { return mComponent; }
00093 
00094   private:
00095     ICalFormatImpl *mImpl;
00096     icalcomponent *mComponent;
00097     Scheduler::Method mMethod;
00098 };
00099 
00100 icalcomponent *ICalFormatImpl::writeIncidence( IncidenceBase *incidence, Scheduler::Method method )
00101 {
00102   ToComponentVisitor v( this, method );
00103   if ( incidence->accept(v) )
00104     return v.component();
00105   else return 0;
00106 }
00107 
00108 icalcomponent *ICalFormatImpl::writeTodo(Todo *todo)
00109 {
00110   QString tmpStr;
00111   QStringList tmpStrList;
00112 
00113   icalcomponent *vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT);
00114 
00115   writeIncidence(vtodo,todo);
00116 
00117   // due date
00118   if (todo->hasDueDate()) {
00119     icaltimetype due;
00120     if (todo->doesFloat()) {
00121       due = writeICalDate(todo->dtDue(true).date());
00122     } else {
00123       due = writeICalDateTime(todo->dtDue(true));
00124     }
00125     icalcomponent_add_property(vtodo,icalproperty_new_due(due));
00126   }
00127 
00128   // start time
00129   if ( todo->hasStartDate() || todo->doesRecur() ) {
00130     icaltimetype start;
00131     if (todo->doesFloat()) {
00132 //      kdDebug(5800) << " Incidence " << todo->summary() << " floats." << endl;
00133       start = writeICalDate(todo->dtStart(true).date());
00134     } else {
00135 //      kdDebug(5800) << " incidence " << todo->summary() << " has time." << endl;
00136       start = writeICalDateTime(todo->dtStart(true));
00137     }
00138     icalcomponent_add_property(vtodo,icalproperty_new_dtstart(start));
00139   }
00140 
00141   // completion date
00142   if (todo->isCompleted()) {
00143     if (!todo->hasCompletedDate()) {
00144       // If todo was created by KOrganizer <2.2 it has no correct completion
00145       // date. Set it to now.
00146       todo->setCompleted(QDateTime::currentDateTime());
00147     }
00148     icaltimetype completed = writeICalDateTime(todo->completed());
00149     icalcomponent_add_property(vtodo,icalproperty_new_completed(completed));
00150   }
00151 
00152   icalcomponent_add_property(vtodo,
00153       icalproperty_new_percentcomplete(todo->percentComplete()));
00154 
00155   if( todo->doesRecur() ) {
00156     icalcomponent_add_property(vtodo,
00157         icalproperty_new_recurrenceid( writeICalDateTime( todo->dtDue())));
00158   }
00159 
00160   return vtodo;
00161 }
00162 
00163 icalcomponent *ICalFormatImpl::writeEvent(Event *event)
00164 {
00165 #if 0
00166   kdDebug(5800) << "Write Event '" << event->summary() << "' (" << event->uid()
00167                 << ")" << endl;
00168 #endif
00169 
00170   QString tmpStr;
00171   QStringList tmpStrList;
00172 
00173   icalcomponent *vevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
00174 
00175   writeIncidence(vevent,event);
00176 
00177   // start time
00178   icaltimetype start;
00179   if (event->doesFloat()) {
00180 //    kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl;
00181     start = writeICalDate(event->dtStart().date());
00182   } else {
00183 //    kdDebug(5800) << " incidence " << event->summary() << " has time." << endl;
00184     start = writeICalDateTime(event->dtStart());
00185   }
00186   icalcomponent_add_property(vevent,icalproperty_new_dtstart(start));
00187 
00188   if (event->hasEndDate()) {
00189     // End time.
00190     // RFC2445 says that if DTEND is present, it has to be greater than DTSTART.
00191     icaltimetype end;
00192     if (event->doesFloat()) {
00193 //      kdDebug(5800) << " Event " << event->summary() << " floats." << endl;
00194       // +1 day because end date is non-inclusive.
00195       end = writeICalDate( event->dtEnd().date().addDays( 1 ) );
00196       icalcomponent_add_property(vevent,icalproperty_new_dtend(end));
00197     } else {
00198 //      kdDebug(5800) << " Event " << event->summary() << " has time." << endl;
00199       if (event->dtEnd() != event->dtStart()) {
00200         end = writeICalDateTime(event->dtEnd());
00201         icalcomponent_add_property(vevent,icalproperty_new_dtend(end));
00202       }
00203     }
00204   }
00205 
00206 // TODO: resources
00207 #if 0
00208   // resources
00209   tmpStrList = anEvent->resources();
00210   tmpStr = tmpStrList.join(";");
00211   if (!tmpStr.isEmpty())
00212     addPropValue(vevent, VCResourcesProp, tmpStr.utf8());
00213 
00214 #endif
00215 
00216   // Transparency
00217   switch( event->transparency() ) {
00218   case Event::Transparent:
00219     icalcomponent_add_property(
00220       vevent,
00221       icalproperty_new_transp( ICAL_TRANSP_TRANSPARENT ) );
00222     break;
00223   case Event::Opaque:
00224     icalcomponent_add_property(
00225       vevent,
00226       icalproperty_new_transp( ICAL_TRANSP_OPAQUE ) );
00227     break;
00228   }
00229 
00230   return vevent;
00231 }
00232 
00233 icalcomponent *ICalFormatImpl::writeFreeBusy(FreeBusy *freebusy,
00234                                              Scheduler::Method method)
00235 {
00236 #if QT_VERSION >= 300
00237   kdDebug(5800) << "icalformatimpl: writeFreeBusy: startDate: "
00238     << freebusy->dtStart().toString("ddd MMMM d yyyy: h:m:s ap") << " End Date: "
00239     << freebusy->dtEnd().toString("ddd MMMM d yyyy: h:m:s ap") << endl;
00240 #endif
00241 
00242   icalcomponent *vfreebusy = icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
00243 
00244   writeIncidenceBase(vfreebusy,freebusy);
00245 
00246   icalcomponent_add_property(vfreebusy, icalproperty_new_dtstart(
00247       writeICalDateTime(freebusy->dtStart())));
00248 
00249   icalcomponent_add_property(vfreebusy, icalproperty_new_dtend(
00250       writeICalDateTime(freebusy->dtEnd())));
00251 
00252   if (method == Scheduler::Request) {
00253     icalcomponent_add_property(vfreebusy,icalproperty_new_uid(
00254        freebusy->uid().utf8()));
00255   }
00256 
00257   //Loops through all the periods in the freebusy object
00258   QValueList<Period> list = freebusy->busyPeriods();
00259   QValueList<Period>::Iterator it;
00260   icalperiodtype period = icalperiodtype_null_period();
00261   for (it = list.begin(); it!= list.end(); ++it) {
00262     period.start = writeICalDateTime((*it).start());
00263     if ( (*it).hasDuration() ) {
00264       period.duration = writeICalDuration( (*it).duration().asSeconds() );
00265     } else {
00266       period.end = writeICalDateTime((*it).end());
00267     }
00268     icalcomponent_add_property(vfreebusy, icalproperty_new_freebusy(period) );
00269   }
00270 
00271   return vfreebusy;
00272 }
00273 
00274 icalcomponent *ICalFormatImpl::writeJournal(Journal *journal)
00275 {
00276   icalcomponent *vjournal = icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
00277 
00278   writeIncidence(vjournal,journal);
00279 
00280   // start time
00281   if (journal->dtStart().isValid()) {
00282     icaltimetype start;
00283     if (journal->doesFloat()) {
00284 //      kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl;
00285       start = writeICalDate(journal->dtStart().date());
00286     } else {
00287 //      kdDebug(5800) << " incidence " << event->summary() << " has time." << endl;
00288       start = writeICalDateTime(journal->dtStart());
00289     }
00290     icalcomponent_add_property(vjournal,icalproperty_new_dtstart(start));
00291   }
00292 
00293   return vjournal;
00294 }
00295 
00296 void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence)
00297 {
00298   // pilot sync stuff
00299 // TODO: move this application-specific code to kpilot
00300   if (incidence->pilotId()) {
00301     // NOTE: we can't do setNonKDECustomProperty here because this changes
00302     // data and triggers an updated() event...
00303     // incidence->setNonKDECustomProperty("X-PILOTSTAT", QString::number(incidence->syncStatus()));
00304     // incidence->setNonKDECustomProperty("X-PILOTID", QString::number(incidence->pilotId()));
00305 
00306     icalproperty *p = 0;
00307     p = icalproperty_new_x(QString::number(incidence->syncStatus()).utf8());
00308     icalproperty_set_x_name(p,"X-PILOTSTAT");
00309     icalcomponent_add_property(parent,p);
00310 
00311     p = icalproperty_new_x(QString::number(incidence->pilotId()).utf8());
00312     icalproperty_set_x_name(p,"X-PILOTID");
00313     icalcomponent_add_property(parent,p);
00314   }
00315 
00316   if ( incidence->schedulingID() != incidence->uid() )
00317     // We need to store the UID in here. The rawSchedulingID will
00318     // go into the iCal UID component
00319     incidence->setCustomProperty( "LIBKCAL", "ID", incidence->uid() );
00320   else
00321     incidence->removeCustomProperty( "LIBKCAL", "ID" );
00322 
00323   writeIncidenceBase(parent,incidence);
00324 
00325   // creation date
00326   icalcomponent_add_property(parent,icalproperty_new_created(
00327       writeICalDateTime(incidence->created())));
00328 
00329   // unique id
00330   // If the scheduling ID is different from the real UID, the real
00331   // one is stored on X-REALID above
00332   if ( !incidence->schedulingID().isEmpty() ) {
00333     icalcomponent_add_property(parent,icalproperty_new_uid(
00334         incidence->schedulingID().utf8()));
00335   }
00336 
00337   // revision
00338   if ( incidence->revision() > 0 ) { // 0 is default, so don't write that out
00339     icalcomponent_add_property(parent,icalproperty_new_sequence(
00340         incidence->revision()));
00341   }
00342 
00343   // last modification date
00344   if ( incidence->lastModified().isValid() ) {
00345    icalcomponent_add_property(parent,icalproperty_new_lastmodified(
00346        writeICalDateTime(incidence->lastModified())));
00347   }
00348 
00349   // description
00350   if (!incidence->description().isEmpty()) {
00351     icalcomponent_add_property(parent,icalproperty_new_description(
00352         incidence->description().utf8()));
00353   }
00354 
00355   // summary
00356   if (!incidence->summary().isEmpty()) {
00357     icalcomponent_add_property(parent,icalproperty_new_summary(
00358         incidence->summary().utf8()));
00359   }
00360 
00361   // location
00362   if (!incidence->location().isEmpty()) {
00363     icalcomponent_add_property(parent,icalproperty_new_location(
00364         incidence->location().utf8()));
00365   }
00366 
00367   // status
00368   icalproperty_status status = ICAL_STATUS_NONE;
00369   switch (incidence->status()) {
00370     case Incidence::StatusTentative:    status = ICAL_STATUS_TENTATIVE;  break;
00371     case Incidence::StatusConfirmed:    status = ICAL_STATUS_CONFIRMED;  break;
00372     case Incidence::StatusCompleted:    status = ICAL_STATUS_COMPLETED;  break;
00373     case Incidence::StatusNeedsAction:  status = ICAL_STATUS_NEEDSACTION;  break;
00374     case Incidence::StatusCanceled:     status = ICAL_STATUS_CANCELLED;  break;
00375     case Incidence::StatusInProcess:    status = ICAL_STATUS_INPROCESS;  break;
00376     case Incidence::StatusDraft:        status = ICAL_STATUS_DRAFT;  break;
00377     case Incidence::StatusFinal:        status = ICAL_STATUS_FINAL;  break;
00378     case Incidence::StatusX: {
00379       icalproperty* p = icalproperty_new_status(ICAL_STATUS_X);
00380       icalvalue_set_x(icalproperty_get_value(p), incidence->statusStr().utf8());
00381       icalcomponent_add_property(parent, p);
00382       break;
00383     }
00384     case Incidence::StatusNone:
00385     default:
00386       break;
00387   }
00388   if (status != ICAL_STATUS_NONE)
00389     icalcomponent_add_property(parent, icalproperty_new_status(status));
00390 
00391   // secrecy
00392   icalproperty_class secClass;
00393   switch (incidence->secrecy()) {
00394     case Incidence::SecrecyPublic:
00395       secClass = ICAL_CLASS_PUBLIC;
00396       break;
00397     case Incidence::SecrecyConfidential:
00398       secClass = ICAL_CLASS_CONFIDENTIAL;
00399       break;
00400     case Incidence::SecrecyPrivate:
00401     default:
00402       secClass = ICAL_CLASS_PRIVATE;
00403       break;
00404   }
00405   if ( secClass != ICAL_CLASS_PUBLIC ) {
00406     icalcomponent_add_property(parent,icalproperty_new_class(secClass));
00407   }
00408 
00409   // priority
00410   if ( incidence->priority() > 0 ) { // 0 is undefined priority
00411     icalcomponent_add_property(parent,icalproperty_new_priority(
00412         incidence->priority()));
00413   }
00414 
00415   // categories
00416   QStringList categories = incidence->categories();
00417   QStringList::Iterator it;
00418   for(it = categories.begin(); it != categories.end(); ++it ) {
00419     icalcomponent_add_property(parent,icalproperty_new_categories((*it).utf8()));
00420   }
00421 
00422   // related event
00423   if ( !incidence->relatedToUid().isEmpty() ) {
00424     icalcomponent_add_property(parent,icalproperty_new_relatedto(
00425         incidence->relatedToUid().utf8()));
00426   }
00427 
00428 //   kdDebug(5800) << "Write recurrence for '" << incidence->summary() << "' (" << incidence->uid()
00429 //             << ")" << endl;
00430 
00431   RecurrenceRule::List rrules( incidence->recurrence()->rRules() );
00432   RecurrenceRule::List::ConstIterator rit;
00433   for ( rit = rrules.begin(); rit != rrules.end(); ++rit ) {
00434     icalcomponent_add_property( parent, icalproperty_new_rrule(
00435                                 writeRecurrenceRule( (*rit) ) ) );
00436   }
00437 
00438   RecurrenceRule::List exrules( incidence->recurrence()->exRules() );
00439   RecurrenceRule::List::ConstIterator exit;
00440   for ( exit = exrules.begin(); exit != exrules.end(); ++exit ) {
00441     icalcomponent_add_property( parent, icalproperty_new_rrule(
00442                                 writeRecurrenceRule( (*exit) ) ) );
00443   }
00444 
00445   DateList dateList = incidence->recurrence()->exDates();
00446   DateList::ConstIterator exIt;
00447   for(exIt = dateList.begin(); exIt != dateList.end(); ++exIt) {
00448     icalcomponent_add_property(parent,icalproperty_new_exdate(
00449         writeICalDate(*exIt)));
00450   }
00451   DateTimeList dateTimeList = incidence->recurrence()->exDateTimes();
00452   DateTimeList::ConstIterator extIt;
00453   for(extIt = dateTimeList.begin(); extIt != dateTimeList.end(); ++extIt) {
00454     icalcomponent_add_property(parent,icalproperty_new_exdate(
00455         writeICalDateTime(*extIt)));
00456   }
00457 
00458 
00459   dateList = incidence->recurrence()->rDates();
00460   DateList::ConstIterator rdIt;
00461   for( rdIt = dateList.begin(); rdIt != dateList.end(); ++rdIt) {
00462      icalcomponent_add_property( parent, icalproperty_new_rdate(
00463          writeICalDatePeriod(*rdIt) ) );
00464   }
00465   dateTimeList = incidence->recurrence()->rDateTimes();
00466   DateTimeList::ConstIterator rdtIt;
00467   for( rdtIt = dateTimeList.begin(); rdtIt != dateTimeList.end(); ++rdtIt) {
00468      icalcomponent_add_property( parent, icalproperty_new_rdate(
00469          writeICalDateTimePeriod(*rdtIt) ) );
00470   }
00471 
00472   // attachments
00473   Attachment::List attachments = incidence->attachments();
00474   Attachment::List::ConstIterator atIt;
00475   for ( atIt = attachments.begin(); atIt != attachments.end(); ++atIt ) {
00476     icalcomponent_add_property( parent, writeAttachment( *atIt ) );
00477   }
00478 
00479   // alarms
00480   Alarm::List::ConstIterator alarmIt;
00481   for ( alarmIt = incidence->alarms().begin();
00482         alarmIt != incidence->alarms().end(); ++alarmIt ) {
00483     if ( (*alarmIt)->enabled() ) {
00484 //      kdDebug(5800) << "Write alarm for " << incidence->summary() << endl;
00485       icalcomponent_add_component( parent, writeAlarm( *alarmIt ) );
00486     }
00487   }
00488 
00489   // duration
00490   if (incidence->hasDuration()) {
00491     icaldurationtype duration;
00492     duration = writeICalDuration( incidence->duration() );
00493     icalcomponent_add_property(parent,icalproperty_new_duration(duration));
00494   }
00495 }
00496 
00497 void ICalFormatImpl::writeIncidenceBase( icalcomponent *parent,
00498                                          IncidenceBase * incidenceBase )
00499 {
00500   icalcomponent_add_property( parent, icalproperty_new_dtstamp(
00501       writeICalDateTime( QDateTime::currentDateTime() ) ) );
00502 
00503   // organizer stuff
00504   if ( !incidenceBase->organizer().isEmpty() ) {
00505     icalcomponent_add_property( parent, writeOrganizer( incidenceBase->organizer() ) );
00506   }
00507 
00508   // attendees
00509   if ( incidenceBase->attendeeCount() > 0 ) {
00510     Attendee::List::ConstIterator it;
00511     for( it = incidenceBase->attendees().begin();
00512          it != incidenceBase->attendees().end(); ++it ) {
00513       icalcomponent_add_property( parent, writeAttendee( *it ) );
00514     }
00515   }
00516 
00517   // comments
00518   QStringList comments = incidenceBase->comments();
00519   for (QStringList::Iterator it=comments.begin(); it!=comments.end(); ++it) {
00520     icalcomponent_add_property(parent, icalproperty_new_comment((*it).utf8()));
00521   }
00522 
00523   // custom properties
00524   writeCustomProperties( parent, incidenceBase );
00525 }
00526 
00527 void ICalFormatImpl::writeCustomProperties(icalcomponent *parent,CustomProperties *properties)
00528 {
00529   QMap<QCString, QString> custom = properties->customProperties();
00530   for (QMap<QCString, QString>::Iterator c = custom.begin();  c != custom.end();  ++c) {
00531     icalproperty *p = icalproperty_new_x(c.data().utf8());
00532     icalproperty_set_x_name(p,c.key());
00533     icalcomponent_add_property(parent,p);
00534   }
00535 }
00536 
00537 icalproperty *ICalFormatImpl::writeOrganizer( const Person &organizer )
00538 {
00539   icalproperty *p = icalproperty_new_organizer("MAILTO:" + organizer.email().utf8());
00540 
00541   if (!organizer.name().isEmpty()) {
00542     icalproperty_add_parameter( p, icalparameter_new_cn(organizer.name().utf8()) );
00543   }
00544   // TODO: Write dir, sent-by and language
00545 
00546   return p;
00547 }
00548 
00549 
00550 icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee)
00551 {
00552   icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8());
00553 
00554   if (!attendee->name().isEmpty()) {
00555     icalproperty_add_parameter(p,icalparameter_new_cn(attendee->name().utf8()));
00556   }
00557 
00558 
00559   icalproperty_add_parameter(p,icalparameter_new_rsvp(
00560           attendee->RSVP() ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE ));
00561 
00562   icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
00563   switch (attendee->status()) {
00564     default:
00565     case Attendee::NeedsAction:
00566       status = ICAL_PARTSTAT_NEEDSACTION;
00567       break;
00568     case Attendee::Accepted:
00569       status = ICAL_PARTSTAT_ACCEPTED;
00570       break;
00571     case Attendee::Declined:
00572       status = ICAL_PARTSTAT_DECLINED;
00573       break;
00574     case Attendee::Tentative:
00575       status = ICAL_PARTSTAT_TENTATIVE;
00576       break;
00577     case Attendee::Delegated:
00578       status = ICAL_PARTSTAT_DELEGATED;
00579       break;
00580     case Attendee::Completed:
00581       status = ICAL_PARTSTAT_COMPLETED;
00582       break;
00583     case Attendee::InProcess:
00584       status = ICAL_PARTSTAT_INPROCESS;
00585       break;
00586   }
00587   icalproperty_add_parameter(p,icalparameter_new_partstat(status));
00588 
00589   icalparameter_role role = ICAL_ROLE_REQPARTICIPANT;
00590   switch (attendee->role()) {
00591     case Attendee::Chair:
00592       role = ICAL_ROLE_CHAIR;
00593       break;
00594     default:
00595     case Attendee::ReqParticipant:
00596       role = ICAL_ROLE_REQPARTICIPANT;
00597       break;
00598     case Attendee::OptParticipant:
00599       role = ICAL_ROLE_OPTPARTICIPANT;
00600       break;
00601     case Attendee::NonParticipant:
00602       role = ICAL_ROLE_NONPARTICIPANT;
00603       break;
00604   }
00605   icalproperty_add_parameter(p,icalparameter_new_role(role));
00606 
00607   if (!attendee->uid().isEmpty()) {
00608     icalparameter* icalparameter_uid = icalparameter_new_x(attendee->uid().utf8());
00609     icalparameter_set_xname(icalparameter_uid,"X-UID");
00610     icalproperty_add_parameter(p,icalparameter_uid);
00611   }
00612 
00613   if ( !attendee->delegate().isEmpty() ) {
00614     icalparameter* icalparameter_delegate = icalparameter_new_delegatedto( attendee->delegate().utf8() );
00615     icalproperty_add_parameter( p, icalparameter_delegate );
00616   }
00617 
00618   if ( !attendee->delegator().isEmpty() ) {
00619     icalparameter* icalparameter_delegator = icalparameter_new_delegatedfrom( attendee->delegator().utf8() );
00620     icalproperty_add_parameter( p, icalparameter_delegator );
00621   }
00622 
00623   return p;
00624 }
00625 
00626 icalproperty *ICalFormatImpl::writeAttachment(Attachment *att)
00627 {
00628   icalattach *attach;
00629   if (att->isUri())
00630       attach = icalattach_new_from_url( att->uri().utf8().data());
00631   else
00632       attach = icalattach_new_from_data ( (unsigned char *)att->data(), 0, 0);
00633   icalproperty *p = icalproperty_new_attach(attach);
00634 
00635   if ( !att->mimeType().isEmpty() ) {
00636     icalproperty_add_parameter( p,
00637         icalparameter_new_fmttype( att->mimeType().utf8().data() ) );
00638   }
00639 
00640   if ( att->isBinary() ) {
00641     icalproperty_add_parameter( p,
00642         icalparameter_new_value( ICAL_VALUE_BINARY ) );
00643     icalproperty_add_parameter( p,
00644         icalparameter_new_encoding( ICAL_ENCODING_BASE64 ) );
00645   }
00646 
00647   if ( att->showInline() ) {
00648     icalparameter* icalparameter_inline = icalparameter_new_x( "inline" );
00649     icalparameter_set_xname( icalparameter_inline, "X-CONTENT-DISPOSITION" );
00650     icalproperty_add_parameter( p, icalparameter_inline );
00651   }
00652 
00653   if ( !att->label().isEmpty() ) {
00654     icalparameter* icalparameter_label = icalparameter_new_x( att->label().utf8() );
00655     icalparameter_set_xname( icalparameter_label, "X-LABEL" );
00656     icalproperty_add_parameter( p, icalparameter_label );
00657   }
00658 
00659   return p;
00660 }
00661 
00662 icalrecurrencetype ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur )
00663 {
00664 //  kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl;
00665 
00666   icalrecurrencetype r;
00667   icalrecurrencetype_clear(&r);
00668 
00669   switch( recur->recurrenceType() ) {
00670     case RecurrenceRule::rSecondly:
00671       r.freq = ICAL_SECONDLY_RECURRENCE;
00672       break;
00673     case RecurrenceRule::rMinutely:
00674       r.freq = ICAL_MINUTELY_RECURRENCE;
00675       break;
00676     case RecurrenceRule::rHourly:
00677       r.freq = ICAL_HOURLY_RECURRENCE;
00678       break;
00679     case RecurrenceRule::rDaily:
00680       r.freq = ICAL_DAILY_RECURRENCE;
00681       break;
00682     case RecurrenceRule::rWeekly:
00683       r.freq = ICAL_WEEKLY_RECURRENCE;
00684       break;
00685     case RecurrenceRule::rMonthly:
00686       r.freq = ICAL_MONTHLY_RECURRENCE;
00687       break;
00688     case RecurrenceRule::rYearly:
00689       r.freq = ICAL_YEARLY_RECURRENCE;
00690       break;
00691     default:
00692       r.freq = ICAL_NO_RECURRENCE;
00693       kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl;
00694       break;
00695   }
00696 
00697   int index = 0;
00698   QValueList<int> bys;
00699   QValueList<int>::ConstIterator it;
00700 
00701   // Now write out the BY* parts:
00702   bys = recur->bySeconds();
00703   index = 0;
00704   for ( it = bys.begin(); it != bys.end(); ++it ) {
00705     r.by_second[index++] = *it;
00706   }
00707 
00708   bys = recur->byMinutes();
00709   index = 0;
00710   for ( it = bys.begin(); it != bys.end(); ++it ) {
00711     r.by_minute[index++] = *it;
00712   }
00713 
00714   bys = recur->byHours();
00715   index = 0;
00716   for ( it = bys.begin(); it != bys.end(); ++it ) {
00717     r.by_hour[index++] = *it;
00718   }
00719 
00720   bys = recur->byMonthDays();
00721   index = 0;
00722   for ( it = bys.begin(); it != bys.end(); ++it ) {
00723     r.by_month_day[index++] = icalrecurrencetype_day_position( (*it) * 8 );
00724   }
00725 
00726   bys = recur->byYearDays();
00727   index = 0;
00728   for ( it = bys.begin(); it != bys.end(); ++it ) {
00729     r.by_year_day[index++] = *it;
00730   }
00731 
00732   bys = recur->byWeekNumbers();
00733   index = 0;
00734   for ( it = bys.begin(); it != bys.end(); ++it ) {
00735      r.by_week_no[index++] = *it;
00736   }
00737 
00738   bys = recur->byMonths();
00739   index = 0;
00740   for ( it = bys.begin(); it != bys.end(); ++it ) {
00741     r.by_month[index++] = *it;
00742   }
00743 
00744   bys = recur->bySetPos();
00745   index = 0;
00746   for ( it = bys.begin(); it != bys.end(); ++it ) {
00747      r.by_set_pos[index++] = *it;
00748   }
00749 
00750 
00751   QValueList<RecurrenceRule::WDayPos> byd = recur->byDays();
00752   int day;
00753   index = 0;
00754   for ( QValueList<RecurrenceRule::WDayPos>::ConstIterator dit = byd.begin();
00755         dit != byd.end(); ++dit ) {
00756     day = (*dit).day() % 7 + 1;     // convert from Monday=1 to Sunday=1
00757     if ( (*dit).pos() < 0 ) {
00758       day += (-(*dit).pos())*8;
00759       day = -day;
00760     } else {
00761       day += (*dit).pos()*8;
00762     }
00763     r.by_day[index++] = day;
00764   }
00765 
00766   r.week_start = static_cast<icalrecurrencetype_weekday>(
00767                                              recur->weekStart()%7 + 1);
00768 
00769   if ( recur->frequency() > 1 ) {
00770     // Dont' write out INTERVAL=1, because that's the default anyway
00771     r.interval = recur->frequency();
00772   }
00773 
00774   if ( recur->duration() > 0 ) {
00775     r.count = recur->duration();
00776   } else if ( recur->duration() == -1 ) {
00777     r.count = 0;
00778   } else {
00779     if ( recur->doesFloat() )
00780       r.until = writeICalDate(recur->endDt().date());
00781     else
00782       r.until = writeICalDateTime(recur->endDt());
00783   }
00784 
00785 // Debug output
00786 #if 0
00787   const char *str = icalrecurrencetype_as_string(&r);
00788   if (str) {
00789     kdDebug(5800) << " String: " << str << endl;
00790   } else {
00791     kdDebug(5800) << " No String" << endl;
00792   }
00793 #endif
00794 
00795   return r;
00796 }
00797 
00798 
00799 icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
00800 {
00801 // kdDebug(5800) << " ICalFormatImpl::writeAlarm" << endl;
00802   icalcomponent *a = icalcomponent_new(ICAL_VALARM_COMPONENT);
00803 
00804   icalproperty_action action;
00805   icalattach *attach = 0;
00806 
00807   switch (alarm->type()) {
00808     case Alarm::Procedure:
00809       action = ICAL_ACTION_PROCEDURE;
00810       attach = icalattach_new_from_url(QFile::encodeName(alarm->programFile()).data());
00811       icalcomponent_add_property(a,icalproperty_new_attach(attach));
00812       if (!alarm->programArguments().isEmpty()) {
00813         icalcomponent_add_property(a,icalproperty_new_description(alarm->programArguments().utf8()));
00814       }
00815       break;
00816     case Alarm::Audio:
00817       action = ICAL_ACTION_AUDIO;
00818 // kdDebug(5800) << " It's an audio action, file: " << alarm->audioFile() << endl;
00819       if (!alarm->audioFile().isEmpty()) {
00820         attach = icalattach_new_from_url(QFile::encodeName( alarm->audioFile() ).data());
00821         icalcomponent_add_property(a,icalproperty_new_attach(attach));
00822       }
00823       break;
00824     case Alarm::Email: {
00825       action = ICAL_ACTION_EMAIL;
00826       QValueList<Person> addresses = alarm->mailAddresses();
00827       for (QValueList<Person>::Iterator ad = addresses.begin();  ad != addresses.end();  ++ad) {
00828         icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8());
00829         if (!(*ad).name().isEmpty()) {
00830           icalproperty_add_parameter(p,icalparameter_new_cn((*ad).name().utf8()));
00831         }
00832         icalcomponent_add_property(a,p);
00833       }
00834       icalcomponent_add_property(a,icalproperty_new_summary(alarm->mailSubject().utf8()));
00835       icalcomponent_add_property(a,icalproperty_new_description(alarm->mailText().utf8()));
00836       QStringList attachments = alarm->mailAttachments();
00837       if (attachments.count() > 0) {
00838         for (QStringList::Iterator at = attachments.begin();  at != attachments.end();  ++at) {
00839           attach = icalattach_new_from_url(QFile::encodeName( *at ).data());
00840           icalcomponent_add_property(a,icalproperty_new_attach(attach));
00841         }
00842       }
00843       break;
00844     }
00845     case Alarm::Display:
00846       action = ICAL_ACTION_DISPLAY;
00847       icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8()));
00848       break;
00849     case Alarm::Invalid:
00850     default:
00851       kdDebug(5800) << "Unknown type of alarm" << endl;
00852       action = ICAL_ACTION_NONE;
00853       break;
00854   }
00855   icalcomponent_add_property(a,icalproperty_new_action(action));
00856 
00857   // Trigger time
00858   icaltriggertype trigger;
00859   if ( alarm->hasTime() ) {
00860     trigger.time = writeICalDateTime(alarm->time());
00861     trigger.duration = icaldurationtype_null_duration();
00862   } else {
00863     trigger.time = icaltime_null_time();
00864     Duration offset;
00865     if ( alarm->hasStartOffset() )
00866       offset = alarm->startOffset();
00867     else
00868       offset = alarm->endOffset();
00869     trigger.duration = icaldurationtype_from_int( offset.asSeconds() );
00870   }
00871   icalproperty *p = icalproperty_new_trigger(trigger);
00872   if ( alarm->hasEndOffset() )
00873     icalproperty_add_parameter(p,icalparameter_new_related(ICAL_RELATED_END));
00874   icalcomponent_add_property(a,p);
00875 
00876   // Repeat count and duration
00877   if (alarm->repeatCount()) {
00878     icalcomponent_add_property(a,icalproperty_new_repeat(alarm->repeatCount()));
00879     icalcomponent_add_property(a,icalproperty_new_duration(
00880                              icaldurationtype_from_int(alarm->snoozeTime()*60)));
00881   }
00882 
00883   // Custom properties
00884   QMap<QCString, QString> custom = alarm->customProperties();
00885   for (QMap<QCString, QString>::Iterator c = custom.begin();  c != custom.end();  ++c) {
00886     icalproperty *p = icalproperty_new_x(c.data().utf8());
00887     icalproperty_set_x_name(p,c.key());
00888     icalcomponent_add_property(a,p);
00889   }
00890 
00891   return a;
00892 }
00893 
00894 Todo *ICalFormatImpl::readTodo(icalcomponent *vtodo)
00895 {
00896   Todo *todo = new Todo;
00897 
00898   readIncidence(vtodo, 0, todo); // FIXME timezone
00899 
00900   icalproperty *p = icalcomponent_get_first_property(vtodo,ICAL_ANY_PROPERTY);
00901 
00902 //  int intvalue;
00903   icaltimetype icaltime;
00904 
00905   QStringList categories;
00906 
00907   while (p) {
00908     icalproperty_kind kind = icalproperty_isa(p);
00909     switch (kind) {
00910 
00911       case ICAL_DUE_PROPERTY:  // due date
00912         icaltime = icalproperty_get_due(p);
00913         if (icaltime.is_date) {
00914           todo->setDtDue(QDateTime(readICalDate(icaltime),QTime(0,0,0)),true);
00915         } else {
00916           todo->setDtDue(readICalDateTime(icaltime),true);
00917           todo->setFloats(false);
00918         }
00919         todo->setHasDueDate(true);
00920         break;
00921 
00922       case ICAL_COMPLETED_PROPERTY:  // completion date
00923         icaltime = icalproperty_get_completed(p);
00924         todo->setCompleted(readICalDateTime(icaltime));
00925         break;
00926 
00927       case ICAL_PERCENTCOMPLETE_PROPERTY:  // Percent completed
00928         todo->setPercentComplete(icalproperty_get_percentcomplete(p));
00929         break;
00930 
00931       case ICAL_RELATEDTO_PROPERTY:  // related todo (parent)
00932         todo->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
00933         mTodosRelate.append(todo);
00934         break;
00935 
00936       case ICAL_DTSTART_PROPERTY: {
00937         // Flag that todo has start date. Value is read in by readIncidence().
00938         if ( todo->comments().grep("NoStartDate").count() )
00939           todo->setHasStartDate( false );
00940         else
00941           todo->setHasStartDate( true );
00942         break;
00943       }
00944 
00945       case ICAL_RECURRENCEID_PROPERTY:
00946         icaltime = icalproperty_get_recurrenceid(p);
00947         todo->setDtRecurrence( readICalDateTime(icaltime) );
00948         break;
00949 
00950       default:
00951 //        kdDebug(5800) << "ICALFormat::readTodo(): Unknown property: " << kind
00952 //                  << endl;
00953         break;
00954     }
00955 
00956     p = icalcomponent_get_next_property(vtodo,ICAL_ANY_PROPERTY);
00957   }
00958 
00959   if (mCompat) mCompat->fixEmptySummary( todo );
00960 
00961   return todo;
00962 }
00963 
00964 Event *ICalFormatImpl::readEvent( icalcomponent *vevent, icalcomponent *vtimezone )
00965 {
00966   Event *event = new Event;
00967 
00968   // FIXME where is this freed?
00969   icaltimezone *tz = icaltimezone_new();
00970   if ( !icaltimezone_set_component( tz, vtimezone ) ) {
00971     icaltimezone_free( tz, 1 );
00972     tz = 0;
00973   }
00974 
00975   readIncidence( vevent, tz, event);
00976 
00977   icalproperty *p = icalcomponent_get_first_property(vevent,ICAL_ANY_PROPERTY);
00978 
00979 //  int intvalue;
00980   icaltimetype icaltime;
00981 
00982   QStringList categories;
00983   icalproperty_transp transparency;
00984 
00985   bool dtEndProcessed = false;
00986 
00987   while (p) {
00988     icalproperty_kind kind = icalproperty_isa(p);
00989     switch (kind) {
00990 
00991       case ICAL_DTEND_PROPERTY:  // start date and time
00992         icaltime = icalproperty_get_dtend(p);
00993         if (icaltime.is_date) {
00994           // End date is non-inclusive
00995           QDate endDate = readICalDate( icaltime ).addDays( -1 );
00996           if ( mCompat ) mCompat->fixFloatingEnd( endDate );
00997           if ( endDate < event->dtStart().date() ) {
00998             endDate = event->dtStart().date();
00999           }
01000           event->setDtEnd( QDateTime( endDate, QTime( 0, 0, 0 ) ) );
01001         } else {
01002           event->setDtEnd(readICalDateTime(icaltime, tz));
01003           event->setFloats( false );
01004         }
01005         dtEndProcessed = true;
01006         break;
01007 
01008       case ICAL_RELATEDTO_PROPERTY:  // related event (parent)
01009         event->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
01010         mEventsRelate.append(event);
01011         break;
01012 
01013 
01014       case ICAL_TRANSP_PROPERTY:  // Transparency
01015         transparency = icalproperty_get_transp(p);
01016         if( transparency == ICAL_TRANSP_TRANSPARENT )
01017           event->setTransparency( Event::Transparent );
01018         else
01019           event->setTransparency( Event::Opaque );
01020         break;
01021 
01022       default:
01023 //        kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind
01024 //                  << endl;
01025         break;
01026     }
01027 
01028     p = icalcomponent_get_next_property(vevent,ICAL_ANY_PROPERTY);
01029   }
01030 
01031   // according to rfc2445 the dtend shouldn't be written when it equals
01032   // start date. so assign one equal to start date.
01033   if ( !dtEndProcessed && !event->hasDuration() ) {
01034     event->setDtEnd( event->dtStart() );
01035   }
01036 
01037   QString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT");
01038   if (!msade.isNull()) {
01039     bool floats = (msade == QString::fromLatin1("TRUE"));
01040 //    kdDebug(5800) << "ICALFormat::readEvent(): all day event: " << floats << endl;
01041     event->setFloats(floats);
01042     if (floats) {
01043       QDateTime endDate = event->dtEnd();
01044       event->setDtEnd(endDate.addDays(-1));
01045     }
01046   }
01047 
01048   if ( mCompat ) mCompat->fixEmptySummary( event );
01049 
01050   return event;
01051 }
01052 
01053 FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
01054 {
01055   FreeBusy *freebusy = new FreeBusy;
01056 
01057   readIncidenceBase(vfreebusy, freebusy);
01058 
01059   icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY);
01060 
01061   icaltimetype icaltime;
01062   PeriodList periods;
01063 
01064   while (p) {
01065     icalproperty_kind kind = icalproperty_isa(p);
01066     switch (kind) {
01067 
01068       case ICAL_DTSTART_PROPERTY:  // start date and time
01069         icaltime = icalproperty_get_dtstart(p);
01070         freebusy->setDtStart(readICalDateTime(icaltime));
01071         break;
01072 
01073       case ICAL_DTEND_PROPERTY:  // end Date and Time
01074         icaltime = icalproperty_get_dtend(p);
01075         freebusy->setDtEnd(readICalDateTime(icaltime));
01076         break;
01077 
01078       case ICAL_FREEBUSY_PROPERTY: { //Any FreeBusy Times
01079         icalperiodtype icalperiod = icalproperty_get_freebusy(p);
01080         QDateTime period_start = readICalDateTime(icalperiod.start);
01081         if ( !icaltime_is_null_time(icalperiod.end) ) {
01082           QDateTime period_end = readICalDateTime(icalperiod.end);
01083           periods.append( Period(period_start, period_end) );
01084         } else {
01085           Duration duration = readICalDuration( icalperiod.duration );
01086           periods.append( Period(period_start, duration) );
01087         }
01088         break;}
01089 
01090       default:
01091 //        kdDebug(5800) << "ICalFormatImpl::readFreeBusy(): Unknown property: "
01092 //                      << kind << endl;
01093       break;
01094     }
01095     p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY);
01096   }
01097   freebusy->addPeriods( periods );
01098 
01099   return freebusy;
01100 }
01101 
01102 Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal)
01103 {
01104   Journal *journal = new Journal;
01105 
01106   readIncidence(vjournal, 0, journal); // FIXME tz?
01107 
01108   return journal;
01109 }
01110 
01111 Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee)
01112 {
01113   icalparameter *p = 0;
01114 
01115   QString email = QString::fromUtf8(icalproperty_get_attendee(attendee));
01116   if ( email.startsWith( "mailto:", false ) ) {
01117     email = email.mid( 7 );
01118   }
01119 
01120   QString name;
01121   QString uid = QString::null;
01122   p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER);
01123   if (p) {
01124     name = QString::fromUtf8(icalparameter_get_cn(p));
01125   } else {
01126   }
01127 
01128   bool rsvp=false;
01129   p = icalproperty_get_first_parameter(attendee,ICAL_RSVP_PARAMETER);
01130   if (p) {
01131     icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp(p);
01132     if (rsvpParameter == ICAL_RSVP_TRUE) rsvp = true;
01133   }
01134 
01135   Attendee::PartStat status = Attendee::NeedsAction;
01136   p = icalproperty_get_first_parameter(attendee,ICAL_PARTSTAT_PARAMETER);
01137   if (p) {
01138     icalparameter_partstat partStatParameter = icalparameter_get_partstat(p);
01139     switch(partStatParameter) {
01140       default:
01141       case ICAL_PARTSTAT_NEEDSACTION:
01142         status = Attendee::NeedsAction;
01143         break;
01144       case ICAL_PARTSTAT_ACCEPTED:
01145         status = Attendee::Accepted;
01146         break;
01147       case ICAL_PARTSTAT_DECLINED:
01148         status = Attendee::Declined;
01149         break;
01150       case ICAL_PARTSTAT_TENTATIVE:
01151         status = Attendee::Tentative;
01152         break;
01153       case ICAL_PARTSTAT_DELEGATED:
01154         status = Attendee::Delegated;
01155         break;
01156       case ICAL_PARTSTAT_COMPLETED:
01157         status = Attendee::Completed;
01158         break;
01159       case ICAL_PARTSTAT_INPROCESS:
01160         status = Attendee::InProcess;
01161         break;
01162     }
01163   }
01164 
01165   Attendee::Role role = Attendee::ReqParticipant;
01166   p = icalproperty_get_first_parameter(attendee,ICAL_ROLE_PARAMETER);
01167   if (p) {
01168     icalparameter_role roleParameter = icalparameter_get_role(p);
01169     switch(roleParameter) {
01170       case ICAL_ROLE_CHAIR:
01171         role = Attendee::Chair;
01172         break;
01173       default:
01174       case ICAL_ROLE_REQPARTICIPANT:
01175         role = Attendee::ReqParticipant;
01176         break;
01177       case ICAL_ROLE_OPTPARTICIPANT:
01178         role = Attendee::OptParticipant;
01179         break;
01180       case ICAL_ROLE_NONPARTICIPANT:
01181         role = Attendee::NonParticipant;
01182         break;
01183     }
01184   }
01185 
01186   p = icalproperty_get_first_parameter(attendee,ICAL_X_PARAMETER);
01187   uid = icalparameter_get_xvalue(p);
01188   // This should be added, but there seems to be a libical bug here.
01189   // TODO: does this work now in libical-0.24 or greater?
01190   /*while (p) {
01191    // if (icalparameter_get_xname(p) == "X-UID") {
01192     uid = icalparameter_get_xvalue(p);
01193     p = icalproperty_get_next_parameter(attendee,ICAL_X_PARAMETER);
01194   } */
01195 
01196   Attendee *a = new Attendee( name, email, rsvp, status, role, uid );
01197 
01198   p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDTO_PARAMETER );
01199   if ( p )
01200     a->setDelegate( icalparameter_get_delegatedto( p ) );
01201 
01202   p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDFROM_PARAMETER );
01203   if ( p )
01204     a->setDelegator( icalparameter_get_delegatedfrom( p ) );
01205 
01206   return a;
01207 }
01208 
01209 Person ICalFormatImpl::readOrganizer( icalproperty *organizer )
01210 {
01211   QString email = QString::fromUtf8(icalproperty_get_organizer(organizer));
01212   if ( email.startsWith( "mailto:", false ) ) {
01213     email = email.mid( 7 );
01214   }
01215   QString cn;
01216 
01217   icalparameter *p = icalproperty_get_first_parameter(
01218              organizer, ICAL_CN_PARAMETER );
01219 
01220   if ( p ) {
01221     cn = QString::fromUtf8( icalparameter_get_cn( p ) );
01222   }
01223   Person org( cn, email );
01224   // TODO: Treat sent-by, dir and language here, too
01225   return org;
01226 }
01227 
01228 Attachment *ICalFormatImpl::readAttachment(icalproperty *attach)
01229 {
01230   Attachment *attachment = 0;
01231 
01232   icalvalue_kind value_kind = icalvalue_isa(icalproperty_get_value(attach));
01233 
01234   if ( value_kind == ICAL_ATTACH_VALUE || value_kind == ICAL_BINARY_VALUE ) {
01235     icalattach *a = icalproperty_get_attach(attach);
01236 
01237     int isurl = icalattach_get_is_url (a);
01238     if (isurl == 0)
01239       attachment = new Attachment((const char*)icalattach_get_data(a));
01240     else {
01241       attachment = new Attachment(QString::fromUtf8(icalattach_get_url(a)));
01242     }
01243   }
01244   else if ( value_kind == ICAL_URI_VALUE ) {
01245     attachment = new Attachment(QString::fromUtf8(icalvalue_get_uri(icalproperty_get_value(attach))));
01246   }
01247 
01248   icalparameter *p = icalproperty_get_first_parameter(attach, ICAL_FMTTYPE_PARAMETER);
01249   if (p && attachment)
01250     attachment->setMimeType(QString(icalparameter_get_fmttype(p)));
01251 
01252   p = icalproperty_get_first_parameter(attach,ICAL_X_PARAMETER);
01253   while (p) {
01254    if ( strncmp (icalparameter_get_xname(p), "X-LABEL", 7) == 0 )
01255      attachment->setLabel( icalparameter_get_xvalue(p) );
01256     p = icalproperty_get_next_parameter(attach, ICAL_X_PARAMETER);
01257   }
01258 
01259   return attachment;
01260 }
01261 
01262 void ICalFormatImpl::readIncidence(icalcomponent *parent, icaltimezone *tz, Incidence *incidence)
01263 {
01264   readIncidenceBase(parent,incidence);
01265 
01266   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
01267 
01268   const char *text;
01269   int intvalue, inttext;
01270   icaltimetype icaltime;
01271   icaldurationtype icalduration;
01272 
01273   QStringList categories;
01274 
01275   while (p) {
01276     icalproperty_kind kind = icalproperty_isa(p);
01277     switch (kind) {
01278 
01279       case ICAL_CREATED_PROPERTY:
01280         icaltime = icalproperty_get_created(p);
01281         incidence->setCreated(readICalDateTime(icaltime, tz));
01282         break;
01283 
01284       case ICAL_SEQUENCE_PROPERTY:  // sequence
01285         intvalue = icalproperty_get_sequence(p);
01286         incidence->setRevision(intvalue);
01287         break;
01288 
01289       case ICAL_LASTMODIFIED_PROPERTY:  // last modification date
01290         icaltime = icalproperty_get_lastmodified(p);
01291         incidence->setLastModified(readICalDateTime(icaltime, tz));
01292         break;
01293 
01294       case ICAL_DTSTART_PROPERTY:  // start date and time
01295         icaltime = icalproperty_get_dtstart(p);
01296         if (icaltime.is_date) {
01297           incidence->setDtStart(QDateTime(readICalDate(icaltime),QTime(0,0,0)));
01298           incidence->setFloats( true );
01299         } else {
01300           incidence->setDtStart(readICalDateTime(icaltime, tz));
01301           incidence->setFloats( false );
01302         }
01303         break;
01304 
01305       case ICAL_DURATION_PROPERTY:  // start date and time
01306         icalduration = icalproperty_get_duration(p);
01307         incidence->setDuration(readICalDuration(icalduration));
01308         break;
01309 
01310       case ICAL_DESCRIPTION_PROPERTY:  // description
01311         text = icalproperty_get_description(p);
01312         incidence->setDescription(QString::fromUtf8(text));
01313         break;
01314 
01315       case ICAL_SUMMARY_PROPERTY:  // summary
01316         text = icalproperty_get_summary(p);
01317         incidence->setSummary(QString::fromUtf8(text));
01318         break;
01319 
01320       case ICAL_LOCATION_PROPERTY:  // location
01321         text = icalproperty_get_location(p);
01322         incidence->setLocation(QString::fromUtf8(text));
01323         break;
01324 
01325       case ICAL_STATUS_PROPERTY: {  // status
01326         Incidence::Status stat;
01327         switch (icalproperty_get_status(p)) {
01328           case ICAL_STATUS_TENTATIVE:   stat = Incidence::StatusTentative; break;
01329           case ICAL_STATUS_CONFIRMED:   stat = Incidence::StatusConfirmed; break;
01330           case ICAL_STATUS_COMPLETED:   stat = Incidence::StatusCompleted; break;
01331           case ICAL_STATUS_NEEDSACTION: stat = Incidence::StatusNeedsAction; break;
01332           case ICAL_STATUS_CANCELLED:   stat = Incidence::StatusCanceled; break;
01333           case ICAL_STATUS_INPROCESS:   stat = Incidence::StatusInProcess; break;
01334           case ICAL_STATUS_DRAFT:       stat = Incidence::StatusDraft; break;
01335           case ICAL_STATUS_FINAL:       stat = Incidence::StatusFinal; break;
01336           case ICAL_STATUS_X:
01337             incidence->setCustomStatus(QString::fromUtf8(icalvalue_get_x(icalproperty_get_value(p))));
01338             stat = Incidence::StatusX;
01339             break;
01340           case ICAL_STATUS_NONE:
01341           default:                      stat = Incidence::StatusNone; break;
01342         }
01343         if (stat != Incidence::StatusX)
01344           incidence->setStatus(stat);
01345         break;
01346       }
01347 
01348       case ICAL_PRIORITY_PROPERTY:  // priority
01349         intvalue = icalproperty_get_priority( p );
01350         if ( mCompat )
01351           intvalue = mCompat->fixPriority( intvalue );
01352         incidence->setPriority( intvalue );
01353         break;
01354 
01355       case ICAL_CATEGORIES_PROPERTY:  // categories
01356         text = icalproperty_get_categories(p);
01357         categories.append(QString::fromUtf8(text));
01358         break;
01359 
01360       case ICAL_RRULE_PROPERTY:
01361         readRecurrenceRule( p, incidence );
01362         break;
01363 
01364       case ICAL_RDATE_PROPERTY: {
01365         icaldatetimeperiodtype rd = icalproperty_get_rdate( p );
01366         if ( icaltime_is_valid_time( rd.time ) ) {
01367           if ( icaltime_is_date( rd.time ) ) {
01368             incidence->recurrence()->addRDate( readICalDate( rd.time ) );
01369           } else {
01370             incidence->recurrence()->addRDateTime( readICalDateTime( rd.time, tz ) );
01371           }
01372         } else {
01373           // TODO: RDates as period are not yet implemented!
01374         }
01375         break; }
01376 
01377       case ICAL_EXRULE_PROPERTY:
01378         readExceptionRule( p, incidence );
01379         break;
01380 
01381       case ICAL_EXDATE_PROPERTY:
01382         icaltime = icalproperty_get_exdate(p);
01383         if ( icaltime_is_date(icaltime) ) {
01384           incidence->recurrence()->addExDate( readICalDate(icaltime) );
01385         } else {
01386           incidence->recurrence()->addExDateTime( readICalDateTime(icaltime, tz) );
01387         }
01388         break;
01389 
01390       case ICAL_CLASS_PROPERTY:
01391         inttext = icalproperty_get_class(p);
01392         if (inttext == ICAL_CLASS_PUBLIC ) {
01393           incidence->setSecrecy(Incidence::SecrecyPublic);
01394         } else if (inttext == ICAL_CLASS_CONFIDENTIAL ) {
01395           incidence->setSecrecy(Incidence::SecrecyConfidential);
01396         } else {
01397           incidence->setSecrecy(Incidence::SecrecyPrivate);
01398         }
01399         break;
01400 
01401       case ICAL_ATTACH_PROPERTY:  // attachments
01402         incidence->addAttachment(readAttachment(p));
01403         break;
01404 
01405       default:
01406 //        kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
01407 //                  << endl;
01408         break;
01409     }
01410 
01411     p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
01412   }
01413 
01414   // Set the scheduling ID
01415   const QString uid = incidence->customProperty( "LIBKCAL", "ID" );
01416   if ( !uid.isNull() ) {
01417     // The UID stored in incidencebase is actually the scheduling ID
01418     // It has to be stored in the iCal UID component for compatibility
01419     // with other iCal applications
01420     incidence->setSchedulingID( incidence->uid() );
01421     incidence->setUid( uid );
01422   }
01423 
01424   // Now that recurrence and exception stuff is completely set up,
01425   // do any backwards compatibility adjustments.
01426   if ( incidence->doesRecur() && mCompat )
01427       mCompat->fixRecurrence( incidence );
01428 
01429   // add categories
01430   incidence->setCategories(categories);
01431 
01432   // iterate through all alarms
01433   for (icalcomponent *alarm = icalcomponent_get_first_component(parent,ICAL_VALARM_COMPONENT);
01434        alarm;
01435        alarm = icalcomponent_get_next_component(parent,ICAL_VALARM_COMPONENT)) {
01436     readAlarm(alarm,incidence);
01437   }
01438   // Fix incorrect alarm settings by other applications (like outloook 9)
01439   if ( mCompat ) mCompat->fixAlarms( incidence );
01440 
01441 }
01442 
01443 void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
01444 {
01445   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
01446 
01447   while (p) {
01448     icalproperty_kind kind = icalproperty_isa(p);
01449     switch (kind) {
01450 
01451       case ICAL_UID_PROPERTY:  // unique id
01452         incidenceBase->setUid(QString::fromUtf8(icalproperty_get_uid(p)));
01453         break;
01454 
01455       case ICAL_ORGANIZER_PROPERTY:  // organizer
01456         incidenceBase->setOrganizer( readOrganizer(p));
01457         break;
01458 
01459       case ICAL_ATTENDEE_PROPERTY:  // attendee
01460         incidenceBase->addAttendee(readAttendee(p));
01461         break;
01462 
01463       case ICAL_COMMENT_PROPERTY:
01464         incidenceBase->addComment(
01465             QString::fromUtf8(icalproperty_get_comment(p)));
01466         break;
01467 
01468       default:
01469         break;
01470     }
01471 
01472     p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
01473   }
01474 
01475   // kpilot stuff
01476   // TODO: move this application-specific code to kpilot
01477   // need to get X-PILOT* attributes out, set correct properties, and get
01478   // rid of them...
01479   // Pointer fun, as per libical documentation
01480   // (documented in UsingLibical.txt)
01481   icalproperty *next =0;
01482 
01483   for ( p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
01484        p != 0; 
01485        p = next )
01486   {
01487 
01488     next = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
01489 
01490     QString value = QString::fromUtf8(icalproperty_get_x(p));
01491     QString name = icalproperty_get_x_name(p);
01492 
01493     if (name == "X-PILOTID" && !value.isEmpty()) {
01494       incidenceBase->setPilotId(value.toInt());
01495       icalcomponent_remove_property(parent,p);
01496     } else if (name == "X-PILOTSTAT" && !value.isEmpty()) {
01497       incidenceBase->setSyncStatus(value.toInt());
01498       icalcomponent_remove_property(parent,p);
01499     }
01500   }
01501 
01502   // custom properties
01503   readCustomProperties(parent, incidenceBase);
01504 }
01505 
01506 void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties)
01507 {
01508   QMap<QCString, QString> customProperties;
01509 
01510   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
01511 
01512   while (p) {
01513 
01514     QString value = QString::fromUtf8(icalproperty_get_x(p));
01515     const char *name = icalproperty_get_x_name(p);
01516     customProperties[name] = value;
01517     // kdDebug(5800) << "Set custom property [" << name << '=' << value << ']' << endl;
01518     p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
01519   }
01520 
01521   properties->setCustomProperties(customProperties);
01522 }
01523 
01524 
01525 
01526 void ICalFormatImpl::readRecurrenceRule(icalproperty *rrule,Incidence *incidence )
01527 {
01528 //  kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
01529 
01530   Recurrence *recur = incidence->recurrence();
01531 
01532   struct icalrecurrencetype r = icalproperty_get_rrule(rrule);
01533 //   dumpIcalRecurrence(r);
01534 
01535   RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
01536   recurrule->setStartDt( incidence->dtStart() );
01537   readRecurrence( r, recurrule );
01538   recur->addRRule( recurrule );
01539 }
01540 
01541 void ICalFormatImpl::readExceptionRule( icalproperty *rrule, Incidence *incidence )
01542 {
01543 //  kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
01544 
01545   struct icalrecurrencetype r = icalproperty_get_exrule(rrule);
01546 //   dumpIcalRecurrence(r);
01547 
01548   RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
01549   recurrule->setStartDt( incidence->dtStart() );
01550   readRecurrence( r, recurrule );
01551 
01552   Recurrence *recur = incidence->recurrence();
01553   recur->addExRule( recurrule );
01554 }
01555 
01556 void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, RecurrenceRule* recur )
01557 {
01558   // Generate the RRULE string
01559   recur->mRRule = QString( icalrecurrencetype_as_string( const_cast<struct icalrecurrencetype*>(&r) ) );
01560   // Period
01561   switch ( r.freq ) {
01562     case ICAL_SECONDLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rSecondly ); break;
01563     case ICAL_MINUTELY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rMinutely ); break;
01564     case ICAL_HOURLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rHourly ); break;
01565     case ICAL_DAILY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rDaily ); break;
01566     case ICAL_WEEKLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rWeekly ); break;
01567     case ICAL_MONTHLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rMonthly ); break;
01568     case ICAL_YEARLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rYearly ); break;
01569     case ICAL_NO_RECURRENCE:
01570     default:
01571         recur->setRecurrenceType( RecurrenceRule::rNone );
01572   }
01573   // Frequency
01574   recur->setFrequency( r.interval );
01575 
01576   // Duration & End Date
01577   if ( !icaltime_is_null_time( r.until ) ) {
01578     icaltimetype t;
01579     t = r.until;
01580     // Convert to the correct time zone! it's in UTC by specification.
01581     QDateTime endDate( readICalDateTime(t) );
01582     recur->setEndDt( endDate );
01583   } else {
01584     if (r.count == 0)
01585       recur->setDuration( -1 );
01586     else
01587       recur->setDuration( r.count );
01588   }
01589 
01590   // Week start setting
01591   int wkst = (r.week_start + 5)%7 + 1;
01592   recur->setWeekStart( wkst );
01593 
01594   // And now all BY*
01595   QValueList<int> lst;
01596   int i;
01597   int index = 0;
01598 
01599 #define readSetByList(rrulecomp,setfunc) \
01600   index = 0; \
01601   lst.clear(); \
01602   while ( (i = r.rrulecomp[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) \
01603     lst.append( i ); \
01604   if ( !lst.isEmpty() ) recur->setfunc( lst );
01605 
01606   // BYSECOND, MINUTE and HOUR, MONTHDAY, YEARDAY, WEEKNUMBER, MONTH
01607   // and SETPOS are standard int lists, so we can treat them with the
01608   // same macro
01609   readSetByList( by_second, setBySeconds );
01610   readSetByList( by_minute, setByMinutes );
01611   readSetByList( by_hour, setByHours );
01612   readSetByList( by_month_day, setByMonthDays );
01613   readSetByList( by_year_day, setByYearDays );
01614   readSetByList( by_week_no, setByWeekNumbers );
01615   readSetByList( by_month, setByMonths );
01616   readSetByList( by_set_pos, setBySetPos );
01617 #undef readSetByList
01618 
01619   // BYDAY is a special case, since it's not an int list
01620   QValueList<RecurrenceRule::WDayPos> wdlst;
01621   short day;
01622   index=0;
01623   while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01624     RecurrenceRule::WDayPos pos;
01625     pos.setDay( ( icalrecurrencetype_day_day_of_week( day ) + 5 )%7 + 1 );
01626     pos.setPos( icalrecurrencetype_day_position( day ) );
01627 //     kdDebug(5800)<< "    o) By day, index="<<index-1<<", pos="<<pos.Pos<<", day="<<pos.Day<<endl;
01628     wdlst.append( pos );
01629   }
01630   if ( !wdlst.isEmpty() ) recur->setByDays( wdlst );
01631 
01632 
01633   // TODO Store all X- fields of the RRULE inside the recurrence (so they are
01634   // preserved
01635 }
01636 
01637 
01638 void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
01639 {
01640 //   kdDebug(5800) << "Read alarm for " << incidence->summary() << endl;
01641 
01642   Alarm* ialarm = incidence->newAlarm();
01643   ialarm->setRepeatCount(0);
01644   ialarm->setEnabled(true);
01645 
01646   // Determine the alarm's action type
01647   icalproperty *p = icalcomponent_get_first_property(alarm,ICAL_ACTION_PROPERTY);
01648   Alarm::Type type = Alarm::Display;
01649   icalproperty_action action = ICAL_ACTION_DISPLAY;
01650   if ( !p ) {
01651     kdDebug(5800) << "Unknown type of alarm, using default" << endl;
01652 //    return;
01653   } else {
01654 
01655     action = icalproperty_get_action(p);
01656     switch ( action ) {
01657       case ICAL_ACTION_DISPLAY:   type = Alarm::Display;  break;
01658       case ICAL_ACTION_AUDIO:     type = Alarm::Audio;  break;
01659       case ICAL_ACTION_PROCEDURE: type = Alarm::Procedure;  break;
01660       case ICAL_ACTION_EMAIL:     type = Alarm::Email;  break;
01661       default:
01662         kdDebug(5800) << "Unknown type of alarm: " << action << endl;
01663 //        type = Alarm::Invalid;
01664     }
01665   }
01666   ialarm->setType(type);
01667 // kdDebug(5800) << " alarm type =" << type << endl;
01668 
01669   p = icalcomponent_get_first_property(alarm,ICAL_ANY_PROPERTY);
01670   while (p) {
01671     icalproperty_kind kind = icalproperty_isa(p);
01672 
01673     switch (kind) {
01674 
01675       case ICAL_TRIGGER_PROPERTY: {
01676         icaltriggertype trigger = icalproperty_get_trigger(p);
01677         if (icaltime_is_null_time(trigger.time)) {
01678           if (icaldurationtype_is_null_duration(trigger.duration)) {
01679             kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl;
01680           } else {
01681             Duration duration = icaldurationtype_as_int( trigger.duration );
01682             icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER);
01683             if (param && icalparameter_get_related(param) == ICAL_RELATED_END)
01684               ialarm->setEndOffset(duration);
01685             else
01686               ialarm->setStartOffset(duration);
01687           }
01688         } else {
01689           ialarm->setTime(readICalDateTime(trigger.time));
01690         }
01691         break;
01692       }
01693       case ICAL_DURATION_PROPERTY: {
01694         icaldurationtype duration = icalproperty_get_duration(p);
01695         ialarm->setSnoozeTime(icaldurationtype_as_int(duration)/60);
01696         break;
01697       }
01698       case ICAL_REPEAT_PROPERTY:
01699         ialarm->setRepeatCount(icalproperty_get_repeat(p));
01700         break;
01701 
01702       // Only in DISPLAY and EMAIL and PROCEDURE alarms
01703       case ICAL_DESCRIPTION_PROPERTY: {
01704         QString description = QString::fromUtf8(icalproperty_get_description(p));
01705         switch ( action ) {
01706           case ICAL_ACTION_DISPLAY:
01707             ialarm->setText( description );
01708             break;
01709           case ICAL_ACTION_PROCEDURE:
01710             ialarm->setProgramArguments( description );
01711             break;
01712           case ICAL_ACTION_EMAIL:
01713             ialarm->setMailText( description );
01714             break;
01715           default:
01716             break;
01717         }
01718         break;
01719       }
01720       // Only in EMAIL alarm
01721       case ICAL_SUMMARY_PROPERTY:
01722         ialarm->setMailSubject(QString::fromUtf8(icalproperty_get_summary(p)));
01723         break;
01724 
01725       // Only in EMAIL alarm
01726       case ICAL_ATTENDEE_PROPERTY: {
01727         QString email = QString::fromUtf8(icalproperty_get_attendee(p));
01728         if ( email.startsWith("mailto:", false ) ) {
01729           email = email.mid( 7 );
01730         }
01731         QString name;
01732         icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER);
01733         if (param) {
01734           name = QString::fromUtf8(icalparameter_get_cn(param));
01735         }
01736         ialarm->addMailAddress(Person(name, email));
01737         break;
01738       }
01739       // Only in AUDIO and EMAIL and PROCEDURE alarms
01740       case ICAL_ATTACH_PROPERTY: {
01741         Attachment *attach = readAttachment( p );
01742         if ( attach && attach->isUri() ) {
01743           switch ( action ) {
01744             case ICAL_ACTION_AUDIO:
01745               ialarm->setAudioFile( attach->uri() );
01746               break;
01747             case ICAL_ACTION_PROCEDURE:
01748               ialarm->setProgramFile( attach->uri() );
01749               break;
01750             case ICAL_ACTION_EMAIL:
01751               ialarm->addMailAttachment( attach->uri() );
01752               break;
01753             default:
01754               break;
01755           }
01756         } else {
01757           kdDebug() << "Alarm attachments currently only support URIs, but "
01758                        "no binary data" << endl;
01759         }
01760         delete attach;
01761         break;
01762       }
01763       default:
01764         break;
01765     }
01766 
01767     p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY);
01768   }
01769 
01770   // custom properties
01771   readCustomProperties(alarm, ialarm);
01772 
01773   // TODO: check for consistency of alarm properties
01774 }
01775 
01776 icaldatetimeperiodtype ICalFormatImpl::writeICalDatePeriod( const QDate &date )
01777 {
01778   icaldatetimeperiodtype t;
01779   t.time = writeICalDate( date );
01780   t.period = icalperiodtype_null_period();
01781   return t;
01782 }
01783 
01784 icaldatetimeperiodtype ICalFormatImpl::writeICalDateTimePeriod( const QDateTime &date )
01785 {
01786   icaldatetimeperiodtype t;
01787   t.time = writeICalDateTime( date );
01788   t.period = icalperiodtype_null_period();
01789   return t;
01790 }
01791 
01792 icaltimetype ICalFormatImpl::writeICalDate(const QDate &date)
01793 {
01794   icaltimetype t = icaltime_null_time();
01795 
01796   t.year = date.year();
01797   t.month = date.month();
01798   t.day = date.day();
01799 
01800   t.hour = 0;
01801   t.minute = 0;
01802   t.second = 0;
01803 
01804   t.is_date = 1;
01805 
01806   t.is_utc = 0;
01807 
01808   t.zone = 0;
01809 
01810   return t;
01811 }
01812 
01813 icaltimetype ICalFormatImpl::writeICalDateTime(const QDateTime &datetime)
01814 {
01815   icaltimetype t = icaltime_null_time();
01816 
01817   t.year = datetime.date().year();
01818   t.month = datetime.date().month();
01819   t.day = datetime.date().day();
01820 
01821   t.hour = datetime.time().hour();
01822   t.minute = datetime.time().minute();
01823   t.second = datetime.time().second();
01824 
01825   t.is_date = 0;
01826   t.zone = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
01827   t.is_utc = 0;
01828 
01829  // _dumpIcaltime( t );
01830   /* The QDateTime we get passed in is to be considered in the timezone of
01831    * the current calendar (mParent's), or, if there is none, to be floating.
01832    * In the later case store a floating time, in the former normalize to utc. */
01833   if (mParent->timeZoneId().isEmpty())
01834     t = icaltime_convert_to_zone( t, 0 ); //make floating timezone
01835   else {
01836     icaltimezone* tz = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
01837     icaltimezone* utc = icaltimezone_get_utc_timezone();
01838     if ( tz != utc ) {
01839       t.zone = tz;
01840       t = icaltime_convert_to_zone( t, utc );
01841     } else {
01842       t.is_utc = 1;
01843       t.zone = utc;
01844     }
01845   }
01846 //  _dumpIcaltime( t );
01847 
01848   return t;
01849 }
01850 
01851 QDateTime ICalFormatImpl::readICalDateTime( icaltimetype& t, icaltimezone* tz )
01852 {
01853 //   kdDebug(5800) << "ICalFormatImpl::readICalDateTime()" << endl;
01854   icaltimezone *zone = tz;
01855   if ( tz && t.is_utc == 0 ) { // Only use the TZ if time is not UTC.
01856     // FIXME: We'll need to make sure to apply the appropriate TZ, not just
01857     //        the first one found.
01858     t.zone = tz;
01859     t.is_utc = (tz == icaltimezone_get_utc_timezone())?1:0;
01860   } else {
01861     zone = icaltimezone_get_utc_timezone();
01862   }
01863   //_dumpIcaltime( t );
01864 
01865   // Convert to view time
01866   if ( !mParent->timeZoneId().isEmpty() && t.zone ) {
01867 //    kdDebug(5800) << "--- Converting time from: " << icaltimezone_get_tzid( const_cast<icaltimezone*>( t.zone ) ) << " (" << ICalDate2QDate(t) << ")." << endl;
01868     icaltimezone* viewTimeZone = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
01869     icaltimezone_convert_time(  &t, zone, viewTimeZone );
01870 //    kdDebug(5800) << "--- Converted to zone " << mParent->timeZoneId() << " (" << ICalDate2QDate(t) << ")." << endl;
01871   }
01872 
01873   return ICalDate2QDate(t);
01874 }
01875 
01876 QDate ICalFormatImpl::readICalDate(icaltimetype t)
01877 {
01878   return ICalDate2QDate(t).date();
01879 }
01880 
01881 icaldurationtype ICalFormatImpl::writeICalDuration(int seconds)
01882 {
01883   icaldurationtype d;
01884 
01885   d.is_neg  = (seconds<0)?1:0;
01886   if (seconds<0) seconds = -seconds;
01887 
01888   d.weeks    = seconds / gSecondsPerWeek;
01889   seconds   %= gSecondsPerWeek;
01890   d.days     = seconds / gSecondsPerDay;
01891   seconds   %= gSecondsPerDay;
01892   d.hours    = seconds / gSecondsPerHour;
01893   seconds   %= gSecondsPerHour;
01894   d.minutes  = seconds / gSecondsPerMinute;
01895   seconds   %= gSecondsPerMinute;
01896   d.seconds  = seconds;
01897 
01898   return d;
01899 }
01900 
01901 int ICalFormatImpl::readICalDuration(icaldurationtype d)
01902 {
01903   int result = 0;
01904 
01905   result += d.weeks   * gSecondsPerWeek;
01906   result += d.days    * gSecondsPerDay;
01907   result += d.hours   * gSecondsPerHour;
01908   result += d.minutes * gSecondsPerMinute;
01909   result += d.seconds;
01910 
01911   if (d.is_neg) result *= -1;
01912 
01913   return result;
01914 }
01915 
01916 icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal)
01917 {
01918   icalcomponent *calendar;
01919 
01920   // Root component
01921   calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
01922 
01923   icalproperty *p;
01924 
01925   // Product Identifier
01926   p = icalproperty_new_prodid(CalFormat::productId().utf8());
01927   icalcomponent_add_property(calendar,p);
01928 
01929   // TODO: Add time zone
01930 
01931   // iCalendar version (2.0)
01932   p = icalproperty_new_version(const_cast<char *>(_ICAL_VERSION));
01933   icalcomponent_add_property(calendar,p);
01934 
01935   // Custom properties
01936   if( cal != 0 )
01937     writeCustomProperties(calendar, cal);
01938 
01939   return calendar;
01940 }
01941 
01942 
01943 
01944 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
01945 // and break it down from its tree-like format into the dictionary format
01946 // that is used internally in the ICalFormatImpl.
01947 bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
01948 {
01949   // this function will populate the caldict dictionary and other event
01950   // lists. It turns vevents into Events and then inserts them.
01951 
01952     if (!calendar) return false;
01953 
01954 // TODO: check for METHOD
01955 
01956   icalproperty *p;
01957 
01958   p = icalcomponent_get_first_property(calendar,ICAL_PRODID_PROPERTY);
01959   if (!p) {
01960     kdDebug(5800) << "No PRODID property found" << endl;
01961     mLoadedProductId = "";
01962   } else {
01963     mLoadedProductId = QString::fromUtf8(icalproperty_get_prodid(p));
01964 //    kdDebug(5800) << "VCALENDAR prodid: '" << mLoadedProductId << "'" << endl;
01965 
01966     delete mCompat;
01967     mCompat = CompatFactory::createCompat( mLoadedProductId );
01968   }
01969 
01970   p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY);
01971   if (!p) {
01972     kdDebug(5800) << "No VERSION property found" << endl;
01973     mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
01974     return false;
01975   } else {
01976     const char *version = icalproperty_get_version(p);
01977 //    kdDebug(5800) << "VCALENDAR version: '" << version << "'" << endl;
01978 
01979     if (strcmp(version,"1.0") == 0) {
01980       kdDebug(5800) << "Expected iCalendar, got vCalendar" << endl;
01981       mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1,
01982                             i18n("Expected iCalendar format")));
01983       return false;
01984     } else if (strcmp(version,"2.0") != 0) {
01985       kdDebug(5800) << "Expected iCalendar, got unknown format" << endl;
01986       mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
01987       return false;
01988     }
01989   }
01990 
01991   // custom properties
01992   readCustomProperties(calendar, cal);
01993 
01994 // TODO: set time zone
01995 
01996   // read a VTIMEZONE if there is one
01997   icalcomponent *ctz =
01998     icalcomponent_get_first_component( calendar, ICAL_VTIMEZONE_COMPONENT );
01999 
02000   // Store all events with a relatedTo property in a list for post-processing
02001   mEventsRelate.clear();
02002   mTodosRelate.clear();
02003   // TODO: make sure that only actually added events go to this lists.
02004 
02005   icalcomponent *c;
02006 
02007   // Iterate through all todos
02008   c = icalcomponent_get_first_component(calendar,ICAL_VTODO_COMPONENT);
02009   while (c) {
02010 //    kdDebug(5800) << "----Todo found" << endl;
02011     Todo *todo = readTodo(c);
02012     if (todo) {
02013       if (!cal->todo(todo->uid())) {
02014         cal->addTodo(todo);
02015       } else {
02016         delete todo;
02017         mTodosRelate.remove( todo );
02018       }
02019     }
02020     c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT);
02021   }
02022 
02023   // Iterate through all events
02024   c = icalcomponent_get_first_component(calendar,ICAL_VEVENT_COMPONENT);
02025   while (c) {
02026 //    kdDebug(5800) << "----Event found" << endl;
02027     Event *event = readEvent(c, ctz);
02028     if (event) {
02029       if (!cal->event(event->uid())) {
02030         cal->addEvent(event);
02031       } else {
02032         delete event;
02033         mEventsRelate.remove( event );
02034       }
02035     }
02036     c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT);
02037   }
02038 
02039   // Iterate through all journals
02040   c = icalcomponent_get_first_component(calendar,ICAL_VJOURNAL_COMPONENT);
02041   while (c) {
02042 //    kdDebug(5800) << "----Journal found" << endl;
02043     Journal *journal = readJournal(c);
02044     if (journal) {
02045       if (!cal->journal(journal->uid())) {
02046         cal->addJournal(journal);
02047       } else {
02048         delete journal;
02049       }
02050     }
02051     c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT);
02052   }
02053 
02054   // Post-Process list of events with relations, put Event objects in relation
02055   Event::List::ConstIterator eIt;
02056   for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) {
02057     (*eIt)->setRelatedTo( cal->incidence( (*eIt)->relatedToUid() ) );
02058   }
02059   Todo::List::ConstIterator tIt;
02060   for ( tIt = mTodosRelate.begin(); tIt != mTodosRelate.end(); ++tIt ) {
02061     (*tIt)->setRelatedTo( cal->incidence( (*tIt)->relatedToUid() ) );
02062    }
02063 
02064   return true;
02065 }
02066 
02067 QString ICalFormatImpl::extractErrorProperty(icalcomponent *c)
02068 {
02069 //  kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: "
02070 //            << icalcomponent_as_ical_string(c) << endl;
02071 
02072   QString errorMessage;
02073 
02074   icalproperty *error;
02075   error = icalcomponent_get_first_property(c,ICAL_XLICERROR_PROPERTY);
02076   while(error) {
02077     errorMessage += icalproperty_get_xlicerror(error);
02078     errorMessage += "\n";
02079     error = icalcomponent_get_next_property(c,ICAL_XLICERROR_PROPERTY);
02080   }
02081 
02082 //  kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " << errorMessage << endl;
02083 
02084   return errorMessage;
02085 }
02086 
02087 void ICalFormatImpl::dumpIcalRecurrence(icalrecurrencetype r)
02088 {
02089   int i;
02090 
02091   kdDebug(5800) << " Freq: " << r.freq << endl;
02092   kdDebug(5800) << " Until: " << icaltime_as_ical_string(r.until) << endl;
02093   kdDebug(5800) << " Count: " << r.count << endl;
02094   if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02095     int index = 0;
02096     QString out = " By Day: ";
02097     while((i = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02098       out.append(QString::number(i) + " ");
02099     }
02100     kdDebug(5800) << out << endl;
02101   }
02102   if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02103     int index = 0;
02104     QString out = " By Month Day: ";
02105     while((i = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02106       out.append(QString::number(i) + " ");
02107     }
02108     kdDebug(5800) << out << endl;
02109   }
02110   if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02111     int index = 0;
02112     QString out = " By Year Day: ";
02113     while((i = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02114       out.append(QString::number(i) + " ");
02115     }
02116     kdDebug(5800) << out << endl;
02117   }
02118   if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02119     int index = 0;
02120     QString out = " By Month: ";
02121     while((i = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02122       out.append(QString::number(i) + " ");
02123     }
02124     kdDebug(5800) << out << endl;
02125   }
02126   if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02127     int index = 0;
02128     QString out = " By Set Pos: ";
02129     while((i = r.by_set_pos[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02130       kdDebug(5800) << "========= " << i << endl;
02131       out.append(QString::number(i) + " ");
02132     }
02133     kdDebug(5800) << out << endl;
02134   }
02135 }
02136 
02137 icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence,
02138                                                    Scheduler::Method method)
02139 {
02140   icalcomponent *message = createCalendarComponent();
02141 
02142   icalproperty_method icalmethod = ICAL_METHOD_NONE;
02143 
02144   switch (method) {
02145     case Scheduler::Publish:
02146       icalmethod = ICAL_METHOD_PUBLISH;
02147       break;
02148     case Scheduler::Request:
02149       icalmethod = ICAL_METHOD_REQUEST;
02150       break;
02151     case Scheduler::Refresh:
02152       icalmethod = ICAL_METHOD_REFRESH;
02153       break;
02154     case Scheduler::Cancel:
02155       icalmethod = ICAL_METHOD_CANCEL;
02156       break;
02157     case Scheduler::Add:
02158       icalmethod = ICAL_METHOD_ADD;
02159       break;
02160     case Scheduler::Reply:
02161       icalmethod = ICAL_METHOD_REPLY;
02162       break;
02163     case Scheduler::Counter:
02164       icalmethod = ICAL_METHOD_COUNTER;
02165       break;
02166     case Scheduler::Declinecounter:
02167       icalmethod = ICAL_METHOD_DECLINECOUNTER;
02168       break;
02169     default:
02170       kdDebug(5800) << "ICalFormat::createScheduleMessage(): Unknow method" << endl;
02171       return message;
02172   }
02173 
02174   icalcomponent_add_property(message,icalproperty_new_method(icalmethod));
02175 
02176   icalcomponent *inc = writeIncidence( incidence, method );
02177   /*
02178    * RFC 2446 states in section 3.4.3 ( REPLY to a VTODO ), that
02179    * a REQUEST-STATUS property has to be present. For the other two, event and
02180    * free busy, it can be there, but is optional. Until we do more
02181    * fine grained handling, assume all is well. Note that this is the
02182    * status of the _request_, not the attendee. Just to avoid confusion.
02183    * - till
02184    */
02185   if ( icalmethod == ICAL_METHOD_REPLY ) {
02186     struct icalreqstattype rst;
02187     rst.code = ICAL_2_0_SUCCESS_STATUS;
02188     rst.desc = 0;
02189     rst.debug = 0;
02190     icalcomponent_add_property( inc, icalproperty_new_requeststatus( rst ) );
02191   }
02192   icalcomponent_add_component( message, inc );
02193 
02194   return message;
02195 }
KDE Home | KDE Accessibility Home | Description of Access Keys