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