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