libkcal Library API Documentation

icalformatimpl.cpp

00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019     Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <qdatetime.h>
00023 #include <qstring.h>
00024 #include <qptrlist.h>
00025 #include <qfile.h>
00026 #include <cstdlib>
00027 
00028 #include <kdebug.h>
00029 #include <klocale.h>
00030 
00031 extern "C" {
00032   #include <ical.h>
00033   #include <icalss.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 namespace KCal {
00049 
00054 typedef struct icaltimezonephase icaltimezonephase;
00055 class TimezonePhase : private icaltimezonephase {
00056   public:
00060     TimezonePhase(ICalFormatImpl *parent, icalcomponent *c)
00061     {
00062       tzname = (const char *)0;
00063       is_stdandard = 1;
00064       mIsStandard = 1;
00065       dtstart = icaltime_null_time();
00066       offsetto = 0;
00067       tzoffsetfrom = 0;
00068       comment = (const char *)0;
00069       rdate.time = icaltime_null_time();
00070       rdate.period = icalperiodtype_null_period();
00071       rrule = (const char *)0;
00072       mRrule = new Recurrence((Incidence *)0);
00073 
00074       // Now do the ical reading.
00075       icalproperty *p = icalcomponent_get_first_property(c,ICAL_ANY_PROPERTY);
00076       while (p) {
00077         icalproperty_kind kind = icalproperty_isa(p);
00078         switch (kind) {
00079 
00080           case ICAL_TZNAME_PROPERTY:
00081             tzname = icalproperty_get_tzname(p);
00082             break;
00083 
00084           case ICAL_DTSTART_PROPERTY:
00085             dtstart = icalproperty_get_dtstart(p);
00086             break;
00087 
00088           case ICAL_TZOFFSETTO_PROPERTY:
00089             offsetto = icalproperty_get_tzoffsetto(p);
00090             break;
00091 
00092           case ICAL_TZOFFSETFROM_PROPERTY:
00093             tzoffsetfrom = icalproperty_get_tzoffsetfrom(p);
00094             break;
00095 
00096           case ICAL_COMMENT_PROPERTY:
00097             comment = icalproperty_get_comment(p);
00098             break;
00099 
00100           case ICAL_RDATE_PROPERTY:
00101             rdate = icalproperty_get_rdate(p);
00102             break;
00103 
00104           case ICAL_RRULE_PROPERTY:
00105             {
00106               struct icalrecurrencetype r = icalproperty_get_rrule(p);
00107 
00108               parent->readRecurrence(r,mRrule);
00109             }
00110             break;
00111 
00112           default:
00113             kdDebug(5800) << "TimezonePhase::TimezonePhase(): Unknown property: " << kind
00114                       << endl;
00115             break;
00116         }
00117         p = icalcomponent_get_next_property(c,ICAL_ANY_PROPERTY);
00118       }
00119     }
00120 
00124     ~TimezonePhase()
00125     {
00126       delete mRrule;
00127     }
00128 
00132     QDateTime nearestStart(const QDateTime &t) const
00133     {
00134       QDateTime tmp(QDate(dtstart.year,dtstart.month,dtstart.day), QTime(dtstart.hour,dtstart.minute,dtstart.second));
00135       // If this phase was not valid at the given time, give up.
00136       if (tmp > t) {
00137         kdDebug(5800) << "TimezonePhase::nearestStart(): Phase not valid" << endl;
00138         return QDateTime();
00139       }
00140 
00141       // The Recurrance class's getPreviousDateTime() logic was not designed for
00142       // start times which are not aligned with a reference time, but a little
00143       // magic is sufficient to work around that...
00144       QDateTime previous = mRrule->getPreviousDateTime(tmp);
00145       if (mRrule->getNextDateTime(previous) < tmp)
00146         previous = mRrule->getNextDateTime(previous);
00147       return previous;
00148     }
00149 
00153     int offset() const
00154     {
00155       return offsetto;
00156     }
00157 
00158     // Hide the missnamed "is_stdandard" variable in the base class.
00159     int mIsStandard;
00160 
00161     // Supplement the "rrule" in the base class.
00162     Recurrence *mRrule;
00163 };
00164 
00168 typedef struct icaltimezonetype icaltimezonetype;
00169 class Timezone : private icaltimezonetype {
00170   public:
00174     Timezone(ICalFormatImpl *parent, icalcomponent *vtimezone)
00175     {
00176       tzid = (const char *)0;
00177       last_mod = icaltime_null_time();
00178       tzurl = (const char *)0;
00179 
00180       // The phases list is defined to be terminated by a phase with a
00181       // null name.
00182       phases = (icaltimezonephase *)malloc(sizeof(*phases));
00183       phases[0].tzname = (const char *)0;
00184       mPhases.setAutoDelete( true );
00185 
00186       // Now do the ical reading.
00187       icalproperty *p = icalcomponent_get_first_property(vtimezone,ICAL_ANY_PROPERTY);
00188       while (p) {
00189         icalproperty_kind kind = icalproperty_isa(p);
00190         switch (kind) {
00191 
00192           case ICAL_TZID_PROPERTY:
00193             // The timezone id is basically a unique string which is used to
00194             // identify this timezone. Note that if it begins with a "/", then it
00195             // is suppsed to have some externally specified meaning, but we are
00196             // just after its unique value.
00197             tzid = icalproperty_get_tzid(p);
00198             break;
00199 
00200           case ICAL_TZURL_PROPERTY:
00201             tzurl = icalproperty_get_tzurl(p);
00202             break;
00203 
00204           default:
00205             kdDebug(5800) << "Timezone::Timezone(): Unknown property: " << kind
00206                       << endl;
00207             break;
00208         }
00209         p = icalcomponent_get_next_property(vtimezone,ICAL_ANY_PROPERTY);
00210       }
00211       kdDebug(5800) << "---zoneId: \"" << tzid << '"' << endl;
00212 
00213       icalcomponent *c;
00214 
00215       TimezonePhase *phase;
00216 
00217       // Iterate through all timezones before we do anything else. That way, the
00218       // information needed to interpret times in actually usefulobject is
00219       // available below.
00220       c = icalcomponent_get_first_component(vtimezone,ICAL_ANY_COMPONENT);
00221       while (c) {
00222         icalcomponent_kind kind = icalcomponent_isa(c);
00223         switch (kind) {
00224 
00225           case ICAL_XSTANDARD_COMPONENT:
00226             kdDebug(5800) << "---standard phase: found" << endl;
00227             phase = new TimezonePhase(parent,c);
00228             phase->mIsStandard = 1;
00229             mPhases.append(phase);
00230             break;
00231 
00232           case ICAL_XDAYLIGHT_COMPONENT:
00233             kdDebug(5800) << "---daylight phase: found" << endl;
00234             phase = new TimezonePhase(parent,c);
00235             phase->mIsStandard = 0;
00236             mPhases.append(phase);
00237             break;
00238 
00239           default:
00240             kdDebug(5800) << "Timezone::Timezone(): Unknown component: " << kind
00241                       << endl;
00242             break;
00243         }
00244         c = icalcomponent_get_next_component(vtimezone,ICAL_ANY_COMPONENT);
00245       }
00246     }
00247 
00251     ~Timezone()
00252     {
00253       free(phases);
00254     }
00255 
00259     QString id() const
00260     {
00261       if (tzid[0] != '"') {
00262         return QString("\"") + tzid + '"';
00263       } else {
00264         return tzid;
00265       }
00266     }
00267 
00271     const TimezonePhase *nearestStart(const QDateTime &t)
00272     {
00273       unsigned i;
00274       unsigned result = 0;
00275       QDateTime previous;
00276       QDateTime next;
00277 
00278       // Main loop. Find the phase with the latest start date before t.
00279       for (i = 0; i < mPhases.count(); i++) {
00280         next = mPhases.at(i)->nearestStart(t);
00281         if (previous.isNull() || previous < next) {
00282           previous = next;
00283           result = i;
00284         }
00285       }
00286       return mPhases.at(result);
00287     }
00288 
00292     int offset(icaltimetype t)
00293     {
00294       QDateTime tmp(QDate(t.year,t.month,t.day), QTime(t.hour,t.minute,t.second));
00295       const TimezonePhase *phase = nearestStart(tmp);
00296 
00297       if (phase) {
00298         return phase->offset();
00299       } else {
00300         kdError(5800) << "Timezone::offset() cannot find phase for " << tmp << endl;
00301         return 0;
00302       }
00303     }
00304 
00305     // Phases we have seen.
00306     QPtrList<TimezonePhase> mPhases;
00307 };
00308 
00309 }
00310 
00311 const int gSecondsPerMinute = 60;
00312 const int gSecondsPerHour   = gSecondsPerMinute * 60;
00313 const int gSecondsPerDay    = gSecondsPerHour   * 24;
00314 const int gSecondsPerWeek   = gSecondsPerDay    * 7;
00315 
00316 ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) :
00317   mParent( parent ), mCalendarVersion( 0 )
00318 {
00319   mCompat = new Compat;
00320   mTimezones.setAutoDelete( true );
00321 }
00322 
00323 ICalFormatImpl::~ICalFormatImpl()
00324 {
00325   delete mCompat;
00326 }
00327 
00328 class ToStringVisitor : public Incidence::Visitor
00329 {
00330   public:
00331     ToStringVisitor( ICalFormatImpl *impl ) : mImpl( impl ), mComponent( 0 ) {}
00332 
00333     bool visit( Event *e ) { mComponent = mImpl->writeEvent( e ); return true; }
00334     bool visit( Todo *e ) { mComponent = mImpl->writeTodo( e ); return true; }
00335     bool visit( Journal *e ) { mComponent = mImpl->writeJournal( e ); return true; }
00336 
00337     icalcomponent *component() { return mComponent; }
00338 
00339   private:
00340     ICalFormatImpl *mImpl;
00341     icalcomponent *mComponent;
00342 };
00343 
00344 icalcomponent *ICalFormatImpl::writeIncidence(Incidence *incidence)
00345 {
00346   ToStringVisitor v( this );
00347   incidence->accept(v);
00348   return v.component();
00349 }
00350 
00351 icalcomponent *ICalFormatImpl::writeTodo(Todo *todo)
00352 {
00353   QString tmpStr;
00354   QStringList tmpStrList;
00355 
00356   icalcomponent *vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT);
00357 
00358   writeIncidence(vtodo,todo);
00359 
00360   // due date
00361   if (todo->hasDueDate()) {
00362     icaltimetype due;
00363     if (todo->doesFloat()) {
00364       due = writeICalDate(todo->dtDue(true).date());
00365     } else {
00366       due = writeICalDateTime(todo->dtDue(true));
00367     }
00368     icalcomponent_add_property(vtodo,icalproperty_new_due(due));
00369   }
00370 
00371   // start time
00372   if ( todo->hasStartDate() || todo->doesRecur() ) {
00373     icaltimetype start;
00374     if (todo->doesFloat()) {
00375 //      kdDebug(5800) << " Incidence " << todo->summary() << " floats." << endl;
00376       start = writeICalDate(todo->dtStart(true).date());
00377     } else {
00378 //      kdDebug(5800) << " incidence " << todo->summary() << " has time." << endl;
00379       start = writeICalDateTime(todo->dtStart(true));
00380     }
00381     icalcomponent_add_property(vtodo,icalproperty_new_dtstart(start));
00382   }
00383 
00384   // completion date
00385   if (todo->isCompleted()) {
00386     if (!todo->hasCompletedDate()) {
00387       // If todo was created by KOrganizer <2.2 it has no correct completion
00388       // date. Set it to now.
00389       todo->setCompleted(QDateTime::currentDateTime());
00390     }
00391     icaltimetype completed = writeICalDateTime(todo->completed());
00392     icalcomponent_add_property(vtodo,icalproperty_new_completed(completed));
00393   }
00394 
00395   icalcomponent_add_property(vtodo,
00396       icalproperty_new_percentcomplete(todo->percentComplete()));
00397 
00398   if( todo->doesRecur() ) {
00399     icalcomponent_add_property(vtodo,
00400         icalproperty_new_recurrenceid( writeICalDateTime( todo->dtDue())));
00401   }
00402 
00403   return vtodo;
00404 }
00405 
00406 icalcomponent *ICalFormatImpl::writeEvent(Event *event)
00407 {
00408 #if 0
00409   kdDebug(5800) << "Write Event '" << event->summary() << "' (" << event->uid()
00410                 << ")" << endl;
00411 #endif
00412 
00413   QString tmpStr;
00414   QStringList tmpStrList;
00415 
00416   icalcomponent *vevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
00417 
00418   writeIncidence(vevent,event);
00419 
00420   // start time
00421   icaltimetype start;
00422   if (event->doesFloat()) {
00423 //    kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl;
00424     start = writeICalDate(event->dtStart().date());
00425   } else {
00426 //    kdDebug(5800) << " incidence " << event->summary() << " has time." << endl;
00427     start = writeICalDateTime(event->dtStart());
00428   }
00429   icalcomponent_add_property(vevent,icalproperty_new_dtstart(start));
00430 
00431   if (event->hasEndDate()) {
00432     // end time
00433     icaltimetype end;
00434     if (event->doesFloat()) {
00435 //      kdDebug(5800) << " Event " << event->summary() << " floats." << endl;
00436       // +1 day because end date is non-inclusive.
00437       end = writeICalDate( event->dtEnd().date().addDays( 1 ) );
00438     } else {
00439 //      kdDebug(5800) << " Event " << event->summary() << " has time." << endl;
00440       end = writeICalDateTime(event->dtEnd());
00441     }
00442     icalcomponent_add_property(vevent,icalproperty_new_dtend(end));
00443   }
00444 
00445 // TODO: resources
00446 #if 0
00447   // resources
00448   tmpStrList = anEvent->resources();
00449   tmpStr = tmpStrList.join(";");
00450   if (!tmpStr.isEmpty())
00451     addPropValue(vevent, VCResourcesProp, tmpStr.utf8());
00452 
00453 #endif
00454 
00455   // Transparency
00456   switch( event->transparency() ) {
00457   case Event::Transparent:
00458     icalcomponent_add_property(vevent, icalproperty_new_transp("TRANSPARENT"));
00459     break;
00460   case Event::Opaque:
00461     icalcomponent_add_property(vevent, icalproperty_new_transp("OPAQUE"));
00462     break;
00463   }
00464 
00465   return vevent;
00466 }
00467 
00468 icalcomponent *ICalFormatImpl::writeFreeBusy(FreeBusy *freebusy,
00469                                              Scheduler::Method method)
00470 {
00471 #if QT_VERSION >= 300
00472   kdDebug(5800) << "icalformatimpl: writeFreeBusy: startDate: "
00473     << freebusy->dtStart().toString("ddd MMMM d yyyy: h:m:s ap") << " End Date: "
00474     << freebusy->dtEnd().toString("ddd MMMM d yyyy: h:m:s ap") << endl;
00475 #endif
00476 
00477   icalcomponent *vfreebusy = icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
00478 
00479   writeIncidenceBase(vfreebusy,freebusy);
00480 
00481   icalcomponent_add_property(vfreebusy, icalproperty_new_dtstart(
00482       writeICalDateTime(freebusy->dtStart())));
00483 
00484   icalcomponent_add_property(vfreebusy, icalproperty_new_dtend(
00485       writeICalDateTime(freebusy->dtEnd())));
00486 
00487   if (method == Scheduler::Request) {
00488     icalcomponent_add_property(vfreebusy,icalproperty_new_uid(
00489        freebusy->uid().utf8()));
00490   }
00491 
00492   //Loops through all the periods in the freebusy object
00493   QValueList<Period> list = freebusy->busyPeriods();
00494   QValueList<Period>::Iterator it;
00495   icalperiodtype period;
00496   for (it = list.begin(); it!= list.end(); ++it) {
00497     period.start = writeICalDateTime((*it).start());
00498     period.end = writeICalDateTime((*it).end());
00499     icalcomponent_add_property(vfreebusy, icalproperty_new_freebusy(period) );
00500   }
00501 
00502   return vfreebusy;
00503 }
00504 
00505 icalcomponent *ICalFormatImpl::writeJournal(Journal *journal)
00506 {
00507   icalcomponent *vjournal = icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
00508 
00509   writeIncidence(vjournal,journal);
00510 
00511   // start time
00512   if (journal->dtStart().isValid()) {
00513     icaltimetype start;
00514     if (journal->doesFloat()) {
00515 //      kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl;
00516       start = writeICalDate(journal->dtStart().date());
00517     } else {
00518 //      kdDebug(5800) << " incidence " << event->summary() << " has time." << endl;
00519       start = writeICalDateTime(journal->dtStart());
00520     }
00521     icalcomponent_add_property(vjournal,icalproperty_new_dtstart(start));
00522   }
00523 
00524   return vjournal;
00525 }
00526 
00527 void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence)
00528 {
00529   // pilot sync stuff
00530 // TODO: move this application-specific code to kpilot
00531   if (incidence->pilotId()) {
00532     incidence->setNonKDECustomProperty("X-PILOTID", QString::number(incidence->pilotId()));
00533     incidence->setNonKDECustomProperty("X-PILOTSTAT", QString::number(incidence->syncStatus()));
00534   }
00535 
00536   writeIncidenceBase(parent,incidence);
00537 
00538   // creation date
00539   icalcomponent_add_property(parent,icalproperty_new_created(
00540       writeICalDateTime(incidence->created())));
00541 
00542   // unique id
00543   icalcomponent_add_property(parent,icalproperty_new_uid(
00544       incidence->uid().utf8()));
00545 
00546   // revision
00547   icalcomponent_add_property(parent,icalproperty_new_sequence(
00548       incidence->revision()));
00549 
00550   // last modification date
00551   icalcomponent_add_property(parent,icalproperty_new_lastmodified(
00552       writeICalDateTime(incidence->lastModified())));
00553 
00554   // description
00555   if (!incidence->description().isEmpty()) {
00556     icalcomponent_add_property(parent,icalproperty_new_description(
00557         incidence->description().utf8()));
00558   }
00559 
00560   // summary
00561   if (!incidence->summary().isEmpty()) {
00562     icalcomponent_add_property(parent,icalproperty_new_summary(
00563         incidence->summary().utf8()));
00564   }
00565 
00566   // location
00567   if (!incidence->location().isEmpty()) {
00568     icalcomponent_add_property(parent,icalproperty_new_location(
00569         incidence->location().utf8()));
00570   }
00571 
00572   // status
00573   icalproperty_status status = ICAL_STATUS_NONE;
00574   switch (incidence->status()) {
00575     case Incidence::StatusTentative:    status = ICAL_STATUS_TENTATIVE;  break;
00576     case Incidence::StatusConfirmed:    status = ICAL_STATUS_CONFIRMED;  break;
00577     case Incidence::StatusCompleted:    status = ICAL_STATUS_COMPLETED;  break;
00578     case Incidence::StatusNeedsAction:  status = ICAL_STATUS_NEEDSACTION;  break;
00579     case Incidence::StatusCanceled:     status = ICAL_STATUS_CANCELLED;  break;
00580     case Incidence::StatusInProcess:    status = ICAL_STATUS_INPROCESS;  break;
00581     case Incidence::StatusDraft:        status = ICAL_STATUS_DRAFT;  break;
00582     case Incidence::StatusFinal:        status = ICAL_STATUS_FINAL;  break;
00583     case Incidence::StatusX: {
00584       icalproperty* p = icalproperty_new_status(ICAL_STATUS_X);
00585       icalvalue_set_x(icalproperty_get_value(p), incidence->statusStr().utf8());
00586       icalcomponent_add_property(parent, p);
00587       break;
00588     }
00589     case Incidence::StatusNone:
00590     default:
00591       break;
00592   }
00593   if (status != ICAL_STATUS_NONE)
00594     icalcomponent_add_property(parent, icalproperty_new_status(status));
00595 
00596   // secrecy
00597   const char *classStr;
00598   switch (incidence->secrecy()) {
00599     case Incidence::SecrecyPublic:
00600       classStr = "PUBLIC";
00601       break;
00602     case Incidence::SecrecyConfidential:
00603       classStr = "CONFIDENTIAL";
00604       break;
00605     case Incidence::SecrecyPrivate:
00606     default:
00607       classStr = "PRIVATE";
00608       break;
00609   }
00610   icalcomponent_add_property(parent,icalproperty_new_class(classStr));
00611 
00612   // priority
00613   icalcomponent_add_property(parent,icalproperty_new_priority(
00614       incidence->priority()));
00615 
00616   // categories
00617   QStringList categories = incidence->categories();
00618   QStringList::Iterator it;
00619   for(it = categories.begin(); it != categories.end(); ++it ) {
00620     icalcomponent_add_property(parent,icalproperty_new_categories((*it).utf8()));
00621   }
00622 // TODO: Ensure correct concatenation of categories properties.
00623 
00624 /*
00625   // categories
00626   tmpStrList = incidence->getCategories();
00627   tmpStr = "";
00628   QString catStr;
00629   for ( QStringList::Iterator it = tmpStrList.begin();
00630         it != tmpStrList.end();
00631         ++it ) {
00632     catStr = *it;
00633     if (catStr[0] == ' ')
00634       tmpStr += catStr.mid(1);
00635     else
00636       tmpStr += catStr;
00637     // this must be a ';' character as the vCalendar specification requires!
00638     // vcc.y has been hacked to translate the ';' to a ',' when the vcal is
00639     // read in.
00640     tmpStr += ";";
00641   }
00642   if (!tmpStr.isEmpty()) {
00643     tmpStr.truncate(tmpStr.length()-1);
00644     icalcomponent_add_property(parent,icalproperty_new_categories(
00645         writeText(incidence->getCategories().join(";"))));
00646   }
00647 */
00648 
00649   // related event
00650   if ( !incidence->relatedToUid().isEmpty() ) {
00651     icalcomponent_add_property(parent,icalproperty_new_relatedto(
00652         incidence->relatedToUid().utf8()));
00653   }
00654 
00655   // recurrence rule stuff
00656   if (incidence->doesRecur()) {
00657     kdDebug(5800) << "Write recurrence for '" << incidence->summary() << "' (" << incidence->uid()
00658               << ")" << endl;
00659     icalcomponent_add_property(parent,writeRecurrenceRule(incidence->recurrence()));
00660   }
00661 
00662   // recurrence exception dates and date/times
00663   DateList dateList = incidence->exDates();
00664   DateList::ConstIterator exIt;
00665   for(exIt = dateList.begin(); exIt != dateList.end(); ++exIt) {
00666     icalcomponent_add_property(parent,icalproperty_new_exdate(
00667         writeICalDate(*exIt)));
00668   }
00669   DateTimeList dateTimeList = incidence->exDateTimes();
00670   DateTimeList::ConstIterator extIt;
00671   for(extIt = dateTimeList.begin(); extIt != dateTimeList.end(); ++extIt) {
00672     icalcomponent_add_property(parent,icalproperty_new_exdate(
00673         writeICalDateTime(*extIt)));
00674   }
00675 
00676   // attachments
00677   Attachment::List attachments = incidence->attachments();
00678   Attachment::List::ConstIterator atIt;
00679   for ( atIt = attachments.begin(); atIt != attachments.end(); ++atIt )
00680     icalcomponent_add_property( parent, writeAttachment( *atIt ) );
00681 
00682   // alarms
00683   Alarm::List::ConstIterator alarmIt;
00684   for ( alarmIt = incidence->alarms().begin();
00685         alarmIt != incidence->alarms().end(); ++alarmIt ) {
00686     if ( (*alarmIt)->enabled() ) {
00687       kdDebug(5800) << "Write alarm for " << incidence->summary() << endl;
00688       icalcomponent_add_component( parent, writeAlarm( *alarmIt ) );
00689     }
00690   }
00691 
00692   // duration
00693 
00694 // turned off as it always is set to PTS0 (and must not occur together with DTEND
00695 
00696   if (incidence->hasDuration()) {
00697     icaldurationtype duration;
00698     duration = writeICalDuration(incidence->duration());
00699     icalcomponent_add_property(parent,icalproperty_new_duration(duration));
00700   }
00701 }
00702 
00703 void ICalFormatImpl::writeIncidenceBase( icalcomponent *parent,
00704                                          IncidenceBase * incidenceBase )
00705 {
00706   icalcomponent_add_property( parent, icalproperty_new_dtstamp(
00707       writeICalDateTime( QDateTime::currentDateTime() ) ) );
00708 
00709   // organizer stuff
00710   icalcomponent_add_property( parent, writeOrganizer( incidenceBase->organizer() ) );
00711 
00712   // attendees
00713   if ( incidenceBase->attendeeCount() > 0 ) {
00714     Attendee::List::ConstIterator it;
00715     for( it = incidenceBase->attendees().begin();
00716          it != incidenceBase->attendees().end(); ++it ) {
00717       icalcomponent_add_property( parent, writeAttendee( *it ) );
00718     }
00719   }
00720 
00721   // comments
00722   QStringList comments = incidenceBase->comments();
00723   for (QStringList::Iterator it=comments.begin(); it!=comments.end(); ++it) {
00724     icalcomponent_add_property(parent, icalproperty_new_comment((*it).utf8()));
00725   }
00726 
00727   // custom properties
00728   writeCustomProperties( parent, incidenceBase );
00729 }
00730 
00731 void ICalFormatImpl::writeCustomProperties(icalcomponent *parent,CustomProperties *properties)
00732 {
00733   QMap<QCString, QString> custom = properties->customProperties();
00734   for (QMap<QCString, QString>::Iterator c = custom.begin();  c != custom.end();  ++c) {
00735     icalproperty *p = icalproperty_new_x(c.data().utf8());
00736     icalproperty_set_x_name(p,c.key());
00737     icalcomponent_add_property(parent,p);
00738   }
00739 }
00740 
00741 icalproperty *ICalFormatImpl::writeOrganizer( const Person &organizer )
00742 {
00743   icalproperty *p = icalproperty_new_organizer("MAILTO:" + organizer.email().utf8());
00744 
00745   if (!organizer.name().isEmpty()) {
00746     icalproperty_add_parameter( p, icalparameter_new_cn(organizer.name().utf8()) );
00747   }
00748   // TODO: Write dir, senty-by and language
00749 
00750   return p;
00751 }
00752 
00753 
00754 icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee)
00755 {
00756   icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8());
00757 
00758   if (!attendee->name().isEmpty()) {
00759     icalproperty_add_parameter(p,icalparameter_new_cn(attendee->name().utf8()));
00760   }
00761 
00762 
00763   icalproperty_add_parameter(p,icalparameter_new_rsvp(
00764           attendee->RSVP() ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE ));
00765 
00766   icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
00767   switch (attendee->status()) {
00768     default:
00769     case Attendee::NeedsAction:
00770       status = ICAL_PARTSTAT_NEEDSACTION;
00771       break;
00772     case Attendee::Accepted:
00773       status = ICAL_PARTSTAT_ACCEPTED;
00774       break;
00775     case Attendee::Declined:
00776       status = ICAL_PARTSTAT_DECLINED;
00777       break;
00778     case Attendee::Tentative:
00779       status = ICAL_PARTSTAT_TENTATIVE;
00780       break;
00781     case Attendee::Delegated:
00782       status = ICAL_PARTSTAT_DELEGATED;
00783       break;
00784     case Attendee::Completed:
00785       status = ICAL_PARTSTAT_COMPLETED;
00786       break;
00787     case Attendee::InProcess:
00788       status = ICAL_PARTSTAT_INPROCESS;
00789       break;
00790   }
00791   icalproperty_add_parameter(p,icalparameter_new_partstat(status));
00792 
00793   icalparameter_role role = ICAL_ROLE_REQPARTICIPANT;
00794   switch (attendee->role()) {
00795     case Attendee::Chair:
00796       role = ICAL_ROLE_CHAIR;
00797       break;
00798     default:
00799     case Attendee::ReqParticipant:
00800       role = ICAL_ROLE_REQPARTICIPANT;
00801       break;
00802     case Attendee::OptParticipant:
00803       role = ICAL_ROLE_OPTPARTICIPANT;
00804       break;
00805     case Attendee::NonParticipant:
00806       role = ICAL_ROLE_NONPARTICIPANT;
00807       break;
00808   }
00809   icalproperty_add_parameter(p,icalparameter_new_role(role));
00810 
00811   if (!attendee->uid().isEmpty()) {
00812     icalparameter* icalparameter_uid = icalparameter_new_x(attendee->uid().utf8());
00813     icalparameter_set_xname(icalparameter_uid,"X-UID");
00814     icalproperty_add_parameter(p,icalparameter_uid);
00815   }
00816 
00817   return p;
00818 }
00819 
00820 icalproperty *ICalFormatImpl::writeAttachment(Attachment *att)
00821 {
00822   icalattachtype *attach = icalattachtype_new();
00823   if ( att->isUri() )
00824     icalattachtype_set_url( attach, att->uri().utf8().data() );
00825   else
00826     icalattachtype_set_base64( attach, att->data(), 0 );
00827 
00828   icalproperty *p = icalproperty_new_attach( attach );
00829   icalattachtype_free( attach );
00830 
00831   if ( !att->mimeType().isEmpty() ) {
00832     icalproperty_add_parameter( p,
00833         icalparameter_new_fmttype( att->mimeType().utf8().data() ) );
00834   }
00835 
00836   if ( att->isBinary() ) {
00837     icalproperty_add_parameter( p,
00838         icalparameter_new_value( ICAL_VALUE_BINARY ) );
00839     icalproperty_add_parameter( p,
00840         icalparameter_new_encoding( ICAL_ENCODING_BASE64 ) );
00841   }
00842   return p;
00843 }
00844 
00845 icalproperty *ICalFormatImpl::writeRecurrenceRule(Recurrence *recur)
00846 {
00847 //  kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl;
00848 
00849   icalrecurrencetype r;
00850 
00851   icalrecurrencetype_clear(&r);
00852 
00853   int index = 0;
00854   int index2 = 0;
00855 
00856   QPtrList<Recurrence::rMonthPos> tmpPositions;
00857   QPtrList<int> tmpDays;
00858   int *tmpDay;
00859   Recurrence::rMonthPos *tmpPos;
00860   bool datetime = false;
00861   int day;
00862   int i;
00863 
00864   switch(recur->doesRecur()) {
00865     case Recurrence::rMinutely:
00866       r.freq = ICAL_MINUTELY_RECURRENCE;
00867       datetime = true;
00868       break;
00869     case Recurrence::rHourly:
00870       r.freq = ICAL_HOURLY_RECURRENCE;
00871       datetime = true;
00872       break;
00873     case Recurrence::rDaily:
00874       r.freq = ICAL_DAILY_RECURRENCE;
00875       break;
00876     case Recurrence::rWeekly:
00877       r.freq = ICAL_WEEKLY_RECURRENCE;
00878       r.week_start = static_cast<icalrecurrencetype_weekday>(recur->weekStart()%7 + 1);
00879       for (i = 0; i < 7; i++) {
00880         if (recur->days().testBit(i)) {
00881           day = (i + 1)%7 + 1;     // convert from Monday=0 to Sunday=1
00882           r.by_day[index++] = icalrecurrencetype_day_day_of_week(day);
00883         }
00884       }
00885 //      r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
00886       break;
00887     case Recurrence::rMonthlyPos:
00888       r.freq = ICAL_MONTHLY_RECURRENCE;
00889 
00890       tmpPositions = recur->monthPositions();
00891       for (tmpPos = tmpPositions.first();
00892            tmpPos;
00893            tmpPos = tmpPositions.next()) {
00894         for (i = 0; i < 7; i++) {
00895           if (tmpPos->rDays.testBit(i)) {
00896             day = (i + 1)%7 + 1;     // convert from Monday=0 to Sunday=1
00897             day += tmpPos->rPos*8;
00898             if (tmpPos->negative) day = -day;
00899             r.by_day[index++] = day;
00900           }
00901         }
00902       }
00903 //      r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
00904       break;
00905     case Recurrence::rMonthlyDay:
00906       r.freq = ICAL_MONTHLY_RECURRENCE;
00907 
00908       tmpDays = recur->monthDays();
00909       for (tmpDay = tmpDays.first();
00910            tmpDay;
00911            tmpDay = tmpDays.next()) {
00912         r.by_month_day[index++] = icalrecurrencetype_day_position(*tmpDay*8);
00913       }
00914 //      r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
00915       break;
00916     case Recurrence::rYearlyMonth:
00917     case Recurrence::rYearlyPos:
00918       r.freq = ICAL_YEARLY_RECURRENCE;
00919 
00920       tmpDays = recur->yearNums();
00921       for (tmpDay = tmpDays.first();
00922            tmpDay;
00923            tmpDay = tmpDays.next()) {
00924         r.by_month[index++] = *tmpDay;
00925       }
00926 //      r.by_set_pos[index] = ICAL_RECURRENCE_ARRAY_MAX;
00927       if (recur->doesRecur() == Recurrence::rYearlyPos) {
00928         tmpPositions = recur->monthPositions();
00929         for (tmpPos = tmpPositions.first();
00930              tmpPos;
00931              tmpPos = tmpPositions.next()) {
00932           for (i = 0; i < 7; i++) {
00933             if (tmpPos->rDays.testBit(i)) {
00934               day = (i + 1)%7 + 1;     // convert from Monday=0 to Sunday=1
00935               day += tmpPos->rPos*8;
00936               if (tmpPos->negative) day = -day;
00937               r.by_day[index2++] = day;
00938             }
00939           }
00940         }
00941 //        r.by_day[index2] = ICAL_RECURRENCE_ARRAY_MAX;
00942       }
00943       else {
00944         tmpDays = recur->monthDays();
00945         for (tmpDay = tmpDays.first();
00946              tmpDay;
00947              tmpDay = tmpDays.next()) {
00948           r.by_month_day[index2++] = icalrecurrencetype_day_position(*tmpDay*8);
00949         }
00950 //        r.by_month_day[index2] = ICAL_RECURRENCE_ARRAY_MAX;
00951       }
00952       break;
00953     case Recurrence::rYearlyDay:
00954       r.freq = ICAL_YEARLY_RECURRENCE;
00955 
00956       tmpDays = recur->yearNums();
00957       for (tmpDay = tmpDays.first();
00958            tmpDay;
00959            tmpDay = tmpDays.next()) {
00960         r.by_year_day[index++] = *tmpDay;
00961       }
00962 //      r.by_year_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
00963       break;
00964     default:
00965       r.freq = ICAL_NO_RECURRENCE;
00966       kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl;
00967       break;
00968   }
00969 
00970   r.interval = recur->frequency();
00971 
00972   if (recur->duration() > 0) {
00973     r.count = recur->duration();
00974   } else if (recur->duration() == -1) {
00975     r.count = 0;
00976   } else {
00977     if (datetime)
00978       r.until = writeICalDateTime(recur->endDateTime());
00979     else
00980       r.until = writeICalDate(recur->endDate());
00981   }
00982 
00983 // Debug output
00984 #if 0
00985   const char *str = icalrecurrencetype_as_string(&r);
00986   if (str) {
00987     kdDebug(5800) << " String: " << str << endl;
00988   } else {
00989     kdDebug(5800) << " No String" << endl;
00990   }
00991 #endif
00992 
00993   return icalproperty_new_rrule(r);
00994 }
00995 
00996 icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
00997 {
00998   icalcomponent *a = icalcomponent_new(ICAL_VALARM_COMPONENT);
00999 
01000   icalproperty_action action;
01001   icalattachtype *attach = 0;
01002 
01003   switch (alarm->type()) {
01004     case Alarm::Procedure:
01005       action = ICAL_ACTION_PROCEDURE;
01006       attach = icalattachtype_new();
01007       icalattachtype_set_url(attach,QFile::encodeName(alarm->programFile()).data());
01008       icalcomponent_add_property(a,icalproperty_new_attach(attach));
01009       icalattachtype_free(attach);
01010       if (!alarm->programArguments().isEmpty()) {
01011         icalcomponent_add_property(a,icalproperty_new_description(alarm->programArguments().utf8()));
01012       }
01013       break;
01014     case Alarm::Audio:
01015       action = ICAL_ACTION_AUDIO;
01016       if (!alarm->audioFile().isEmpty()) {
01017         attach = icalattachtype_new();
01018         icalattachtype_set_url(attach,QFile::encodeName( alarm->audioFile() ).data());
01019         icalcomponent_add_property(a,icalproperty_new_attach(attach));
01020         icalattachtype_free(attach);
01021       }
01022       break;
01023     case Alarm::Email: {
01024       action = ICAL_ACTION_EMAIL;
01025       QValueList<Person> addresses = alarm->mailAddresses();
01026       for (QValueList<Person>::Iterator ad = addresses.begin();  ad != addresses.end();  ++ad) {
01027         icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8());
01028         if (!(*ad).name().isEmpty()) {
01029           icalproperty_add_parameter(p,icalparameter_new_cn((*ad).name().utf8()));
01030         }
01031         icalcomponent_add_property(a,p);
01032       }
01033       icalcomponent_add_property(a,icalproperty_new_summary(alarm->mailSubject().utf8()));
01034       icalcomponent_add_property(a,icalproperty_new_description(alarm->mailText().utf8()));
01035       QStringList attachments = alarm->mailAttachments();
01036       if (attachments.count() > 0) {
01037         for (QStringList::Iterator at = attachments.begin();  at != attachments.end();  ++at) {
01038           attach = icalattachtype_new();
01039           icalattachtype_set_url(attach,QFile::encodeName( *at ).data());
01040           icalcomponent_add_property(a,icalproperty_new_attach(attach));
01041           icalattachtype_free(attach);
01042         }
01043       }
01044       break;
01045     }
01046     case Alarm::Display:
01047       action = ICAL_ACTION_DISPLAY;
01048       icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8()));
01049       break;
01050     case Alarm::Invalid:
01051     default:
01052       kdDebug(5800) << "Unknown type of alarm" << endl;
01053       action = ICAL_ACTION_NONE;
01054       break;
01055   }
01056   icalcomponent_add_property(a,icalproperty_new_action(action));
01057 
01058   // Trigger time
01059   icaltriggertype trigger;
01060   if ( alarm->hasTime() ) {
01061     trigger.time = writeICalDateTime(alarm->time());
01062     trigger.duration = icaldurationtype_null_duration();
01063   } else {
01064     trigger.time = icaltime_null_time();
01065     Duration offset;
01066     if ( alarm->hasStartOffset() )
01067       offset = alarm->startOffset();
01068     else
01069       offset = alarm->endOffset();
01070     trigger.duration = icaldurationtype_from_int( offset.asSeconds() );
01071   }
01072   icalproperty *p = icalproperty_new_trigger(trigger);
01073   if ( alarm->hasEndOffset() )
01074     icalproperty_add_parameter(p,icalparameter_new_related(ICAL_RELATED_END));
01075   icalcomponent_add_property(a,p);
01076 
01077   // Repeat count and duration
01078   if (alarm->repeatCount()) {
01079     icalcomponent_add_property(a,icalproperty_new_repeat(alarm->repeatCount()));
01080     icalcomponent_add_property(a,icalproperty_new_duration(
01081                              icaldurationtype_from_int(alarm->snoozeTime()*60)));
01082   }
01083 
01084   // Custom properties
01085   QMap<QCString, QString> custom = alarm->customProperties();
01086   for (QMap<QCString, QString>::Iterator c = custom.begin();  c != custom.end();  ++c) {
01087     icalproperty *p = icalproperty_new_x(c.data().utf8());
01088     icalproperty_set_x_name(p,c.key());
01089     icalcomponent_add_property(a,p);
01090   }
01091 
01092   return a;
01093 }
01094 
01095 // Read a timezone and store it in a list where it can be accessed as needed
01096 // by the other readXXX() routines. Note that no writeTimezone is needed
01097 // because we always store in UTC.
01098 void ICalFormatImpl::readTimezone(icalcomponent *vtimezone)
01099 {
01100   Timezone *timezone = new Timezone(this, vtimezone);
01101 
01102   mTimezones.insert(timezone->id(), timezone);
01103 }
01104 
01105 Todo *ICalFormatImpl::readTodo(icalcomponent *vtodo)
01106 {
01107   Todo *todo = new Todo;
01108 
01109   readIncidence(vtodo,todo);
01110 
01111   icalproperty *p = icalcomponent_get_first_property(vtodo,ICAL_ANY_PROPERTY);
01112 
01113 //  int intvalue;
01114   icaltimetype icaltime;
01115 
01116   QStringList categories;
01117 
01118   while (p) {
01119     icalproperty_kind kind = icalproperty_isa(p);
01120     switch (kind) {
01121 
01122       case ICAL_DUE_PROPERTY:  // due date
01123         icaltime = icalproperty_get_due(p);
01124         readTzidParameter(p,icaltime);
01125         if (icaltime.is_date) {
01126           todo->setDtDue(QDateTime(readICalDate(icaltime),QTime(0,0,0)),true);
01127           todo->setFloats(true);
01128 
01129         } else {
01130           todo->setDtDue(readICalDateTime(icaltime),true);
01131           todo->setFloats(false);
01132         }
01133         todo->setHasDueDate(true);
01134         break;
01135 
01136       case ICAL_COMPLETED_PROPERTY:  // completion date
01137         icaltime = icalproperty_get_completed(p);
01138         readTzidParameter(p,icaltime);
01139         todo->setCompleted(readICalDateTime(icaltime));
01140         break;
01141 
01142       case ICAL_PERCENTCOMPLETE_PROPERTY:  // Percent completed
01143         todo->setPercentComplete(icalproperty_get_percentcomplete(p));
01144         break;
01145 
01146       case ICAL_RELATEDTO_PROPERTY:  // related todo (parent)
01147         todo->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
01148         mTodosRelate.append(todo);
01149         break;
01150 
01151       case ICAL_DTSTART_PROPERTY: {
01152         // Flag that todo has start date. Value is read in by readIncidence().
01153         if ( todo->comments().grep("NoStartDate").count() )
01154           todo->setHasStartDate( false );
01155         else
01156           todo->setHasStartDate( true );
01157         break;
01158       }
01159 
01160       case ICAL_RECURRENCEID_PROPERTY:
01161         icaltime = icalproperty_get_recurrenceid(p);
01162         readTzidParameter(p,icaltime);
01163         todo->setDtRecurrence( readICalDateTime(icaltime) );
01164         break;
01165 
01166       default:
01167 //        kdDebug(5800) << "ICALFormat::readTodo(): Unknown property: " << kind
01168 //                  << endl;
01169         break;
01170     }
01171 
01172     p = icalcomponent_get_next_property(vtodo,ICAL_ANY_PROPERTY);
01173   }
01174 
01175   mCompat->fixEmptySummary( todo );
01176 
01177   return todo;
01178 }
01179 
01180 Event *ICalFormatImpl::readEvent(icalcomponent *vevent)
01181 {
01182   Event *event = new Event;
01183   event->setFloats(false);
01184 
01185   readIncidence(vevent,event);
01186 
01187   icalproperty *p = icalcomponent_get_first_property(vevent,ICAL_ANY_PROPERTY);
01188 
01189 //  int intvalue;
01190   icaltimetype icaltime;
01191 
01192   QStringList categories;
01193   QString transparency;
01194 
01195   while (p) {
01196     icalproperty_kind kind = icalproperty_isa(p);
01197     switch (kind) {
01198 
01199       case ICAL_DTEND_PROPERTY:  // start date and time
01200         icaltime = icalproperty_get_dtend(p);
01201         readTzidParameter(p,icaltime);
01202         if (icaltime.is_date) {
01203           event->setFloats( true );
01204           // End date is non-inclusive
01205           QDate endDate = readICalDate( icaltime ).addDays( -1 );
01206           mCompat->fixFloatingEnd( endDate );
01207           if ( endDate < event->dtStart().date() ) {
01208             endDate = event->dtStart().date();
01209           }
01210           event->setDtEnd( QDateTime( endDate, QTime( 0, 0, 0 ) ) );
01211         } else {
01212           event->setDtEnd(readICalDateTime(icaltime));
01213         }
01214         break;
01215 
01216 // TODO:
01217   // at this point, there should be at least a start or end time.
01218   // fix up for events that take up no time but have a time associated
01219 #if 0
01220   if (!(vo = isAPropertyOf(vevent, VCDTstartProp)))
01221     anEvent->setDtStart(anEvent->dtEnd());
01222   if (!(vo = isAPropertyOf(vevent, VCDTendProp)))
01223     anEvent->setDtEnd(anEvent->dtStart());
01224 #endif
01225 
01226 #if 0
01227   // secrecy
01228   if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) {
01229     anEvent->setSecrecy(s = fakeCString(vObjectUStringZValue(vo)));
01230     deleteStr(s);
01231   }
01232   else
01233     anEvent->setSecrecy("PUBLIC");
01234 
01235   // attachments
01236   tmpStrList.clear();
01237   initPropIterator(&voi, vevent);
01238   while (moreIteration(&voi)) {
01239     vo = nextVObject(&voi);
01240     if (strcmp(vObjectName(vo), VCAttachProp) == 0) {
01241       tmpStrList.append(s = fakeCString(vObjectUStringZValue(vo)));
01242       deleteStr(s);
01243     }
01244   }
01245   anEvent->setAttachments(tmpStrList);
01246 
01247   // resources
01248   if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) {
01249     QString resources = (s = fakeCString(vObjectUStringZValue(vo)));
01250     deleteStr(s);
01251     tmpStrList.clear();
01252     index1 = 0;
01253     index2 = 0;
01254     QString resource;
01255     while ((index2 = resources.find(';', index1)) != -1) {
01256       resource = resources.mid(index1, (index2 - index1));
01257       tmpStrList.append(resource);
01258       index1 = index2;
01259     }
01260     anEvent->setResources(tmpStrList);
01261   }
01262 #endif
01263 
01264       case ICAL_RELATEDTO_PROPERTY:  // related event (parent)
01265         event->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
01266         mEventsRelate.append(event);
01267         break;
01268 
01269 
01270       case ICAL_TRANSP_PROPERTY:  // Transparency
01271     transparency = QString::fromUtf8(icalproperty_get_transp(p));
01272     if( transparency == "TRANSPARENT" )
01273       event->setTransparency( Event::Transparent );
01274     else
01275       event->setTransparency( Event::Opaque );
01276     break;
01277 
01278       default:
01279 //        kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind
01280 //                  << endl;
01281         break;
01282     }
01283 
01284     p = icalcomponent_get_next_property(vevent,ICAL_ANY_PROPERTY);
01285   }
01286 
01287   QString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT");
01288   if (!msade.isNull()) {
01289     bool floats = (msade == QString::fromLatin1("TRUE"));
01290     kdDebug(5800) << "ICALFormat::readEvent(): all day event: " << floats << endl;
01291     event->setFloats(floats);
01292     if (floats) {
01293       QDateTime endDate = event->dtEnd();
01294       event->setDtEnd(endDate.addDays(-1));
01295     }
01296   }
01297 
01298   mCompat->fixEmptySummary( event );
01299 
01300   return event;
01301 }
01302 
01303 FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
01304 {
01305   FreeBusy *freebusy = new FreeBusy;
01306 
01307   readIncidenceBase(vfreebusy,freebusy);
01308 
01309   icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY);
01310 
01311   icaltimetype icaltime;
01312   icalperiodtype icalperiod;
01313   QDateTime period_start, period_end;
01314 
01315   while (p) {
01316     icalproperty_kind kind = icalproperty_isa(p);
01317     switch (kind) {
01318 
01319       case ICAL_DTSTART_PROPERTY:  // start date and time
01320         icaltime = icalproperty_get_dtstart(p);
01321         readTzidParameter(p,icaltime);
01322         freebusy->setDtStart(readICalDateTime(icaltime));
01323         break;
01324 
01325       case ICAL_DTEND_PROPERTY:  // start End Date and Time
01326         icaltime = icalproperty_get_dtend(p);
01327         readTzidParameter(p,icaltime);
01328         freebusy->setDtEnd(readICalDateTime(icaltime));
01329         break;
01330 
01331       case ICAL_FREEBUSY_PROPERTY:  //Any FreeBusy Times
01332         icalperiod = icalproperty_get_freebusy(p);
01333         readTzidParameter(p,icalperiod.start);
01334         readTzidParameter(p,icalperiod.end);
01335         period_start = readICalDateTime(icalperiod.start);
01336         period_end = readICalDateTime(icalperiod.end);
01337         freebusy->addPeriod(period_start, period_end);
01338         break;
01339 
01340       default:
01341 //        kdDebug(5800) << "ICalFormatImpl::readIncidence(): Unknown property: "
01342 //                      << kind << endl;
01343       break;
01344     }
01345     p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY);
01346   }
01347 
01348   return freebusy;
01349 }
01350 
01351 Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal)
01352 {
01353   Journal *journal = new Journal;
01354 
01355   readIncidence(vjournal,journal);
01356 
01357   return journal;
01358 }
01359 
01360 Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee)
01361 {
01362   icalparameter *p = 0;
01363 
01364   QString email = QString::fromUtf8(icalproperty_get_attendee(attendee));
01365 
01366   QString name;
01367   QString uid = QString::null;
01368   p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER);
01369   if (p) {
01370     name = QString::fromUtf8(icalparameter_get_cn(p));
01371   } else {
01372   }
01373 
01374   bool rsvp=false;
01375   p = icalproperty_get_first_parameter(attendee,ICAL_RSVP_PARAMETER);
01376   if (p) {
01377     icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp(p);
01378     if (rsvpParameter == ICAL_RSVP_TRUE) rsvp = true;
01379   }
01380 
01381   Attendee::PartStat status = Attendee::NeedsAction;
01382   p = icalproperty_get_first_parameter(attendee,ICAL_PARTSTAT_PARAMETER);
01383   if (p) {
01384     icalparameter_partstat partStatParameter = icalparameter_get_partstat(p);
01385     switch(partStatParameter) {
01386       default:
01387       case ICAL_PARTSTAT_NEEDSACTION:
01388         status = Attendee::NeedsAction;
01389         break;
01390       case ICAL_PARTSTAT_ACCEPTED:
01391         status = Attendee::Accepted;
01392         break;
01393       case ICAL_PARTSTAT_DECLINED:
01394         status = Attendee::Declined;
01395         break;
01396       case ICAL_PARTSTAT_TENTATIVE:
01397         status = Attendee::Tentative;
01398         break;
01399       case ICAL_PARTSTAT_DELEGATED:
01400         status = Attendee::Delegated;
01401         break;
01402       case ICAL_PARTSTAT_COMPLETED:
01403         status = Attendee::Completed;
01404         break;
01405       case ICAL_PARTSTAT_INPROCESS:
01406         status = Attendee::InProcess;
01407         break;
01408     }
01409   }
01410 
01411   Attendee::Role role = Attendee::ReqParticipant;
01412   p = icalproperty_get_first_parameter(attendee,ICAL_ROLE_PARAMETER);
01413   if (p) {
01414     icalparameter_role roleParameter = icalparameter_get_role(p);
01415     switch(roleParameter) {
01416       case ICAL_ROLE_CHAIR:
01417         role = Attendee::Chair;
01418         break;
01419       default:
01420       case ICAL_ROLE_REQPARTICIPANT:
01421         role = Attendee::ReqParticipant;
01422         break;
01423       case ICAL_ROLE_OPTPARTICIPANT:
01424         role = Attendee::OptParticipant;
01425         break;
01426       case ICAL_ROLE_NONPARTICIPANT:
01427         role = Attendee::NonParticipant;
01428         break;
01429     }
01430   }
01431 
01432   p = icalproperty_get_first_parameter(attendee,ICAL_X_PARAMETER);
01433   uid = icalparameter_get_xvalue(p);
01434   // This should be added, but there seems to be a libical bug here.
01435   /*while (p) {
01436    // if (icalparameter_get_xname(p) == "X-UID") {
01437     uid = icalparameter_get_xvalue(p);
01438     p = icalproperty_get_next_parameter(attendee,ICAL_X_PARAMETER);
01439   } */
01440 
01441   return new Attendee( name, email, rsvp, status, role, uid );
01442 }
01443 
01444 Person ICalFormatImpl::readOrganizer( icalproperty *organizer )
01445 {
01446   QString email = QString::fromUtf8(icalproperty_get_organizer(organizer));
01447   if ( email.startsWith("mailto:", false ) ) {
01448     email = email.remove(0,7);
01449   }
01450   QString cn;
01451   
01452   icalparameter *p = icalproperty_get_first_parameter( 
01453              organizer, ICAL_CN_PARAMETER );
01454   
01455   if ( p ) {
01456     cn = QString::fromUtf8( icalparameter_get_cn( p ) );
01457   }
01458   Person org( cn, email );
01459   // TODO: Treat sent-by, dir and language here, too
01460   return org;
01461 }
01462 
01463 Attachment *ICalFormatImpl::readAttachment(icalproperty *attach)
01464 {
01465   icalattachtype *a = icalproperty_get_attach(attach);
01466   icalparameter_value v = ICAL_VALUE_NONE;
01467   icalparameter_encoding e = ICAL_ENCODING_NONE;
01468 
01469   Attachment *attachment = 0;
01470 
01471   icalparameter *vp = icalproperty_get_first_parameter(attach, ICAL_VALUE_PARAMETER);
01472   if (vp)
01473     v = icalparameter_get_value(vp);
01474 
01475   icalparameter *ep = icalproperty_get_first_parameter(attach, ICAL_ENCODING_PARAMETER);
01476   if (ep)
01477     e = icalparameter_get_encoding(ep);
01478 
01479   if (v == ICAL_VALUE_BINARY && e == ICAL_ENCODING_BASE64) {
01480     attachment = new Attachment(icalattachtype_get_base64(a));
01481   } else if ((v == ICAL_VALUE_NONE || v == ICAL_VALUE_URI) && (e == ICAL_ENCODING_NONE || e == ICAL_ENCODING_8BIT)) {
01482     attachment = new Attachment(QString(icalattachtype_get_url(a)));
01483   } else {
01484     kdWarning(5800) << "Unsupported attachment format, discarding it!" << endl;
01485     return 0;
01486   }
01487 
01488   icalparameter *p = icalproperty_get_first_parameter(attach, ICAL_FMTTYPE_PARAMETER);
01489   if (p)
01490     attachment->setMimeType(QString(icalparameter_get_fmttype(p)));
01491 
01492   return attachment;
01493 }
01494 
01495 void ICalFormatImpl::readIncidence(icalcomponent *parent,Incidence *incidence)
01496 {
01497   readIncidenceBase(parent,incidence);
01498 
01499   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
01500 
01501   const char *text;
01502   int intvalue;
01503   icaltimetype icaltime;
01504   icaldurationtype icalduration;
01505 
01506   QStringList categories;
01507 
01508   while (p) {
01509     icalproperty_kind kind = icalproperty_isa(p);
01510     switch (kind) {
01511 
01512       case ICAL_CREATED_PROPERTY:
01513         icaltime = icalproperty_get_created(p);
01514         readTzidParameter(p,icaltime);
01515         incidence->setCreated(readICalDateTime(icaltime));
01516         break;
01517 
01518       case ICAL_SEQUENCE_PROPERTY:  // sequence
01519         intvalue = icalproperty_get_sequence(p);
01520         incidence->setRevision(intvalue);
01521         break;
01522 
01523       case ICAL_LASTMODIFIED_PROPERTY:  // last modification date
01524         icaltime = icalproperty_get_lastmodified(p);
01525         readTzidParameter(p,icaltime);
01526         incidence->setLastModified(readICalDateTime(icaltime));
01527         break;
01528 
01529       case ICAL_DTSTART_PROPERTY:  // start date and time
01530         icaltime = icalproperty_get_dtstart(p);
01531         readTzidParameter(p,icaltime);
01532         if (icaltime.is_date) {
01533           incidence->setDtStart(QDateTime(readICalDate(icaltime),QTime(0,0,0)));
01534           incidence->setFloats(true);
01535         } else {
01536           incidence->setDtStart(readICalDateTime(icaltime));
01537         }
01538         break;
01539 
01540       case ICAL_DURATION_PROPERTY:  // start date and time
01541         icalduration = icalproperty_get_duration(p);
01542         incidence->setDuration(readICalDuration(icalduration));
01543         break;
01544 
01545       case ICAL_DESCRIPTION_PROPERTY:  // description
01546         text = icalproperty_get_description(p);
01547         incidence->setDescription(QString::fromUtf8(text));
01548         break;
01549 
01550       case ICAL_SUMMARY_PROPERTY:  // summary
01551         text = icalproperty_get_summary(p);
01552         incidence->setSummary(QString::fromUtf8(text));
01553         break;
01554 
01555       case ICAL_LOCATION_PROPERTY:  // location
01556         text = icalproperty_get_location(p);
01557         incidence->setLocation(QString::fromUtf8(text));
01558         break;
01559 
01560       case ICAL_STATUS_PROPERTY: {  // status
01561         Incidence::Status stat;
01562         switch (icalproperty_get_status(p)) {
01563           case ICAL_STATUS_TENTATIVE:   stat = Incidence::StatusTentative; break;
01564           case ICAL_STATUS_CONFIRMED:   stat = Incidence::StatusConfirmed; break;
01565           case ICAL_STATUS_COMPLETED:   stat = Incidence::StatusCompleted; break;
01566           case ICAL_STATUS_NEEDSACTION: stat = Incidence::StatusNeedsAction; break;
01567           case ICAL_STATUS_CANCELLED:   stat = Incidence::StatusCanceled; break;
01568           case ICAL_STATUS_INPROCESS:   stat = Incidence::StatusInProcess; break;
01569           case ICAL_STATUS_DRAFT:       stat = Incidence::StatusDraft; break;
01570           case ICAL_STATUS_FINAL:       stat = Incidence::StatusFinal; break;
01571           case ICAL_STATUS_X:
01572             incidence->setCustomStatus(QString::fromUtf8(icalvalue_get_x(icalproperty_get_value(p))));
01573             stat = Incidence::StatusX;
01574             break;
01575           case ICAL_STATUS_NONE:
01576           default:                      stat = Incidence::StatusNone; break;
01577         }
01578         if (stat != Incidence::StatusX)
01579           incidence->setStatus(stat);
01580         break;
01581       }
01582 
01583       case ICAL_PRIORITY_PROPERTY:  // priority
01584         intvalue = icalproperty_get_priority(p);
01585         incidence->setPriority(intvalue);
01586         break;
01587 
01588       case ICAL_CATEGORIES_PROPERTY:  // categories
01589         text = icalproperty_get_categories(p);
01590         categories.append(QString::fromUtf8(text));
01591         break;
01592 
01593       case ICAL_RRULE_PROPERTY:
01594         readRecurrenceRule(p,incidence);
01595         break;
01596 
01597       case ICAL_EXDATE_PROPERTY:
01598         icaltime = icalproperty_get_exdate(p);
01599         readTzidParameter(p,icaltime);
01600         if (icaltime.is_date) {
01601           incidence->addExDate(readICalDate(icaltime));
01602         } else {
01603           incidence->addExDateTime(readICalDateTime(icaltime));
01604         }
01605         break;
01606 
01607       case ICAL_CLASS_PROPERTY:
01608         text = icalproperty_get_class(p);
01609         if (strcmp(text,"PUBLIC") == 0) {
01610           incidence->setSecrecy(Incidence::SecrecyPublic);
01611         } else if (strcmp(text,"CONFIDENTIAL") == 0) {
01612           incidence->setSecrecy(Incidence::SecrecyConfidential);
01613         } else {
01614           incidence->setSecrecy(Incidence::SecrecyPrivate);
01615         }
01616         break;
01617 
01618       case ICAL_ATTACH_PROPERTY:  // attachments
01619         incidence->addAttachment(readAttachment(p));
01620         break;
01621 
01622       default:
01623 //        kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
01624 //                  << endl;
01625         break;
01626     }
01627 
01628     p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
01629   }
01630 
01631   // kpilot stuff
01632 // TODO: move this application-specific code to kpilot
01633   QString kp = incidence->nonKDECustomProperty("X-PILOTID");
01634   if (!kp.isNull()) {
01635     incidence->setPilotId(kp.toInt());
01636   }
01637   kp = incidence->nonKDECustomProperty("X-PILOTSTAT");
01638   if (!kp.isNull()) {
01639     incidence->setSyncStatus(kp.toInt());
01640   }
01641 
01642   // Now that recurrence and exception stuff is completely set up,
01643   // do any backwards compatibility adjustments.
01644   if (incidence->doesRecur())
01645       mCompat->fixRecurrence( incidence );
01646 
01647   // add categories
01648   incidence->setCategories(categories);
01649 
01650   // iterate through all alarms
01651   for (icalcomponent *alarm = icalcomponent_get_first_component(parent,ICAL_VALARM_COMPONENT);
01652        alarm;
01653        alarm = icalcomponent_get_next_component(parent,ICAL_VALARM_COMPONENT)) {
01654     readAlarm(alarm,incidence);
01655   }
01656 }
01657 
01658 void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
01659 {
01660   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
01661 
01662   while (p) {
01663     icalproperty_kind kind = icalproperty_isa(p);
01664     switch (kind) {
01665 
01666       case ICAL_UID_PROPERTY:  // unique id
01667         incidenceBase->setUid(QString::fromUtf8(icalproperty_get_uid(p)));
01668         break;
01669 
01670       case ICAL_ORGANIZER_PROPERTY:  // organizer
01671         incidenceBase->setOrganizer( readOrganizer(p));
01672         break;
01673 
01674       case ICAL_ATTENDEE_PROPERTY:  // attendee
01675         incidenceBase->addAttendee(readAttendee(p));
01676         break;
01677 
01678       case ICAL_COMMENT_PROPERTY:
01679         incidenceBase->addComment(
01680             QString::fromUtf8(icalproperty_get_comment(p)));
01681         break;
01682 
01683       default:
01684         break;
01685     }
01686 
01687     p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
01688   }
01689 
01690   // custom properties
01691   readCustomProperties(parent, incidenceBase);
01692 }
01693 
01694 void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties)
01695 {
01696   QMap<QCString, QString> customProperties;
01697 
01698   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
01699 
01700   while (p) {
01701 
01702     QString value = QString::fromUtf8(icalproperty_get_x(p));
01703     customProperties[icalproperty_get_name(p)] = value;
01704 
01705     p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
01706   }
01707 
01708   properties->setCustomProperties(customProperties);
01709 }
01710 
01711 void ICalFormatImpl::readRecurrenceRule(icalproperty *rrule,Incidence *incidence)
01712 {
01713 //  kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
01714 
01715   Recurrence *recur = incidence->recurrence();
01716   recur->setCompatVersion(mCalendarVersion);
01717   recur->unsetRecurs();
01718 
01719   struct icalrecurrencetype r = icalproperty_get_rrule(rrule);
01720 
01721   dumpIcalRecurrence(r);
01722 
01723   readRecurrence( r, recur );
01724 }
01725 
01726 void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, Recurrence* recur )
01727 {
01728   int wkst;
01729   int index = 0;
01730   short day = 0;
01731   QBitArray qba(7);
01732 
01733   switch (r.freq) {
01734     case ICAL_MINUTELY_RECURRENCE:
01735       if (!icaltime_is_null_time(r.until)) {
01736         recur->setMinutely(r.interval,readICalDateTime(r.until));
01737       } else {
01738         if (r.count == 0)
01739           recur->setMinutely(r.interval,-1);
01740         else
01741           recur->setMinutely(r.interval,r.count);
01742       }
01743       break;
01744     case ICAL_HOURLY_RECURRENCE:
01745       if (!icaltime_is_null_time(r.until)) {
01746         recur->setHourly(r.interval,readICalDateTime(r.until));
01747       } else {
01748         if (r.count == 0)
01749           recur->setHourly(r.interval,-1);
01750         else
01751           recur->setHourly(r.interval,r.count);
01752       }
01753       break;
01754     case ICAL_DAILY_RECURRENCE:
01755       if (!icaltime_is_null_time(r.until)) {
01756         recur->setDaily(r.interval,readICalDate(r.until));
01757       } else {
01758         if (r.count == 0)
01759           recur->setDaily(r.interval,-1);
01760         else
01761           recur->setDaily(r.interval,r.count);
01762       }
01763       break;
01764     case ICAL_WEEKLY_RECURRENCE:
01765 //      kdDebug(5800) << "WEEKLY_RECURRENCE" << endl;
01766       wkst = (r.week_start + 5)%7 + 1;
01767       if (!icaltime_is_null_time(r.until)) {
01768         recur->setWeekly(r.interval,qba,readICalDate(r.until),wkst);
01769       } else {
01770         if (r.count == 0)
01771           recur->setWeekly(r.interval,qba,-1,wkst);
01772         else
01773           recur->setWeekly(r.interval,qba,r.count,wkst);
01774       }
01775       while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01776 //        kdDebug(5800) << " " << day << endl;
01777         qba.setBit((day+5)%7);    // convert from Sunday=1 to Monday=0
01778       }
01779       break;
01780     case ICAL_MONTHLY_RECURRENCE:
01781       if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
01782         if (!icaltime_is_null_time(r.until)) {
01783           recur->setMonthly(Recurrence::rMonthlyPos,r.interval,
01784                             readICalDate(r.until));
01785         } else {
01786           if (r.count == 0)
01787             recur->setMonthly(Recurrence::rMonthlyPos,r.interval,-1);
01788           else
01789             recur->setMonthly(Recurrence::rMonthlyPos,r.interval,r.count);
01790         }
01791         bool useSetPos = false;
01792         short pos = 0;
01793         while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01794 //          kdDebug(5800) << "----a " << index << ": " << day << endl;
01795           pos = icalrecurrencetype_day_position(day);
01796           if (pos) {
01797             day = icalrecurrencetype_day_day_of_week(day);
01798             QBitArray ba(7);          // don't wipe qba
01799             ba.setBit((day+5)%7);     // convert from Sunday=1 to Monday=0
01800             recur->addMonthlyPos(pos,ba);
01801           } else {
01802             qba.setBit((day+5)%7);    // convert from Sunday=1 to Monday=0
01803             useSetPos = true;
01804           }
01805         }
01806         if (useSetPos) {
01807           if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
01808             recur->addMonthlyPos(r.by_set_pos[0],qba);
01809           }
01810         }
01811       } else if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
01812         if (!icaltime_is_null_time(r.until)) {
01813           recur->setMonthly(Recurrence::rMonthlyDay,r.interval,
01814                             readICalDate(r.until));
01815         } else {
01816           if (r.count == 0)
01817             recur->setMonthly(Recurrence::rMonthlyDay,r.interval,-1);
01818           else
01819             recur->setMonthly(Recurrence::rMonthlyDay,r.interval,r.count);
01820         }
01821         while((day = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01822 //          kdDebug(5800) << "----b " << day << endl;
01823           recur->addMonthlyDay(day);
01824         }
01825       }
01826       break;
01827     case ICAL_YEARLY_RECURRENCE:
01828       if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
01829         if (!icaltime_is_null_time(r.until)) {
01830           recur->setYearly(Recurrence::rYearlyDay,r.interval,
01831                             readICalDate(r.until));
01832         } else {
01833           if (r.count == 0)
01834             recur->setYearly(Recurrence::rYearlyDay,r.interval,-1);
01835           else
01836             recur->setYearly(Recurrence::rYearlyDay,r.interval,r.count);
01837         }
01838         while((day = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01839           recur->addYearlyNum(day);
01840         }
01841       } if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) {
01842         if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
01843           if (!icaltime_is_null_time(r.until)) {
01844             recur->setYearly(Recurrence::rYearlyPos,r.interval,
01845                               readICalDate(r.until));
01846           } else {
01847             if (r.count == 0)
01848               recur->setYearly(Recurrence::rYearlyPos,r.interval,-1);
01849             else
01850               recur->setYearly(Recurrence::rYearlyPos,r.interval,r.count);
01851           }
01852           bool useSetPos = false;
01853           short pos = 0;
01854           while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01855 //            kdDebug(5800) << "----a " << index << ": " << day << endl;
01856             pos = icalrecurrencetype_day_position(day);
01857             if (pos) {
01858               day = icalrecurrencetype_day_day_of_week(day);
01859               QBitArray ba(7);          // don't wipe qba
01860               ba.setBit((day+5)%7);     // convert from Sunday=1 to Monday=0
01861               recur->addYearlyMonthPos(pos,ba);
01862             } else {
01863               qba.setBit((day+5)%7);    // convert from Sunday=1 to Monday=0
01864               useSetPos = true;
01865             }
01866           }
01867           if (useSetPos) {
01868             if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
01869               recur->addYearlyMonthPos(r.by_set_pos[0],qba);
01870             }
01871           }
01872         } else {
01873           if (!icaltime_is_null_time(r.until)) {
01874             recur->setYearly(Recurrence::rYearlyMonth,r.interval,
01875                               readICalDate(r.until));
01876           } else {
01877             if (r.count == 0)
01878               recur->setYearly(Recurrence::rYearlyMonth,r.interval,-1);
01879             else
01880               recur->setYearly(Recurrence::rYearlyMonth,r.interval,r.count);
01881           }
01882           while((day = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01883             recur->addMonthlyDay(day);
01884           }
01885         }
01886         index = 0;
01887         while((day = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01888           recur->addYearlyNum(day);
01889         }
01890       }
01891       break;
01892     default:
01893       kdDebug(5800) << "Unknown type of recurrence: " << r.freq << endl;
01894       break;
01895   }
01896 }
01897 
01898 void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
01899 {
01900   //kdDebug(5800) << "Read alarm for " << incidence->summary() << endl;
01901 
01902   Alarm* ialarm = incidence->newAlarm();
01903   ialarm->setRepeatCount(0);
01904   ialarm->setEnabled(true);
01905 
01906   // Determine the alarm's action type
01907   icalproperty *p = icalcomponent_get_first_property(alarm,ICAL_ACTION_PROPERTY);
01908   Alarm::Type type = Alarm::Display;
01909   icalproperty_action action = ICAL_ACTION_DISPLAY;
01910   if ( !p ) {
01911     kdDebug(5800) << "Unknown type of alarm, using default" << endl;
01912 //    return;
01913   } else {
01914 
01915     action = icalproperty_get_action(p);
01916     switch ( action ) {
01917       case ICAL_ACTION_DISPLAY:   type = Alarm::Display;  break;
01918       case ICAL_ACTION_AUDIO:     type = Alarm::Audio;  break;
01919       case ICAL_ACTION_PROCEDURE: type = Alarm::Procedure;  break;
01920       case ICAL_ACTION_EMAIL:     type = Alarm::Email;  break;
01921       default:
01922         kdDebug(5800) << "Unknown type of alarm: " << action << endl;
01923 //        type = Alarm::Invalid;
01924     }
01925   }
01926   ialarm->setType(type);
01927 
01928   p = icalcomponent_get_first_property(alarm,ICAL_ANY_PROPERTY);
01929   while (p) {
01930     icalproperty_kind kind = icalproperty_isa(p);
01931 
01932     switch (kind) {
01933 
01934       case ICAL_TRIGGER_PROPERTY: {
01935         icaltriggertype trigger = icalproperty_get_trigger(p);
01936         if (icaltime_is_null_time(trigger.time)) {
01937           if (icaldurationtype_is_null_duration(trigger.duration)) {
01938             kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl;
01939           } else {
01940             Duration duration = icaldurationtype_as_int( trigger.duration );
01941             icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER);
01942             if (param && icalparameter_get_related(param) == ICAL_RELATED_END)
01943               ialarm->setEndOffset(duration);
01944             else
01945               ialarm->setStartOffset(duration);
01946           }
01947         } else {
01948           ialarm->setTime(readICalDateTime(trigger.time));
01949         }
01950         break;
01951       }
01952       case ICAL_DURATION_PROPERTY: {
01953         icaldurationtype duration = icalproperty_get_duration(p);
01954         ialarm->setSnoozeTime(icaldurationtype_as_int(duration)/60);
01955         break;
01956       }
01957       case ICAL_REPEAT_PROPERTY:
01958         ialarm->setRepeatCount(icalproperty_get_repeat(p));
01959         break;
01960 
01961       // Only in DISPLAY and EMAIL and PROCEDURE alarms
01962       case ICAL_DESCRIPTION_PROPERTY: {
01963         QString description = QString::fromUtf8(icalproperty_get_description(p));
01964         switch ( action ) {
01965           case ICAL_ACTION_DISPLAY:
01966             ialarm->setText( description );
01967             break;
01968           case ICAL_ACTION_PROCEDURE:
01969             ialarm->setProgramArguments( description );
01970             break;
01971           case ICAL_ACTION_EMAIL:
01972             ialarm->setMailText( description );
01973             break;
01974           default:
01975             break;
01976         }
01977         break;
01978       }
01979       // Only in EMAIL alarm
01980       case ICAL_SUMMARY_PROPERTY:
01981         ialarm->setMailSubject(QString::fromUtf8(icalproperty_get_summary(p)));
01982         break;
01983 
01984       // Only in EMAIL alarm
01985       case ICAL_ATTENDEE_PROPERTY: {
01986         QString email = QString::fromUtf8(icalproperty_get_attendee(p));
01987         QString name;
01988         icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER);
01989         if (param) {
01990           name = QString::fromUtf8(icalparameter_get_cn(param));
01991         }
01992         ialarm->addMailAddress(Person(name, email));
01993         break;
01994       }
01995       // Only in AUDIO and EMAIL and PROCEDURE alarms
01996       case ICAL_ATTACH_PROPERTY: {
01997         icalattachtype *attach = icalproperty_get_attach(p);
01998         QString url = QFile::decodeName(icalattachtype_get_url(attach));
01999         switch ( action ) {
02000           case ICAL_ACTION_AUDIO:
02001             ialarm->setAudioFile( url );
02002             break;
02003           case ICAL_ACTION_PROCEDURE:
02004             ialarm->setProgramFile( url );
02005             break;
02006           case ICAL_ACTION_EMAIL:
02007             ialarm->addMailAttachment( url );
02008             break;
02009           default:
02010             break;
02011         }
02012         break;
02013       }
02014       default:
02015         break;
02016     }
02017 
02018     p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY);
02019   }
02020 
02021   // custom properties
02022   readCustomProperties(alarm, ialarm);
02023 
02024   // TODO: check for consistency of alarm properties
02025 }
02026 
02027 icaltimetype ICalFormatImpl::writeICalDate(const QDate &date)
02028 {
02029   icaltimetype t;
02030 
02031   t.year = date.year();
02032   t.month = date.month();
02033   t.day = date.day();
02034 
02035   t.hour = 0;
02036   t.minute = 0;
02037   t.second = 0;
02038 
02039   t.is_date = 1;
02040 
02041   t.is_utc = 0;
02042 
02043   t.zone = 0;
02044 
02045   return t;
02046 }
02047 
02048 icaltimetype ICalFormatImpl::writeICalDateTime(const QDateTime &datetime)
02049 {
02050   icaltimetype t;
02051 
02052   t.year = datetime.date().year();
02053   t.month = datetime.date().month();
02054   t.day = datetime.date().day();
02055 
02056   t.hour = datetime.time().hour();
02057   t.minute = datetime.time().minute();
02058   t.second = datetime.time().second();
02059 
02060   t.is_date = 0;
02061   t.zone = 0;
02062   t.is_utc = 0;
02063 
02064   if ( mParent->utc() ) {
02065     if (mParent->timeZoneId().isEmpty())
02066       t = icaltime_as_utc(t, 0);
02067     else
02068       t = icaltime_as_utc(t,mParent->timeZoneId().utf8());
02069   }
02070 
02071   return t;
02072 }
02073 
02074 QDateTime ICalFormatImpl::readICalDateTime(icaltimetype t)
02075 {
02076 /*
02077   kdDebug(5800) << "ICalFormatImpl::readICalDateTime()" << endl;
02078   kdDebug(5800) << "--- Y: " << t.year << " M: " << t.month << " D: " << t.day
02079             << endl;
02080   kdDebug(5800) << "--- H: " << t.hour << " M: " << t.minute << " S: " << t.second
02081             << endl;
02082   kdDebug(5800) << "--- isDate: " << t.is_date << endl;
02083   kdDebug(5800) << "--- isUtc: " << t.is_utc << endl;
02084   kdDebug(5800) << "--- zoneId: " << t.zone << endl;
02085 */
02086 
02087   // First convert the time into UTC if required.
02088   if ( !t.is_utc && t.zone ) {
02089     Timezone *timezone;
02090 
02091     // Always lookup with quotes.
02092     if (t.zone[0] != '"') {
02093       timezone = mTimezones.find(QString("\"") + t.zone + '"');
02094     } else {
02095       timezone = mTimezones.find(t.zone);
02096     }
02097     if (timezone) {
02098       // Apply the offset, and mark the structure as UTC!
02099       t.second -= timezone->offset(t);
02100       t = icaltime_normalize(t);
02101       t.is_utc = 1;
02102     } else {
02103       kdError(5800) << "ICalFormatImpl::readICalDateTime() cannot find timezone "
02104             << t.zone << endl;
02105     }
02106   }
02107 
02108   if ( t.is_utc && mCompat->useTimeZoneShift() ) {
02109 //    kdDebug(5800) << "--- Converting time to zone '" << cal->timeZoneId() << "'." << endl;
02110     if (mParent->timeZoneId().isEmpty())
02111       t = icaltime_as_zone(t, 0);
02112     else
02113       t = icaltime_as_zone(t,mParent->timeZoneId().utf8());
02114   }
02115   QDateTime result(QDate(t.year,t.month,t.day),
02116                    QTime(t.hour,t.minute,t.second));
02117 
02118   return result;
02119 }
02120 
02121 QDate ICalFormatImpl::readICalDate(icaltimetype t)
02122 {
02123   return QDate(t.year,t.month,t.day);
02124 }
02125 
02126 icaldurationtype ICalFormatImpl::writeICalDuration(int seconds)
02127 {
02128   icaldurationtype d;
02129 
02130   d.is_neg  = (seconds<0)?1:0;
02131   if (seconds<0) seconds = -seconds;
02132 
02133   d.weeks    = seconds / gSecondsPerWeek;
02134   seconds   %= gSecondsPerWeek;
02135   d.days     = seconds / gSecondsPerDay;
02136   seconds   %= gSecondsPerDay;
02137   d.hours    = seconds / gSecondsPerHour;
02138   seconds   %= gSecondsPerHour;
02139   d.minutes  = seconds / gSecondsPerMinute;
02140   seconds   %= gSecondsPerMinute;
02141   d.seconds  = seconds;
02142 
02143   return d;
02144 }
02145 
02146 int ICalFormatImpl::readICalDuration(icaldurationtype d)
02147 {
02148   int result = 0;
02149 
02150   result += d.weeks   * gSecondsPerWeek;
02151   result += d.days    * gSecondsPerDay;
02152   result += d.hours   * gSecondsPerHour;
02153   result += d.minutes * gSecondsPerMinute;
02154   result += d.seconds;
02155 
02156   if (d.is_neg) result *= -1;
02157 
02158   return result;
02159 }
02160 
02161 icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal)
02162 {
02163   icalcomponent *calendar;
02164 
02165   // Root component
02166   calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
02167 
02168   icalproperty *p;
02169 
02170   // Product Identifier
02171   p = icalproperty_new_prodid(CalFormat::productId().utf8());
02172   icalcomponent_add_property(calendar,p);
02173 
02174   // TODO: Add time zone
02175 
02176   // iCalendar version (2.0)
02177   p = icalproperty_new_version(const_cast<char *>(_ICAL_VERSION));
02178   icalcomponent_add_property(calendar,p);
02179 
02180   // Custom properties
02181   if( cal != 0 )
02182     writeCustomProperties(calendar, cal);
02183 
02184   return calendar;
02185 }
02186 
02187 
02188 
02189 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
02190 // and break it down from its tree-like format into the dictionary format
02191 // that is used internally in the ICalFormatImpl.
02192 bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
02193 {
02194   // this function will populate the caldict dictionary and other event
02195   // lists. It turns vevents into Events and then inserts them.
02196 
02197     if (!calendar) return false;
02198 
02199 // TODO: check for METHOD
02200 #if 0
02201   if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) {
02202     char *methodType = 0;
02203     methodType = fakeCString(vObjectUStringZValue(curVO));
02204     if (mEnableDialogs)
02205       KMessageBox::information(mTopWidget,
02206                                i18n("This calendar is an iTIP transaction of type \"%1\".")
02207                                .arg(methodType),
02208                                i18n("%1: iTIP Transaction").arg(CalFormat::application()));
02209     delete methodType;
02210   }
02211 #endif
02212 
02213   icalproperty *p;
02214 
02215   p = icalcomponent_get_first_property(calendar,ICAL_PRODID_PROPERTY);
02216   if (!p) {
02217     kdDebug(5800) << "No PRODID property found" << endl;
02218 // TODO: does no PRODID really matter?
02219 //    mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
02220 //    return false;
02221     mLoadedProductId = "";
02222     mCalendarVersion = 0;
02223   } else {
02224     mLoadedProductId = QString::fromUtf8(icalproperty_get_prodid(p));
02225     mCalendarVersion = CalFormat::calendarVersion(mLoadedProductId.latin1());
02226 //    kdDebug(5800) << "VCALENDAR prodid: '" << mLoadedProductId << "'" << endl;
02227 
02228     delete mCompat;
02229     mCompat = CompatFactory::createCompat( mLoadedProductId );
02230   }
02231 
02232 // TODO: check for unknown PRODID
02233 #if 0
02234   if (!mCalendarVersion
02235   &&  CalFormat::productId() != mLoadedProductId) {
02236     // warn the user that we might have trouble reading non-known calendar.
02237     if (mEnableDialogs)
02238       KMessageBox::information(mTopWidget,
02239                              i18n("This vCalendar file was not created by KOrganizer "
02240                                      "or any other product we support. Loading anyway..."),
02241                              i18n("%1: Unknown vCalendar Vendor").arg(CalFormat::application()));
02242   }
02243 #endif
02244 
02245   p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY);
02246   if (!p) {
02247     kdDebug(5800) << "No VERSION property found" << endl;
02248     mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
02249     return false;
02250   } else {
02251     const char *version = icalproperty_get_version(p);
02252 //    kdDebug(5800) << "VCALENDAR version: '" << version << "'" << endl;
02253 
02254     if (strcmp(version,"1.0") == 0) {
02255       kdDebug(5800) << "Expected iCalendar, got vCalendar" << endl;
02256       mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1,
02257                             i18n("Expected iCalendar format")));
02258       return false;
02259     } else if (strcmp(version,"2.0") != 0) {
02260       kdDebug(5800) << "Expected iCalendar, got unknown format" << endl;
02261       mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
02262       return false;
02263     }
02264   }
02265 
02266 
02267 // TODO: check for calendar format version
02268 #if 0
02269   // warn the user we might have trouble reading this unknown version.
02270   if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) {
02271     char *s = fakeCString(vObjectUStringZValue(curVO));
02272     if (strcmp(_VCAL_VERSION, s) != 0)
02273       if (mEnableDialogs)
02274         KMessageBox::sorry(mTopWidget,
02275                              i18n("This vCalendar file has version %1.\n"
02276                                   "We only support %2.")
02277                              .arg(s).arg(_VCAL_VERSION),
02278                              i18n("%1: Unknown vCalendar Version").arg(CalFormat::application()));
02279     deleteStr(s);
02280   }
02281 #endif
02282 
02283   // custom properties
02284   readCustomProperties(calendar, cal);
02285 
02286 // TODO: set time zone
02287 #if 0
02288   // set the time zone
02289   if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) {
02290     char *s = fakeCString(vObjectUStringZValue(curVO));
02291     cal->setTimeZone(s);
02292     deleteStr(s);
02293   }
02294 #endif
02295 
02296   // Store all events with a relatedTo property in a list for post-processing
02297   mEventsRelate.clear();
02298   mTodosRelate.clear();
02299   // TODO: make sure that only actually added ecvens go to this lists.
02300 
02301   icalcomponent *c;
02302 
02303   // Iterate through all timezones before we do anything else. That way, the
02304   // information needed to interpret times in actually useful objects is
02305   // available below.
02306   c = icalcomponent_get_first_component(calendar,ICAL_VTIMEZONE_COMPONENT);
02307   while (c) {
02308 //    kdDebug(5800) << "----Timezone found" << endl;
02309     readTimezone(c);
02310     c = icalcomponent_get_next_component(calendar,ICAL_VTIMEZONE_COMPONENT);
02311   }
02312 
02313   // Iterate through all todos
02314   c = icalcomponent_get_first_component(calendar,ICAL_VTODO_COMPONENT);
02315   while (c) {
02316 //    kdDebug(5800) << "----Todo found" << endl;
02317     Todo *todo = readTodo(c);
02318     if (todo && !cal->todo(todo->uid())) cal->addTodo(todo);
02319     c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT);
02320   }
02321 
02322   // Iterate through all events
02323   c = icalcomponent_get_first_component(calendar,ICAL_VEVENT_COMPONENT);
02324   while (c) {
02325 //    kdDebug(5800) << "----Event found" << endl;
02326     Event *event = readEvent(c);
02327     if (event && !cal->event(event->uid())) cal->addEvent(event);
02328     c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT);
02329   }
02330 
02331   // Iterate through all journals
02332   c = icalcomponent_get_first_component(calendar,ICAL_VJOURNAL_COMPONENT);
02333   while (c) {
02334 //    kdDebug(5800) << "----Journal found" << endl;
02335     Journal *journal = readJournal(c);
02336     if (journal && !cal->journal(journal->uid())) cal->addJournal(journal);
02337     c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT);
02338   }
02339 
02340 #if 0
02341   initPropIterator(&i, vcal);
02342 
02343   // go through all the vobjects in the vcal
02344   while (moreIteration(&i)) {
02345     curVO = nextVObject(&i);
02346 
02347     /************************************************************************/
02348 
02349     // now, check to see that the object is an event or todo.
02350     if (strcmp(vObjectName(curVO), VCEventProp) == 0) {
02351 
02352       if ((curVOProp = isAPropertyOf(curVO, KPilotStatusProp)) != 0) {
02353         char *s;
02354         s = fakeCString(vObjectUStringZValue(curVOProp));
02355         // check to see if event was deleted by the kpilot conduit
02356         if (atoi(s) == Event::SYNCDEL) {
02357           deleteStr(s);
02358           kdDebug(5800) << "skipping pilot-deleted event" << endl;
02359           goto SKIP;
02360         }
02361         deleteStr(s);
02362       }
02363 
02364       // this code checks to see if we are trying to read in an event
02365       // that we already find to be in the calendar.  If we find this
02366       // to be the case, we skip the event.
02367       if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) {
02368         char *s = fakeCString(vObjectUStringZValue(curVOProp));
02369         QString tmpStr(s);
02370         deleteStr(s);
02371 
02372         if (cal->event(tmpStr)) {
02373           goto SKIP;
02374         }
02375         if (cal->todo(tmpStr)) {
02376           goto SKIP;
02377         }
02378       }
02379 
02380       if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) &&
02381           (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) {
02382         kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl;
02383         goto SKIP;
02384       }
02385 
02386       anEvent = VEventToEvent(curVO);
02387       // we now use addEvent instead of insertEvent so that the
02388       // signal/slot get connected.
02389       if (anEvent)
02390         cal->addEvent(anEvent);
02391       else {
02392         // some sort of error must have occurred while in translation.
02393         goto SKIP;
02394       }
02395     } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) {
02396       anEvent = VTodoToEvent(curVO);
02397       cal->addTodo(anEvent);
02398     } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) ||
02399                (strcmp(vObjectName(curVO), VCProdIdProp) == 0) ||
02400                (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) {
02401       // do nothing, we know these properties and we want to skip them.
02402       // we have either already processed them or are ignoring them.
02403       ;
02404     } else {
02405       kdDebug(5800) << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"" << endl;
02406     }
02407   SKIP:
02408     ;
02409   } // while
02410 #endif
02411 
02412   // Post-Process list of events with relations, put Event objects in relation
02413   Event::List::ConstIterator eIt;
02414   for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) {
02415     (*eIt)->setRelatedTo( cal->incidence( (*eIt)->relatedToUid() ) );
02416   }
02417   Todo::List::ConstIterator tIt;
02418   for ( tIt = mTodosRelate.begin(); tIt != mTodosRelate.end(); ++tIt ) {
02419     (*tIt)->setRelatedTo( cal->incidence( (*tIt)->relatedToUid() ) );
02420    }
02421 
02422   return true;
02423 }
02424 
02425 QString ICalFormatImpl::extractErrorProperty(icalcomponent *c)
02426 {
02427 //  kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: "
02428 //            << icalcomponent_as_ical_string(c) << endl;
02429 
02430   QString errorMessage;
02431 
02432   icalproperty *error;
02433   error = icalcomponent_get_first_property(c,ICAL_XLICERROR_PROPERTY);
02434   while(error) {
02435     errorMessage += icalproperty_get_xlicerror(error);
02436     errorMessage += "\n";
02437     error = icalcomponent_get_next_property(c,ICAL_XLICERROR_PROPERTY);
02438   }
02439 
02440 //  kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " << errorMessage << endl;
02441 
02442   return errorMessage;
02443 }
02444 
02445 void ICalFormatImpl::dumpIcalRecurrence(icalrecurrencetype r)
02446 {
02447   int i;
02448 
02449   kdDebug(5800) << " Freq: " << r.freq << endl;
02450   kdDebug(5800) << " Until: " << icaltime_as_ctime(r.until) << endl;
02451   kdDebug(5800) << " Count: " << r.count << endl;
02452   if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02453     int index = 0;
02454     QString out = " By Day: ";
02455     while((i = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02456       out.append(QString::number(i) + " ");
02457     }
02458     kdDebug(5800) << out << endl;
02459   }
02460   if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02461     int index = 0;
02462     QString out = " By Month Day: ";
02463     while((i = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02464       out.append(QString::number(i) + " ");
02465     }
02466     kdDebug(5800) << out << endl;
02467   }
02468   if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02469     int index = 0;
02470     QString out = " By Year Day: ";
02471     while((i = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02472       out.append(QString::number(i) + " ");
02473     }
02474     kdDebug(5800) << out << endl;
02475   }
02476   if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02477     int index = 0;
02478     QString out = " By Month: ";
02479     while((i = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02480       out.append(QString::number(i) + " ");
02481     }
02482     kdDebug(5800) << out << endl;
02483   }
02484   if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02485     int index = 0;
02486     QString out = " By Set Pos: ";
02487     while((i = r.by_set_pos[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02488       kdDebug(5800) << "========= " << i << endl;
02489       out.append(QString::number(i) + " ");
02490     }
02491     kdDebug(5800) << out << endl;
02492   }
02493 }
02494 
02495 icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence,
02496                                                    Scheduler::Method method)
02497 {
02498   icalcomponent *message = createCalendarComponent();
02499 
02500   icalproperty_method icalmethod = ICAL_METHOD_NONE;
02501 
02502   switch (method) {
02503     case Scheduler::Publish:
02504       icalmethod = ICAL_METHOD_PUBLISH;
02505       break;
02506     case Scheduler::Request:
02507       icalmethod = ICAL_METHOD_REQUEST;
02508       break;
02509     case Scheduler::Refresh:
02510       icalmethod = ICAL_METHOD_REFRESH;
02511       break;
02512     case Scheduler::Cancel:
02513       icalmethod = ICAL_METHOD_CANCEL;
02514       break;
02515     case Scheduler::Add:
02516       icalmethod = ICAL_METHOD_ADD;
02517       break;
02518     case Scheduler::Reply:
02519       icalmethod = ICAL_METHOD_REPLY;
02520       break;
02521     case Scheduler::Counter:
02522       icalmethod = ICAL_METHOD_COUNTER;
02523       break;
02524     case Scheduler::Declinecounter:
02525       icalmethod = ICAL_METHOD_DECLINECOUNTER;
02526       break;
02527     default:
02528       kdDebug(5800) << "ICalFormat::createScheduleMessage(): Unknow method" << endl;
02529       return message;
02530   }
02531 
02532   icalcomponent_add_property(message,icalproperty_new_method(icalmethod));
02533 
02534   if(incidence->type() == "Todo") {
02535     Todo *todo = static_cast<Todo *>(incidence);
02536     icalcomponent *vtodo = writeTodo(todo);
02537     /*
02538      * RFC 2446 states in section 3.4.3 ( REPLY to a VTODO ), that
02539      * a REQUEST-STATUS property has to be present. Until we do more 
02540      * fine grained handling, assume all is well. Note that this is the 
02541      * status of the _request_, not the attendee. Just to avoid confusion.
02542      * - till
02543      */
02544     if ( icalmethod == ICAL_METHOD_REPLY ) {
02545       struct icalreqstattype rst;
02546       rst.code = ICAL_2_0_SUCCESS_STATUS;
02547       rst.desc = 0;
02548       rst.debug = 0;
02549       icalcomponent_add_property( vtodo, icalproperty_new_requeststatus( rst ) );
02550     }
02551     icalcomponent_add_component(message,vtodo);
02552   }
02553   if(incidence->type() == "Event") {
02554     Event *event = static_cast<Event *>(incidence);
02555     icalcomponent_add_component(message,writeEvent(event));
02556   }
02557   if(incidence->type() == "FreeBusy") {
02558     FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);
02559     icalcomponent_add_component(message,writeFreeBusy(freebusy, method));
02560   }
02561   if (incidence->type() == "Journal" ) {
02562     Journal *journal = static_cast<Journal *>(incidence);
02563     icalcomponent_add_component( message, writeJournal( journal ) );
02564   }
02565 
02566   return message;
02567 }
02568 
02569 // This function reads any TZID setting for an icaltime. TBD: incorporate
02570 // this into icalproperty_get_datetime() so it is picked up everywhere as
02571 // needed?
02572 void ICalFormatImpl::readTzidParameter( icalcomponent *p,
02573                                         icaltimetype &icaltime )
02574 {
02575   icalproperty *tzp = icalproperty_get_first_parameter( p,
02576                                                         ICAL_TZID_PARAMETER );
02577   if ( tzp ) {
02578     icaltime.zone = icalparameter_get_tzid( tzp );
02579   }
02580 }
02581 
KDE Logo
This file is part of the documentation for libkcal Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 22:38:36 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003