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