KCalendarCore

icalformat.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcalcore library.
3 
4  SPDX-FileCopyrightText: 2001 Cornelius Schumacher <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 /**
9  @file
10  This file is part of the API for handling calendar data and
11  defines the ICalFormat class.
12 
13  @brief
14  iCalendar format implementation: a layer of abstraction for libical.
15 
16  @author Cornelius Schumacher <[email protected]>
17 */
18 #include "icalformat.h"
19 #include "calendar_p.h"
20 #include "calformat_p.h"
21 #include "icalformat_p.h"
22 #include "icaltimezones_p.h"
23 #include "kcalendarcore_debug.h"
24 #include "memorycalendar.h"
25 
26 #include <QFile>
27 #include <QSaveFile>
28 #include <QTimeZone>
29 
30 extern "C" {
31 #include <libical/ical.h>
32 #include <libical/icalmemory.h>
33 #include <libical/icalparser.h>
34 #include <libical/icalrestriction.h>
35 #include <libical/icalss.h>
36 }
37 
38 using namespace KCalendarCore;
39 
40 //@cond PRIVATE
41 class KCalendarCore::ICalFormatPrivate : public KCalendarCore::CalFormatPrivate
42 {
43 public:
44  ICalFormatPrivate(ICalFormat *parent)
45  : mImpl(parent)
46  , mTimeZone(QTimeZone::utc())
47  {
48  }
49  ICalFormatImpl mImpl;
50  QTimeZone mTimeZone;
51 };
52 //@endcond
53 
55  : CalFormat(new ICalFormatPrivate(this))
56 {
57 }
58 
60 {
61  icalmemory_free_ring();
62 }
63 
64 bool ICalFormat::load(const Calendar::Ptr &calendar, const QString &fileName)
65 {
66  qCDebug(KCALCORE_LOG) << fileName;
67 
69 
70  QFile file(fileName);
71  if (!file.open(QIODevice::ReadOnly)) {
72  qCritical() << "load error: unable to open " << fileName;
74  return false;
75  }
76  const QByteArray text = file.readAll().trimmed();
77  file.close();
78 
79  if (!text.isEmpty()) {
80  if (!calendar->hasValidNotebook(fileName) && !calendar->addNotebook(fileName, true)) {
81  qCWarning(KCALCORE_LOG) << "Unable to add" << fileName << "as a notebook in calendar";
82  }
83  if (!fromRawString(calendar, text, false, fileName)) {
84  qCWarning(KCALCORE_LOG) << fileName << " is not a valid iCalendar file";
86  return false;
87  }
88  }
89 
90  // Note: we consider empty files to be valid
91 
92  return true;
93 }
94 
95 bool ICalFormat::save(const Calendar::Ptr &calendar, const QString &fileName)
96 {
97  qCDebug(KCALCORE_LOG) << fileName;
98 
100 
101  QString text = toString(calendar);
102  if (text.isEmpty()) {
103  return false;
104  }
105 
106  // Write backup file
107  const QString backupFile = fileName + QLatin1Char('~');
108  QFile::remove(backupFile);
109  QFile::copy(fileName, backupFile);
110 
111  QSaveFile file(fileName);
112  if (!file.open(QIODevice::WriteOnly)) {
113  qCritical() << "file open error: " << file.errorString() << ";filename=" << fileName;
114  setException(new Exception(Exception::SaveErrorOpenFile, QStringList(fileName)));
115 
116  return false;
117  }
118 
119  // Convert to UTF8 and save
120  QByteArray textUtf8 = text.toUtf8();
121  file.write(textUtf8.data(), textUtf8.size());
122  // QSaveFile doesn't report a write error when the device is full (see Qt
123  // bug 75077), so check that the data can actually be written.
124  if (!file.flush()) {
125  qCDebug(KCALCORE_LOG) << "file write error (flush failed)";
126  setException(new Exception(Exception::SaveErrorSaveFile, QStringList(fileName)));
127  return false;
128  }
129 
130  if (!file.commit()) {
131  qCDebug(KCALCORE_LOG) << "file finalize error:" << file.errorString();
132  setException(new Exception(Exception::SaveErrorSaveFile, QStringList(fileName)));
133 
134  return false;
135  }
136 
137  return true;
138 }
139 
140 #if KCALENDARCORE_BUILD_DEPRECATED_SINCE(5, 97)
141 bool ICalFormat::fromString(const Calendar::Ptr &cal, const QString &string, bool deleted, const QString &notebook)
142 {
143  return fromRawString(cal, string.toUtf8(), deleted, notebook);
144 }
145 #endif
146 
148 {
149  Q_D(ICalFormat);
150 
151  // Let's defend const correctness until the very gates of hell^Wlibical
152  icalcomponent *calendar = icalcomponent_new_from_string(const_cast<char *>(string.constData()));
153  if (!calendar) {
154  qCritical() << "parse error from icalcomponent_new_from_string. string=" << QString::fromLatin1(string);
156  return Incidence::Ptr();
157  }
158 
159  ICalTimeZoneCache tzCache;
160  ICalTimeZoneParser parser(&tzCache);
161  parser.parse(calendar);
162 
163  Incidence::Ptr incidence;
164  if (icalcomponent_isa(calendar) == ICAL_VCALENDAR_COMPONENT) {
165  incidence = d->mImpl.readOneIncidence(calendar, &tzCache);
166  } else if (icalcomponent_isa(calendar) == ICAL_XROOT_COMPONENT) {
167  icalcomponent *comp = icalcomponent_get_first_component(calendar, ICAL_VCALENDAR_COMPONENT);
168  if (comp) {
169  incidence = d->mImpl.readOneIncidence(comp, &tzCache);
170  }
171  }
172 
173  if (!incidence) {
174  qCDebug(KCALCORE_LOG) << "No VCALENDAR component found";
176  }
177 
178  icalcomponent_free(calendar);
179  icalmemory_free_ring();
180 
181  return incidence;
182 }
183 
184 bool ICalFormat::fromRawString(const Calendar::Ptr &cal, const QByteArray &string, bool deleted, const QString &notebook)
185 {
186  Q_D(ICalFormat);
187 
188  // Get first VCALENDAR component.
189  // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components
190  icalcomponent *calendar;
191 
192  // Let's defend const correctness until the very gates of hell^Wlibical
193  calendar = icalcomponent_new_from_string(const_cast<char *>(string.constData()));
194  if (!calendar) {
195  qCritical() << "parse error from icalcomponent_new_from_string. string=" << QString::fromLatin1(string);
197  return false;
198  }
199 
200  bool success = true;
201 
202  if (icalcomponent_isa(calendar) == ICAL_XROOT_COMPONENT) {
203  icalcomponent *comp;
204  for (comp = icalcomponent_get_first_component(calendar, ICAL_VCALENDAR_COMPONENT); comp;
205  comp = icalcomponent_get_next_component(calendar, ICAL_VCALENDAR_COMPONENT)) {
206  // put all objects into their proper places
207  if (!d->mImpl.populate(cal, comp, deleted)) {
208  qCritical() << "Could not populate calendar";
209  if (!exception()) {
211  }
212  success = false;
213  } else {
214  setLoadedProductId(d->mImpl.loadedProductId());
215  }
216  }
217  } else if (icalcomponent_isa(calendar) != ICAL_VCALENDAR_COMPONENT) {
218  qCDebug(KCALCORE_LOG) << "No VCALENDAR component found";
220  success = false;
221  } else {
222  // put all objects into their proper places
223  if (!d->mImpl.populate(cal, calendar, deleted, notebook)) {
224  qCDebug(KCALCORE_LOG) << "Could not populate calendar";
225  if (!exception()) {
227  }
228  success = false;
229  } else {
230  setLoadedProductId(d->mImpl.loadedProductId());
231  }
232  }
233 
234  icalcomponent_free(calendar);
235  icalmemory_free_ring();
236 
237  return success;
238 }
239 
241 {
242  Q_D(ICalFormat);
243 
244  MemoryCalendar::Ptr cal(new MemoryCalendar(d->mTimeZone));
245  fromString(cal, string);
246 
247  const Incidence::List list = cal->incidences();
248  return !list.isEmpty() ? list.first() : Incidence::Ptr();
249 }
250 
251 QString ICalFormat::toString(const Calendar::Ptr &cal, const QString &notebook, bool deleted)
252 {
253  Q_D(ICalFormat);
254 
255  icalcomponent *calendar = d->mImpl.createCalendarComponent(cal);
256  icalcomponent *component;
257 
258  QVector<QTimeZone> tzUsedList;
259  TimeZoneEarliestDate earliestTz;
260 
261  // todos
262  Todo::List todoList = deleted ? cal->deletedTodos() : cal->rawTodos();
263  for (auto it = todoList.cbegin(), end = todoList.cend(); it != end; ++it) {
264  if (!deleted || !cal->todo((*it)->uid(), (*it)->recurrenceId())) {
265  // use existing ones, or really deleted ones
266  if (notebook.isEmpty() || (!cal->notebook(*it).isEmpty() && notebook.endsWith(cal->notebook(*it)))) {
267  component = d->mImpl.writeTodo(*it, &tzUsedList);
268  icalcomponent_add_component(calendar, component);
269  ICalTimeZoneParser::updateTzEarliestDate((*it), &earliestTz);
270  }
271  }
272  }
273  // events
274  Event::List events = deleted ? cal->deletedEvents() : cal->rawEvents();
275  for (auto it = events.cbegin(), end = events.cend(); it != end; ++it) {
276  if (!deleted || !cal->event((*it)->uid(), (*it)->recurrenceId())) {
277  // use existing ones, or really deleted ones
278  if (notebook.isEmpty() || (!cal->notebook(*it).isEmpty() && notebook.endsWith(cal->notebook(*it)))) {
279  component = d->mImpl.writeEvent(*it, &tzUsedList);
280  icalcomponent_add_component(calendar, component);
281  ICalTimeZoneParser::updateTzEarliestDate((*it), &earliestTz);
282  }
283  }
284  }
285 
286  // journals
287  Journal::List journals = deleted ? cal->deletedJournals() : cal->rawJournals();
288  for (auto it = journals.cbegin(), end = journals.cend(); it != end; ++it) {
289  if (!deleted || !cal->journal((*it)->uid(), (*it)->recurrenceId())) {
290  // use existing ones, or really deleted ones
291  if (notebook.isEmpty() || (!cal->notebook(*it).isEmpty() && notebook.endsWith(cal->notebook(*it)))) {
292  component = d->mImpl.writeJournal(*it, &tzUsedList);
293  icalcomponent_add_component(calendar, component);
294  ICalTimeZoneParser::updateTzEarliestDate((*it), &earliestTz);
295  }
296  }
297  }
298 
299  // time zones
300  if (todoList.isEmpty() && events.isEmpty() && journals.isEmpty()) {
301  // no incidences means no used timezones, use all timezones
302  // this will export a calendar having only timezone definitions
303  tzUsedList = cal->d->mTimeZones;
304  }
305  for (const auto &qtz : std::as_const(tzUsedList)) {
306  if (qtz != QTimeZone::utc()) {
307  icaltimezone *tz = ICalTimeZoneParser::icaltimezoneFromQTimeZone(qtz, earliestTz[qtz]);
308  if (!tz) {
309  qCritical() << "bad time zone";
310  } else {
311  component = icalcomponent_new_clone(icaltimezone_get_component(tz));
312  icalcomponent_add_component(calendar, component);
313  icaltimezone_free(tz, 1);
314  }
315  }
316  }
317 
318  char *const componentString = icalcomponent_as_ical_string_r(calendar);
319  const QString &text = QString::fromUtf8(componentString);
320  free(componentString);
321 
322  icalcomponent_free(calendar);
323  icalmemory_free_ring();
324 
325  if (text.isEmpty()) {
326  setException(new Exception(Exception::LibICalError));
327  }
328 
329  return text;
330 }
331 
333 {
334  Q_D(ICalFormat);
335 
336  MemoryCalendar::Ptr cal(new MemoryCalendar(d->mTimeZone));
337  cal->addIncidence(Incidence::Ptr(incidence->clone()));
338  return toString(cal.staticCast<Calendar>());
339 }
340 
342 {
343  return QString::fromUtf8(toRawString(incidence));
344 }
345 
347 {
348  Q_D(ICalFormat);
349  TimeZoneList tzUsedList;
350 
351  icalcomponent *component = d->mImpl.writeIncidence(incidence, iTIPRequest, &tzUsedList);
352 
353  QByteArray text = icalcomponent_as_ical_string(component);
354 
355  TimeZoneEarliestDate earliestTzDt;
356  ICalTimeZoneParser::updateTzEarliestDate(incidence, &earliestTzDt);
357 
358  // time zones
359  for (const auto &qtz : std::as_const(tzUsedList)) {
360  if (qtz != QTimeZone::utc()) {
361  icaltimezone *tz = ICalTimeZoneParser::icaltimezoneFromQTimeZone(qtz, earliestTzDt[qtz]);
362  if (!tz) {
363  qCritical() << "bad time zone";
364  } else {
365  icalcomponent *tzcomponent = icaltimezone_get_component(tz);
366  icalcomponent_add_component(component, component);
367  text.append(icalcomponent_as_ical_string(tzcomponent));
368  icaltimezone_free(tz, 1);
369  }
370  }
371  }
372 
373  icalcomponent_free(component);
374 
375  return text;
376 }
377 
379 {
380  Q_D(ICalFormat);
381  icalproperty *property = icalproperty_new_rrule(d->mImpl.writeRecurrenceRule(recurrence));
382  QString text = QString::fromUtf8(icalproperty_as_ical_string(property));
383  icalproperty_free(property);
384  return text;
385 }
386 
388 {
389  Q_D(const ICalFormat);
390  const auto icalDuration = d->mImpl.writeICalDuration(duration);
391  // contrary to the libical API docs, the returned string is actually freed by icalmemory_free_ring,
392  // freeing it here explicitly causes a double deletion failure
393  return QString::fromUtf8(icaldurationtype_as_ical_string(icalDuration));
394 }
395 
396 bool ICalFormat::fromString(RecurrenceRule *recurrence, const QString &rrule)
397 {
398  Q_D(ICalFormat);
399  if (!recurrence) {
400  return false;
401  }
402  bool success = true;
403  icalerror_clear_errno();
404  struct icalrecurrencetype recur = icalrecurrencetype_from_string(rrule.toLatin1().constData());
405  if (icalerrno != ICAL_NO_ERROR) {
406  qCDebug(KCALCORE_LOG) << "Recurrence parsing error:" << icalerror_strerror(icalerrno);
407  success = false;
408  }
409 
410  if (success) {
411  d->mImpl.readRecurrence(recur, recurrence);
412  }
413 
414  return success;
415 }
416 
418 {
419  Q_D(const ICalFormat);
420  icalerror_clear_errno();
421  const auto icalDuration = icaldurationtype_from_string(duration.toUtf8().constData());
422  if (icalerrno != ICAL_NO_ERROR) {
423  qCDebug(KCALCORE_LOG) << "Duration parsing error:" << icalerror_strerror(icalerrno);
424  return {};
425  }
426  return d->mImpl.readICalDuration(icalDuration);
427 }
428 
430 {
431  Q_D(ICalFormat);
432  icalcomponent *message = nullptr;
433 
434  if (incidence->type() == Incidence::TypeEvent || incidence->type() == Incidence::TypeTodo) {
435  Incidence::Ptr i = incidence.staticCast<Incidence>();
436 
437  // Recurring events need timezone information to allow proper calculations
438  // across timezones with different DST.
439  const bool useUtcTimes = !i->recurs();
440 
441  const bool hasSchedulingId = (i->schedulingID() != i->uid());
442 
443  const bool incidenceNeedChanges = (useUtcTimes || hasSchedulingId);
444 
445  if (incidenceNeedChanges) {
446  // The incidence need changes, so clone it before we continue
447  i = Incidence::Ptr(i->clone());
448 
449  // Handle conversion to UTC times
450  if (useUtcTimes) {
451  i->shiftTimes(QTimeZone::utc(), QTimeZone::utc());
452  }
453 
454  // Handle scheduling ID being present
455  if (hasSchedulingId) {
456  // We have a separation of scheduling ID and UID
457  i->setSchedulingID(QString(), i->schedulingID());
458  }
459 
460  // Build the message with the cloned incidence
461  message = d->mImpl.createScheduleComponent(i, method);
462  }
463  }
464 
465  if (message == nullptr) {
466  message = d->mImpl.createScheduleComponent(incidence, method);
467  }
468 
469  QString messageText = QString::fromUtf8(icalcomponent_as_ical_string(message));
470 
471  icalcomponent_free(message);
472  return messageText;
473 }
474 
476 {
477  Q_D(ICalFormat);
478  clearException();
479 
480  icalcomponent *message = icalparser_parse_string(str.toUtf8().constData());
481 
482  if (!message) {
483  return FreeBusy::Ptr();
484  }
485 
486  FreeBusy::Ptr freeBusy;
487 
488  icalcomponent *c = nullptr;
489  for (c = icalcomponent_get_first_component(message, ICAL_VFREEBUSY_COMPONENT); c != nullptr;
490  c = icalcomponent_get_next_component(message, ICAL_VFREEBUSY_COMPONENT)) {
491  FreeBusy::Ptr fb = d->mImpl.readFreeBusy(c);
492 
493  if (freeBusy) {
494  freeBusy->merge(fb);
495  } else {
496  freeBusy = fb;
497  }
498  }
499 
500  if (!freeBusy) {
501  qCDebug(KCALCORE_LOG) << "object is not a freebusy.";
502  }
503 
504  icalcomponent_free(message);
505 
506  return freeBusy;
507 }
508 
510 {
511  Q_D(ICalFormat);
512  setTimeZone(cal->timeZone());
513  clearException();
514 
515  if (messageText.isEmpty()) {
516  setException(new Exception(Exception::ParseErrorEmptyMessage));
517  return ScheduleMessage::Ptr();
518  }
519 
520  icalcomponent *message = icalparser_parse_string(messageText.toUtf8().constData());
521 
522  if (!message) {
523  setException(new Exception(Exception::ParseErrorUnableToParse));
524 
525  return ScheduleMessage::Ptr();
526  }
527 
528  icalproperty *m = icalcomponent_get_first_property(message, ICAL_METHOD_PROPERTY);
529  if (!m) {
530  setException(new Exception(Exception::ParseErrorMethodProperty));
531 
532  return ScheduleMessage::Ptr();
533  }
534 
535  // Populate the message's time zone collection with all VTIMEZONE components
536  ICalTimeZoneCache tzlist;
537  ICalTimeZoneParser parser(&tzlist);
538  parser.parse(message);
539 
540  IncidenceBase::Ptr incidence;
541  icalcomponent *c = icalcomponent_get_first_component(message, ICAL_VEVENT_COMPONENT);
542  if (c) {
543  incidence = d->mImpl.readEvent(c, &tzlist).staticCast<IncidenceBase>();
544  }
545 
546  if (!incidence) {
547  c = icalcomponent_get_first_component(message, ICAL_VTODO_COMPONENT);
548  if (c) {
549  incidence = d->mImpl.readTodo(c, &tzlist).staticCast<IncidenceBase>();
550  }
551  }
552 
553  if (!incidence) {
554  c = icalcomponent_get_first_component(message, ICAL_VJOURNAL_COMPONENT);
555  if (c) {
556  incidence = d->mImpl.readJournal(c, &tzlist).staticCast<IncidenceBase>();
557  }
558  }
559 
560  if (!incidence) {
561  c = icalcomponent_get_first_component(message, ICAL_VFREEBUSY_COMPONENT);
562  if (c) {
563  incidence = d->mImpl.readFreeBusy(c).staticCast<IncidenceBase>();
564  }
565  }
566 
567  if (!incidence) {
568  qCDebug(KCALCORE_LOG) << "object is not a freebusy, event, todo or journal";
569  setException(new Exception(Exception::ParseErrorNotIncidence));
570 
571  return ScheduleMessage::Ptr();
572  }
573 
574  icalproperty_method icalmethod = icalproperty_get_method(m);
575  iTIPMethod method;
576 
577  switch (icalmethod) {
578  case ICAL_METHOD_PUBLISH:
579  method = iTIPPublish;
580  break;
581  case ICAL_METHOD_REQUEST:
582  method = iTIPRequest;
583  break;
584  case ICAL_METHOD_REFRESH:
585  method = iTIPRefresh;
586  break;
587  case ICAL_METHOD_CANCEL:
588  method = iTIPCancel;
589  break;
590  case ICAL_METHOD_ADD:
591  method = iTIPAdd;
592  break;
593  case ICAL_METHOD_REPLY:
594  method = iTIPReply;
595  break;
596  case ICAL_METHOD_COUNTER:
597  method = iTIPCounter;
598  break;
599  case ICAL_METHOD_DECLINECOUNTER:
600  method = iTIPDeclineCounter;
601  break;
602  default:
603  method = iTIPNoMethod;
604  qCDebug(KCALCORE_LOG) << "Unknown method";
605  break;
606  }
607 
608  if (!icalrestriction_check(message)) {
609  qCWarning(KCALCORE_LOG) << "\nkcalcore library reported a problem while parsing:";
610  qCWarning(KCALCORE_LOG) << ScheduleMessage::methodName(method) << ":" << d->mImpl.extractErrorProperty(c);
611  }
612 
613  Incidence::Ptr existingIncidence = cal->incidence(incidence->uid());
614 
615  icalcomponent *calendarComponent = nullptr;
616  if (existingIncidence) {
617  calendarComponent = d->mImpl.createCalendarComponent(cal);
618 
619  // TODO: check, if cast is required, or if it can be done by virtual funcs.
620  // TODO: Use a visitor for this!
621  if (existingIncidence->type() == Incidence::TypeTodo) {
622  Todo::Ptr todo = existingIncidence.staticCast<Todo>();
623  icalcomponent_add_component(calendarComponent, d->mImpl.writeTodo(todo));
624  }
625  if (existingIncidence->type() == Incidence::TypeEvent) {
626  Event::Ptr event = existingIncidence.staticCast<Event>();
627  icalcomponent_add_component(calendarComponent, d->mImpl.writeEvent(event));
628  }
629  } else {
630  icalcomponent_free(message);
631  return ScheduleMessage::Ptr(new ScheduleMessage(incidence, method, ScheduleMessage::Unknown));
632  }
633 
634  icalproperty_xlicclass result = icalclassify(message, calendarComponent, static_cast<const char *>(""));
635 
637 
638  switch (result) {
639  case ICAL_XLICCLASS_PUBLISHNEW:
641  break;
642  case ICAL_XLICCLASS_PUBLISHUPDATE:
644  break;
645  case ICAL_XLICCLASS_OBSOLETE:
647  break;
648  case ICAL_XLICCLASS_REQUESTNEW:
650  break;
651  case ICAL_XLICCLASS_REQUESTUPDATE:
653  break;
654  case ICAL_XLICCLASS_UNKNOWN:
655  default:
657  break;
658  }
659 
660  icalcomponent_free(message);
661  icalcomponent_free(calendarComponent);
662 
663  return ScheduleMessage::Ptr(new ScheduleMessage(incidence, method, status));
664 }
665 
666 void ICalFormat::setTimeZone(const QTimeZone &timeZone)
667 {
668  Q_D(ICalFormat);
669  d->mTimeZone = timeZone;
670 }
671 
673 {
674  Q_D(const ICalFormat);
675  return d->mTimeZone;
676 }
677 
679 {
680  Q_D(const ICalFormat);
681  return d->mTimeZone.id();
682 }
683 
684 #if KCALENDARCORE_BUILD_DEPRECATED_SINCE(5, 96)
685 void ICalFormat::virtual_hook(int id, void *data)
686 {
687  Q_UNUSED(id);
688  Q_UNUSED(data);
689  Q_ASSERT(false);
690 }
691 #endif
QTimeZone utc()
@ iTIPNoMethod
No method.
T & first()
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool fromRawString(const Calendar::Ptr &calendar, const QByteArray &string, bool deleted=false, const QString &notebook=QString()) override
Definition: icalformat.cpp:184
QString errorString() const const
bool isEmpty() const const
Represents a span of time measured in seconds or days.
Definition: duration.h:43
QString fromUtf8(const char *str, int size)
bool remove()
QString toString(const Calendar::Ptr &calendar, const QString &notebook=QString(), bool deleted=false) override
Definition: icalformat.cpp:251
bool load(const Calendar::Ptr &calendar, const QString &fileName) override
Definition: icalformat.cpp:64
QByteArray & append(char ch)
virtual bool open(QIODevice::OpenMode mode) override
QVector::const_iterator cend() const const
bool copy(const QString &newName)
Incidence::Ptr readIncidence(const QByteArray &string)
Parses a bytearray, returning the first iCal component as an Incidence, ignoring timezone information...
Definition: icalformat.cpp:147
@ iTIPDeclineCounter
Event or to-do decline a counter proposal.
Namespace for all KCalendarCore types.
Definition: alarm.h:36
void setTimeZone(const QTimeZone &timeZone)
Sets the iCalendar time zone.
Definition: icalformat.cpp:666
void clearException()
Clears the exception status.
Definition: calformat.cpp:54
bool commit()
QByteArray trimmed() const const
Provides the abstract base class common to non-FreeBusy (Events, To-dos, Journals) calendar component...
Definition: incidence.h:59
FreeBusy::Ptr parseFreeBusy(const QString &string)
Converts a QString into a FreeBusy object.
Definition: icalformat.cpp:475
QByteArray toLatin1() const const
@ TypeTodo
Type is a to-do.
QString toICalString(const Incidence::Ptr &incidence)
Converts an Incidence to iCalendar formatted text.
Definition: icalformat.cpp:332
QSharedPointer< ScheduleMessage > Ptr
A shared pointer to a ScheduleMessage.
Exception base class, currently used as a fancy kind of error code and not as an C++ exception.
Definition: exceptions.h:41
void setException(Exception *error)
Sets an exception that is to be used by the functions of this class to report errors.
Definition: calformat.cpp:59
virtual bool open(QIODevice::OpenMode mode) override
QString createScheduleMessage(const IncidenceBase::Ptr &incidence, iTIPMethod method)
Creates a scheduling message string for an Incidence.
Definition: icalformat.cpp:429
bool fromString(const Calendar::Ptr &calendar, const QString &string, bool deleted, const QString &notebook) override
Definition: icalformat.cpp:141
@ LoadError
Load error.
Definition: exceptions.h:48
@ iTIPCancel
Event, to-do or journal cancellation notice.
An abstract class that provides a common base for all calendar incidence classes.
Definition: incidencebase.h:98
@ iTIPPublish
Event, to-do, journal or freebusy posting.
Represents the main calendar class.
Definition: calendar.h:132
QByteArray timeZoneId() const
Returns the timezone id string used by the iCalendar; an empty string if the iCalendar does not have ...
Definition: icalformat.cpp:678
Provides a To-do in the sense of RFC2445.
Definition: todo.h:33
@ iTIPAdd
Event, to-do or journal additional property request.
void setLoadedProductId(const QString &id)
Sets the PRODID string loaded from calendar file.
Definition: calformat.cpp:90
QSharedPointer< Incidence > Ptr
A shared pointer to an Incidence.
Definition: incidence.h:121
QVector::const_iterator cbegin() const const
bool isEmpty() const const
QByteArray toUtf8() const const
Q_SCRIPTABLE CaptureState status()
Exception * exception() const
Returns an exception, if there is any, containing information about the last error that occurred.
Definition: calformat.cpp:64
@ PublishNew
New message posting.
bool isEmpty() const const
iTIPMethod
iTIP methods.
virtual void close() override
@ iTIPRefresh
Event or to-do description update request.
@ iTIPCounter
Event or to-do submit counter proposal.
@ iTIPReply
Event, to-do or freebusy reply to request.
This class represents a recurrence rule for a calendar incidence.
@ ParseErrorKcal
Parse error in libkcal.
Definition: exceptions.h:51
iCalendar format implementation.
Definition: icalformat.h:44
QTimeZone timeZone() const
Returns the iCalendar time zone.
Definition: icalformat.cpp:672
bool flush()
bool isEmpty() const const
const char * constData() const const
ICalFormat()
Constructor a new iCalendar Format object.
Definition: icalformat.cpp:54
bool save(const Calendar::Ptr &calendar, const QString &fileName) override
Definition: icalformat.cpp:95
An abstract base class that provides an interface to various calendar formats.
Definition: calformat.h:38
ScheduleMessage::Ptr parseScheduleMessage(const Calendar::Ptr &calendar, const QString &string)
Parses a Calendar scheduling message string into ScheduleMessage object.
Definition: icalformat.cpp:509
QString fromLatin1(const char *str, int size)
@ RequestNew
Request new message posting.
Duration durationFromString(const QString &duration) const
Parses a string representation of a duration.
Definition: icalformat.cpp:417
@ ParseErrorIcal
Parse error in libical.
Definition: exceptions.h:50
@ TypeEvent
Type is an event.
int size() const const
QByteArray readAll()
@ iTIPRequest
Event, to-do or freebusy scheduling request.
void virtual_hook(int id, void *data) override
Definition: icalformat.cpp:685
QSharedPointer< X > staticCast() const const
This class provides a calendar stored in memory.
A Scheduling message class.
~ICalFormat() override
Destructor.
Definition: icalformat.cpp:59
QSharedPointer< FreeBusy > Ptr
A shared pointer to a FreeBusy object.
Definition: freebusy.h:51
QByteArray toRawString(const Incidence::Ptr &incidence)
Converts an Incidence to a QByteArray.
Definition: icalformat.cpp:346
static QString methodName(iTIPMethod method)
Returns a machine-readable (not translatable) name for a iTIP method.
@ NoCalendar
No calendar component found.
Definition: exceptions.h:52
QString message
Q_D(Todo)
Private class that helps to provide binary compatibility between releases.
char * data()
qint64 write(const char *data, qint64 maxSize)
@ RequestUpdate
Request updated message.
This class provides an Event in the sense of RFC2445.
Definition: event.h:32
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 28 2023 03:53:12 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.