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