libkcal

icalformatimpl.cpp

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