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

KDE's Doxygen guidelines are available online.