Commit 1ba2357f authored by David Jarvie's avatar David Jarvie

Refactor detection of calendar format version, to make the function available to

Akonadi resource.

svn path=/trunk/KDE/kdepim/; revision=1134156
parent a45baa7a
......@@ -78,7 +78,8 @@ bool AlarmCalendar::initialiseCalendars()
resources->showProgress(true);
mResourcesCalendar = new AlarmCalendar();
mDisplayCalendar = new AlarmCalendar(displayCal, KCalEvent::DISPLAYING);
CalFormat::setApplication(QLatin1String(KALARM_NAME), QString::fromLatin1(KAEvent::icalProductId()));
KCalendar::setProductId(KALARM_NAME, KALARM_VERSION);
CalFormat::setApplication(QLatin1String(KALARM_NAME), QString::fromLatin1(KCalendar::icalProductId()));
return true;
}
......
......@@ -6,6 +6,7 @@ set(kalarm_calendar_LIB_SRCS
identities.cpp
kaevent.cpp
datetime.cpp
version.cpp
)
kde4_add_library(kalarm_calendar SHARED ${kalarm_calendar_LIB_SRCS})
......
......@@ -18,7 +18,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
#include "alarmtext.h"
#include "kaevent.h"
......
/*
* datetime.cpp - date/time with start-of-day time for date-only values
* Program: kalarm
* Copyright © 2003,2005-2007,2009 by David Jarvie <djarvie@kde.org>
* Copyright © 2003,2005-2007,2009,2010 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -17,7 +17,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
#include "datetime.h"
#include <kglobal.h>
......
......@@ -18,12 +18,12 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
#include "kaevent.h"
#include "alarmresource.h"
#include "alarmtext.h"
#include "identities.h"
#include "version.h"
#include <kcal/calendarlocal.h>
#include <kholidays/holidays.h>
......@@ -45,11 +45,6 @@ using namespace KHolidays;
QByteArray KAEvent::currentCalendarVersionString() { return QByteArray("2.2.9"); }
int KAEvent::currentCalendarVersion() { return KAlarm::Version(2,2,9); }
QByteArray KAEvent::icalProductId()
{
return QByteArray("-//K Desktop Environment//NONSGML " KALARM_NAME " " KALARM_VERSION "//EN");
}
// Custom calendar properties.
// Note that all custom property names are prefixed with X-KDE-KALARM- in the calendar file.
......
......@@ -469,7 +469,6 @@ class KALARM_CAL_EXPORT KAEvent
#else
void dumpDebug() const { d->dumpDebug(); }
#endif
static QByteArray icalProductId();
static int currentCalendarVersion();
static QByteArray currentCalendarVersionString();
static bool convertKCalEvents(KCal::CalendarLocal&, int calendarVersion, bool adjustSummerTime);
......
/*
* karecurrence.cpp - recurrence with special yearly February 29th handling
* Program: kalarm
* Copyright © 2005-2009 by David Jarvie <djarvie@kde.org>
* Copyright © 2005-2010 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,7 +18,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
#include "karecurrence.h"
#include "datetime.h"
......
/*
* kcalendar.cpp - kcal library calendar and event functions
* Program: kalarm
* Copyright © 2006,2007,2009 by David Jarvie <djarvie@kde.org>
* Copyright © 2001-2010 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,22 +18,198 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kalarm.h" //krazy:exclude=includes (kalarm.h must be first)
#include "kcalendar.h"
#include "kaevent.h"
#include "version.h"
#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>
#include <kcal/event.h>
#include <kcal/alarm.h>
#include <kcal/calendarlocal.h>
#include <QMap>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
QByteArray KCalendar::APPNAME = "KALARM";
static const QByteArray VERSION_PROPERTY("VERSION"); // X-KDE-KALARM-VERSION VCALENDAR property
using namespace KCal;
static bool isUTC(const QString& localFile);
/*=============================================================================
* Class: KCalendar
*============================================================================*/
QByteArray KCalendar::mIcalProductId;
bool KCalendar::mHaveKAlarmCatalog = false;
void KCalendar::setProductId(const QByteArray& progName, const QByteArray& progVersion)
{
mIcalProductId = QByteArray("-//K Desktop Environment//NONSGML " + progName + " " + progVersion + "//EN");
}
QByteArray KCalendar::icalProductId()
{
return mIcalProductId.isEmpty() ? QByteArray("-//K Desktop Environment//NONSGML //EN") : mIcalProductId;
}
/******************************************************************************
* Check the version of KAlarm which wrote a calendar file, and convert it in
* memory to the current KAlarm format if possible. The storage file is not
* updated. The compability of the calendar format is indicated by the return
* value.
*/
int KCalendar::checkCompatibility(CalendarLocal& calendar, const QString& localFile, QString& versionString)
{
bool version057_UTC = false;
QString subVersion;
int version = readKAlarmVersion(calendar, localFile, subVersion, versionString);
if (!version)
return 0; // calendar is in the current KAlarm format
if (version < 0 || version > KAEvent::currentCalendarVersion())
return -1; // calendar was created by another program, or an unknown version of KAlarm
// Calendar was created by an earlier version of KAlarm.
// Convert it to the current format.
if (version == KAlarm::Version(0,5,7) && !localFile.isEmpty())
{
// KAlarm version 0.5.7 - check whether times are stored in UTC, in which
// case it is the KDE 3.0.0 version, which needs adjustment of summer times.
version057_UTC = isUTC(localFile);
kDebug() << "KAlarm version 0.5.7 (" << (version057_UTC ?"" :"non-") << "UTC)";
}
else
kDebug() << "KAlarm version" << version;
// Convert events to current KAlarm format for when/if the calendar is saved
KAEvent::convertKCalEvents(calendar, version, version057_UTC);
return version;
}
/******************************************************************************
* Return the KAlarm version which wrote the calendar which has been loaded.
* The format is, for example, 000507 for 0.5.7.
* Reply = 0 if the calendar was created by the current version of KAlarm
* = -1 if it was created by KAlarm pre-0.3.5, or another program
* = version number if created by another KAlarm version.
*/
int KCalendar::readKAlarmVersion(CalendarLocal& calendar, const QString& localFile, QString& subVersion, QString& versionString)
{
subVersion.clear();
versionString = calendar.customProperty(APPNAME, VERSION_PROPERTY);
if (versionString.isEmpty())
{
// Pre-KAlarm 1.4 defined the KAlarm version number in the PRODID field.
// If another application has written to the file, this may not be present.
const QString prodid = calendar.productId();
if (prodid.isEmpty())
{
// Check whether the calendar file is empty, in which case
// it can be written to freely.
QFileInfo fi(localFile);
if (!fi.size())
return 0;
}
// Find the KAlarm identifier
QString progname = QLatin1String(" KAlarm ");
int i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
if (i < 0)
{
// Older versions used KAlarm's translated name in the product ID, which
// could have created problems using a calendar in different locales.
insertKAlarmCatalog();
progname = QString(" ") + i18n("KAlarm") + ' ';
i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
if (i < 0)
return -1; // calendar wasn't created by KAlarm
}
// Extract the KAlarm version string
versionString = prodid.mid(i + progname.length()).trimmed();
i = versionString.indexOf('/');
int j = versionString.indexOf(' ');
if (j >= 0 && j < i)
i = j;
if (i <= 0)
return -1; // missing version string
versionString = versionString.left(i); // 'versionString' now contains the KAlarm version string
}
if (versionString == KAEvent::currentCalendarVersionString())
return 0; // the calendar is in the current KAlarm format
int ver = KAlarm::getVersionNumber(versionString, &subVersion);
if (ver == KAEvent::currentCalendarVersion())
return 0; // the calendar is in the current KAlarm format
return KAlarm::getVersionNumber(versionString, &subVersion);
}
/******************************************************************************
* Access the KAlarm message translation catalog.
*/
void KCalendar::insertKAlarmCatalog()
{
if (!mHaveKAlarmCatalog)
{
KGlobal::locale()->insertCatalog("kalarm");
mHaveKAlarmCatalog = true;
}
}
/******************************************************************************
* Check whether the calendar file has its times stored as UTC times,
* indicating that it was written by the KDE 3.0.0 version of KAlarm 0.5.7.
* Reply = true if times are stored in UTC
* = false if the calendar is a vCalendar, times are not UTC, or any error occurred.
*/
bool isUTC(const QString& localFile)
{
// Read the calendar file into a string
QFile file(localFile);
if (!file.open(QIODevice::ReadOnly))
return false;
QTextStream ts(&file);
ts.setCodec("ISO 8859-1");
QByteArray text = ts.readAll().toLocal8Bit();
file.close();
// Extract the CREATED property for the first VEVENT from the calendar
const QByteArray BEGIN_VCALENDAR("BEGIN:VCALENDAR");
const QByteArray BEGIN_VEVENT("BEGIN:VEVENT");
const QByteArray CREATED("CREATED:");
QList<QByteArray> lines = text.split('\n');
for (int i = 0, end = lines.count(); i < end; ++i)
{
if (lines[i].startsWith(BEGIN_VCALENDAR))
{
while (++i < end)
{
if (lines[i].startsWith(BEGIN_VEVENT))
{
while (++i < end)
{
if (lines[i].startsWith(CREATED))
return lines[i].endsWith('Z');
}
}
}
break;
}
}
return false;
}
/*=============================================================================
* Class: KCalEvent
*============================================================================*/
// Struct to contain static strings, to allow use of K_GLOBAL_STATIC
// to delete them on program termination.
struct StaticStrings
......@@ -200,3 +376,5 @@ void KCalEvent::setStatus(KCal::Event* event, KCalEvent::Status status, const QS
text += ';' + param;
event->setCustomProperty(KCalendar::APPNAME, staticStrings->STATUS_PROPERTY, text);
}
// vim: et sw=4:
/*
* kcalendar.h - kcal library calendar and event categorisation
* Program: kalarm
* Copyright © 2006,2007,2010 by David Jarvie <djarvie@kde.org>
* Copyright © 2005-2008,2010 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -22,11 +22,13 @@
#define KCALENDAR_H
#include "kalarm_cal_export.h"
#include <QByteArray>
#include <QString>
namespace KCal {
class Event;
class Alarm;
class CalendarLocal;
}
class KALARM_CAL_EXPORT KCalendar
......@@ -42,6 +44,35 @@ class KALARM_CAL_EXPORT KCalendar
Incompatible, // not written by KAlarm, or in a newer KAlarm version
ByEvent // individual events have their own compatibility status
};
/** Check the version of KAlarm which wrote a calendar file, and convert
* it in memory to the current KAlarm format if possible. The storage
* file is not updated. The compability of the calendar format is
* indicated by the return value.
*
* @param calendar calendar stored in @p localFile
* @param localFile full path of the calendar's file storage
* @param versionString receives calendar's KAlarm version as a string
* @return 0 if the calendar is in the current KAlarm format;
* >0 the older KAlarm version which wrote the calendar;
* -1 calendar is not a KAlarm format or is an unknown KAlarm format
*/
static int checkCompatibility(KCal::CalendarLocal& calendar, const QString& localFile, QString& versionString);
/** Set the program name and version for use in calendars. */
static void setProductId(const QByteArray& progName, const QByteArray& progVersion);
/** Return the product ID string for use in calendars.
* setProductId() must have been called previously.
*/
static QByteArray icalProductId();
private:
static int readKAlarmVersion(KCal::CalendarLocal&, const QString& localFile, QString& subVersion, QString& versionString);
static void insertKAlarmCatalog();
static QByteArray mIcalProductId;
static bool mHaveKAlarmCatalog;
};
class KALARM_CAL_EXPORT KCalEvent
......
/*
* version.cpp - program version functions
* Program: kalarm
* Copyright © 2002-2007 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "version.h"
#include <QString>
namespace KAlarm
{
/******************************************************************************
* Convert the supplied KAlarm version string to a version number.
* Reply = version number (double digit for each of major, minor & issue number,
* e.g. 010203 for 1.2.3
* = 0 if invalid version string.
*/
int getVersionNumber(const QString& version, QString* subVersion)
{
// N.B. Remember to change Version(int major, int minor, int rev)
// if the representation returned by this method changes.
if (subVersion)
subVersion->clear();
int count = version.count(QChar('.')) + 1;
if (count < 2)
return 0;
bool ok;
unsigned vernum = version.section('.', 0, 0).toUInt(&ok) * 10000; // major version
if (!ok)
return 0;
unsigned v = version.section('.', 1, 1).toUInt(&ok); // minor version
if (!ok)
return 0;
vernum += (v < 99 ? v : 99) * 100;
if (count >= 3)
{
// Issue number: allow other characters to follow the last digit
QString issue = version.section('.', 2);
int n = issue.length();
if (!n || !issue[0].isDigit())
return 0;
int i;
for (i = 0; i < n && issue[i].isDigit(); ++i) ;
if (subVersion)
*subVersion = issue.mid(i);
v = issue.left(i).toUInt(); // issue number
vernum += (v < 99 ? v : 99);
}
return vernum;
}
} // namespace KAlarm
/*
* version.h - program version functions
* Program: kalarm
* Copyright © 2005,2009-2010 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef VERSION_H
#define VERSION_H
#include "kalarm_cal_export.h"
class QString;
namespace KAlarm
{
/** Return a specified version as an integer. */
inline int Version(int major, int minor, int rev) { return major*10000 + minor*100 + rev; }
/** Convert a version string to an integer. */
KALARM_CAL_EXPORT int getVersionNumber(const QString& version, QString* subVersion = 0);
}
#endif // VERSION_H
......@@ -65,29 +65,10 @@ KCalendar::Status CalendarCompat::fix(KCal::CalendarLocal& calendar, const QStri
{
if (wrongType)
*wrongType = false;
bool version057_UTC = false;
QString subVersion, versionString;
int version = readKAlarmVersion(calendar, localFile, subVersion, versionString);
if (version < 0 || version > KAlarm::Version())
QString versionString;
int version = KCalendar::checkCompatibility(calendar, localFile, versionString);
if (version < 0)
return KCalendar::Incompatible; // calendar was created by another program, or an unknown version of KAlarm
if (version)
{
// Calendar was created by an earlier version of KAlarm.
// Convert it to the current format.
if (version == KAlarm::Version(0,5,7) && !localFile.isEmpty())
{
// KAlarm version 0.5.7 - check whether times are stored in UTC, in which
// case it is the KDE 3.0.0 version, which needs adjustment of summer times.
version057_UTC = isUTC(localFile);
kDebug() << "KAlarm version 0.5.7 (" << (version057_UTC ?"" :"non-") << "UTC)";
}
else
kDebug() << "KAlarm version" << version;
// Convert events to current KAlarm format for if the calendar is saved
KAEvent::convertKCalEvents(calendar, version, version057_UTC);
}
if (!resource)
return KCalendar::Current; // update non-shared calendars regardless
......@@ -118,103 +99,3 @@ KCalendar::Status CalendarCompat::fix(KCal::CalendarLocal& calendar, const QStri
calendar.setCustomProperty(KCalendar::APPNAME, VERSION_PROPERTY, QLatin1String(KALARM_VERSION));
return KCalendar::Converted;
}
/******************************************************************************
* Return the KAlarm version which wrote the calendar which has been loaded.
* The format is, for example, 000507 for 0.5.7.
* Reply = 0 if the calendar was created by the current version of KAlarm
* = -1 if it was created by KAlarm pre-0.3.5, or another program
* = version number if created by another KAlarm version.
*/
int CalendarCompat::readKAlarmVersion(KCal::CalendarLocal& calendar, const QString& localFile, QString& subVersion, QString& versionString)
{
subVersion.clear();
versionString = calendar.customProperty(KCalendar::APPNAME, VERSION_PROPERTY);
if (versionString.isEmpty())
{
// Pre-KAlarm 1.4 defined the KAlarm version number in the PRODID field.
// If another application has written to the file, this may not be present.
const QString prodid = calendar.productId();
if (prodid.isEmpty())
{
// Check whether the calendar file is empty, in which case
// it can be written to freely.
QFileInfo fi(localFile);
if (!fi.size())
return 0;
}
// Find the KAlarm identifier
QString progname = QLatin1String(" KAlarm ");
int i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
if (i < 0)
{
// Older versions used KAlarm's translated name in the product ID, which
// could have created problems using a calendar in different locales.
progname = QString(" ") + KGlobal::mainComponent().aboutData()->programName() + ' ';
i = prodid.indexOf(progname, 0, Qt::CaseInsensitive);
if (i < 0)
return -1; // calendar wasn't created by KAlarm
}
// Extract the KAlarm version string
versionString = prodid.mid(i + progname.length()).trimmed();
i = versionString.indexOf('/');
int j = versionString.indexOf(' ');
if (j >= 0 && j < i)
i = j;
if (i <= 0)
return -1; // missing version string
versionString = versionString.left(i); // 'versionString' now contains the KAlarm version string
}
if (versionString == KAEvent::currentCalendarVersionString())
return 0; // the calendar is in the current KAlarm format
int ver = KAlarm::getVersionNumber(versionString, &subVersion);
if (ver >= KAEvent::currentCalendarVersion() && ver <= KAlarm::Version())
return 0; // the calendar is in the current KAlarm format
return KAlarm::getVersionNumber(versionString, &subVersion);
}
/******************************************************************************
* Check whether the calendar file has its times stored as UTC times,
* indicating that it was written by the KDE 3.0.0 version of KAlarm 0.5.7.
* Reply = true if times are stored in UTC
* = false if the calendar is a vCalendar, times are not UTC, or any error occurred.
*/
bool CalendarCompat::isUTC(const QString& localFile)
{
// Read the calendar file into a string
QFile file(localFile);
if (!file.open(QIODevice::ReadOnly))
return false;
QTextStream ts(&file);
ts.setCodec("ISO 8859-1");
QByteArray text = ts.readAll().toLocal8Bit();
file.close();
// Extract the CREATED property for the first VEVENT from the calendar
const QByteArray BEGIN_VCALENDAR("BEGIN:VCALENDAR");
const QByteArray BEGIN_VEVENT("BEGIN:VEVENT");
const QByteArray CREATED("CREATED:");
QList<QByteArray> lines = text.split('\n');
for (int i = 0, end = lines.count(); i < end; ++i)
{
if (lines[i].startsWith(BEGIN_VCALENDAR))
{
while (++i < end)
{
if (lines[i].startsWith(BEGIN_VEVENT))
{
while (++i < end)
{
if (lines[i].startsWith(CREATED))
return lines[i].endsWith('Z');
}
}
}
break;
}
}
return false;
}
......@@ -23,21 +23,16 @@
#undef QT3_SUPPORT
#define KALARM_VERSION "2.4.2"
#define KALARM_VERSION "2.5.2"
#define KALARM_NAME "KAlarm"
#define KALARM_DBUS_SERVICE "org.kde.kalarm" // D-Bus service name of KAlarm application
#include <kdeversion.h>
class QString;
namespace KAlarm
{
/** Return current KAlarm version number as an integer. */
int Version();
/** Return a specified version as an integer. */
inline int Version(int major, int minor, int rev) { return major*10000 + minor*100 + rev; }
/** Convert a version string to an integer. */
int getVersionNumber(const QString& version, QString* subVersion = 0);
int Version();
}
#endif // KALARM_H
......
......@@ -20,14 +20,15 @@
#include "kalarm.h"
#include <stdlib.h>
#include "kalarmapp.h"
#include "version.h"
#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kdebug.h>