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>
53class KCalCore::ICalFormat::Private
58 mTimeSpec(KDateTime::UTC)
64 KDateTime::Spec mTimeSpec;
69 : d(new Private(this))
75 icalmemory_free_ring();
86 if (!file.open(QIODevice::ReadOnly)) {
87 kError() <<
"load error";
91 QTextStream ts(&file);
93 QByteArray text = ts.readAll().trimmed().toUtf8();
106 kDebug() << fileName;
111 if (text.isEmpty()) {
116 KSaveFile::backupFile(fileName);
118 KSaveFile file(fileName);
120 kError() <<
"file open error: " << file.errorString() <<
";filename=" << fileName;
122 QStringList(fileName)));
128 QByteArray textUtf8 = text.toUtf8();
129 file.write(textUtf8.data(), textUtf8.size());
131 if (!file.finalize()) {
132 kDebug() <<
"file finalize error:" << file.errorString();
134 QStringList(fileName)));
143 bool deleted,
const QString ¬ebook)
145 return fromRawString(cal,
string.toUtf8(), deleted, notebook);
149 bool deleted,
const QString ¬ebook)
154 icalcomponent *calendar;
157 calendar = icalcomponent_new_from_string(
const_cast<char*
>(
string.constData()));
159 kError() <<
"parse error from icalcomponent_new_from_string. string=" << QString::fromLatin1(
string);
166 if (icalcomponent_isa(calendar) == ICAL_XROOT_COMPONENT) {
168 for (comp = icalcomponent_get_first_component(calendar, ICAL_VCALENDAR_COMPONENT);
169 comp; comp = icalcomponent_get_next_component(calendar, ICAL_VCALENDAR_COMPONENT)) {
171 if (!d->mImpl->populate(cal, comp, deleted)) {
172 kError() <<
"Could not populate calendar";
181 }
else if (icalcomponent_isa(calendar) != ICAL_VCALENDAR_COMPONENT) {
182 kDebug() <<
"No VCALENDAR component found";
187 if (!d->mImpl->populate(cal, calendar, deleted)) {
188 kDebug() <<
"Could not populate calendar";
198 icalcomponent_free(calendar);
199 icalmemory_free_ring();
214 const QString ¬ebook,
bool deleted)
216 icalcomponent *calendar = d->mImpl->createCalendarComponent(cal);
217 icalcomponent *component;
223 Todo::List todoList = deleted ? cal->deletedTodos() : cal->rawTodos();
224 Todo::List::ConstIterator it;
225 for (it = todoList.constBegin(); it != todoList.constEnd(); ++it) {
226 if (!deleted || !cal->todo((*it)->uid(), (*it)->recurrenceId())) {
228 if (notebook.isEmpty() ||
229 (!cal->notebook(*it).isEmpty() && notebook.endsWith(cal->notebook(*it)))) {
230 component = d->mImpl->writeTodo(*it, tzlist, &tzUsedList);
231 icalcomponent_add_component(calendar, component);
236 Event::List events = deleted ? cal->deletedEvents() : cal->rawEvents();
237 Event::List::ConstIterator it2;
238 for (it2 = events.constBegin(); it2 != events.constEnd(); ++it2) {
239 if (!deleted || !cal->event((*it2)->uid(), (*it2)->recurrenceId())) {
241 if (notebook.isEmpty() ||
242 (!cal->notebook(*it2).isEmpty() && notebook.endsWith(cal->notebook(*it2)))) {
243 component = d->mImpl->writeEvent(*it2, tzlist, &tzUsedList);
244 icalcomponent_add_component(calendar, component);
250 Journal::List journals = deleted ? cal->deletedJournals() : cal->rawJournals();
251 Journal::List::ConstIterator it3;
252 for (it3 = journals.constBegin(); it3 != journals.constEnd(); ++it3) {
253 if (!deleted || !cal->journal((*it3)->uid(), (*it3)->recurrenceId())) {
255 if (notebook.isEmpty() ||
256 (!cal->notebook(*it3).isEmpty() && notebook.endsWith(cal->notebook(*it3)))) {
257 component = d->mImpl->writeJournal(*it3, tzlist, &tzUsedList);
258 icalcomponent_add_component(calendar, component);
264 ICalTimeZones::ZoneMap zones = tzUsedList.
zones();
265 if (todoList.isEmpty() && events.isEmpty() && journals.isEmpty()) {
268 zones = tzlist->
zones();
270 for (ICalTimeZones::ZoneMap::ConstIterator it = zones.constBegin();
271 it != zones.constEnd(); ++it) {
272 icaltimezone *tz = (*it).icalTimezone();
274 kError() <<
"bad time zone";
276 component = icalcomponent_new_clone(icaltimezone_get_component(tz));
277 icalcomponent_add_component(calendar, component);
278 icaltimezone_free(tz, 1);
282 char *
const componentString = icalcomponent_as_ical_string_r(calendar);
283 const QString &text = QString::fromUtf8(componentString);
284 free(componentString);
286 icalcomponent_free(calendar);
287 icalmemory_free_ring();
289 if (text.isEmpty()) {
310 icalcomponent *component;
314 component = d->mImpl->writeIncidence(incidence,
iTIPRequest, &tzlist, &tzUsedList);
316 QByteArray text = icalcomponent_as_ical_string(component);
319 ICalTimeZones::ZoneMap zones = tzUsedList.
zones();
320 for (ICalTimeZones::ZoneMap::ConstIterator it = zones.constBegin();
321 it != zones.constEnd(); ++it) {
322 icaltimezone *tz = (*it).icalTimezone();
324 kError() <<
"bad time zone";
326 icalcomponent *tzcomponent = icaltimezone_get_component(tz);
327 icalcomponent_add_component(component, component);
328 text.append(icalcomponent_as_ical_string(tzcomponent));
329 icaltimezone_free(tz, 1);
333 icalcomponent_free(component);
340 icalproperty *property;
341 property = icalproperty_new_rrule(d->mImpl->writeRecurrenceRule(recurrence));
342 QString text = QString::fromUtf8(icalproperty_as_ical_string(property));
343 icalproperty_free(property);
353 icalerror_clear_errno();
354 struct icalrecurrencetype recur = icalrecurrencetype_from_string(rrule.toLatin1());
355 if (icalerrno != ICAL_NO_ERROR) {
356 kDebug() <<
"Recurrence parsing error:" << icalerror_strerror(icalerrno);
361 d->mImpl->readRecurrence(recur, recurrence);
370 icalcomponent *message = 0;
379 const bool useUtcTimes = !i->
recurs();
381 const bool hasSchedulingId = (i->schedulingID() != i->uid());
383 const bool incidenceNeedChanges = (useUtcTimes || hasSchedulingId);
385 if (incidenceNeedChanges) {
391 i->shiftTimes(KDateTime::Spec::UTC(), KDateTime::Spec::UTC());
395 if (hasSchedulingId) {
397 i->setSchedulingID(QString(), i->schedulingID());
402 message = d->mImpl->createScheduleComponent(i, method);
407 message = d->mImpl->createScheduleComponent(incidence, method);
410 QString messageText = QString::fromUtf8(icalcomponent_as_ical_string(message));
412 icalcomponent_free(message);
420 icalcomponent *message;
421 message = icalparser_parse_string(str.toUtf8());
430 for (c = icalcomponent_get_first_component(message, ICAL_VFREEBUSY_COMPONENT);
431 c != 0; c = icalcomponent_get_next_component(message, ICAL_VFREEBUSY_COMPONENT)) {
442 kDebug() <<
"object is not a freebusy.";
445 icalcomponent_free(message);
451 const QString &messageText)
456 if (messageText.isEmpty()) {
458 new Exception(Exception::ParseErrorEmptyMessage));
462 icalcomponent *message;
463 message = icalparser_parse_string(messageText.toUtf8());
467 new Exception(Exception::ParseErrorUnableToParse));
473 icalcomponent_get_first_property(message, ICAL_METHOD_PROPERTY);
476 new Exception(Exception::ParseErrorMethodProperty));
484 tzs.
parse(message, tzlist);
489 c = icalcomponent_get_first_component(message, ICAL_VEVENT_COMPONENT);
491 incidence = d->mImpl->readEvent(c, &tzlist).staticCast<
IncidenceBase>();
495 c = icalcomponent_get_first_component(message, ICAL_VTODO_COMPONENT);
497 incidence = d->mImpl->readTodo(c, &tzlist).staticCast<
IncidenceBase>();
502 c = icalcomponent_get_first_component(message, ICAL_VJOURNAL_COMPONENT);
504 incidence = d->mImpl->readJournal(c, &tzlist).staticCast<
IncidenceBase>();
509 c = icalcomponent_get_first_component(message, ICAL_VFREEBUSY_COMPONENT);
511 incidence = d->mImpl->readFreeBusy(c).staticCast<
IncidenceBase>();
516 kDebug() <<
"object is not a freebusy, event, todo or journal";
522 icalproperty_method icalmethod = icalproperty_get_method(m);
525 switch (icalmethod) {
526 case ICAL_METHOD_PUBLISH:
529 case ICAL_METHOD_REQUEST:
532 case ICAL_METHOD_REFRESH:
535 case ICAL_METHOD_CANCEL:
538 case ICAL_METHOD_ADD:
541 case ICAL_METHOD_REPLY:
544 case ICAL_METHOD_COUNTER:
547 case ICAL_METHOD_DECLINECOUNTER:
552 kDebug() <<
"Unknown method";
556 if (!icalrestriction_check(message)) {
558 <<
"kcalcore library reported a problem while parsing:";
560 << d->mImpl->extractErrorProperty(c);
563 Incidence::Ptr existingIncidence = cal->incidence(incidence->uid());
565 icalcomponent *calendarComponent = 0;
566 if (existingIncidence) {
567 calendarComponent = d->mImpl->createCalendarComponent(cal);
573 icalcomponent_add_component(calendarComponent,
574 d->mImpl->writeTodo(todo));
578 icalcomponent_add_component(calendarComponent,
579 d->mImpl->writeEvent(event));
582 icalcomponent_free(message);
587 icalproperty_xlicclass result =
588 icalclassify(message, calendarComponent,
static_cast<const char *
>(
""));
593 case ICAL_XLICCLASS_PUBLISHNEW:
596 case ICAL_XLICCLASS_PUBLISHUPDATE:
599 case ICAL_XLICCLASS_OBSOLETE:
602 case ICAL_XLICCLASS_REQUESTNEW:
605 case ICAL_XLICCLASS_REQUESTUPDATE:
608 case ICAL_XLICCLASS_UNKNOWN:
614 icalcomponent_free(message);
615 icalcomponent_free(calendarComponent);
632 KTimeZone tz = d->mTimeSpec.timeZone();
633 return tz.isValid() ? tz.name() : QString();
Represents the main calendar class.
QSharedPointer< Calendar > Ptr
A shared pointer to a Calendar.
This class provides an Event in the sense of RFC2445.
QSharedPointer< Event > Ptr
A shared pointer to an Event object.
QVector< Ptr > List
List of events.
Exception base class, currently used as a fancy kind of error code and not as an C++ exception.
@ ParseErrorKcal
Parse error in libkcal.
@ NoCalendar
No calendar component found.
@ ParseErrorIcal
Parse error in libical.
QSharedPointer< FreeBusy > Ptr
A shared pointer to a FreeBusy object.
A class which reads and parses iCalendar VTIMEZONE components, and accesses libical time zone data.
ICalTimeZone parse(icalcomponent *vtimezone)
Creates an ICalTimeZone instance containing the detailed information parsed from an iCalendar VTIMEZO...
The ICalTimeZones class represents a time zone database which consists of a collection of individual ...
const ZoneMap zones() const
Returns all the time zones defined in this collection.
An abstract class that provides a common base for all calendar incidence classes.
@ TypeEvent
Type is an event.
@ TypeTodo
Type is a to-do.
QSharedPointer< IncidenceBase > Ptr
A shared pointer to an IncidenceBase.
Provides the abstract base class common to non-FreeBusy (Events, To-dos, Journals) calendar component...
QVector< Ptr > List
List of incidences.
bool recurs() const
Returns whether the event recurs at all.
QSharedPointer< Incidence > Ptr
A shared pointer to an Incidence.
QVector< Ptr > List
List of journals.
This class provides a calendar stored in memory.
QSharedPointer< MemoryCalendar > Ptr
A shared pointer to a MemoryCalendar.
This class represents a recurrence rule for a calendar incidence.
A Scheduling message class.
QSharedPointer< ScheduleMessage > Ptr
A shared pointer to a ScheduleMessage.
@ RequestNew
Request new message posting.
@ RequestUpdate
Request updated message.
@ PublishNew
New message posting.
@ PublishUpdate
Updated message.
static QString methodName(iTIPMethod method)
Returns a machine-readable (not translatable) name for a iTIP method.
Provides a To-do in the sense of RFC2445.
QVector< Ptr > List
List of to-dos.
QSharedPointer< Todo > Ptr
A shared pointer to a Todo object.
This file is part of the API for handling calendar data and defines the FreeBusy class.
This file is part of the API for handling calendar data and defines the MemoryCalendar class.
@ iTIPRefresh
Event or to-do description update request.
@ iTIPCounter
Event or to-do submit counter proposal.
@ iTIPDeclineCounter
Event or to-do decline a counter proposal.
@ iTIPCancel
Event, to-do or journal cancellation notice.
@ iTIPPublish
Event, to-do, journal or freebusy posting.
@ iTIPAdd
Event, to-do or journal additional property request.
@ iTIPReply
Event, to-do or freebusy reply to request.
@ iTIPRequest
Event, to-do or freebusy scheduling request.