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