33 #include "icaltimezones.h"
40 #include <QtCore/QFile>
43 #include <libical/ical.h>
44 #include <libical/icalss.h>
45 #include <libical/icalparser.h>
46 #include <libical/icalrestriction.h>
47 #include <libical/icalmemory.h>
50 using namespace KCalCore;
53 class KCalCore::ICalFormat::Private
58 mTimeSpec( KDateTime::UTC )
60 ~Private() {
delete mImpl; }
62 KDateTime::Spec mTimeSpec;
67 : d( new Private( this ) )
73 icalmemory_free_ring();
83 QFile file( fileName );
84 if ( !file.open( QIODevice::ReadOnly ) ) {
85 kError() <<
"load error";
89 QTextStream ts( &file );
90 ts.setCodec(
"UTF-8" );
91 QByteArray text = ts.readAll().trimmed().toUtf8();
94 if ( text.isEmpty() ) {
104 kDebug() << fileName;
108 QString text =
toString( calendar );
109 if ( text.isEmpty() ) {
114 KSaveFile::backupFile( fileName );
116 KSaveFile file( fileName );
117 if ( !file.open() ) {
118 kDebug() <<
"file open error:" << file.errorString();
120 QStringList( fileName ) ) );
126 QByteArray textUtf8 = text.toUtf8();
127 file.write( textUtf8.data(), textUtf8.size() );
129 if ( !file.finalize() ) {
130 kDebug() <<
"file finalize error:" << file.errorString();
132 QStringList( fileName ) ) );
141 bool deleted,
const QString ¬ebook )
143 return fromRawString( cal,
string.toUtf8(), deleted, notebook );
147 bool deleted,
const QString ¬ebook )
149 Q_UNUSED( notebook );
152 icalcomponent *calendar;
155 calendar = icalcomponent_new_from_string( const_cast<char*>( (
const char * )
string ) );
157 kError() <<
"parse error ; string is empty?" <<
string.isEmpty();
164 if ( icalcomponent_isa( calendar ) == ICAL_XROOT_COMPONENT ) {
166 for ( comp = icalcomponent_get_first_component( calendar, ICAL_VCALENDAR_COMPONENT );
167 comp; comp = icalcomponent_get_next_component( calendar, ICAL_VCALENDAR_COMPONENT ) ) {
169 if ( !d->mImpl->populate( cal, comp, deleted ) ) {
170 kError() <<
"Could not populate calendar";
179 }
else if ( icalcomponent_isa( calendar ) != ICAL_VCALENDAR_COMPONENT ) {
180 kDebug() <<
"No VCALENDAR component found";
185 if ( !d->mImpl->populate( cal, calendar, deleted ) ) {
186 kDebug() <<
"Could not populate calendar";
196 icalcomponent_free( calendar );
197 icalmemory_free_ring();
209 if ( elist.count() > 0 ) {
210 ical = elist.first();
213 if ( tlist.count() > 0 ) {
214 ical = tlist.first();
217 if ( jlist.count() > 0 ) {
218 ical = jlist.first();
227 const QString ¬ebook,
bool deleted )
229 icalcomponent *calendar = d->mImpl->createCalendarComponent( cal );
230 icalcomponent *component;
236 Todo::List todoList = deleted ? cal->deletedTodos() : cal->rawTodos();
237 Todo::List::ConstIterator it;
238 for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) {
239 if ( !deleted || !cal->todo( ( *it )->uid(), ( *it )->recurrenceId() ) ) {
241 if ( notebook.isEmpty() ||
242 ( !cal->notebook( *it ).isEmpty() && notebook.endsWith( cal->notebook( *it ) ) ) ) {
243 component = d->mImpl->writeTodo( *it, tzlist, &tzUsedList );
244 icalcomponent_add_component( calendar, component );
249 Event::List events = deleted ? cal->deletedEvents() : cal->rawEvents();
250 Event::List::ConstIterator it2;
251 for ( it2 = events.constBegin(); it2 != events.constEnd(); ++it2 ) {
252 if ( !deleted || !cal->event( ( *it2 )->uid(), ( *it2 )->recurrenceId() ) ) {
254 if ( notebook.isEmpty() ||
255 ( !cal->notebook( *it2 ).isEmpty() && notebook.endsWith( cal->notebook( *it2 ) ) ) ) {
256 component = d->mImpl->writeEvent( *it2, tzlist, &tzUsedList );
257 icalcomponent_add_component( calendar, component );
263 Journal::List journals = deleted ? cal->deletedJournals() : cal->rawJournals();
264 Journal::List::ConstIterator it3;
265 for ( it3 = journals.constBegin(); it3 != journals.constEnd(); ++it3 ) {
266 if ( !deleted || !cal->journal( ( *it3 )->uid(), ( *it3 )->recurrenceId() ) ) {
268 if ( notebook.isEmpty() ||
269 ( !cal->notebook( *it3 ).isEmpty() && notebook.endsWith( cal->notebook( *it3 ) ) ) ) {
270 component = d->mImpl->writeJournal( *it3, tzlist, &tzUsedList );
271 icalcomponent_add_component( calendar, component );
277 ICalTimeZones::ZoneMap zones = tzUsedList.
zones();
278 if ( todoList.isEmpty() && events.isEmpty() && journals.isEmpty() ) {
281 zones = tzlist->
zones();
283 for ( ICalTimeZones::ZoneMap::ConstIterator it = zones.constBegin();
284 it != zones.constEnd(); ++it ) {
285 icaltimezone *tz = ( *it ).icalTimezone();
287 kError() <<
"bad time zone";
289 component = icalcomponent_new_clone( icaltimezone_get_component( tz ) );
290 icalcomponent_add_component( calendar, component );
291 icaltimezone_free( tz, 1 );
295 char *
const componentString = icalcomponent_as_ical_string_r( calendar );
296 const QString &text = QString::fromUtf8( componentString );
297 free( componentString );
299 icalcomponent_free( calendar );
300 icalmemory_free_ring();
302 if ( text.isEmpty() ) {
318 return QString::fromUtf8(
toRawString( incidence ) );
323 icalcomponent *component;
327 component = d->mImpl->writeIncidence( incidence,
iTIPRequest, &tzlist, &tzUsedList );
329 QByteArray text = icalcomponent_as_ical_string( component );
332 ICalTimeZones::ZoneMap zones = tzUsedList.
zones();
333 for ( ICalTimeZones::ZoneMap::ConstIterator it = zones.constBegin();
334 it != zones.constEnd(); ++it ) {
335 icaltimezone *tz = ( *it ).icalTimezone();
337 kError() <<
"bad time zone";
339 icalcomponent *tzcomponent = icaltimezone_get_component( tz );
340 icalcomponent_add_component( component, component );
341 text.append( icalcomponent_as_ical_string( tzcomponent ) );
342 icaltimezone_free( tz, 1 );
346 icalcomponent_free( component );
353 icalproperty *property;
354 property = icalproperty_new_rrule( d->mImpl->writeRecurrenceRule( recurrence ) );
355 QString text = QString::fromUtf8( icalproperty_as_ical_string( property ) );
356 icalproperty_free( property );
366 icalerror_clear_errno();
367 struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule.toLatin1() );
368 if ( icalerrno != ICAL_NO_ERROR ) {
369 kDebug() <<
"Recurrence parsing error:" << icalerror_strerror( icalerrno );
374 d->mImpl->readRecurrence( recur, recurrence );
383 icalcomponent *message = 0;
392 const bool useUtcTimes = !i->
recurs();
394 const bool hasSchedulingId = ( i->schedulingID() != i->uid() );
396 const bool incidenceNeedChanges = ( useUtcTimes || hasSchedulingId );
398 if ( incidenceNeedChanges ) {
404 i->shiftTimes( KDateTime::Spec::UTC(), KDateTime::Spec::UTC() );
408 if ( hasSchedulingId ) {
410 i->setSchedulingID( QString(), i->schedulingID() );
415 message = d->mImpl->createScheduleComponent( i, method );
419 if ( message == 0 ) {
420 message = d->mImpl->createScheduleComponent( incidence, method );
423 QString messageText = QString::fromUtf8( icalcomponent_as_ical_string( message ) );
425 icalcomponent_free( message );
433 icalcomponent *message;
434 message = icalparser_parse_string( str.toUtf8() );
443 for ( c = icalcomponent_get_first_component( message, ICAL_VFREEBUSY_COMPONENT );
444 c != 0; c = icalcomponent_get_next_component( message, ICAL_VFREEBUSY_COMPONENT ) ) {
448 freeBusy->merge( fb );
455 kDebug() <<
"object is not a freebusy.";
458 icalcomponent_free( message );
464 const QString &messageText )
469 if ( messageText.isEmpty() ) {
471 new Exception( Exception::ParseErrorEmptyMessage ) );
475 icalcomponent *message;
476 message = icalparser_parse_string( messageText.toUtf8() );
480 new Exception( Exception::ParseErrorUnableToParse ) );
486 icalcomponent_get_first_property( message, ICAL_METHOD_PROPERTY );
489 new Exception( Exception::ParseErrorMethodProperty ) );
497 tzs.
parse( message, tzlist );
502 c = icalcomponent_get_first_component( message, ICAL_VEVENT_COMPONENT );
504 incidence = d->mImpl->readEvent( c, &tzlist ).staticCast<
IncidenceBase>();
508 c = icalcomponent_get_first_component( message, ICAL_VTODO_COMPONENT );
510 incidence = d->mImpl->readTodo( c, &tzlist ).staticCast<
IncidenceBase>();
515 c = icalcomponent_get_first_component( message, ICAL_VJOURNAL_COMPONENT );
517 incidence = d->mImpl->readJournal( c, &tzlist ).staticCast<
IncidenceBase>();
522 c = icalcomponent_get_first_component( message, ICAL_VFREEBUSY_COMPONENT );
524 incidence = d->mImpl->readFreeBusy( c ).staticCast<
IncidenceBase>();
529 kDebug() <<
"object is not a freebusy, event, todo or journal";
535 icalproperty_method icalmethod = icalproperty_get_method( m );
538 switch ( icalmethod ) {
539 case ICAL_METHOD_PUBLISH:
542 case ICAL_METHOD_REQUEST:
545 case ICAL_METHOD_REFRESH:
548 case ICAL_METHOD_CANCEL:
551 case ICAL_METHOD_ADD:
554 case ICAL_METHOD_REPLY:
557 case ICAL_METHOD_COUNTER:
560 case ICAL_METHOD_DECLINECOUNTER:
565 kDebug() <<
"Unknown method";
569 if ( !icalrestriction_check( message ) ) {
571 <<
"kcalcore library reported a problem while parsing:";
573 << d->mImpl->extractErrorProperty( c );
576 Incidence::Ptr existingIncidence = cal->incidence( incidence->uid() );
578 icalcomponent *calendarComponent = 0;
579 if ( existingIncidence ) {
580 calendarComponent = d->mImpl->createCalendarComponent( cal );
586 icalcomponent_add_component( calendarComponent,
587 d->mImpl->writeTodo( todo ) );
591 icalcomponent_add_component( calendarComponent,
592 d->mImpl->writeEvent( event ) );
595 icalcomponent_free( message );
600 icalproperty_xlicclass result =
601 icalclassify( message, calendarComponent, static_cast<const char *>(
"" ) );
606 case ICAL_XLICCLASS_PUBLISHNEW:
609 case ICAL_XLICCLASS_PUBLISHUPDATE:
612 case ICAL_XLICCLASS_OBSOLETE:
615 case ICAL_XLICCLASS_REQUESTNEW:
618 case ICAL_XLICCLASS_REQUESTUPDATE:
621 case ICAL_XLICCLASS_UNKNOWN:
627 icalcomponent_free( message );
628 icalcomponent_free( calendarComponent );
645 KTimeZone tz = d->mTimeSpec.timeZone();
646 return tz.isValid() ? tz.name() : QString();