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