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> 53 class 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();
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.
bool recurs() const
Returns whether the event recurs at all.
QSharedPointer< ScheduleMessage > Ptr
A shared pointer to a ScheduleMessage.
QVector< Ptr > List
List of events.
This class provides a calendar stored in memory.
const ZoneMap zones() const
Returns all the time zones defined in this collection.
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.
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.
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.