• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepimlibs API Reference
  • KDE Home
  • Contact Us
 

KAlarm Library

  • sources
  • kde-4.12
  • kdepimlibs
  • kalarmcal
kacalendar.cpp
1 /*
2  * kacalendar.cpp - KAlarm kcal library calendar and event functions
3  * This file is part of kalarmcal library, which provides access to KAlarm
4  * calendar data.
5  * Copyright © 2001-2013 by David Jarvie <djarvie@kde.org>
6  *
7  * This library is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Library General Public License as published
9  * by the Free Software Foundation; either version 2 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB. If not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20  * MA 02110-1301, USA.
21  */
22 
23 #include "kacalendar.h"
24 
25 #include "kaevent.h"
26 #include "version.h"
27 
28 #ifndef KALARMCAL_USE_KRESOURCES
29 #include "collectionattribute.h"
30 
31 #include <kcalcore/event.h>
32 #include <kcalcore/alarm.h>
33 #include <kcalcore/memorycalendar.h>
34 
35 #include <kmessagebox.h>
36 #else
37 #include <kcal/event.h>
38 #include <kcal/alarm.h>
39 #include <kcal/calendarlocal.h>
40 #endif
41 
42 #include <kglobal.h>
43 #include <klocalizedstring.h>
44 #include <kdebug.h>
45 
46 #include <QMap>
47 #include <QFile>
48 #include <QFileInfo>
49 #include <QTextStream>
50 
51 #ifndef KALARMCAL_USE_KRESOURCES
52 using namespace KCalCore;
53 using Akonadi::Collection;
54 #else
55 using namespace KCal;
56 #endif
57 
58 static const KCatalogLoader loader(QLatin1String("libkalarmcal"));
59 
60 namespace KAlarmCal
61 {
62 
63 #ifndef KALARMCAL_USE_KRESOURCES
64 const QLatin1String MIME_BASE("application/x-vnd.kde.alarm");
65 const QLatin1String MIME_ACTIVE("application/x-vnd.kde.alarm.active");
66 const QLatin1String MIME_ARCHIVED("application/x-vnd.kde.alarm.archived");
67 const QLatin1String MIME_TEMPLATE("application/x-vnd.kde.alarm.template");
68 #endif
69 
70 static const QByteArray VERSION_PROPERTY("VERSION"); // X-KDE-KALARM-VERSION VCALENDAR property
71 
72 static bool isUTC(const QString& localFile);
73 
74 class Private
75 {
76  public:
77 #ifndef KALARMCAL_USE_KRESOURCES
78  static int readKAlarmVersion(const FileStorage::Ptr&, QString& subVersion, QString& versionString);
79 #else
80  static int readKAlarmVersion(CalendarLocal&, const QString& localFile, QString& subVersion, QString& versionString);
81 #endif
82 
83  static QByteArray mIcalProductId;
84 };
85 
86 QByteArray Private::mIcalProductId;
87 
88 //=============================================================================
89 
90 namespace KACalendar
91 {
92 
93 const QByteArray APPNAME("KALARM");
94 
95 void setProductId(const QByteArray& progName, const QByteArray& progVersion)
96 {
97  Private::mIcalProductId = QByteArray("-//K Desktop Environment//NONSGML " + progName + " " + progVersion + "//EN");
98 }
99 
100 QByteArray icalProductId()
101 {
102  return Private::mIcalProductId.isEmpty() ? QByteArray("-//K Desktop Environment//NONSGML //EN") : Private::mIcalProductId;
103 }
104 
105 /******************************************************************************
106 * Set the X-KDE-KALARM-VERSION property in a calendar.
107 */
108 #ifndef KALARMCAL_USE_KRESOURCES
109 void setKAlarmVersion(const Calendar::Ptr& calendar)
110 {
111  calendar->setCustomProperty(APPNAME, VERSION_PROPERTY, QString::fromLatin1(KAEvent::currentCalendarVersionString()));
112 }
113 #else
114 void setKAlarmVersion(CalendarLocal& calendar)
115 {
116  calendar.setCustomProperty(APPNAME, VERSION_PROPERTY, QString::fromLatin1(KAEvent::currentCalendarVersionString()));
117 }
118 #endif
119 
120 /******************************************************************************
121 * Check the version of KAlarm which wrote a calendar file, and convert it in
122 * memory to the current KAlarm format if possible. The storage file is not
123 * updated. The compatibility of the calendar format is indicated by the return
124 * value.
125 */
126 #ifndef KALARMCAL_USE_KRESOURCES
127 int updateVersion(const FileStorage::Ptr& fileStorage, QString& versionString)
128 #else
129 int updateVersion(CalendarLocal& calendar, const QString& localFile, QString& versionString)
130 #endif
131 {
132  QString subVersion;
133 #ifndef KALARMCAL_USE_KRESOURCES
134  int version = Private::readKAlarmVersion(fileStorage, subVersion, versionString);
135 #else
136  int version = Private::readKAlarmVersion(calendar, localFile, subVersion, versionString);
137 #endif
138  if (version == CurrentFormat)
139  return CurrentFormat; // calendar is in the current KAlarm format
140  if (version == IncompatibleFormat || version > KAEvent::currentCalendarVersion())
141  return IncompatibleFormat; // calendar was created by another program, or an unknown version of KAlarm
142 
143  // Calendar was created by an earlier version of KAlarm.
144  // Convert it to the current format.
145 #ifndef KALARMCAL_USE_KRESOURCES
146  const QString localFile = fileStorage->fileName();
147 #endif
148  int ver = version;
149  if (version == KAlarmCal::Version(0,5,7) && !localFile.isEmpty())
150  {
151  // KAlarm version 0.5.7 - check whether times are stored in UTC, in which
152  // case it is the KDE 3.0.0 version, which needs adjustment of summer times.
153  if (isUTC(localFile))
154  ver = -version;
155  kDebug() << "KAlarm version 0.5.7 (" << (ver < 0 ? "" : "non-") << "UTC)";
156  }
157  else
158  kDebug() << "KAlarm version" << version;
159 
160  // Convert events to current KAlarm format for when/if the calendar is saved
161 #ifndef KALARMCAL_USE_KRESOURCES
162  KAEvent::convertKCalEvents(fileStorage->calendar(), ver);
163 #else
164  KAEvent::convertKCalEvents(calendar, ver);
165 #endif
166  return version;
167 }
168 
169 } // namespace KACalendar
170 
171 /******************************************************************************
172 * Return the KAlarm version which wrote the calendar which has been loaded.
173 * The format is, for example, 000507 for 0.5.7.
174 * Reply = CurrentFormat if the calendar was created by the current version of KAlarm
175 * = IncompatibleFormat if it was created by KAlarm pre-0.3.5, or another program
176 * = version number if created by another KAlarm version.
177 */
178 #ifndef KALARMCAL_USE_KRESOURCES
179 int Private::readKAlarmVersion(const FileStorage::Ptr& fileStorage, QString& subVersion, QString& versionString)
180 #else
181 int Private::readKAlarmVersion(CalendarLocal& calendar, const QString& localFile, QString& subVersion, QString& versionString)
182 #endif
183 {
184  subVersion.clear();
185 #ifndef KALARMCAL_USE_KRESOURCES
186  Calendar::Ptr calendar = fileStorage->calendar();
187  versionString = calendar->customProperty(KACalendar::APPNAME, VERSION_PROPERTY);
188  kDebug() << "File=" << fileStorage->fileName() << ", version=" << versionString;
189 
190 #else
191  versionString = calendar.customProperty(KACalendar::APPNAME, VERSION_PROPERTY);
192 #endif
193 
194  if (versionString.isEmpty())
195  {
196  // Pre-KAlarm 1.4 defined the KAlarm version number in the PRODID field.
197  // If another application has written to the file, this may not be present.
198 #ifndef KALARMCAL_USE_KRESOURCES
199  const QString prodid = calendar->productId();
200 #else
201  const QString prodid = calendar.productId();
202 #endif
203  if (prodid.isEmpty())
204  {
205  // Check whether the calendar file is empty, in which case
206  // it can be written to freely.
207 #ifndef KALARMCAL_USE_KRESOURCES
208  QFileInfo fi(fileStorage->fileName());
209 #else
210  QFileInfo fi(localFile);
211 #endif
212  if (!fi.size())
213  return KACalendar::CurrentFormat;
214  }
215 
216  // Find the KAlarm identifier
217  QString progname = QLatin1String(" KAlarm ");
218  int i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
219  if (i < 0)
220  {
221  // Older versions used KAlarm's translated name in the product ID, which
222  // could have created problems using a calendar in different locales.
223  progname = QLatin1String(" ") + i18n("KAlarm") + QLatin1Char(' ');
224  i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
225  if (i < 0)
226  return KACalendar::IncompatibleFormat; // calendar wasn't created by KAlarm
227  }
228 
229  // Extract the KAlarm version string
230  versionString = prodid.mid(i + progname.length()).trimmed();
231  i = versionString.indexOf(QLatin1Char('/'));
232  int j = versionString.indexOf(QLatin1Char(' '));
233  if (j >= 0 && j < i)
234  i = j;
235  if (i <= 0)
236  return KACalendar::IncompatibleFormat; // missing version string
237  versionString = versionString.left(i); // 'versionString' now contains the KAlarm version string
238  }
239  if (versionString == QLatin1String(KAEvent::currentCalendarVersionString()))
240  return KACalendar::CurrentFormat; // the calendar is in the current KAlarm format
241  int ver = KAlarmCal::getVersionNumber(versionString, &subVersion);
242  if (ver == KAEvent::currentCalendarVersion())
243  return KACalendar::CurrentFormat; // the calendar is in the current KAlarm format
244  return KAlarmCal::getVersionNumber(versionString, &subVersion);
245 }
246 
247 /******************************************************************************
248 * Check whether the calendar file has its times stored as UTC times,
249 * indicating that it was written by the KDE 3.0.0 version of KAlarm 0.5.7.
250 * Reply = true if times are stored in UTC
251 * = false if the calendar is a vCalendar, times are not UTC, or any error occurred.
252 */
253 bool isUTC(const QString& localFile)
254 {
255  // Read the calendar file into a string
256  QFile file(localFile);
257  if (!file.open(QIODevice::ReadOnly))
258  return false;
259  QTextStream ts(&file);
260  ts.setCodec("ISO 8859-1");
261  QByteArray text = ts.readAll().toLocal8Bit();
262  file.close();
263 
264  // Extract the CREATED property for the first VEVENT from the calendar
265  const QByteArray BEGIN_VCALENDAR("BEGIN:VCALENDAR");
266  const QByteArray BEGIN_VEVENT("BEGIN:VEVENT");
267  const QByteArray CREATED("CREATED:");
268  const QList<QByteArray> lines = text.split('\n');
269  for (int i = 0, end = lines.count(); i < end; ++i)
270  {
271  if (lines[i].startsWith(BEGIN_VCALENDAR))
272  {
273  while (++i < end)
274  {
275  if (lines[i].startsWith(BEGIN_VEVENT))
276  {
277  while (++i < end)
278  {
279  if (lines[i].startsWith(CREATED))
280  return lines[i].endsWith('Z');
281  }
282  }
283  }
284  break;
285  }
286  }
287  return false;
288 }
289 
290 //=============================================================================
291 
292 namespace CalEvent
293 {
294 
295 // Struct to contain static strings, to allow use of K_GLOBAL_STATIC
296 // to delete them on program termination.
297 struct StaticStrings
298 {
299  StaticStrings()
300  : STATUS_PROPERTY("TYPE"),
301  ACTIVE_STATUS(QLatin1String("ACTIVE")),
302  TEMPLATE_STATUS(QLatin1String("TEMPLATE")),
303  ARCHIVED_STATUS(QLatin1String("ARCHIVED")),
304  DISPLAYING_STATUS(QLatin1String("DISPLAYING")),
305  ARCHIVED_UID(QLatin1String("-exp-")),
306  DISPLAYING_UID(QLatin1String("-disp-")),
307  TEMPLATE_UID(QLatin1String("-tmpl-"))
308  {}
309  // Event custom properties.
310  // Note that all custom property names are prefixed with X-KDE-KALARM- in the calendar file.
311  const QByteArray STATUS_PROPERTY; // X-KDE-KALARM-TYPE property
312  const QString ACTIVE_STATUS;
313  const QString TEMPLATE_STATUS;
314  const QString ARCHIVED_STATUS;
315  const QString DISPLAYING_STATUS;
316 
317  // Event ID identifiers
318  const QString ARCHIVED_UID;
319  const QString DISPLAYING_UID;
320 
321  // Old KAlarm format identifiers
322  const QString TEMPLATE_UID;
323 };
324 K_GLOBAL_STATIC(StaticStrings, staticStrings)
325 
326 /******************************************************************************
327 * Convert a unique ID to indicate that the event is in a specified calendar file.
328 */
329 QString uid(const QString& id, Type status)
330 {
331  QString result = id;
332  Type oldType;
333  int i, len;
334  if ((i = result.indexOf(staticStrings->ARCHIVED_UID)) > 0)
335  {
336  oldType = ARCHIVED;
337  len = staticStrings->ARCHIVED_UID.length();
338  }
339  else if ((i = result.indexOf(staticStrings->DISPLAYING_UID)) > 0)
340  {
341  oldType = DISPLAYING;
342  len = staticStrings->DISPLAYING_UID.length();
343  }
344  else
345  {
346  oldType = ACTIVE;
347  i = result.lastIndexOf(QLatin1Char('-'));
348  len = 1;
349  if (i < 0)
350  {
351  i = result.length();
352  len = 0;
353  }
354  else
355  len = 1;
356  }
357  if (status != oldType && i > 0)
358  {
359  QString part;
360  switch (status)
361  {
362  case ARCHIVED: part = staticStrings->ARCHIVED_UID; break;
363  case DISPLAYING: part = staticStrings->DISPLAYING_UID; break;
364  case ACTIVE:
365  case TEMPLATE:
366  case EMPTY:
367  default: part = QLatin1String("-"); break;
368  }
369  result.replace(i, len, part);
370  }
371  return result;
372 }
373 
374 /******************************************************************************
375 * Check an event to determine its type - active, archived, template or empty.
376 * The default type is active if it contains alarms and there is nothing to
377 * indicate otherwise.
378 * Note that the mere fact that all an event's alarms have passed does not make
379 * an event archived, since it may be that they have not yet been able to be
380 * triggered. They will be archived once KAlarm tries to handle them.
381 * Do not call this function for the displaying alarm calendar.
382 */
383 #ifndef KALARMCAL_USE_KRESOURCES
384 Type status(const Event::Ptr& event, QString* param)
385 #else
386 Type status(const Event* event, QString* param)
387 #endif
388 {
389  // Set up a static quick lookup for type strings
390  typedef QMap<QString, Type> PropertyMap;
391  static PropertyMap properties;
392  if (properties.isEmpty())
393  {
394  properties[staticStrings->ACTIVE_STATUS] = ACTIVE;
395  properties[staticStrings->TEMPLATE_STATUS] = TEMPLATE;
396  properties[staticStrings->ARCHIVED_STATUS] = ARCHIVED;
397  properties[staticStrings->DISPLAYING_STATUS] = DISPLAYING;
398  }
399 
400  if (param)
401  param->clear();
402  if (!event)
403  return EMPTY;
404  Alarm::List alarms = event->alarms();
405  if (alarms.isEmpty())
406  return EMPTY;
407 
408  const QString property = event->customProperty(KACalendar::APPNAME, staticStrings->STATUS_PROPERTY);
409  if (!property.isEmpty())
410  {
411  // There's a X-KDE-KALARM-TYPE property.
412  // It consists of the event type, plus an optional parameter.
413  PropertyMap::ConstIterator it = properties.constFind(property);
414  if (it != properties.constEnd())
415  return it.value();
416  int i = property.indexOf(QLatin1Char(';'));
417  if (i < 0)
418  return EMPTY;
419  it = properties.constFind(property.left(i));
420  if (it == properties.constEnd())
421  return EMPTY;
422  if (param)
423  *param = property.mid(i + 1);
424  return it.value();
425  }
426 
427  // The event either wasn't written by KAlarm, or was written by a pre-2.0 version.
428  // Check first for an old KAlarm format, which indicated the event type in its UID.
429  QString uid = event->uid();
430  if (uid.indexOf(staticStrings->ARCHIVED_UID) > 0)
431  return ARCHIVED;
432  if (uid.indexOf(staticStrings->TEMPLATE_UID) > 0)
433  return TEMPLATE;
434 
435  // Otherwise, assume it's an active alarm
436  return ACTIVE;
437 }
438 
439 /******************************************************************************
440 * Set the event's type - active, archived, template, etc.
441 * If a parameter is supplied, it will be appended as a second parameter to the
442 * custom property.
443 */
444 #ifndef KALARMCAL_USE_KRESOURCES
445 void setStatus(const Event::Ptr& event, Type status, const QString& param)
446 #else
447 void setStatus(Event* event, Type status, const QString& param)
448 #endif
449 {
450  if (!event)
451  return;
452  QString text;
453  switch (status)
454  {
455  case ACTIVE: text = staticStrings->ACTIVE_STATUS; break;
456  case TEMPLATE: text = staticStrings->TEMPLATE_STATUS; break;
457  case ARCHIVED: text = staticStrings->ARCHIVED_STATUS; break;
458  case DISPLAYING: text = staticStrings->DISPLAYING_STATUS; break;
459  default:
460  event->removeCustomProperty(KACalendar::APPNAME, staticStrings->STATUS_PROPERTY);
461  return;
462  }
463  if (!param.isEmpty())
464  text += QLatin1Char(';') + param;
465  event->setCustomProperty(KACalendar::APPNAME, staticStrings->STATUS_PROPERTY, text);
466 }
467 
468 #ifndef KALARMCAL_USE_KRESOURCES
469 Type type(const QString& mimeType)
470 {
471  if (mimeType == MIME_ACTIVE)
472  return ACTIVE;
473  if (mimeType == MIME_ARCHIVED)
474  return ARCHIVED;
475  if (mimeType == MIME_TEMPLATE)
476  return TEMPLATE;
477  return EMPTY;
478 }
479 
480 Types types(const QStringList& mimeTypes)
481 {
482  Types types = 0;
483  foreach (const QString& type, mimeTypes)
484  {
485  if (type == MIME_ACTIVE)
486  types |= ACTIVE;
487  if (type == MIME_ARCHIVED)
488  types |= ARCHIVED;
489  if (type == MIME_TEMPLATE)
490  types |= TEMPLATE;
491  }
492  return types;
493 }
494 
495 QString mimeType(Type type)
496 {
497  switch (type)
498  {
499  case ACTIVE: return MIME_ACTIVE;
500  case ARCHIVED: return MIME_ARCHIVED;
501  case TEMPLATE: return MIME_TEMPLATE;
502  default: return QString();
503  }
504 }
505 
506 QStringList mimeTypes(Types types)
507 {
508  QStringList mimes;
509  for (int i = 1; types; i <<= 1)
510  {
511  if (types & i)
512  {
513  mimes += mimeType(Type(i));
514  types &= ~i;
515  }
516  }
517  return mimes;
518 }
519 #endif
520 
521 } // namespace CalEvent
522 
523 } // namespace KAlarmCal
524 
525 // vim: et sw=4:
KAlarmCal::CalEvent::type
Type type(const QString &mimeType)
Return the alarm Type for a mime type string.
Definition: kacalendar.cpp:469
KAlarmCal::KACalendar::updateVersion
int updateVersion(const FileStorage::Ptr &fileStorage, QString &versionString)
Check the version of KAlarm which wrote a calendar file, and convert it in memory to the current KAla...
Definition: kacalendar.cpp:127
KAlarmCal::CalEvent::TEMPLATE
the event is an alarm template
Definition: kacalendar.h:160
memorycalendar.h
KCalCore::Event::Ptr
QSharedPointer< Event > Ptr
Akonadi::Collection
KAlarmCal::KACalendar::IncompatibleFormat
not written by KAlarm, or a newer KAlarm version
Definition: kacalendar.h:101
KCalCore::Alarm::List
QVector< Ptr > List
KAlarmCal::KACalendar::icalProductId
QByteArray icalProductId()
Return the product ID string for use in calendars.
Definition: kacalendar.cpp:100
KAlarmCal::CalEvent::Type
Type
The category of an event, indicated by the middle part of its UID.
Definition: kacalendar.h:155
KAlarmCal::KACalendar::APPNAME
const QByteArray APPNAME
The application name ("KALARM") used in calendar properties.
KAlarmCal::CalEvent::DISPLAYING
the event is currently being displayed
Definition: kacalendar.h:161
KAlarmCal::CalEvent::ACTIVE
the event is currently active
Definition: kacalendar.h:158
KAlarmCal::KACalendar::setKAlarmVersion
void setKAlarmVersion(const Calendar::Ptr &calendar)
Set the KAlarm version custom property for a calendar.
Definition: kacalendar.cpp:109
KCalCore::FileStorage::Ptr
QSharedPointer< FileStorage > Ptr
KAlarmCal::CalEvent::mimeTypes
QStringList mimeTypes(Types types)
Return the mime type strings corresponding to alarm Types.
Definition: kacalendar.cpp:506
KCalCore::Calendar::Ptr
QSharedPointer< Calendar > Ptr
alarm.h
KAlarmCal::CalEvent::EMPTY
the event has no alarms
Definition: kacalendar.h:157
event.h
KCalCore::Event
KAlarmCal::KACalendar::CurrentFormat
current KAlarm format
Definition: kacalendar.h:97
KAlarmCal::CalEvent::mimeType
QString mimeType(Type type)
Return the mime type string corresponding to an alarm Type.
Definition: kacalendar.cpp:495
KAlarmCal::CalEvent::ARCHIVED
the event is archived
Definition: kacalendar.h:159
KAlarmCal::KACalendar::setProductId
void setProductId(const QByteArray &progName, const QByteArray &progVersion)
Set the program name and version for use in calendars.
Definition: kacalendar.cpp:95
KAlarmCal::CalEvent::types
Types types(const QStringList &mimeTypes)
Return the alarm Types for a list of mime type strings.
Definition: kacalendar.cpp:480
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:01:14 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KAlarm Library

Skip menu "KAlarm Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal