libkcal

icalformatimpl.cpp

Go to the documentation of this file.
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.isEmpty()) {
01040     bool floats = (msade == QString::fromLatin1("TRUE"));
01041     event->setFloats(floats);
01042   }
01043 
01044   if ( mCompat ) mCompat->fixEmptySummary( event );
01045 
01046   return event;
01047 }
01048 
01049 FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
01050 {
01051   FreeBusy *freebusy = new FreeBusy;
01052 
01053   readIncidenceBase(vfreebusy, freebusy);
01054 
01055   icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY);
01056 
01057   icaltimetype icaltime;
01058   PeriodList periods;
01059 
01060   while (p) {
01061     icalproperty_kind kind = icalproperty_isa(p);
01062     switch (kind) {
01063 
01064       case ICAL_DTSTART_PROPERTY:  // start date and time
01065         icaltime = icalproperty_get_dtstart(p);
01066         freebusy->setDtStart(readICalDateTime(icaltime));
01067         break;
01068 
01069       case ICAL_DTEND_PROPERTY:  // end Date and Time
01070         icaltime = icalproperty_get_dtend(p);
01071         freebusy->setDtEnd(readICalDateTime(icaltime));
01072         break;
01073 
01074       case ICAL_FREEBUSY_PROPERTY: { //Any FreeBusy Times
01075         icalperiodtype icalperiod = icalproperty_get_freebusy(p);
01076         QDateTime period_start = readICalDateTime(icalperiod.start);
01077         Period period;
01078         if ( !icaltime_is_null_time(icalperiod.end) ) {
01079           QDateTime period_end = readICalDateTime(icalperiod.end);
01080           period = Period(period_start, period_end);
01081         } else {
01082           Duration duration = readICalDuration( icalperiod.duration );
01083           period = Period(period_start, duration);
01084         }
01085         QCString param = icalproperty_get_parameter_as_string( p, "X-SUMMARY" );
01086         period.setSummary( QString::fromUtf8( KCodecs::base64Decode( param ) ) );
01087         param = icalproperty_get_parameter_as_string( p, "X-LOCATION" );
01088         period.setLocation( QString::fromUtf8( KCodecs::base64Decode( param ) ) );
01089         periods.append( period );
01090         break;}
01091 
01092       default:
01093 //        kdDebug(5800) << "ICalFormatImpl::readFreeBusy(): Unknown property: "
01094 //                      << kind << endl;
01095       break;
01096     }
01097     p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY);
01098   }
01099   freebusy->addPeriods( periods );
01100 
01101   return freebusy;
01102 }
01103 
01104 Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal)
01105 {
01106   Journal *journal = new Journal;
01107 
01108   readIncidence(vjournal, 0, journal); // FIXME tz?
01109 
01110   return journal;
01111 }
01112 
01113 Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee)
01114 {
01115   icalparameter *p = 0;
01116 
01117   QString email = QString::fromUtf8(icalproperty_get_attendee(attendee));
01118   if ( email.startsWith( "mailto:", false ) ) {
01119     email = email.mid( 7 );
01120   }
01121 
01122   QString name;
01123   QString uid = QString::null;
01124   p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER);
01125   if (p) {
01126     name = QString::fromUtf8(icalparameter_get_cn(p));
01127   } else {
01128   }
01129 
01130   bool rsvp=false;
01131   p = icalproperty_get_first_parameter(attendee,ICAL_RSVP_PARAMETER);
01132   if (p) {
01133     icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp(p);
01134     if (rsvpParameter == ICAL_RSVP_TRUE) rsvp = true;
01135   }
01136 
01137   Attendee::PartStat status = Attendee::NeedsAction;
01138   p = icalproperty_get_first_parameter(attendee,ICAL_PARTSTAT_PARAMETER);
01139   if (p) {
01140     icalparameter_partstat partStatParameter = icalparameter_get_partstat(p);
01141     switch(partStatParameter) {
01142       default:
01143       case ICAL_PARTSTAT_NEEDSACTION:
01144         status = Attendee::NeedsAction;
01145         break;
01146       case ICAL_PARTSTAT_ACCEPTED:
01147         status = Attendee::Accepted;
01148         break;
01149       case ICAL_PARTSTAT_DECLINED:
01150         status = Attendee::Declined;
01151         break;
01152       case ICAL_PARTSTAT_TENTATIVE:
01153         status = Attendee::Tentative;
01154         break;
01155       case ICAL_PARTSTAT_DELEGATED:
01156         status = Attendee::Delegated;
01157         break;
01158       case ICAL_PARTSTAT_COMPLETED:
01159         status = Attendee::Completed;
01160         break;
01161       case ICAL_PARTSTAT_INPROCESS:
01162         status = Attendee::InProcess;
01163         break;
01164     }
01165   }
01166 
01167   Attendee::Role role = Attendee::ReqParticipant;
01168   p = icalproperty_get_first_parameter(attendee,ICAL_ROLE_PARAMETER);
01169   if (p) {
01170     icalparameter_role roleParameter = icalparameter_get_role(p);
01171     switch(roleParameter) {
01172       case ICAL_ROLE_CHAIR:
01173         role = Attendee::Chair;
01174         break;
01175       default:
01176       case ICAL_ROLE_REQPARTICIPANT:
01177         role = Attendee::ReqParticipant;
01178         break;
01179       case ICAL_ROLE_OPTPARTICIPANT:
01180         role = Attendee::OptParticipant;
01181         break;
01182       case ICAL_ROLE_NONPARTICIPANT:
01183         role = Attendee::NonParticipant;
01184         break;
01185     }
01186   }
01187 
01188   p = icalproperty_get_first_parameter(attendee,ICAL_X_PARAMETER);
01189   uid = icalparameter_get_xvalue(p);
01190   // This should be added, but there seems to be a libical bug here.
01191   // TODO: does this work now in libical-0.24 or greater?
01192   /*while (p) {
01193    // if (icalparameter_get_xname(p) == "X-UID") {
01194     uid = icalparameter_get_xvalue(p);
01195     p = icalproperty_get_next_parameter(attendee,ICAL_X_PARAMETER);
01196   } */
01197 
01198   Attendee *a = new Attendee( name, email, rsvp, status, role, uid );
01199 
01200   p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDTO_PARAMETER );
01201   if ( p )
01202     a->setDelegate( icalparameter_get_delegatedto( p ) );
01203 
01204   p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDFROM_PARAMETER );
01205   if ( p )
01206     a->setDelegator( icalparameter_get_delegatedfrom( p ) );
01207 
01208   return a;
01209 }
01210 
01211 Person ICalFormatImpl::readOrganizer( icalproperty *organizer )
01212 {
01213   QString email = QString::fromUtf8(icalproperty_get_organizer(organizer));
01214   if ( email.startsWith( "mailto:", false ) ) {
01215     email = email.mid( 7 );
01216   }
01217   QString cn;
01218 
01219   icalparameter *p = icalproperty_get_first_parameter(
01220              organizer, ICAL_CN_PARAMETER );
01221 
01222   if ( p ) {
01223     cn = QString::fromUtf8( icalparameter_get_cn( p ) );
01224   }
01225   Person org( cn, email );
01226   // TODO: Treat sent-by, dir and language here, too
01227   return org;
01228 }
01229 
01230 Attachment *ICalFormatImpl::readAttachment(icalproperty *attach)
01231 {
01232   Attachment *attachment = 0;
01233 
01234   icalvalue_kind value_kind = icalvalue_isa(icalproperty_get_value(attach));
01235 
01236   if ( value_kind == ICAL_ATTACH_VALUE || value_kind == ICAL_BINARY_VALUE ) {
01237     icalattach *a = icalproperty_get_attach(attach);
01238 
01239     int isurl = icalattach_get_is_url (a);
01240     if (isurl == 0)
01241       attachment = new Attachment((const char*)icalattach_get_data(a));
01242     else {
01243       attachment = new Attachment(QString::fromUtf8(icalattach_get_url(a)));
01244     }
01245   }
01246   else if ( value_kind == ICAL_URI_VALUE ) {
01247     attachment = new Attachment(QString::fromUtf8(icalvalue_get_uri(icalproperty_get_value(attach))));
01248   }
01249 
01250   icalparameter *p = icalproperty_get_first_parameter(attach, ICAL_FMTTYPE_PARAMETER);
01251   if (p && attachment)
01252     attachment->setMimeType(QString(icalparameter_get_fmttype(p)));
01253 
01254   p = icalproperty_get_first_parameter(attach,ICAL_X_PARAMETER);
01255   while (p) {
01256    if ( strncmp (icalparameter_get_xname(p), "X-LABEL", 7) == 0 )
01257      attachment->setLabel( icalparameter_get_xvalue(p) );
01258     p = icalproperty_get_next_parameter(attach, ICAL_X_PARAMETER);
01259   }
01260 
01261   return attachment;
01262 }
01263 
01264 void ICalFormatImpl::readIncidence(icalcomponent *parent, icaltimezone *tz, Incidence *incidence)
01265 {
01266   readIncidenceBase(parent,incidence);
01267 
01268   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
01269 
01270   const char *text;
01271   int intvalue, inttext;
01272   icaltimetype icaltime;
01273   icaldurationtype icalduration;
01274 
01275   QStringList categories;
01276 
01277   while (p) {
01278     icalproperty_kind kind = icalproperty_isa(p);
01279     switch (kind) {
01280 
01281       case ICAL_CREATED_PROPERTY:
01282         icaltime = icalproperty_get_created(p);
01283         incidence->setCreated(readICalDateTime(icaltime, tz));
01284         break;
01285 
01286       case ICAL_SEQUENCE_PROPERTY:  // sequence
01287         intvalue = icalproperty_get_sequence(p);
01288         incidence->setRevision(intvalue);
01289         break;
01290 
01291       case ICAL_LASTMODIFIED_PROPERTY:  // last modification date
01292         icaltime = icalproperty_get_lastmodified(p);
01293         incidence->setLastModified(readICalDateTime(icaltime, tz));
01294         break;
01295 
01296       case ICAL_DTSTART_PROPERTY:  // start date and time
01297         icaltime = icalproperty_get_dtstart(p);
01298         if (icaltime.is_date) {
01299           incidence->setDtStart(QDateTime(readICalDate(icaltime),QTime(0,0,0)));
01300           incidence->setFloats( true );
01301         } else {
01302           incidence->setDtStart(readICalDateTime(icaltime, tz));
01303           incidence->setFloats( false );
01304         }
01305         break;
01306 
01307       case ICAL_DURATION_PROPERTY:  // start date and time
01308         icalduration = icalproperty_get_duration(p);
01309         incidence->setDuration(readICalDuration(icalduration));
01310         break;
01311 
01312       case ICAL_DESCRIPTION_PROPERTY:  // description
01313         text = icalproperty_get_description(p);
01314         incidence->setDescription(QString::fromUtf8(text));
01315         break;
01316 
01317       case ICAL_SUMMARY_PROPERTY:  // summary
01318         text = icalproperty_get_summary(p);
01319         incidence->setSummary(QString::fromUtf8(text));
01320         break;
01321 
01322       case ICAL_LOCATION_PROPERTY:  // location
01323         text = icalproperty_get_location(p);
01324         incidence->setLocation(QString::fromUtf8(text));
01325         break;
01326 
01327       case ICAL_STATUS_PROPERTY: {  // status
01328         Incidence::Status stat;
01329         switch (icalproperty_get_status(p)) {
01330           case ICAL_STATUS_TENTATIVE:   stat = Incidence::StatusTentative; break;
01331           case ICAL_STATUS_CONFIRMED:   stat = Incidence::StatusConfirmed; break;
01332           case ICAL_STATUS_COMPLETED:   stat = Incidence::StatusCompleted; break;
01333           case ICAL_STATUS_NEEDSACTION: stat = Incidence::StatusNeedsAction; break;
01334           case ICAL_STATUS_CANCELLED:   stat = Incidence::StatusCanceled; break;
01335           case ICAL_STATUS_INPROCESS:   stat = Incidence::StatusInProcess; break;
01336           case ICAL_STATUS_DRAFT:       stat = Incidence::StatusDraft; break;
01337           case ICAL_STATUS_FINAL:       stat = Incidence::StatusFinal; break;
01338           case ICAL_STATUS_X:
01339             incidence->setCustomStatus(QString::fromUtf8(icalvalue_get_x(icalproperty_get_value(p))));
01340             stat = Incidence::StatusX;
01341             break;
01342           case ICAL_STATUS_NONE:
01343           default:                      stat = Incidence::StatusNone; break;
01344         }
01345         if (stat != Incidence::StatusX)
01346           incidence->setStatus(stat);
01347         break;
01348       }
01349 
01350       case ICAL_PRIORITY_PROPERTY:  // priority
01351         intvalue = icalproperty_get_priority( p );
01352         if ( mCompat )
01353           intvalue = mCompat->fixPriority( intvalue );
01354         incidence->setPriority( intvalue );
01355         break;
01356 
01357       case ICAL_CATEGORIES_PROPERTY:  // categories
01358         text = icalproperty_get_categories(p);
01359         categories.append(QString::fromUtf8(text));
01360         break;
01361 
01362       case ICAL_RRULE_PROPERTY:
01363         readRecurrenceRule( p, incidence );
01364         break;
01365 
01366       case ICAL_RDATE_PROPERTY: {
01367         icaldatetimeperiodtype rd = icalproperty_get_rdate( p );
01368         if ( icaltime_is_valid_time( rd.time ) ) {
01369           if ( icaltime_is_date( rd.time ) ) {
01370             incidence->recurrence()->addRDate( readICalDate( rd.time ) );
01371           } else {
01372             incidence->recurrence()->addRDateTime( readICalDateTime( rd.time, tz ) );
01373           }
01374         } else {
01375           // TODO: RDates as period are not yet implemented!
01376         }
01377         break; }
01378 
01379       case ICAL_EXRULE_PROPERTY:
01380         readExceptionRule( p, incidence );
01381         break;
01382 
01383       case ICAL_EXDATE_PROPERTY:
01384         icaltime = icalproperty_get_exdate(p);
01385         if ( icaltime_is_date(icaltime) ) {
01386           incidence->recurrence()->addExDate( readICalDate(icaltime) );
01387         } else {
01388           incidence->recurrence()->addExDateTime( readICalDateTime(icaltime, tz) );
01389         }
01390         break;
01391 
01392       case ICAL_CLASS_PROPERTY:
01393         inttext = icalproperty_get_class(p);
01394         if (inttext == ICAL_CLASS_PUBLIC ) {
01395           incidence->setSecrecy(Incidence::SecrecyPublic);
01396         } else if (inttext == ICAL_CLASS_CONFIDENTIAL ) {
01397           incidence->setSecrecy(Incidence::SecrecyConfidential);
01398         } else {
01399           incidence->setSecrecy(Incidence::SecrecyPrivate);
01400         }
01401         break;
01402 
01403       case ICAL_ATTACH_PROPERTY:  // attachments
01404         incidence->addAttachment(readAttachment(p));
01405         break;
01406 
01407       default:
01408 //        kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
01409 //                  << endl;
01410         break;
01411     }
01412 
01413     p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
01414   }
01415 
01416   // Set the scheduling ID
01417   const QString uid = incidence->customProperty( "LIBKCAL", "ID" );
01418   if ( !uid.isNull() ) {
01419     // The UID stored in incidencebase is actually the scheduling ID
01420     // It has to be stored in the iCal UID component for compatibility
01421     // with other iCal applications
01422     incidence->setSchedulingID( incidence->uid() );
01423     incidence->setUid( uid );
01424   }
01425 
01426   // Now that recurrence and exception stuff is completely set up,
01427   // do any backwards compatibility adjustments.
01428   if ( incidence->doesRecur() && mCompat )
01429       mCompat->fixRecurrence( incidence );
01430 
01431   // add categories
01432   incidence->setCategories(categories);
01433 
01434   // iterate through all alarms
01435   for (icalcomponent *alarm = icalcomponent_get_first_component(parent,ICAL_VALARM_COMPONENT);
01436        alarm;
01437        alarm = icalcomponent_get_next_component(parent,ICAL_VALARM_COMPONENT)) {
01438     readAlarm(alarm,incidence);
01439   }
01440   // Fix incorrect alarm settings by other applications (like outloook 9)
01441   if ( mCompat ) mCompat->fixAlarms( incidence );
01442 
01443 }
01444 
01445 void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
01446 {
01447   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
01448 
01449   while (p) {
01450     icalproperty_kind kind = icalproperty_isa(p);
01451     switch (kind) {
01452 
01453       case ICAL_UID_PROPERTY:  // unique id
01454         incidenceBase->setUid(QString::fromUtf8(icalproperty_get_uid(p)));
01455         break;
01456 
01457       case ICAL_ORGANIZER_PROPERTY:  // organizer
01458         incidenceBase->setOrganizer( readOrganizer(p));
01459         break;
01460 
01461       case ICAL_ATTENDEE_PROPERTY:  // attendee
01462         incidenceBase->addAttendee(readAttendee(p));
01463         break;
01464 
01465       case ICAL_COMMENT_PROPERTY:
01466         incidenceBase->addComment(
01467             QString::fromUtf8(icalproperty_get_comment(p)));
01468         break;
01469 
01470       default:
01471         break;
01472     }
01473 
01474     p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
01475   }
01476 
01477   // kpilot stuff
01478   // TODO: move this application-specific code to kpilot
01479   // need to get X-PILOT* attributes out, set correct properties, and get
01480   // rid of them...
01481   // Pointer fun, as per libical documentation
01482   // (documented in UsingLibical.txt)
01483   icalproperty *next =0;
01484 
01485   for ( p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
01486        p != 0;
01487        p = next )
01488   {
01489 
01490     next = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
01491 
01492     QString value = QString::fromUtf8(icalproperty_get_x(p));
01493     QString name = icalproperty_get_x_name(p);
01494 
01495     if (name == "X-PILOTID" && !value.isEmpty()) {
01496       incidenceBase->setPilotId(value.toInt());
01497       icalcomponent_remove_property(parent,p);
01498     } else if (name == "X-PILOTSTAT" && !value.isEmpty()) {
01499       incidenceBase->setSyncStatus(value.toInt());
01500       icalcomponent_remove_property(parent,p);
01501     }
01502   }
01503 
01504   // custom properties
01505   readCustomProperties(parent, incidenceBase);
01506 }
01507 
01508 void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties)
01509 {
01510   QMap<QCString, QString> customProperties;
01511   QString lastProperty;
01512 
01513   icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
01514 
01515   while (p) {
01516 
01517     QString value = QString::fromUtf8(icalproperty_get_x(p));
01518     const char *name = icalproperty_get_x_name(p);
01519     if ( lastProperty != name ) {
01520       customProperties[name] = value;
01521     } else {
01522       customProperties[name] = customProperties[name].append( "," ).append( value );
01523     }
01524     // kdDebug(5800) << "Set custom property [" << name << '=' << value << ']' << endl;
01525     p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
01526     lastProperty = name;
01527   }
01528 
01529   properties->setCustomProperties(customProperties);
01530 }
01531 
01532 
01533 
01534 void ICalFormatImpl::readRecurrenceRule(icalproperty *rrule,Incidence *incidence )
01535 {
01536 //  kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
01537 
01538   Recurrence *recur = incidence->recurrence();
01539 
01540   struct icalrecurrencetype r = icalproperty_get_rrule(rrule);
01541 //   dumpIcalRecurrence(r);
01542 
01543   RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
01544   recurrule->setStartDt( incidence->dtStart() );
01545   readRecurrence( r, recurrule );
01546   recur->addRRule( recurrule );
01547 }
01548 
01549 void ICalFormatImpl::readExceptionRule( icalproperty *rrule, Incidence *incidence )
01550 {
01551 //  kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
01552 
01553   struct icalrecurrencetype r = icalproperty_get_exrule(rrule);
01554 //   dumpIcalRecurrence(r);
01555 
01556   RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
01557   recurrule->setStartDt( incidence->dtStart() );
01558   readRecurrence( r, recurrule );
01559 
01560   Recurrence *recur = incidence->recurrence();
01561   recur->addExRule( recurrule );
01562 }
01563 
01564 void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, RecurrenceRule* recur )
01565 {
01566   // Generate the RRULE string
01567   recur->mRRule = QString( icalrecurrencetype_as_string( const_cast<struct icalrecurrencetype*>(&r) ) );
01568   // Period
01569   switch ( r.freq ) {
01570     case ICAL_SECONDLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rSecondly ); break;
01571     case ICAL_MINUTELY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rMinutely ); break;
01572     case ICAL_HOURLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rHourly ); break;
01573     case ICAL_DAILY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rDaily ); break;
01574     case ICAL_WEEKLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rWeekly ); break;
01575     case ICAL_MONTHLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rMonthly ); break;
01576     case ICAL_YEARLY_RECURRENCE: recur->setRecurrenceType( RecurrenceRule::rYearly ); break;
01577     case ICAL_NO_RECURRENCE:
01578     default:
01579         recur->setRecurrenceType( RecurrenceRule::rNone );
01580   }
01581   // Frequency
01582   recur->setFrequency( r.interval );
01583 
01584   // Duration & End Date
01585   if ( !icaltime_is_null_time( r.until ) ) {
01586     icaltimetype t;
01587     t = r.until;
01588     // Convert to the correct time zone! it's in UTC by specification.
01589     QDateTime endDate( readICalDateTime(t) );
01590     recur->setEndDt( endDate );
01591   } else {
01592     if (r.count == 0)
01593       recur->setDuration( -1 );
01594     else
01595       recur->setDuration( r.count );
01596   }
01597 
01598   // Week start setting
01599   int wkst = (r.week_start + 5)%7 + 1;
01600   recur->setWeekStart( wkst );
01601 
01602   // And now all BY*
01603   QValueList<int> lst;
01604   int i;
01605   int index = 0;
01606 
01607 #define readSetByList(rrulecomp,setfunc) \
01608   index = 0; \
01609   lst.clear(); \
01610   while ( (i = r.rrulecomp[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) \
01611     lst.append( i ); \
01612   if ( !lst.isEmpty() ) recur->setfunc( lst );
01613 
01614   // BYSECOND, MINUTE and HOUR, MONTHDAY, YEARDAY, WEEKNUMBER, MONTH
01615   // and SETPOS are standard int lists, so we can treat them with the
01616   // same macro
01617   readSetByList( by_second, setBySeconds );
01618   readSetByList( by_minute, setByMinutes );
01619   readSetByList( by_hour, setByHours );
01620   readSetByList( by_month_day, setByMonthDays );
01621   readSetByList( by_year_day, setByYearDays );
01622   readSetByList( by_week_no, setByWeekNumbers );
01623   readSetByList( by_month, setByMonths );
01624   readSetByList( by_set_pos, setBySetPos );
01625 #undef readSetByList
01626 
01627   // BYDAY is a special case, since it's not an int list
01628   QValueList<RecurrenceRule::WDayPos> wdlst;
01629   short day;
01630   index=0;
01631   while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
01632     RecurrenceRule::WDayPos pos;
01633     pos.setDay( ( icalrecurrencetype_day_day_of_week( day ) + 5 )%7 + 1 );
01634     pos.setPos( icalrecurrencetype_day_position( day ) );
01635 //     kdDebug(5800)<< "    o) By day, index="<<index-1<<", pos="<<pos.Pos<<", day="<<pos.Day<<endl;
01636     wdlst.append( pos );
01637   }
01638   if ( !wdlst.isEmpty() ) recur->setByDays( wdlst );
01639 
01640 
01641   // TODO Store all X- fields of the RRULE inside the recurrence (so they are
01642   // preserved
01643 }
01644 
01645 
01646 void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
01647 {
01648 //   kdDebug(5800) << "Read alarm for " << incidence->summary() << endl;
01649 
01650   Alarm* ialarm = incidence->newAlarm();
01651   ialarm->setRepeatCount(0);
01652   ialarm->setEnabled(true);
01653 
01654   // Determine the alarm's action type
01655   icalproperty *p = icalcomponent_get_first_property(alarm,ICAL_ACTION_PROPERTY);
01656   Alarm::Type type = Alarm::Display;
01657   icalproperty_action action = ICAL_ACTION_DISPLAY;
01658   if ( !p ) {
01659     kdDebug(5800) << "Unknown type of alarm, using default" << endl;
01660 //    return;
01661   } else {
01662 
01663     action = icalproperty_get_action(p);
01664     switch ( action ) {
01665       case ICAL_ACTION_DISPLAY:   type = Alarm::Display;  break;
01666       case ICAL_ACTION_AUDIO:     type = Alarm::Audio;  break;
01667       case ICAL_ACTION_PROCEDURE: type = Alarm::Procedure;  break;
01668       case ICAL_ACTION_EMAIL:     type = Alarm::Email;  break;
01669       default:
01670         kdDebug(5800) << "Unknown type of alarm: " << action << endl;
01671 //        type = Alarm::Invalid;
01672     }
01673   }
01674   ialarm->setType(type);
01675 // kdDebug(5800) << " alarm type =" << type << endl;
01676 
01677   p = icalcomponent_get_first_property(alarm,ICAL_ANY_PROPERTY);
01678   while (p) {
01679     icalproperty_kind kind = icalproperty_isa(p);
01680 
01681     switch (kind) {
01682 
01683       case ICAL_TRIGGER_PROPERTY: {
01684         icaltriggertype trigger = icalproperty_get_trigger(p);
01685         if (icaltime_is_null_time(trigger.time)) {
01686           if (icaldurationtype_is_null_duration(trigger.duration)) {
01687             kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl;
01688           } else {
01689             Duration duration = icaldurationtype_as_int( trigger.duration );
01690             icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER);
01691             if (param && icalparameter_get_related(param) == ICAL_RELATED_END)
01692               ialarm->setEndOffset(duration);
01693             else
01694               ialarm->setStartOffset(duration);
01695           }
01696         } else {
01697           ialarm->setTime(readICalDateTime(trigger.time));
01698         }
01699         break;
01700       }
01701       case ICAL_DURATION_PROPERTY: {
01702         icaldurationtype duration = icalproperty_get_duration(p);
01703         ialarm->setSnoozeTime(icaldurationtype_as_int(duration)/60);
01704         break;
01705       }
01706       case ICAL_REPEAT_PROPERTY:
01707         ialarm->setRepeatCount(icalproperty_get_repeat(p));
01708         break;
01709 
01710       // Only in DISPLAY and EMAIL and PROCEDURE alarms
01711       case ICAL_DESCRIPTION_PROPERTY: {
01712         QString description = QString::fromUtf8(icalproperty_get_description(p));
01713         switch ( action ) {
01714           case ICAL_ACTION_DISPLAY:
01715             ialarm->setText( description );
01716             break;
01717           case ICAL_ACTION_PROCEDURE:
01718             ialarm->setProgramArguments( description );
01719             break;
01720           case ICAL_ACTION_EMAIL:
01721             ialarm->setMailText( description );
01722             break;
01723           default:
01724             break;
01725         }
01726         break;
01727       }
01728       // Only in EMAIL alarm
01729       case ICAL_SUMMARY_PROPERTY:
01730         ialarm->setMailSubject(QString::fromUtf8(icalproperty_get_summary(p)));
01731         break;
01732 
01733       // Only in EMAIL alarm
01734       case ICAL_ATTENDEE_PROPERTY: {
01735         QString email = QString::fromUtf8(icalproperty_get_attendee(p));
01736         if ( email.startsWith("mailto:", false ) ) {
01737           email = email.mid( 7 );
01738         }
01739         QString name;
01740         icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER);
01741         if (param) {
01742           name = QString::fromUtf8(icalparameter_get_cn(param));
01743         }
01744         ialarm->addMailAddress(Person(name, email));
01745         break;
01746       }
01747       // Only in AUDIO and EMAIL and PROCEDURE alarms
01748       case ICAL_ATTACH_PROPERTY: {
01749         Attachment *attach = readAttachment( p );
01750         if ( attach && attach->isUri() ) {
01751           switch ( action ) {
01752             case ICAL_ACTION_AUDIO:
01753               ialarm->setAudioFile( attach->uri() );
01754               break;
01755             case ICAL_ACTION_PROCEDURE:
01756               ialarm->setProgramFile( attach->uri() );
01757               break;
01758             case ICAL_ACTION_EMAIL:
01759               ialarm->addMailAttachment( attach->uri() );
01760               break;
01761             default:
01762               break;
01763           }
01764         } else {
01765           kdDebug() << "Alarm attachments currently only support URIs, but "
01766                        "no binary data" << endl;
01767         }
01768         delete attach;
01769         break;
01770       }
01771       default:
01772         break;
01773     }
01774 
01775     p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY);
01776   }
01777 
01778   // custom properties
01779   readCustomProperties(alarm, ialarm);
01780 
01781   // TODO: check for consistency of alarm properties
01782 }
01783 
01784 icaldatetimeperiodtype ICalFormatImpl::writeICalDatePeriod( const QDate &date )
01785 {
01786   icaldatetimeperiodtype t;
01787   t.time = writeICalDate( date );
01788   t.period = icalperiodtype_null_period();
01789   return t;
01790 }
01791 
01792 icaldatetimeperiodtype ICalFormatImpl::writeICalDateTimePeriod( const QDateTime &date )
01793 {
01794   icaldatetimeperiodtype t;
01795   t.time = writeICalDateTime( date );
01796   t.period = icalperiodtype_null_period();
01797   return t;
01798 }
01799 
01800 icaltimetype ICalFormatImpl::writeICalDate(const QDate &date)
01801 {
01802   icaltimetype t = icaltime_null_time();
01803 
01804   t.year = date.year();
01805   t.month = date.month();
01806   t.day = date.day();
01807 
01808   t.hour = 0;
01809   t.minute = 0;
01810   t.second = 0;
01811 
01812   t.is_date = 1;
01813 
01814   t.is_utc = 0;
01815 
01816   t.zone = 0;
01817 
01818   return t;
01819 }
01820 
01821 icaltimetype ICalFormatImpl::writeICalDateTime(const QDateTime &datetime)
01822 {
01823   icaltimetype t = icaltime_null_time();
01824 
01825   t.year = datetime.date().year();
01826   t.month = datetime.date().month();
01827   t.day = datetime.date().day();
01828 
01829   t.hour = datetime.time().hour();
01830   t.minute = datetime.time().minute();
01831   t.second = datetime.time().second();
01832 
01833   t.is_date = 0;
01834   t.zone = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
01835   t.is_utc = 0;
01836 
01837  // _dumpIcaltime( t );
01838   /* The QDateTime we get passed in is to be considered in the timezone of
01839    * the current calendar (mParent's), or, if there is none, to be floating.
01840    * In the later case store a floating time, in the former normalize to utc. */
01841   if (mParent->timeZoneId().isEmpty())
01842     t = icaltime_convert_to_zone( t, 0 ); //make floating timezone
01843   else {
01844     icaltimezone* tz = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
01845     icaltimezone* utc = icaltimezone_get_utc_timezone();
01846     if ( tz != utc ) {
01847       t.zone = tz;
01848       t = icaltime_convert_to_zone( t, utc );
01849     } else {
01850       t.is_utc = 1;
01851       t.zone = utc;
01852     }
01853   }
01854 //  _dumpIcaltime( t );
01855 
01856   return t;
01857 }
01858 
01859 QDateTime ICalFormatImpl::readICalDateTime( icaltimetype& t, icaltimezone* tz )
01860 {
01861 //   kdDebug(5800) << "ICalFormatImpl::readICalDateTime()" << endl;
01862   icaltimezone *zone = tz;
01863   if ( tz && t.is_utc == 0 ) { // Only use the TZ if time is not UTC.
01864     // FIXME: We'll need to make sure to apply the appropriate TZ, not just
01865     //        the first one found.
01866     t.zone = tz;
01867     t.is_utc = (tz == icaltimezone_get_utc_timezone())?1:0;
01868   } else {
01869     zone = icaltimezone_get_utc_timezone();
01870   }
01871   //_dumpIcaltime( t );
01872 
01873   // Convert to view time
01874   if ( !mParent->timeZoneId().isEmpty() && t.zone ) {
01875 //    kdDebug(5800) << "--- Converting time from: " << icaltimezone_get_tzid( const_cast<icaltimezone*>( t.zone ) ) << " (" << ICalDate2QDate(t) << ")." << endl;
01876     icaltimezone* viewTimeZone = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() );
01877     icaltimezone_convert_time(  &t, zone, viewTimeZone );
01878 //    kdDebug(5800) << "--- Converted to zone " << mParent->timeZoneId() << " (" << ICalDate2QDate(t) << ")." << endl;
01879   }
01880 
01881   return ICalDate2QDate(t);
01882 }
01883 
01884 QDate ICalFormatImpl::readICalDate(icaltimetype t)
01885 {
01886   return ICalDate2QDate(t).date();
01887 }
01888 
01889 icaldurationtype ICalFormatImpl::writeICalDuration(int seconds)
01890 {
01891   icaldurationtype d;
01892 
01893   d.is_neg  = (seconds<0)?1:0;
01894   if (seconds<0) seconds = -seconds;
01895 
01896   d.weeks    = seconds / gSecondsPerWeek;
01897   seconds   %= gSecondsPerWeek;
01898   d.days     = seconds / gSecondsPerDay;
01899   seconds   %= gSecondsPerDay;
01900   d.hours    = seconds / gSecondsPerHour;
01901   seconds   %= gSecondsPerHour;
01902   d.minutes  = seconds / gSecondsPerMinute;
01903   seconds   %= gSecondsPerMinute;
01904   d.seconds  = seconds;
01905 
01906   return d;
01907 }
01908 
01909 int ICalFormatImpl::readICalDuration(icaldurationtype d)
01910 {
01911   int result = 0;
01912 
01913   result += d.weeks   * gSecondsPerWeek;
01914   result += d.days    * gSecondsPerDay;
01915   result += d.hours   * gSecondsPerHour;
01916   result += d.minutes * gSecondsPerMinute;
01917   result += d.seconds;
01918 
01919   if (d.is_neg) result *= -1;
01920 
01921   return result;
01922 }
01923 
01924 icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal)
01925 {
01926   icalcomponent *calendar;
01927 
01928   // Root component
01929   calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
01930 
01931   icalproperty *p;
01932 
01933   // Product Identifier
01934   p = icalproperty_new_prodid(CalFormat::productId().utf8());
01935   icalcomponent_add_property(calendar,p);
01936 
01937   // TODO: Add time zone
01938 
01939   // iCalendar version (2.0)
01940   p = icalproperty_new_version(const_cast<char *>(_ICAL_VERSION));
01941   icalcomponent_add_property(calendar,p);
01942 
01943   // Custom properties
01944   if( cal != 0 )
01945     writeCustomProperties(calendar, cal);
01946 
01947   return calendar;
01948 }
01949 
01950 
01951 
01952 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
01953 // and break it down from its tree-like format into the dictionary format
01954 // that is used internally in the ICalFormatImpl.
01955 bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
01956 {
01957   // this function will populate the caldict dictionary and other event
01958   // lists. It turns vevents into Events and then inserts them.
01959 
01960     if (!calendar) return false;
01961 
01962 // TODO: check for METHOD
01963 
01964   icalproperty *p;
01965 
01966   p = icalcomponent_get_first_property(calendar,ICAL_PRODID_PROPERTY);
01967   if (!p) {
01968     kdDebug(5800) << "No PRODID property found" << endl;
01969     mLoadedProductId = "";
01970   } else {
01971     mLoadedProductId = QString::fromUtf8(icalproperty_get_prodid(p));
01972 //    kdDebug(5800) << "VCALENDAR prodid: '" << mLoadedProductId << "'" << endl;
01973 
01974     delete mCompat;
01975     mCompat = CompatFactory::createCompat( mLoadedProductId );
01976   }
01977 
01978   p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY);
01979   if (!p) {
01980     kdDebug(5800) << "No VERSION property found" << endl;
01981     mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
01982     return false;
01983   } else {
01984     const char *version = icalproperty_get_version(p);
01985 //    kdDebug(5800) << "VCALENDAR version: '" << version << "'" << endl;
01986 
01987     if (strcmp(version,"1.0") == 0) {
01988       kdDebug(5800) << "Expected iCalendar, got vCalendar" << endl;
01989       mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1,
01990                             i18n("Expected iCalendar format")));
01991       return false;
01992     } else if (strcmp(version,"2.0") != 0) {
01993       kdDebug(5800) << "Expected iCalendar, got unknown format" << endl;
01994       mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
01995       return false;
01996     }
01997   }
01998 
01999   // custom properties
02000   readCustomProperties(calendar, cal);
02001 
02002 // TODO: set time zone
02003 
02004   // read a VTIMEZONE if there is one
02005   icalcomponent *ctz =
02006     icalcomponent_get_first_component( calendar, ICAL_VTIMEZONE_COMPONENT );
02007 
02008   // Store all events with a relatedTo property in a list for post-processing
02009   mEventsRelate.clear();
02010   mTodosRelate.clear();
02011   // TODO: make sure that only actually added events go to this lists.
02012 
02013   icalcomponent *c;
02014 
02015   // Iterate through all todos
02016   c = icalcomponent_get_first_component(calendar,ICAL_VTODO_COMPONENT);
02017   while (c) {
02018 //    kdDebug(5800) << "----Todo found" << endl;
02019     Todo *todo = readTodo(c);
02020     if (todo) {
02021       if (!cal->todo(todo->uid())) {
02022         cal->addTodo(todo);
02023       } else {
02024         delete todo;
02025         mTodosRelate.remove( todo );
02026       }
02027     }
02028     c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT);
02029   }
02030 
02031   // Iterate through all events
02032   c = icalcomponent_get_first_component(calendar,ICAL_VEVENT_COMPONENT);
02033   while (c) {
02034 //    kdDebug(5800) << "----Event found" << endl;
02035     Event *event = readEvent(c, ctz);
02036     if (event) {
02037       if (!cal->event(event->uid())) {
02038         cal->addEvent(event);
02039       } else {
02040         delete event;
02041         mEventsRelate.remove( event );
02042       }
02043     }
02044     c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT);
02045   }
02046 
02047   // Iterate through all journals
02048   c = icalcomponent_get_first_component(calendar,ICAL_VJOURNAL_COMPONENT);
02049   while (c) {
02050 //    kdDebug(5800) << "----Journal found" << endl;
02051     Journal *journal = readJournal(c);
02052     if (journal) {
02053       if (!cal->journal(journal->uid())) {
02054         cal->addJournal(journal);
02055       } else {
02056         delete journal;
02057       }
02058     }
02059     c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT);
02060   }
02061 
02062   // Post-Process list of events with relations, put Event objects in relation
02063   Event::List::ConstIterator eIt;
02064   for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) {
02065     (*eIt)->setRelatedTo( cal->incidence( (*eIt)->relatedToUid() ) );
02066   }
02067   Todo::List::ConstIterator tIt;
02068   for ( tIt = mTodosRelate.begin(); tIt != mTodosRelate.end(); ++tIt ) {
02069     (*tIt)->setRelatedTo( cal->incidence( (*tIt)->relatedToUid() ) );
02070    }
02071 
02072   return true;
02073 }
02074 
02075 QString ICalFormatImpl::extractErrorProperty(icalcomponent *c)
02076 {
02077 //  kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: "
02078 //            << icalcomponent_as_ical_string(c) << endl;
02079 
02080   QString errorMessage;
02081 
02082   icalproperty *error;
02083   error = icalcomponent_get_first_property(c,ICAL_XLICERROR_PROPERTY);
02084   while(error) {
02085     errorMessage += icalproperty_get_xlicerror(error);
02086     errorMessage += "\n";
02087     error = icalcomponent_get_next_property(c,ICAL_XLICERROR_PROPERTY);
02088   }
02089 
02090 //  kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " << errorMessage << endl;
02091 
02092   return errorMessage;
02093 }
02094 
02095 void ICalFormatImpl::dumpIcalRecurrence(icalrecurrencetype r)
02096 {
02097   int i;
02098 
02099   kdDebug(5800) << " Freq: " << r.freq << endl;
02100   kdDebug(5800) << " Until: " << icaltime_as_ical_string(r.until) << endl;
02101   kdDebug(5800) << " Count: " << r.count << endl;
02102   if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02103     int index = 0;
02104     QString out = " By Day: ";
02105     while((i = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02106       out.append(QString::number(i) + " ");
02107     }
02108     kdDebug(5800) << out << endl;
02109   }
02110   if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02111     int index = 0;
02112     QString out = " By Month Day: ";
02113     while((i = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02114       out.append(QString::number(i) + " ");
02115     }
02116     kdDebug(5800) << out << endl;
02117   }
02118   if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02119     int index = 0;
02120     QString out = " By Year Day: ";
02121     while((i = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02122       out.append(QString::number(i) + " ");
02123     }
02124     kdDebug(5800) << out << endl;
02125   }
02126   if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02127     int index = 0;
02128     QString out = " By Month: ";
02129     while((i = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02130       out.append(QString::number(i) + " ");
02131     }
02132     kdDebug(5800) << out << endl;
02133   }
02134   if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
02135     int index = 0;
02136     QString out = " By Set Pos: ";
02137     while((i = r.by_set_pos[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
02138       kdDebug(5800) << "========= " << i << endl;
02139       out.append(QString::number(i) + " ");
02140     }
02141     kdDebug(5800) << out << endl;
02142   }
02143 }
02144 
02145 icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence,
02146                                                    Scheduler::Method method)
02147 {
02148   icalcomponent *message = createCalendarComponent();
02149 
02150   icalproperty_method icalmethod = ICAL_METHOD_NONE;
02151 
02152   switch (method) {
02153     case Scheduler::Publish:
02154       icalmethod = ICAL_METHOD_PUBLISH;
02155       break;
02156     case Scheduler::Request:
02157       icalmethod = ICAL_METHOD_REQUEST;
02158       break;
02159     case Scheduler::Refresh:
02160       icalmethod = ICAL_METHOD_REFRESH;
02161       break;
02162     case Scheduler::Cancel:
02163       icalmethod = ICAL_METHOD_CANCEL;
02164       break;
02165     case Scheduler::Add:
02166       icalmethod = ICAL_METHOD_ADD;
02167       break;
02168     case Scheduler::Reply:
02169       icalmethod = ICAL_METHOD_REPLY;
02170       break;
02171     case Scheduler::Counter:
02172       icalmethod = ICAL_METHOD_COUNTER;
02173       break;
02174     case Scheduler::Declinecounter:
02175       icalmethod = ICAL_METHOD_DECLINECOUNTER;
02176       break;
02177     default:
02178       kdDebug(5800) << "ICalFormat::createScheduleMessage(): Unknow method" << endl;
02179       return message;
02180   }
02181 
02182   icalcomponent_add_property(message,icalproperty_new_method(icalmethod));
02183 
02184   icalcomponent *inc = writeIncidence( incidence, method );
02185   /*
02186    * RFC 2446 states in section 3.4.3 ( REPLY to a VTODO ), that
02187    * a REQUEST-STATUS property has to be present. For the other two, event and
02188    * free busy, it can be there, but is optional. Until we do more
02189    * fine grained handling, assume all is well. Note that this is the
02190    * status of the _request_, not the attendee. Just to avoid confusion.
02191    * - till
02192    */
02193   if ( icalmethod == ICAL_METHOD_REPLY ) {
02194     struct icalreqstattype rst;
02195     rst.code = ICAL_2_0_SUCCESS_STATUS;
02196     rst.desc = 0;
02197     rst.debug = 0;
02198     icalcomponent_add_property( inc, icalproperty_new_requeststatus( rst ) );
02199   }
02200   icalcomponent_add_component( message, inc );
02201 
02202   return message;
02203 }