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

KAlarm Library

kacalendar.cpp
00001 /*
00002  *  kacalendar.cpp  -  KAlarm kcal library calendar and event functions
00003  *  This file is part of kalarmcal library, which provides access to KAlarm
00004  *  calendar data.
00005  *  Copyright © 2001-2012 by David Jarvie <djarvie@kde.org>
00006  *
00007  *  This library is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU Library General Public License as published
00009  *  by the Free Software Foundation; either version 2 of the License, or (at
00010  *  your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful, but WITHOUT
00013  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00015  *  License for more details.
00016  *
00017  *  You should have received a copy of the GNU Library General Public License
00018  *  along with this library; see the file COPYING.LIB.  If not, write to the
00019  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00020  *  MA 02110-1301, USA.
00021  */
00022 
00023 #include "kacalendar.h"
00024 
00025 #include "kaevent.h"
00026 #include "version.h"
00027 
00028 #ifndef KALARMCAL_USE_KRESOURCES
00029 #include "collectionattribute.h"
00030 
00031 #include <kcalcore/event.h>
00032 #include <kcalcore/alarm.h>
00033 #include <kcalcore/memorycalendar.h>
00034 
00035 #include <kmessagebox.h>
00036 #else
00037 #include <kcal/event.h>
00038 #include <kcal/alarm.h>
00039 #include <kcal/calendarlocal.h>
00040 #endif
00041 
00042 #include <kglobal.h>
00043 #include <klocale.h>
00044 #include <kdebug.h>
00045 
00046 #include <QMap>
00047 #include <QFile>
00048 #include <QFileInfo>
00049 #include <QTextStream>
00050 
00051 #ifndef KALARMCAL_USE_KRESOURCES
00052 using namespace KCalCore;
00053 using Akonadi::Collection;
00054 #else
00055 using namespace KCal;
00056 #endif
00057 
00058 
00059 static const KCatalogLoader loader("libkalarmcal");
00060 
00061 namespace KAlarmCal
00062 {
00063 
00064 #ifndef KALARMCAL_USE_KRESOURCES
00065 const QLatin1String MIME_BASE("application/x-vnd.kde.alarm");
00066 const QLatin1String MIME_ACTIVE("application/x-vnd.kde.alarm.active");
00067 const QLatin1String MIME_ARCHIVED("application/x-vnd.kde.alarm.archived");
00068 const QLatin1String MIME_TEMPLATE("application/x-vnd.kde.alarm.template");
00069 #endif
00070 
00071 static const QByteArray VERSION_PROPERTY("VERSION");     // X-KDE-KALARM-VERSION VCALENDAR property
00072 
00073 static bool isUTC(const QString& localFile);
00074 
00075 
00076 class Private
00077 {
00078     public:
00079 #ifndef KALARMCAL_USE_KRESOURCES
00080         static int  readKAlarmVersion(const FileStorage::Ptr&, QString& subVersion, QString& versionString);
00081 #else
00082         static int  readKAlarmVersion(CalendarLocal&, const QString& localFile, QString& subVersion, QString& versionString);
00083 #endif
00084 
00085         static QByteArray mIcalProductId;
00086 };
00087 
00088 QByteArray Private::mIcalProductId;
00089 
00090 
00091 namespace KACalendar
00092 {
00093 
00094 const QByteArray APPNAME("KALARM");
00095 
00096 void setProductId(const QByteArray& progName, const QByteArray& progVersion)
00097 {
00098     Private::mIcalProductId = QByteArray("-//K Desktop Environment//NONSGML " + progName + " " + progVersion + "//EN");
00099 }
00100 
00101 QByteArray icalProductId()
00102 {
00103     return Private::mIcalProductId.isEmpty() ? QByteArray("-//K Desktop Environment//NONSGML  //EN") : Private::mIcalProductId;
00104 }
00105 
00106 /******************************************************************************
00107 * Set the X-KDE-KALARM-VERSION property in a calendar.
00108 */
00109 #ifndef KALARMCAL_USE_KRESOURCES
00110 void setKAlarmVersion(const Calendar::Ptr& calendar)
00111 {
00112     calendar->setCustomProperty(APPNAME, VERSION_PROPERTY, QString::fromLatin1(KAEvent::currentCalendarVersionString()));
00113 }
00114 #else
00115 void setKAlarmVersion(CalendarLocal& calendar)
00116 {
00117     calendar.setCustomProperty(APPNAME, VERSION_PROPERTY, QString::fromLatin1(KAEvent::currentCalendarVersionString()));
00118 }
00119 #endif
00120 
00121 /******************************************************************************
00122 * Check the version of KAlarm which wrote a calendar file, and convert it in
00123 * memory to the current KAlarm format if possible. The storage file is not
00124 * updated. The compatibility of the calendar format is indicated by the return
00125 * value.
00126 */
00127 #ifndef KALARMCAL_USE_KRESOURCES
00128 int updateVersion(const FileStorage::Ptr& fileStorage, QString& versionString)
00129 #else
00130 int updateVersion(CalendarLocal& calendar, const QString& localFile, QString& versionString)
00131 #endif
00132 {
00133     QString subVersion;
00134 #ifndef KALARMCAL_USE_KRESOURCES
00135     int version = Private::readKAlarmVersion(fileStorage, subVersion, versionString);
00136 #else
00137     int version = Private::readKAlarmVersion(calendar, localFile, subVersion, versionString);
00138 #endif
00139     if (version == CurrentFormat)
00140         return CurrentFormat;       // calendar is in the current KAlarm format
00141     if (version == IncompatibleFormat  ||  version > KAEvent::currentCalendarVersion())
00142         return IncompatibleFormat;  // calendar was created by another program, or an unknown version of KAlarm
00143 
00144     // Calendar was created by an earlier version of KAlarm.
00145     // Convert it to the current format.
00146 #ifndef KALARMCAL_USE_KRESOURCES
00147     const QString localFile = fileStorage->fileName();
00148 #endif
00149     int ver = version;
00150     if (version == KAlarmCal::Version(0,5,7)  &&  !localFile.isEmpty())
00151     {
00152         // KAlarm version 0.5.7 - check whether times are stored in UTC, in which
00153         // case it is the KDE 3.0.0 version, which needs adjustment of summer times.
00154         if (isUTC(localFile))
00155             ver = -version;
00156         kDebug() << "KAlarm version 0.5.7 (" << (ver < 0 ? "" : "non-") << "UTC)";
00157     }
00158     else
00159         kDebug() << "KAlarm version" << version;
00160 
00161     // Convert events to current KAlarm format for when/if the calendar is saved
00162 #ifndef KALARMCAL_USE_KRESOURCES
00163     KAEvent::convertKCalEvents(fileStorage->calendar(), ver);
00164 #else
00165     KAEvent::convertKCalEvents(calendar, ver);
00166 #endif
00167     return version;
00168 }
00169 
00170 } // namespace KACalendar
00171 
00172 /******************************************************************************
00173 * Return the KAlarm version which wrote the calendar which has been loaded.
00174 * The format is, for example, 000507 for 0.5.7.
00175 * Reply = CurrentFormat if the calendar was created by the current version of KAlarm
00176 *       = IncompatibleFormat if it was created by KAlarm pre-0.3.5, or another program
00177 *       = version number if created by another KAlarm version.
00178 */
00179 #ifndef KALARMCAL_USE_KRESOURCES
00180 int Private::readKAlarmVersion(const FileStorage::Ptr& fileStorage, QString& subVersion, QString& versionString)
00181 #else
00182 int Private::readKAlarmVersion(CalendarLocal& calendar, const QString& localFile, QString& subVersion, QString& versionString)
00183 #endif
00184 {
00185     subVersion.clear();
00186 #ifndef KALARMCAL_USE_KRESOURCES
00187     Calendar::Ptr calendar = fileStorage->calendar();
00188     versionString = calendar->customProperty(KACalendar::APPNAME, VERSION_PROPERTY);
00189     kDebug() << "File=" << fileStorage->fileName() << ", version=" << versionString;
00190 
00191 #else
00192     versionString = calendar.customProperty(KACalendar::APPNAME, VERSION_PROPERTY);
00193 #endif
00194 
00195     if (versionString.isEmpty())
00196     {
00197         // Pre-KAlarm 1.4 defined the KAlarm version number in the PRODID field.
00198         // If another application has written to the file, this may not be present.
00199 #ifndef KALARMCAL_USE_KRESOURCES
00200         const QString prodid = calendar->productId();
00201 #else
00202         const QString prodid = calendar.productId();
00203 #endif
00204         if (prodid.isEmpty())
00205         {
00206             // Check whether the calendar file is empty, in which case
00207             // it can be written to freely.
00208 #ifndef KALARMCAL_USE_KRESOURCES
00209             QFileInfo fi(fileStorage->fileName());
00210 #else
00211             QFileInfo fi(localFile);
00212 #endif
00213             if (!fi.size())
00214                 return KACalendar::CurrentFormat;
00215         }
00216 
00217         // Find the KAlarm identifier
00218         QString progname = QLatin1String(" KAlarm ");
00219         int i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
00220         if (i < 0)
00221         {
00222             // Older versions used KAlarm's translated name in the product ID, which
00223             // could have created problems using a calendar in different locales.
00224             progname = QString(" ") + i18n("KAlarm") + ' ';
00225             i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
00226             if (i < 0)
00227                 return KACalendar::IncompatibleFormat;    // calendar wasn't created by KAlarm
00228         }
00229 
00230         // Extract the KAlarm version string
00231         versionString = prodid.mid(i + progname.length()).trimmed();
00232         i = versionString.indexOf('/');
00233         int j = versionString.indexOf(' ');
00234         if (j >= 0  &&  j < i)
00235             i = j;
00236         if (i <= 0)
00237             return KACalendar::IncompatibleFormat;    // missing version string
00238         versionString = versionString.left(i);   // 'versionString' now contains the KAlarm version string
00239     }
00240     if (versionString == KAEvent::currentCalendarVersionString())
00241         return KACalendar::CurrentFormat;      // the calendar is in the current KAlarm format
00242     int ver = KAlarmCal::getVersionNumber(versionString, &subVersion);
00243     if (ver == KAEvent::currentCalendarVersion())
00244         return KACalendar::CurrentFormat;      // the calendar is in the current KAlarm format
00245     return KAlarmCal::getVersionNumber(versionString, &subVersion);
00246 }
00247 
00248 /******************************************************************************
00249 * Check whether the calendar file has its times stored as UTC times,
00250 * indicating that it was written by the KDE 3.0.0 version of KAlarm 0.5.7.
00251 * Reply = true if times are stored in UTC
00252 *       = false if the calendar is a vCalendar, times are not UTC, or any error occurred.
00253 */
00254 bool isUTC(const QString& localFile)
00255 {
00256     // Read the calendar file into a string
00257     QFile file(localFile);
00258     if (!file.open(QIODevice::ReadOnly))
00259         return false;
00260     QTextStream ts(&file);
00261     ts.setCodec("ISO 8859-1");
00262     QByteArray text = ts.readAll().toLocal8Bit();
00263     file.close();
00264 
00265     // Extract the CREATED property for the first VEVENT from the calendar
00266     const QByteArray BEGIN_VCALENDAR("BEGIN:VCALENDAR");
00267     const QByteArray BEGIN_VEVENT("BEGIN:VEVENT");
00268     const QByteArray CREATED("CREATED:");
00269     QList<QByteArray> lines = text.split('\n');
00270     for (int i = 0, end = lines.count();  i < end;  ++i)
00271     {
00272         if (lines[i].startsWith(BEGIN_VCALENDAR))
00273         {
00274             while (++i < end)
00275             {
00276                 if (lines[i].startsWith(BEGIN_VEVENT))
00277                 {
00278                     while (++i < end)
00279                     {
00280                         if (lines[i].startsWith(CREATED))
00281                             return lines[i].endsWith('Z');
00282                     }
00283                 }
00284             }
00285             break;
00286         }
00287     }
00288     return false;
00289 }
00290 
00291 
00292 namespace CalEvent
00293 {
00294 
00295 // Struct to contain static strings, to allow use of K_GLOBAL_STATIC
00296 // to delete them on program termination.
00297 struct StaticStrings
00298 {
00299     StaticStrings()
00300         : STATUS_PROPERTY("TYPE"),
00301           ACTIVE_STATUS(QLatin1String("ACTIVE")),
00302           TEMPLATE_STATUS(QLatin1String("TEMPLATE")),
00303           ARCHIVED_STATUS(QLatin1String("ARCHIVED")),
00304           DISPLAYING_STATUS(QLatin1String("DISPLAYING")),
00305           ARCHIVED_UID(QLatin1String("-exp-")),
00306           DISPLAYING_UID(QLatin1String("-disp-")),
00307           TEMPLATE_UID(QLatin1String("-tmpl-"))
00308     {}
00309     // Event custom properties.
00310     // Note that all custom property names are prefixed with X-KDE-KALARM- in the calendar file.
00311     const QByteArray STATUS_PROPERTY;    // X-KDE-KALARM-TYPE property
00312     const QString ACTIVE_STATUS;
00313     const QString TEMPLATE_STATUS;
00314     const QString ARCHIVED_STATUS;
00315     const QString DISPLAYING_STATUS;
00316 
00317     // Event ID identifiers
00318     const QString ARCHIVED_UID;
00319     const QString DISPLAYING_UID;
00320 
00321     // Old KAlarm format identifiers
00322     const QString TEMPLATE_UID;
00323 };
00324 K_GLOBAL_STATIC(StaticStrings, staticStrings)
00325 
00326 /******************************************************************************
00327 * Convert a unique ID to indicate that the event is in a specified calendar file.
00328 */
00329 QString uid(const QString& id, Type status)
00330 {
00331     QString result = id;
00332     Type oldType;
00333     int i, len;
00334     if ((i = result.indexOf(staticStrings->ARCHIVED_UID)) > 0)
00335     {
00336         oldType = ARCHIVED;
00337         len = staticStrings->ARCHIVED_UID.length();
00338     }
00339     else if ((i = result.indexOf(staticStrings->DISPLAYING_UID)) > 0)
00340     {
00341         oldType = DISPLAYING;
00342         len = staticStrings->DISPLAYING_UID.length();
00343     }
00344     else
00345     {
00346         oldType = ACTIVE;
00347         i = result.lastIndexOf('-');
00348         len = 1;
00349         if (i < 0)
00350         {
00351             i = result.length();
00352             len = 0;
00353         }
00354         else
00355             len = 1;
00356     }
00357     if (status != oldType  &&  i > 0)
00358     {
00359         QString part;
00360         switch (status)
00361         {
00362             case ARCHIVED:    part = staticStrings->ARCHIVED_UID;  break;
00363             case DISPLAYING:  part = staticStrings->DISPLAYING_UID;  break;
00364             case ACTIVE:
00365             case TEMPLATE:
00366             case EMPTY:
00367             default:          part = QLatin1String("-");  break;
00368         }
00369         result.replace(i, len, part);
00370     }
00371     return result;
00372 }
00373 
00374 /******************************************************************************
00375 * Check an event to determine its type - active, archived, template or empty.
00376 * The default type is active if it contains alarms and there is nothing to
00377 * indicate otherwise.
00378 * Note that the mere fact that all an event's alarms have passed does not make
00379 * an event archived, since it may be that they have not yet been able to be
00380 * triggered. They will be archived once KAlarm tries to handle them.
00381 * Do not call this function for the displaying alarm calendar.
00382 */
00383 #ifndef KALARMCAL_USE_KRESOURCES
00384 Type status(const Event::Ptr& event, QString* param)
00385 #else
00386 Type status(const Event* event, QString* param)
00387 #endif
00388 {
00389     // Set up a static quick lookup for type strings
00390     typedef QMap<QString, Type> PropertyMap;
00391     static PropertyMap properties;
00392     if (properties.isEmpty())
00393     {
00394         properties[staticStrings->ACTIVE_STATUS]     = ACTIVE;
00395         properties[staticStrings->TEMPLATE_STATUS]   = TEMPLATE;
00396         properties[staticStrings->ARCHIVED_STATUS]   = ARCHIVED;
00397         properties[staticStrings->DISPLAYING_STATUS] = DISPLAYING;
00398     }
00399 
00400     if (param)
00401         param->clear();
00402     if (!event)
00403         return EMPTY;
00404     Alarm::List alarms = event->alarms();
00405     if (alarms.isEmpty())
00406         return EMPTY;
00407 
00408     const QString property = event->customProperty(KACalendar::APPNAME, staticStrings->STATUS_PROPERTY);
00409     if (!property.isEmpty())
00410     {
00411         // There's a X-KDE-KALARM-TYPE property.
00412         // It consists of the event type, plus an optional parameter.
00413         PropertyMap::ConstIterator it = properties.constFind(property);
00414         if (it != properties.constEnd())
00415             return it.value();
00416         int i = property.indexOf(';');
00417         if (i < 0)
00418             return EMPTY;
00419         it = properties.constFind(property.left(i));
00420         if (it == properties.constEnd())
00421             return EMPTY;
00422         if (param)
00423             *param = property.mid(i + 1);
00424         return it.value();
00425     }
00426 
00427     // The event either wasn't written by KAlarm, or was written by a pre-2.0 version.
00428     // Check first for an old KAlarm format, which indicated the event type in its UID.
00429     QString uid = event->uid();
00430     if (uid.indexOf(staticStrings->ARCHIVED_UID) > 0)
00431         return ARCHIVED;
00432     if (uid.indexOf(staticStrings->TEMPLATE_UID) > 0)
00433         return TEMPLATE;
00434 
00435     // Otherwise, assume it's an active alarm
00436     return ACTIVE;
00437 }
00438 
00439 /******************************************************************************
00440 * Set the event's type - active, archived, template, etc.
00441 * If a parameter is supplied, it will be appended as a second parameter to the
00442 * custom property.
00443 */
00444 #ifndef KALARMCAL_USE_KRESOURCES
00445 void setStatus(const Event::Ptr& event, Type status, const QString& param)
00446 #else
00447 void setStatus(Event* event, Type status, const QString& param)
00448 #endif
00449 {
00450     if (!event)
00451         return;
00452     QString text;
00453     switch (status)
00454     {
00455         case ACTIVE:      text = staticStrings->ACTIVE_STATUS;  break;
00456         case TEMPLATE:    text = staticStrings->TEMPLATE_STATUS;  break;
00457         case ARCHIVED:    text = staticStrings->ARCHIVED_STATUS;  break;
00458         case DISPLAYING:  text = staticStrings->DISPLAYING_STATUS;  break;
00459         default:
00460             event->removeCustomProperty(KACalendar::APPNAME, staticStrings->STATUS_PROPERTY);
00461             return;
00462     }
00463     if (!param.isEmpty())
00464         text += ';' + param;
00465     event->setCustomProperty(KACalendar::APPNAME, staticStrings->STATUS_PROPERTY, text);
00466 }
00467 
00468 #ifndef KALARMCAL_USE_KRESOURCES
00469 Type type(const QString& mimeType)
00470 {
00471     if (mimeType == MIME_ACTIVE)
00472         return ACTIVE;
00473     if (mimeType == MIME_ARCHIVED)
00474         return ARCHIVED;
00475     if (mimeType == MIME_TEMPLATE)
00476         return TEMPLATE;
00477     return EMPTY;
00478 }
00479 
00480 Types types(const QStringList& mimeTypes)
00481 {
00482     Types types = 0;
00483     foreach (const QString& type, mimeTypes)
00484     {
00485         if (type == MIME_ACTIVE)
00486             types |= ACTIVE;
00487         if (type == MIME_ARCHIVED)
00488             types |= ARCHIVED;
00489         if (type == MIME_TEMPLATE)
00490             types |= TEMPLATE;
00491     }
00492     return types;
00493 }
00494 
00495 QString mimeType(Type type)
00496 {
00497     switch (type)
00498     {
00499         case ACTIVE:    return MIME_ACTIVE;
00500         case ARCHIVED:  return MIME_ARCHIVED;
00501         case TEMPLATE:  return MIME_TEMPLATE;
00502         default:        return QString();
00503     }
00504 }
00505 
00506 QStringList mimeTypes(Types types)
00507 {
00508     QStringList mimes;
00509     for (int i = 1;  types;  i <<= 1)
00510     {
00511         if (types & i)
00512         {
00513             mimes += mimeType(Type(i));
00514             types &= ~i;
00515         }
00516     }
00517     return mimes;
00518 }
00519 #endif
00520 
00521 } // namespace CalEvent
00522 
00523 } // namespace KAlarmCal
00524 
00525 // vim: et sw=4:
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:11:40 by doxygen 1.8.0 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-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
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