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