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 kError() <<
"file open error: " << file.errorString() <<
";filename=" << fileName;
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();
212 const QString ¬ebook,
bool deleted )
214 icalcomponent *calendar = d->mImpl->createCalendarComponent( cal );
215 icalcomponent *component;
221 Todo::List todoList = deleted ? cal->deletedTodos() : cal->rawTodos();
222 Todo::List::ConstIterator it;
223 for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) {
224 if ( !deleted || !cal->todo( ( *it )->uid(), ( *it )->recurrenceId() ) ) {
226 if ( notebook.isEmpty() ||
227 ( !cal->notebook( *it ).isEmpty() && notebook.endsWith( cal->notebook( *it ) ) ) ) {
228 component = d->mImpl->writeTodo( *it, tzlist, &tzUsedList );
229 icalcomponent_add_component( calendar, component );
234 Event::List events = deleted ? cal->deletedEvents() : cal->rawEvents();
235 Event::List::ConstIterator it2;
236 for ( it2 = events.constBegin(); it2 != events.constEnd(); ++it2 ) {
237 if ( !deleted || !cal->event( ( *it2 )->uid(), ( *it2 )->recurrenceId() ) ) {
239 if ( notebook.isEmpty() ||
240 ( !cal->notebook( *it2 ).isEmpty() && notebook.endsWith( cal->notebook( *it2 ) ) ) ) {
241 component = d->mImpl->writeEvent( *it2, tzlist, &tzUsedList );
242 icalcomponent_add_component( calendar, component );
248 Journal::List journals = deleted ? cal->deletedJournals() : cal->rawJournals();
249 Journal::List::ConstIterator it3;
250 for ( it3 = journals.constBegin(); it3 != journals.constEnd(); ++it3 ) {
251 if ( !deleted || !cal->journal( ( *it3 )->uid(), ( *it3 )->recurrenceId() ) ) {
253 if ( notebook.isEmpty() ||
254 ( !cal->notebook( *it3 ).isEmpty() && notebook.endsWith( cal->notebook( *it3 ) ) ) ) {
255 component = d->mImpl->writeJournal( *it3, tzlist, &tzUsedList );
256 icalcomponent_add_component( calendar, component );
262 ICalTimeZones::ZoneMap zones = tzUsedList.
zones();
263 if ( todoList.isEmpty() && events.isEmpty() && journals.isEmpty() ) {
266 zones = tzlist->
zones();
268 for ( ICalTimeZones::ZoneMap::ConstIterator it = zones.constBegin();
269 it != zones.constEnd(); ++it ) {
270 icaltimezone *tz = ( *it ).icalTimezone();
272 kError() <<
"bad time zone";
274 component = icalcomponent_new_clone( icaltimezone_get_component( tz ) );
275 icalcomponent_add_component( calendar, component );
276 icaltimezone_free( tz, 1 );
280 char *
const componentString = icalcomponent_as_ical_string_r( calendar );
281 const QString &text = QString::fromUtf8( componentString );
282 free( componentString );
284 icalcomponent_free( calendar );
285 icalmemory_free_ring();
287 if ( text.isEmpty() ) {
303 return QString::fromUtf8(
toRawString( incidence ) );
308 icalcomponent *component;
312 component = d->mImpl->writeIncidence( incidence,
iTIPRequest, &tzlist, &tzUsedList );
314 QByteArray text = icalcomponent_as_ical_string( component );
317 ICalTimeZones::ZoneMap zones = tzUsedList.
zones();
318 for ( ICalTimeZones::ZoneMap::ConstIterator it = zones.constBegin();
319 it != zones.constEnd(); ++it ) {
320 icaltimezone *tz = ( *it ).icalTimezone();
322 kError() <<
"bad time zone";
324 icalcomponent *tzcomponent = icaltimezone_get_component( tz );
325 icalcomponent_add_component( component, component );
326 text.append( icalcomponent_as_ical_string( tzcomponent ) );
327 icaltimezone_free( tz, 1 );
331 icalcomponent_free( component );
338 icalproperty *property;
339 property = icalproperty_new_rrule( d->mImpl->writeRecurrenceRule( recurrence ) );
340 QString text = QString::fromUtf8( icalproperty_as_ical_string( property ) );
341 icalproperty_free( property );
351 icalerror_clear_errno();
352 struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule.toLatin1() );
353 if ( icalerrno != ICAL_NO_ERROR ) {
354 kDebug() <<
"Recurrence parsing error:" << icalerror_strerror( icalerrno );
359 d->mImpl->readRecurrence( recur, recurrence );
368 icalcomponent *message = 0;
377 const bool useUtcTimes = !i->
recurs();
379 const bool hasSchedulingId = ( i->schedulingID() != i->uid() );
381 const bool incidenceNeedChanges = ( useUtcTimes || hasSchedulingId );
383 if ( incidenceNeedChanges ) {
389 i->shiftTimes( KDateTime::Spec::UTC(), KDateTime::Spec::UTC() );
393 if ( hasSchedulingId ) {
395 i->setSchedulingID( QString(), i->schedulingID() );
400 message = d->mImpl->createScheduleComponent( i, method );
404 if ( message == 0 ) {
405 message = d->mImpl->createScheduleComponent( incidence, method );
408 QString messageText = QString::fromUtf8( icalcomponent_as_ical_string( message ) );
410 icalcomponent_free( message );
418 icalcomponent *message;
419 message = icalparser_parse_string( str.toUtf8() );
428 for ( c = icalcomponent_get_first_component( message, ICAL_VFREEBUSY_COMPONENT );
429 c != 0; c = icalcomponent_get_next_component( message, ICAL_VFREEBUSY_COMPONENT ) ) {
433 freeBusy->merge( fb );
440 kDebug() <<
"object is not a freebusy.";
443 icalcomponent_free( message );
449 const QString &messageText )
454 if ( messageText.isEmpty() ) {
456 new Exception( Exception::ParseErrorEmptyMessage ) );
460 icalcomponent *message;
461 message = icalparser_parse_string( messageText.toUtf8() );
465 new Exception( Exception::ParseErrorUnableToParse ) );
471 icalcomponent_get_first_property( message, ICAL_METHOD_PROPERTY );
474 new Exception( Exception::ParseErrorMethodProperty ) );
482 tzs.
parse( message, tzlist );
487 c = icalcomponent_get_first_component( message, ICAL_VEVENT_COMPONENT );
489 incidence = d->mImpl->readEvent( c, &tzlist ).staticCast<
IncidenceBase>();
493 c = icalcomponent_get_first_component( message, ICAL_VTODO_COMPONENT );
495 incidence = d->mImpl->readTodo( c, &tzlist ).staticCast<
IncidenceBase>();
500 c = icalcomponent_get_first_component( message, ICAL_VJOURNAL_COMPONENT );
502 incidence = d->mImpl->readJournal( c, &tzlist ).staticCast<
IncidenceBase>();
507 c = icalcomponent_get_first_component( message, ICAL_VFREEBUSY_COMPONENT );
509 incidence = d->mImpl->readFreeBusy( c ).staticCast<
IncidenceBase>();
514 kDebug() <<
"object is not a freebusy, event, todo or journal";
520 icalproperty_method icalmethod = icalproperty_get_method( m );
523 switch ( icalmethod ) {
524 case ICAL_METHOD_PUBLISH:
527 case ICAL_METHOD_REQUEST:
530 case ICAL_METHOD_REFRESH:
533 case ICAL_METHOD_CANCEL:
536 case ICAL_METHOD_ADD:
539 case ICAL_METHOD_REPLY:
542 case ICAL_METHOD_COUNTER:
545 case ICAL_METHOD_DECLINECOUNTER:
550 kDebug() <<
"Unknown method";
554 if ( !icalrestriction_check( message ) ) {
556 <<
"kcalcore library reported a problem while parsing:";
558 << d->mImpl->extractErrorProperty( c );
561 Incidence::Ptr existingIncidence = cal->incidence( incidence->uid() );
563 icalcomponent *calendarComponent = 0;
564 if ( existingIncidence ) {
565 calendarComponent = d->mImpl->createCalendarComponent( cal );
571 icalcomponent_add_component( calendarComponent,
572 d->mImpl->writeTodo( todo ) );
576 icalcomponent_add_component( calendarComponent,
577 d->mImpl->writeEvent( event ) );
580 icalcomponent_free( message );
585 icalproperty_xlicclass result =
586 icalclassify( message, calendarComponent, static_cast<const char *>(
"" ) );
591 case ICAL_XLICCLASS_PUBLISHNEW:
594 case ICAL_XLICCLASS_PUBLISHUPDATE:
597 case ICAL_XLICCLASS_OBSOLETE:
600 case ICAL_XLICCLASS_REQUESTNEW:
603 case ICAL_XLICCLASS_REQUESTUPDATE:
606 case ICAL_XLICCLASS_UNKNOWN:
612 icalcomponent_free( message );
613 icalcomponent_free( calendarComponent );
630 KTimeZone tz = d->mTimeSpec.timeZone();
631 return tz.isValid() ? tz.name() : QString();
Exception base class, currently used as a fancy kind of error code and not as an C++ exception...
QVector< Ptr > List
List of journals.
static QString methodName(iTIPMethod method)
Returns a machine-readable (not translatable) name for a iTIP method.
This file is part of the API for handling calendar data and defines the MemoryCalendar class...
QSharedPointer< Event > Ptr
A shared pointer to an Event object.
A class which reads and parses iCalendar VTIMEZONE components, and accesses libical time zone data...
An abstract class that provides a common base for all calendar incidence classes. ...
A Scheduling message class.
No calendar component found.
QSharedPointer< Incidence > Ptr
A shared pointer to an Incidence.
QSharedPointer< ScheduleMessage > Ptr
A shared pointer to a ScheduleMessage.
QVector< Ptr > List
List of events.
This class provides a calendar stored in memory.
QSharedPointer< MemoryCalendar > Ptr
A shared pointer to a MemoryCalendar.
QSharedPointer< IncidenceBase > Ptr
A shared pointer to an IncidenceBase.
ICalTimeZone parse(icalcomponent *vtimezone)
Creates an ICalTimeZone instance containing the detailed information parsed from an iCalendar VTIMEZO...
Event or to-do submit counter proposal.
This file is part of the API for handling calendar data and defines the FreeBusy class.
Request new message posting.
Event or to-do decline a counter proposal.
Event, to-do or freebusy reply to request.
QSharedPointer< Calendar > Ptr
A shared pointer to a Calendar.
QVector< Ptr > List
List of to-dos.
Event, to-do or journal cancellation notice.
Provides a To-do in the sense of RFC2445.
QSharedPointer< FreeBusy > Ptr
A shared pointer to a FreeBusy object.
QVector< Ptr > List
List of incidences.
This class provides an Event in the sense of RFC2445.
bool recurs() const
Returns whether the event recurs at all.
The ICalTimeZones class represents a time zone database which consists of a collection of individual ...
Represents the main calendar class.
Event, to-do or journal additional property request.
Event, to-do, journal or freebusy posting.
Event or to-do description update request.
QSharedPointer< Todo > Ptr
A shared pointer to a Todo object.
const ZoneMap zones() const
Returns all the time zones defined in this collection.
Event, to-do or freebusy scheduling request.
Provides the abstract base class common to non-FreeBusy (Events, To-dos, Journals) calendar component...
This class represents a recurrence rule for a calendar incidence.