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