Initial CalDAV support

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1130194 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
v3.5.13-sru
tpearson 14 years ago
parent 45c9a75f12
commit a71c4476a7

@ -1,6 +1,6 @@
if include_exchange_SUBDIR
EXCHANGE_SUBDIR=exchange
EXCHANGE_SUBDIR=exchange
endif
SUBDIRS = lib remote egroupware $(EXCHANGE_SUBDIR) kolab slox groupwise featureplan groupdav birthdays newexchange scalix
# SUBDIRS = remote egroupware $(EXCHANGE_SUBDIR) kolab slox groupwise featureplan
SUBDIRS = lib remote egroupware $(EXCHANGE_SUBDIR) kolab slox groupwise featureplan groupdav birthdays newexchange scalix caldav
# SUBDIRS = remote egroupware $(EXCHANGE_SUBDIR) kolab slox groupwise featureplan

@ -0,0 +1,34 @@
INCLUDES = -I$(top_srcdir) $(all_includes)
lib_LTLIBRARIES = libkcal_caldav.la
libkcal_caldav_la_SOURCES = resource.cpp \
config.cpp \
configwidgets.cpp \
preferences.cpp \
job.cpp \
reader.cpp \
writer.cpp \
prefsskel.kcfgc
libkcal_caldav_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) \
-version-info 1:0:0 -no-undefined
libkcal_caldav_la_LIBADD = \
$(top_builddir)/libkcal/libkcal.la \
$(top_builddir)/libkdepim/libkdepim.la \
-lcaldav
libkcal_caldav_la_COMPILE_FIRST = prefsskel.h
kde_module_LTLIBRARIES = kcal_caldav.la
kcal_caldav_la_SOURCES = plugin.cpp
kcal_caldav_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
kcal_caldav_la_LIBADD = libkcal_caldav.la
kcal_caldav_la_COMPILE_FIRST = prefsskel.h
kcal_servicedir = $(kde_servicesdir)/kresources/kcal
kcal_service_DATA = kcal_caldav.desktop
METASOURCES = AUTO
messages: rc.cpp
$(XGETTEXT) *.cpp -o $(podir)/kres_caldav.pot

@ -0,0 +1,162 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Configuration and properties dialog
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#include "resource.h"
#include "config.h"
#include "configwidgets.h"
#include <kcombobox.h>
#include <kdebug.h>
#include <kdialog.h>
#include <klocale.h>
#include <klineedit.h>
#include <klistview.h>
#include <kurlrequester.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qcheckbox.h>
/*=========================================================================
| NAMESPACE
========================================================================*/
using namespace KCal;
/*=========================================================================
| CONSTANTS
========================================================================*/
/*=========================================================================
| STATIC METHODS
========================================================================*/
ResourceCalDav* ResourceCalDavConfig::getCalDavResource(KRES::Resource* resource) {
ResourceCalDav *res = dynamic_cast<ResourceCalDav *>( resource );
if (!res) {
kdDebug() << "invalid resource type";
}
return res;
}
CalDavPrefs* ResourceCalDavConfig::getPrefs(ResourceCalDav* res) {
CalDavPrefs* p = NULL;
if (res) {
p = res->prefs();
if (!p) {
kdDebug() << "CalDAV: res->prefs() returned NULL";
}
}
return p;
}
/*=========================================================================
| CONSTRUCTOR / DESTRUCTOR
========================================================================*/
ResourceCalDavConfig::ResourceCalDavConfig( QWidget *parent )
: KRES::ConfigWidget( parent )
{
setupUI();
}
/*=========================================================================
| METHODS
========================================================================*/
void ResourceCalDavConfig::loadSettings( KRES::Resource *resource ) {
ResourceCalDav* res = getCalDavResource(resource);
CalDavPrefs* p = getPrefs(res);
if (NULL != p) {
mUrl->setText(p->url());
mUsername->setText(p->username());
mRememberPassword->setChecked(p->rememberPassword());
mPassword->setText(p->password());
mReloadConfig->loadSettings(res);
mSaveConfig->loadSettings(res);
}
}
void ResourceCalDavConfig::saveSettings( KRES::Resource *resource ) {
ResourceCalDav* res = getCalDavResource(resource);
if (NULL != res) {
mReloadConfig->saveSettings(res);
mSaveConfig->saveSettings(res);
CalDavPrefs* p = getPrefs(res);
if (NULL != p) {
p->setUrl(mUrl->text());
p->setUsername(mUsername->text());
p->setRememberPassword(mRememberPassword->isChecked());
p->setPassword(mPassword->text());
}
}
}
void ResourceCalDavConfig::setupUI() {
QVBoxLayout *vertical = new QVBoxLayout(this);
QGridLayout *mainLayout = new QGridLayout( this );
// URL
QLabel *label = new QLabel( i18n( "URL:" ), this );
mUrl = new QLineEdit( this );
mainLayout->addWidget( label, 1, 0 );
mainLayout->addWidget( mUrl, 1, 1 );
// Username
label = new QLabel( i18n( "Username:" ), this );
mUsername = new QLineEdit( this );
mainLayout->addWidget( label, 2, 0 );
mainLayout->addWidget( mUsername, 2, 1 );
// Password
label = new QLabel( i18n( "Password:" ), this );
mPassword = new QLineEdit( this );
mPassword->setEchoMode( QLineEdit::Password );
mainLayout->addWidget( label, 3, 0 );
mainLayout->addWidget( mPassword, 3, 1 );
// Remember password checkbox
mRememberPassword = new QCheckBox( i18n("Remember password"), this );
mainLayout->addWidget(mRememberPassword, 4, 1);
// configs
QHBoxLayout* horizontal = new QHBoxLayout(this);
// Reload config
mReloadConfig = new CalDavReloadConfig(this);
horizontal->addWidget(mReloadConfig);
// Save config
mSaveConfig = new CalDavSaveConfig(this);
horizontal->addWidget(mSaveConfig);
// FIXME: This feature does not work; hide the UI elements for later use
mRememberPassword->hide();
label->hide();
mPassword->hide();
// combining layouts
vertical->addLayout(mainLayout);
vertical->addLayout(horizontal);
}
// EOF ========================================================================

@ -0,0 +1,80 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Configuration and properties dialog
========================================================================*/
#ifndef KCAL_RESOURCECALDAVCONFIG_H
#define KCAL_RESOURCECALDAVCONFIG_H
/*=========================================================================
| INCLUDES
========================================================================*/
#include "resource.h"
#include <kdemacros.h>
#include <kresources/configwidget.h>
class QLineEdit;
class QCheckBox;
namespace KCal {
class CalDavReloadConfig;
class CalDavSaveConfig;
/*=========================================================================
| CLASS
========================================================================*/
/**
* Configuration widget for CalDAV resource.
*/
class KDE_EXPORT ResourceCalDavConfig : public KRES::ConfigWidget
{
Q_OBJECT
public:
ResourceCalDavConfig(QWidget *parent = 0);
public slots:
virtual void loadSettings(KRES::Resource *resource);
virtual void saveSettings(KRES::Resource *resource);
protected:
virtual void setupUI();
private:
QLineEdit *mUrl;
QLineEdit *mUsername;
QLineEdit *mPassword;
QCheckBox *mRememberPassword;
CalDavReloadConfig* mReloadConfig;
CalDavSaveConfig* mSaveConfig;
static ResourceCalDav* getCalDavResource(KRES::Resource* res);
/**
* Returns preferences of the given ResourceCalDav object.
* @param res resource object.
* @return if preferences object is obtained successfully, it's returned. Otherwise, NULL is returned.
*/
static CalDavPrefs* getPrefs(ResourceCalDav* res);
};
} // namespace KCal
#endif // KCAL_RESOURCECALDAVCONFIG_H

@ -0,0 +1,246 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Automatic Reload / Automatic Save configuration widgets.
| The code is mostly taken from resourcecachedconfig.h/cpp files from
| the kcal library and changed to meet our requirements.
| The original copyright is below.
========================================================================*/
/*
This file is part of the kcal library.
Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "configwidgets.h"
#include <libkcal/resourcecached.h>
#include <klocale.h>
#include <kdebug.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qcheckbox.h>
#include <qradiobutton.h>
#include <qspinbox.h>
#include <qbuttongroup.h>
#include <qgroupbox.h>
using namespace KCal;
//@cond PRIVATE
class CalDavConfigPrivate
{
public:
CalDavConfigPrivate()
: mGroup( 0 ),
mIntervalSpin( 0 ) {}
QButtonGroup *mGroup;
QSpinBox *mIntervalSpin;
};
class CalDavReloadConfig::Private
: public CalDavConfigPrivate
{
};
class CalDavSaveConfig::Private
: public CalDavConfigPrivate
{
};
//@endcond
CalDavReloadConfig::CalDavReloadConfig( QWidget *parent )
: QWidget( parent ), d( new KCal::CalDavReloadConfig::Private() )
{
QBoxLayout *topLayout = new QVBoxLayout( this );
//QGroupBox *groupBox = new QGroupBox( i18nc( "@title:group", "Automatic Reload" ), this );
QGroupBox *groupBox = new QGroupBox( i18n( "Automatic Reload" ), this );
topLayout->addWidget( groupBox );
QRadioButton *noAutomaticReload =
new QRadioButton(
//i18nc( "@option:radio never reload the cache", "Never" ), groupBox );
i18n( "Never" ), groupBox );
QRadioButton *automaticReloadOnStartup =
new QRadioButton(
//i18nc( "@option:radio reload the cache on startup", "Only on startup" ), groupBox );
i18n( "Only on startup" ), groupBox );
QRadioButton *intervalRadio =
new QRadioButton(
// i18nc( "@option:radio reload the cache at regular intervals",
// "Regular interval" ), groupBox );
i18n( "Regular interval" ), groupBox );
d->mGroup = new QButtonGroup( this );
d->mGroup->hide();
d->mGroup->insert( intervalRadio, 2 );
d->mGroup->insert( automaticReloadOnStartup, 1 );
d->mGroup->insert( noAutomaticReload, 0 );
connect( intervalRadio, SIGNAL( toggled( bool ) ),
SLOT( slotIntervalToggled( bool ) ) );
QHBox *intervalBox = new QHBox( groupBox );
//new QLabel( i18nc( "@label:spinbox", "Interval in minutes:" ), intervalBox );
new QLabel( i18n( "Interval in minutes:" ), intervalBox );
d->mIntervalSpin = new QSpinBox( intervalBox );
d->mIntervalSpin->setRange( 1, 900 );
d->mIntervalSpin->setEnabled( false );
groupBox->setColumnLayout(1, Qt::Vertical);
QVBoxLayout *vbox = new QVBoxLayout(groupBox->layout());
vbox->addWidget(intervalRadio);
vbox->addWidget(intervalBox);
vbox->addWidget(automaticReloadOnStartup);
vbox->addWidget(noAutomaticReload);
vbox->addStretch(1);
}
CalDavReloadConfig::~CalDavReloadConfig()
{
delete d;
}
void CalDavReloadConfig::loadSettings( ResourceCached *resource )
{
d->mIntervalSpin->setValue( resource->reloadInterval() );
d->mGroup->setButton( resource->reloadPolicy() );
}
void CalDavReloadConfig::saveSettings( ResourceCached *resource )
{
resource->setReloadInterval( d->mIntervalSpin->value() );
resource->setReloadPolicy( d->mGroup->selectedId() );
}
void CalDavReloadConfig::slotIntervalToggled( bool checked )
{
if ( checked ) {
d->mIntervalSpin->setEnabled( true );
} else {
d->mIntervalSpin->setEnabled( false );
}
}
CalDavSaveConfig::CalDavSaveConfig( QWidget *parent )
: QWidget( parent ), d( new KCal::CalDavSaveConfig::Private() )
{
QBoxLayout *topLayout = new QVBoxLayout( this );
//QGroupBox *groupBox = new QGroupBox( i18nc( "@title:group", "Automatic Save" ), this );
QGroupBox *groupBox = new QGroupBox( i18n( "Automatic Save" ), this );
d->mGroup = new QButtonGroup( this );
d->mGroup->hide();
topLayout->addWidget( groupBox );
QRadioButton *never =
new QRadioButton(
//i18nc( "@option:radio never save the cache automatically", "Never" ), groupBox );
i18n( "Never" ), groupBox );
QRadioButton *onExit =
new QRadioButton(
//i18nc( "@option:radio save the cache on exit", "Only on exit" ), groupBox );
i18n( "Only on exit" ), groupBox );
QRadioButton *intervalRadio =
new QRadioButton(
//i18nc( "@option:radio save the cache at regular intervals", "Regular interval" ), groupBox );
i18n( "Regular interval" ), groupBox );
d->mGroup = new QButtonGroup( this );
d->mGroup->hide();
d->mGroup->insert( never, 0 );
d->mGroup->insert( onExit, 1 );
d->mGroup->insert( intervalRadio, 2 );
connect( intervalRadio, SIGNAL( toggled( bool ) ),
SLOT( slotIntervalToggled( bool ) ) );
QHBox *intervalBox = new QHBox( groupBox );
//new QLabel( i18nc( "@label:spinbox", "Interval in minutes:" ), intervalBox );
new QLabel( i18n( "Interval in minutes:" ), intervalBox );
d->mIntervalSpin = new QSpinBox( intervalBox );
d->mIntervalSpin->setRange( 1, 900 );
d->mIntervalSpin->setEnabled( false );
QRadioButton *delay =
new QRadioButton(
// i18nc( "@option:radio save the cache after some delay",
// "Delayed after changes" ), groupBox );
i18n( "Delayed after changes" ), groupBox );
QRadioButton *every =
new QRadioButton(
// i18nc( "@option:radio save the cache after every modification",
// "Immediately after changes" ), groupBox );
i18n( "Immediately after changes" ), groupBox );
d->mGroup->insert( delay, 3 );
d->mGroup->insert( every, 4 );
// hide unwanted widgets. They may be useful in future, so don't delete them for now.
intervalRadio->hide();
intervalBox->hide();
groupBox->setColumnLayout(1, Qt::Vertical);
QVBoxLayout *vbox = new QVBoxLayout(groupBox->layout());
vbox->addWidget(delay);
vbox->addWidget(every);
vbox->addWidget(intervalRadio);
vbox->addWidget(intervalBox);
vbox->addWidget(onExit);
vbox->addWidget(never);
vbox->addStretch(1);
}
CalDavSaveConfig::~CalDavSaveConfig()
{
delete d;
}
void CalDavSaveConfig::loadSettings( ResourceCached *resource )
{
d->mIntervalSpin->setValue( resource->saveInterval() );
d->mGroup->setButton( resource->savePolicy() );
}
void CalDavSaveConfig::saveSettings( ResourceCached *resource )
{
resource->setSaveInterval( d->mIntervalSpin->value() );
resource->setSavePolicy( d->mGroup->selectedId() );
}
void CalDavSaveConfig::slotIntervalToggled( bool checked )
{
if ( checked ) {
d->mIntervalSpin->setEnabled( true );
} else {
d->mIntervalSpin->setEnabled( false );
}
}
// EOF ========================================================================

@ -0,0 +1,100 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Automatic Reload / Automatic Save configuration widgets.
| The code is mostly taken from resourcecachedconfig.h/cpp files from
| the kcal library and changed to meet our requirements.
| The original copyright is below.
========================================================================*/
/*
This file is part of the kcal library.
Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KCALDAV_AUTOWIDGETS_H
#define KCALDAV_AUTOWIDGETS_H
#include <qwidget.h>
#include <kdemacros.h>
namespace KCal {
class ResourceCached;
/**
Configuration widget for reload policy
@see ResourceCached
*/
class KDE_EXPORT CalDavReloadConfig : public QWidget
{
Q_OBJECT
public:
explicit CalDavReloadConfig( QWidget *parent = 0 );
~CalDavReloadConfig();
public slots:
void loadSettings( ResourceCached *resource );
void saveSettings( ResourceCached *resource );
protected slots:
void slotIntervalToggled( bool );
private:
//@cond PRIVATE
//Q_DISABLE_COPY( CalDavReloadConfig )
class Private;
Private *const d;
//@endcond
};
/**
Configuration widget for save policy
@see ResourceCached
*/
class KDE_EXPORT CalDavSaveConfig : public QWidget
{
Q_OBJECT
public:
explicit CalDavSaveConfig( QWidget *parent = 0 );
~CalDavSaveConfig();
public slots:
void loadSettings( ResourceCached *resource );
void saveSettings( ResourceCached *resource );
protected slots:
void slotIntervalToggled( bool );
private:
//@cond PRIVATE
//Q_DISABLE_COPY( CalDavSaveConfig )
class Private;
Private *const d;
//@endcond
};
}
#endif // KCALDAV_AUTOWIDGETS_H

@ -0,0 +1,56 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Some support macros.
| The code is mostly taken from KDE source files.
| The original copyright is below.
========================================================================*/
/* This file is part of the KDE project
Copyright (C) 2008 Jarosław Staniek <staniek@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRESOURCES_KDEPIM_EXPORT_H
#define KRESOURCES_KDEPIM_EXPORT_H
/** Exports a function returning kresources plugin factory, for resource class @a resourceclass,
* @a resourceconfigclass config class and @a catalog catalog.
*/
#define EXPORT_KRESOURCES_PLUGIN( resourceclass, resourceconfigclass, catalog ) \
typedef KRES::PluginFactory< resourceclass, resourceconfigclass > FactoryBase; \
class Factory : public FactoryBase { \
public: Factory() { KGlobal::locale()->insertCatalogue(catalog); } \
}; \
K_EXPORT_PLUGIN( Factory )
/** Like EXPORT_KRESOURCES_PLUGIN but allows to specify two catalogs.
*/
#define EXPORT_KRESOURCES_PLUGIN2( resourceclass, resourceconfigclass, catalog1, catalog2 ) \
typedef KRES::PluginFactory< resourceclass, resourceconfigclass > FactoryBase; \
class Factory : public FactoryBase { \
public: Factory() { KGlobal::locale()->insertCatalogue(catalog1); \
KGlobal::locale()->insertCatalogue(catalog2); } \
}; \
K_EXPORT_PLUGIN( Factory )
#endif

@ -0,0 +1,105 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Job class for accessing remote calendars.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#include "job.h"
#include <kdebug.h>
#include <qmutex.h>
#define log(s) kdDebug() << s;
/*=========================================================================
| NAMESPACE
========================================================================*/
using namespace KCal;
/*=========================================================================
| STATIC
========================================================================*/
/*=========================================================================
| CONSTRUCTOR AND DESTRUCTOR
========================================================================*/
CalDavJob::CalDavJob(const QString& url) {
cleanJob();
setUrl(url);
}
CalDavJob::~CalDavJob() {
}
/*=========================================================================
| METHODS
========================================================================*/
void CalDavJob::enableCaldavDebug(runtime_info* rt) {
if (rt && rt->options) {
rt->options->debug = 0; // if debug = 1, it causes major CPU overhead
rt->options->verify_ssl_certificate = FALSE;
}
}
void CalDavJob::setErrorString(const QString& err, const long number) {
mError = true;
mErrorString = err;
mErrorNumber = number;
}
void CalDavJob::processError(const caldav_error* err) {
QString error_string;
long code = err->code;
if (-401 == code) { // unauthorized
error_string = i18n("Unauthorized. Username or password incorrect.");
} else if (-599 <= code && code <= -300) {
error_string = i18n("HTTP error %1. Maybe, URL is not a CalDAV resource.").arg(-code);
} else {
error_string = err->str;
}
setErrorString(error_string, code);
}
void CalDavJob::run() {
log("cleaning job");
cleanJob();
int res = OK;
runtime_info* caldav_runtime = caldav_get_runtime_info();
#ifdef KCALDAV_DEBUG
log("setting debug caldav options");
enableCaldavDebug(caldav_runtime);
#endif // KCALDAV_DEBUG
log("running job");
res = runJob(caldav_runtime);
if (OK != res) {
log("job failed");
processError(caldav_runtime->error);
}
caldav_free_runtime_info(&caldav_runtime);
}
// EOF ========================================================================

@ -0,0 +1,131 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Job class for accessing remote calendars.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#ifndef KCALDAV_JOB_H
#define KCALDAV_JOB_H
#include <qthread.h>
#include <qstring.h>
#include <qdatetime.h>
extern "C" {
#include <libcaldav/caldav.h>
}
namespace KCal {
/*=========================================================================
| CLASS
========================================================================*/
/**
* Calendar job.
*/
class CalDavJob : public QThread {
public:
/**
* @param url URL to load.
*/
CalDavJob(const QString& url = QString());
virtual ~CalDavJob();
/**
* Sets a new URL to load.
*/
virtual void setUrl(const QString& s) {
mUrl = s;
}
/**
* @return URL to load.
*/
virtual QString url() const {
return mUrl;
}
/**
* @return true if downloading process failed.
*/
virtual bool error() const {
return mError;
}
/**
* @return an error string.
*/
virtual QString errorString() const {
return mErrorString;
}
/**
* @return an error number.
*/
virtual long errorNumber() const {
return mErrorNumber;
}
protected:
virtual void run();
/**
* Main run method for jobs. Jobs should not override run() method.
* Instead of this they should override this one.
* @param caldavRuntime specific libcaldav runtime information. This pointer should not be saved for the usage
* outside of runJob.
* @return libcaldav response code (see CALDAV_RESPONSE)
*/
virtual int runJob(runtime_info* caldavRuntime) = 0;
/**
* Some cleaning. Jobs may (and usually should) override this method.
*/
virtual void cleanJob() {
mError = false;
mErrorString = "";
mErrorNumber = 0;
}
/**
* Sets an error string to @p err. Also sets an error flag.
*/
void setErrorString(const QString& str, const long number);
/**
* Process an error.
* Subclasses can overwrite this method, if some special error message handling
* should be done. Call setErrorString() to set the error after processing is done.
* @param err error structure.
*/
virtual void processError(const caldav_error* err);
private:
QString mUrl;
bool mError;
QString mErrorString;
long mErrorNumber;
void enableCaldavDebug(runtime_info*);
};
} // namespace KCal
#endif // KCALDAV_JOB_H

@ -0,0 +1,52 @@
[Desktop Entry]
Name=CalDAV Server (e.g. Google Calendar)
Name[af]=CalDAV bediener (bv. Google Calendar)
Name[bg]=Сървър CalDAV (e.g. Google Calendar)
Name[br]=Servijer CalDAV (e.g. Google Calendar)
Name[ca]=Servidor CalDAV (p.ex. Google Calendar)
Name[cs]=CalDAV server (např. Google Calendar)
Name[da]=CalDAV-server (f.eks. Google Calendar)
Name[de]=CalDAV-Server (z. B. Google Calendar)
Name[el]=Εξυπηρετητής CalDAV (π.χ. Google Calendar)
Name[es]=Servidor CalDAV (por ejemplo, Google Calendar)
Name[et]=CalDAV server (nt. Google Calendar)
Name[eu]=CalDAV zerbitzaria (adib. Google Calendar)
Name[fa]=کارساز CalDAV (مثلاً Google Calendar)
Name[fi]=CalDAV-palvelin (esim. Google Calendar)
Name[fr]=CalDAV Serveur (ex. Google Calendar)
Name[fy]=CalDAV-tsjinner (Google Calendar)
Name[ga]=Freastalaí CalDAV (m.sh. Google Calendar)
Name[gl]=Servidor CalDAV (e.g. Google Calendar)
Name[hu]=CalDAV-kiszolgáló (pl. Google Calendar)
Name[is]=CalDAV þjónn (t.d. Google Calendar)
Name[it]=Server CalDAV (per es. Google Calendar)
Name[ja]=CalDAV サーバ (例 Google Calendar)
Name[ka]=სერვერი CalDAV (მაგ., Google Calendar)
Name[kk]=CalDAV сервері (мысалы Google Calendar)
Name[km]=ម៉ាស៊ីន​បម្រើ CalDAV (ឧ. Google Calendar)
Name[lt]=CalDAV serveris (pvz.: Google Calendar)
Name[ms]=Pelayan CalDAV (misalnya Google Calendar)
Name[nb]=CalDAV-tjener (f.eks. Google Calendar)
Name[nds]=CalDAV-Server (t.B. Google Calendar)
Name[ne]=समूह DAV सर्भर (जस्तै: खुला ग्रुपवेयर)
Name[nl]=CalDAV-server (Google Calendar)
Name[nn]=CalDAV-tenar (t.d. Google Calendar)
Name[pl]=Serwer CalDAV (np. Google Calendar)
Name[pt]=Servidor CalDAV (por exemplo Google Calendar)
Name[pt_BR]=Servidor GroupDav (p. ex. Google Calendar)
Name[ru]=Сервер CalDAV (например, Google Calendar)
Name[sk]=CalDAV Server (napr. Google Calendar)
Name[sl]=Strežnik CalDAV (npr. Google Calendar)
Name[sr]=CalDAV сервер (нпр. Google Calendar)
Name[sr@Latn]=CalDAV server (npr. Google Calendar)
Name[sv]=CalDAV-server (t.ex. Google Calendar)
Name[ta]=CalDAV சேவகன் (e.g. Google Calendar)
Name[tr]=CalDAV Sunucusu (ör. Google Calendar)
Name[uk]=Сервер CalDAV (напр., Google Calendar)
Name[zh_CN]=CalDAV 服务器(如 Google Calendar)
Name[zh_TW]=CalDAV 伺服器 (如: Google Calendar)
X-KDE-Library=kcal_caldav
Type=Service
ServiceTypes=KResources/Plugin
X-KDE-ResourceFamily=calendar
X-KDE-ResourceType=caldav

@ -0,0 +1,49 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| CalDAV resource factory.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#include "resource.h"
#include "config.h"
#include "export.h"
#include <kglobal.h>
#include <klocale.h>
/*=========================================================================
| NAMESPACE
========================================================================*/
using namespace KCal;
/*=========================================================================
| CLASS
========================================================================*/
// Creates the resource factory.
//EXPORT_KRESOURCES_PLUGIN2( ResourceCalDav, ResourceCalDavConfig, "libkcal", "kres_caldav" )
typedef KRES::PluginFactory<ResourceCalDav, ResourceCalDavConfig> CalDavFactory;
extern "C"
{
void *init_kcal_caldav()
{
KGlobal::locale()->insertCatalogue( "libkcal" );
KGlobal::locale()->insertCatalogue( "kres_caldav" );
return new CalDavFactory;
}
}
// EOF ========================================================================

@ -0,0 +1,221 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| CalDAV resource preferences class.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#include "preferences.h"
#include <kwallet.h>
#include <qstring.h>
#include <qurl.h>
#include <kdebug.h>
/*=========================================================================
| NAMESPACES
========================================================================*/
using namespace KCal;
using namespace KWallet;
/*=========================================================================
| CONSTANTS
========================================================================*/
const QString CalDavPrefs::NO_PASSWORD = "";
const QString CalDavPrefs::WALLET_FOLDER = "CalDAV resource";
const QString CalDavPrefs::WALLET_PWD_SUFFIX = ":caldav_password";
/*=========================================================================
| METHODS
========================================================================*/
bool CalDavPrefs::setWalletFolder(const QString& folder) {
bool ret = true;
if (!mNoWallet && NULL != mWallet) {
if (!mWallet->hasFolder(folder)) {
if (!mWallet->createFolder(folder)) {
ret = false;
kdWarning() << "can't create the wallet folder for CalDAV passwords";
}
}
if (!mWallet->setFolder(folder)) {
ret = false;
kdWarning() << "can't set the wallet folder for CalDAV passwords";
}
} else {
// the wallet is inaccessible or not configured
ret = false;
}
return ret;
}
Wallet* CalDavPrefs::getWallet() {
Wallet* ret = NULL;
if (!mNoWallet) {
// the wallet is not marked as inaccessible
if (NULL == mWallet) {
kdDebug() << "creating wallet for " + mPrefix;
mWallet = Wallet::openWallet(Wallet::NetworkWallet(), 0);
if (NULL == mWallet) {
mNoWallet = true; // can't open the wallet, mark it inaccessible
kdWarning() << "can't create a wallet for CalDAV passwords";
} else {
if (setWalletFolder(WALLET_FOLDER)) {
// reserved
} else {
// can't set the wallet folder, remove the wallet and mark it inaccessible
kdWarning() << "can't set the walet folder for CalDAV passwords";
removeWallet(true);
}
}
}
ret = mWallet;
}
return ret;
}
void CalDavPrefs::removeWallet(bool noWallet) {
delete mWallet;
mWallet = NULL;
mNoWallet = noWallet;
}
void CalDavPrefs::addPrefix(const QString& prefix) {
KConfigSkeletonItem::List itemList = items();
KConfigSkeletonItem::List::Iterator it;
for ( it = itemList.begin(); it != itemList.end(); ++it ) {
(*it)->setGroup( prefix + ':' + (*it)->group() );
}
}
bool CalDavPrefs::writePasswordToWallet(const QString& password) {
Wallet* w = getWallet();
bool ret = false;
if (NULL != w) {
int rc = w->writePassword(mPrefix + WALLET_PWD_SUFFIX, password);
if (0 != rc) {
kdWarning() << "CalDAV: can't write password to the wallet";
} else {
ret = true;
}
}
return ret;
}
bool CalDavPrefs::readPasswordFromWallet(QString& password) {
Wallet* w = getWallet();
bool ret = false;
if (NULL != w) {
QString p;
int rc = w->readPassword(mPrefix + WALLET_PWD_SUFFIX, p);
if (0 == rc) {
//CalDavPrefsSkel::setPassword(p);
password = p;
ret = true;
} else {
kdWarning() << "CalDAV: can't read password from the wallet";
password = NO_PASSWORD;
}
}
return ret;
}
bool CalDavPrefs::removePasswordFromWallet() {
Wallet* w = getWallet();
bool ret = false;
if (NULL != w) {
int rc = w->removeEntry(mPrefix + WALLET_PWD_SUFFIX);
if (0 == rc) {
ret = true;
} else {
kdWarning() << "CalDAV: can't remove password from the wallet";
}
}
return ret;
}
void CalDavPrefs::setPassword(const QString& p) {
mPassword = p;
if (rememberPassword()) {
writePasswordToWallet(p);
}
}
QString CalDavPrefs::password() {
if (NO_PASSWORD == mPassword) {
readPasswordFromWallet(mPassword);
}
return mPassword;
}
QString CalDavPrefs::getusername() {
return username();
}
void CalDavPrefs::setRememberPassword(bool v) {
kdDebug() << "remember: " << v;
CalDavPrefsSkel::setRememberPassword(v);
if (!v) {
// we should not remember password. If there is one already stored, it must be removed.
kdDebug() << "removing password from wallet";
removePasswordFromWallet();
}
}
void CalDavPrefs::writeConfig() {
CalDavPrefsSkel::writeConfig();
}
void CalDavPrefs::readConfig() {
CalDavPrefsSkel::readConfig();
// the password is not in config file, try to restore it from the wallet.
/*if (rememberPassword()) {
readPasswordFromWallet();
}*/
}
QString CalDavPrefs::getFullUrl() {
QUrl t(url());
t.setUser(username());
t.setPassword(password());
return t.toString();
}
// EOF ========================================================================

@ -0,0 +1,154 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| CalDAV resource preferences class.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#ifndef KCAL_CALDAVPREFS_H
#define KCAL_CALDAVPREFS_H
#include "prefsskel.h"
#include <kwallet.h>
#include <kdebug.h>
class QString;
namespace KCal {
/*=========================================================================
| CLASS
========================================================================*/
/**
* This class provides access to ResourceCalDav preferences.
* It inherits auto-generated CalDavPrefsSkel class to add password-handling code.
* KWallet is used for storing passwords.
* It also adds code to allow multiple CalDAV resources to store settings in the same
* config file.
*/
class CalDavPrefs : public CalDavPrefsSkel {
public:
/**
* @param prefix Unique prefix of the resource instance (use identifier() method).
*/
CalDavPrefs(const QString& prefix)
: mWallet(NULL)
, mNoWallet(false)
, mPrefix(prefix)
, mPassword(NO_PASSWORD)
{
addPrefix(prefix);
}
virtual ~CalDavPrefs() {
kdDebug() << "removing wallet";
removeWallet();
}
virtual void writeConfig();
virtual void readConfig();
/**
* Sets a new password. Also, if remember password flag is true,
* remembers the password in the wallet. So, if you want the password
* to be properly saved, call this method after ensuring the remember flag
* is set.
*/
void setPassword(const QString& p);
/**
* Returns password. The password is taken from the wallet.
* May return an empty string, if there is no password available.
*/
QString password();
/**
* Returns the username.
*/
QString getusername();
void setRememberPassword(bool v);
/**
* @return A full URL to connect to CalDAV server (including username and password).
*/
QString getFullUrl();
protected:
/**
* Add an unique prefix to KConfigGroup, so that different instances of the resource
* can use the same config file.
* @param prefix Unique prefix of the resource instance.
*/
void addPrefix(const QString& prefix);
/**
* Returns the wallet or NULL, if the wallet can't be obtained.
*/
KWallet::Wallet* getWallet();
/**
* Tries to set a working folder for the wallet. If the wallet is not configured yet, does nothing.
* @param folder the wallet working folder
* @return true, if the folder has been set, and false otherwise.
*/
bool setWalletFolder(const QString& folder);
/**
* Removes the wallet. If @p noWallet is set, the wallet has been marked inaccessible, so that subsequent
* getWallet calls will not try to recreate it.
*/
void removeWallet(bool noWallet = false);
/**
* Wrire password to the wallet.
* @param password password to write
* @return true on success, false on failure
*/
bool writePasswordToWallet(const QString& password);
/**
* Extracts password from the wallet.
* @param password a variable to save read password to.
* @return true on success, false on failure
*/
bool readPasswordFromWallet(QString& password);
/**
* Clears password in the wallet.
* @return true on success, false on failure
*/
bool removePasswordFromWallet();
private:
static const QString NO_PASSWORD;
static const QString WALLET_FOLDER;
static const QString WALLET_PWD_SUFFIX;
KWallet::Wallet* mWallet;
bool mNoWallet;
QString mPrefix;
QString mPassword;
};
} // namespace KCal
#endif // KCAL_CALDAVPREFS_H

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="kresources_caldavrc" />
<group name="General" >
<entry key="Url" type="String" >
<label>URL</label>
</entry>
<entry key="Username" type="String">
<label>User Name</label>
</entry>
<!-- <entry key="Password" type="String" >
<label>Password</label>
</entry>-->
<entry key="RememberPassword" type="Bool" >
<label>Remember password</label>
</entry>
</group>
</kcfg>

@ -0,0 +1,7 @@
# Code generation options for kconfig_compiler
File=prefsskel.kcfg
ClassName=CalDavPrefsSkel
NameSpace=KCal
Singleton=false
Mutators=true
GlobalEnums=true

@ -0,0 +1,65 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Remote calendar loading.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#include "reader.h"
#include <kdebug.h>
/*=========================================================================
| NAMESPACE
========================================================================*/
using namespace KCal;
/*=========================================================================
| METHODS
========================================================================*/
void CalDavReader::cleanJob() {
CalDavJob::cleanJob();
mData = "";
}
int CalDavReader::runJob(runtime_info* RT) {
kdDebug() << "reader::run, url: " << url();
response* result = caldav_get_response();
CALDAV_RESPONSE res = OK;
if (mGetAll) {
kdDebug() << "getting all objects";
res = caldav_getall_object(result, std::string(url().ascii()).c_str(), RT);
} else {
kdDebug() << "getting object from the specified time range";
res = caldav_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(url().ascii()).c_str(), RT);
}
if (OK == res) {
kdDebug() << "success";
if (result->msg) {
mData = result->msg;
} else {
kdDebug() << "empty collection";
// empty collection
mData = "";
}
}
caldav_free_response(&result);
return res;
}
// EOF ========================================================================

@ -0,0 +1,92 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Remote calendar loading class.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#ifndef KCALDAV_LOADER_H
#define KCALDAV_LOADER_H
#include "job.h"
#include <qstring.h>
#include <qdatetime.h>
namespace KCal {
/*=========================================================================
| CLASS
========================================================================*/
/**
* Calendar Reader.
*/
class CalDavReader : public CalDavJob {
public:
/**
* @param url URL to load.
*/
CalDavReader(const QString& url = QString()) :
CalDavJob(url)
, mGetAll(true)
{
}
/**
* Sets a time range. Only event between @p start and @p end will be loaded.
* This method call disables the effect of setGetAll() call.
* setGetAll() call disables the effect of this method.
*/
void setRange(const QDateTime& start, const QDateTime& end) {
mGetAll = false;
mTimeStart = start;
mTimeEnd = end;
}
/**
* Sets the flag to load all events from the remote calendar.
* This method call disables the effect of setRange() call.
* setGetAll() call disables the effect of this method.
*/
void setGetAll() {
mGetAll = true;
}
/**
* @return downloaded calendar data in iCal format.
*/
QString data() const {
return mData;
}
protected:
virtual int runJob(runtime_info* caldavRuntime);
virtual void cleanJob();
private:
QString mData;
bool mGetAll;
QDateTime mTimeStart;
QDateTime mTimeEnd;
};
} // namespace KCal
#endif // KCALDAV_LOADER_H

@ -0,0 +1,566 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Main interface to the KResource system.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#include <string.h>
#include <qurl.h>
#include <qmessagebox.h>
#include <qapplication.h>
#include <qeventloop.h>
#include <libkcal/calendarlocal.h>
#include <libkcal/icalformat.h>
#include <klocale.h>
#include <kpassdlg.h>
#include <qdatetime.h>
#include <qmutex.h>
#include <qthread.h>
#ifdef KCALDAV_DEBUG
#include <qfile.h>
#endif
#include "resource.h"
#include "reader.h"
#include "writer.h"
/*=========================================================================
| NAMESPACE
========================================================================*/
using namespace KCal;
/*=========================================================================
| CONSTANTS
========================================================================*/
const unsigned long ResourceCalDav::TERMINATION_WAITING_TIME = 3 * 1000; // 3 seconds
const int ResourceCalDav::CACHE_DAYS = 90;
const int ResourceCalDav::DEFAULT_RELOAD_INTERVAL = 10;
const int ResourceCalDav::DEFAULT_SAVE_INTERVAL = 10;
const int ResourceCalDav::DEFAULT_RELOAD_POLICY = ResourceCached::ReloadInterval;
const int ResourceCalDav::DEFAULT_SAVE_POLICY = ResourceCached::SaveDelayed;
/*=========================================================================
| UTILITY
========================================================================*/
#define log(s) kdDebug() << identifier() << ": " << (s);
/*=========================================================================
| CONSTRUCTOR / DESTRUCTOR
========================================================================*/
ResourceCalDav::ResourceCalDav( const KConfig *config ) :
ResourceCached(config)
, mLock(true)
, mPrefs(NULL)
, mLoader(NULL)
, mWriter(NULL)
, mLoadingQueueReady(true)
, mWritingQueueReady(true)
{
log("ResourceCalDav(config)");
init();
if ( config ) {
readConfig( config );
}
}
ResourceCalDav::~ResourceCalDav() {
log("jobs termination");
// TODO: do we need termination here?
if (mLoader) {
mLoader->terminate();
}
if (mWriter) {
mWriter->terminate();
}
log("waiting for jobs terminated");
if (mLoader) {
mLoader->wait(TERMINATION_WAITING_TIME);
}
if (mWriter) {
mWriter->wait(TERMINATION_WAITING_TIME);
}
log("deleting jobs");
delete mLoader;
delete mWriter;
log("deleting preferences");
delete mPrefs;
}
/*=========================================================================
| GENERAL METHODS
========================================================================*/
bool ResourceCalDav::doLoad() {
bool syncCache = true;
log(QString("doLoad(%1)").arg(syncCache));
clearCache();
log("loading from cache");
disableChangeNotification();
loadCache();
enableChangeNotification();
log("starting download job");
startLoading(mPrefs->getFullUrl());
return true;
}
bool ResourceCalDav::doSave() {
bool syncCache = true;
log(QString("doSave(%1)").arg(syncCache));
if (!hasChanges()) {
log("no changes");
return true;
}
log("saving cache");
saveCache();
log("start writing job");
startWriting(mPrefs->getFullUrl());
log("clearing changes");
// FIXME: Calling clearChanges() here is not the ideal way since the
// upload might fail, but there is no other place to call it...
clearChanges();
return true;
}
bool ResourceCalDav::doSave( bool syncCache, Incidence *incidence ) {
// To suppress warning about doSave(bool) method hides ResourceCached::doSave(bool, Incidence)
return ResourceCached::doSave();
}
KABC::Lock* ResourceCalDav::lock() {
log("lock()");
return &mLock;
}
void ResourceCalDav::readConfig( const KConfig *config ) {
log("readConfig");
mPrefs->readConfig();
ResourceCached::readConfig(config);
}
void ResourceCalDav::writeConfig( KConfig *config ) {
log("writeConfig()");
ResourceCalendar::writeConfig(config);
mPrefs->writeConfig();
ResourceCached::writeConfig(config);
}
CalDavPrefs* ResourceCalDav::createPrefs() const {
log("createPrefs()");
CalDavPrefs* p = new CalDavPrefs(identifier());
return p;
}
void ResourceCalDav::init() {
// default settings
setReloadInterval(DEFAULT_RELOAD_INTERVAL);
setReloadPolicy(DEFAULT_RELOAD_POLICY);
setSaveInterval(DEFAULT_SAVE_INTERVAL);
setSavePolicy(DEFAULT_SAVE_POLICY);
// creating preferences
mPrefs = createPrefs();
// creating jobs
// FIXME: Qt4 handles this quite differently, as shown below...
// mLoader = new CalDavReader;
// connect(mLoader, SIGNAL(finished()), this, SLOT(loadFinished()));
// mWriter = new CalDavWriter;
// connect(mWriter, SIGNAL(finished()), this, SLOT(writingFinished()));
// ...whereas Qt3 needs events like so:
mLoader = new CalDavReader;
//connect(mLoader, SIGNAL(finished()), this, SLOT(loadFinished()));
mWriter = new CalDavWriter;
//connect(mWriter, SIGNAL(finished()), this, SLOT(writingFinished()));
setType("ResourceCalDav");
}
void ResourceCalDav::setIncidencesReadOnly(Incidence::List& inc, bool readOnly) {
Incidence::List::Iterator it;
for ( it = inc.begin(); it != inc.end(); ++it ) {
(*it)->setReadOnly( readOnly );
}
}
void ResourceCalDav::ensureReadOnlyFlagHonored() {
//disableChangeNotification();
Incidence::List inc( rawIncidences() );
setIncidencesReadOnly(inc, readOnly());
//enableChangeNotification();
emit resourceChanged(this);
}
void ResourceCalDav::setReadOnly(bool v) {
KRES::Resource::setReadOnly(v);
log("ensuring read only flag honored");
ensureReadOnlyFlagHonored();
}
/*=========================================================================
| READING METHODS
========================================================================*/
void ResourceCalDav::loadingQueuePush(const LoadingTask *task) {
mLoadingQueue.enqueue(task);
loadingQueuePop();
}
void ResourceCalDav::loadingQueuePop() {
if (!mLoadingQueueReady || mLoadingQueue.isEmpty()) {
return;
}
if (!mLoader) {
log("loader == NULL");
return;
}
// Loading queue and mLoadingQueueReady flag are not shared resources, i.e. only one thread has an access to them.
// That's why no mutexes are required.
LoadingTask *t = mLoadingQueue.head();
mLoader->setUrl(t->url);
QDateTime dt(QDate::currentDate());
mLoader->setRange(dt.addDays(-CACHE_DAYS), dt.addDays(CACHE_DAYS));
//mLoader->setGetAll();
mLoadingQueueReady = false;
log("starting actual download job");
mLoader->start(QThread::LowestPriority);
// if all ok, removing the task from the queue
mLoadingQueue.dequeue();
delete t;
// FIXME
// Qt3 needs to wait here for the download to finish, as I am too
// lazy to set up the correct event mechanisms at this time
// The correct mechanism would be to have the thread call
// QApplication::postEvent(), have the GUI trap the event,
// and then call loadFinished()
while (mLoader->running() == true)
qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
loadFinished();
}
void ResourceCalDav::startLoading(const QString& url) {
LoadingTask *t = new LoadingTask;
t->url = url;
loadingQueuePush(t);
}
void ResourceCalDav::loadFinished() {
CalDavReader* loader = mLoader;
log("load finished");
if (!loader) {
log("loader is NULL");
return;
}
if (loader->error()) {
if (loader->errorNumber() == -401) {
if (NULL != mPrefs) {
QCString newpass;
if (KPasswordDialog::getPassword (newpass, QString("<b>") + i18n("Remote authorization required") + QString("</b><p>") + i18n("Please input the password for") + QString(" ") + mPrefs->getusername(), NULL) != 1) {
log("load error: " + loader->errorString() );
loadError(QString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString());
}
else {
// Set new password and try again
mPrefs->setPassword(QString(newpass));
startLoading(mPrefs->getFullUrl());
}
}
else {
log("load error: " + loader->errorString() );
loadError(QString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString());
}
}
else {
log("load error: " + loader->errorString() );
loadError(QString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString());
}
} else {
log("successful load");
QString data = loader->data();
if (!data.isNull() && !data.isEmpty()) {
// TODO: I don't know why, but some schedules on http://caldav-test.ioda.net/ (I used it for testing)
// have some lines separated by single \r rather than \n or \r\n.
// ICalFormat fails to parse that.
data.replace("\r\n", "\n"); // to avoid \r\n becomes \n\n after the next line
data.replace('\r', '\n');
log("trying to parse...");
if (parseData(data)) {
log("... parsing is ok");
log("clearing changes");
clearChanges();
emit resourceLoaded(this);
}
}
}
// Loading queue and mLoadingQueueReady flag are not shared resources, i.e. only one thread has an access to them.
// That's why no mutexes are required.
mLoadingQueueReady = true;
loadingQueuePop();
}
bool ResourceCalDav::checkData(const QString& data) {
log("checking the data");
ICalFormat ical;
bool ret = true;
if (!ical.fromString(&mCalendar, data)) {
log("invalid ical string");
ret = false;
}
return ret;
}
bool ResourceCalDav::parseData(const QString& data) {
log("parseData()");
bool ret = true;
// check if the data is OK
// May be it's not efficient (parsing is done twice), but it should be safe
if (!checkData(data)) {
loadError(i18n("Parsing calendar data failed."));
return false;
}
log("clearing cache");
clearCache();
emit resourceChanged(this);
disableChangeNotification();
log("actually parsing the data");
ICalFormat ical;
if ( !ical.fromString( &mCalendar, data ) ) {
// this should never happen, but...
ret = false;
}
// debug code here -------------------------------------------------------
#ifdef KCALDAV_DEBUG
const QString fout_path = "/tmp/kcaldav_download_" + identifier() + ".tmp";
QFile fout(fout_path);
if (fout.open(IO_WriteOnly | IO_Append)) {
QTextStream sout(&fout);
sout << "---------- " << resourceName() << ": --------------------------------\n";
sout << data << "\n";
fout.close();
} else {
loadError(i18n("can't open file"));
}
#endif // KCALDAV_DEBUG
// end of debug code ----------------------------------------------------
enableChangeNotification();
if (ret) {
log("parsing is ok");
//if ( !noReadOnlyOnLoad() && readOnly() ) {
if ( readOnly() ) {
log("ensuring read only flag honored");
ensureReadOnlyFlagHonored();
}
log("saving to cache");
saveCache();
}
emit resourceChanged(this);
return ret;
}
/*=========================================================================
| WRITING METHODS
========================================================================*/
QString ResourceCalDav::getICalString(const Incidence::List& inc) {
if (inc.isEmpty()) {
return "";
}
CalendarLocal loc(timeZoneId());
QString data = "";
ICalFormat ical;
// NOTE: This is very susceptible to invalid entries in added/changed/deletedIncidences
// Be very careful with clearChange/clearChanges, and be sure to clear after load and save...
for(Incidence::List::ConstIterator it = inc.constBegin(); it != inc.constEnd(); ++it) {
Incidence *i = (*it)->clone();
loc.addIncidence(i);
}
data = ical.toString(&loc);
return data;
}
void ResourceCalDav::writingQueuePush(const WritingTask *task) {
// printf("task->added: %s\n\r", task->added.ascii());
// printf("task->deleted: %s\n\r", task->deleted.ascii());
// printf("task->changed: %s\n\r", task->changed.ascii());
mWritingQueue.enqueue(task);
writingQueuePop();
}
void ResourceCalDav::writingQueuePop() {
// FIXME This crashes...
if (!mWritingQueueReady || mWritingQueue.isEmpty()) {
return;
}
if (!mWriter) {
log("writer == NULL");
return;
}
// Writing queue and mWritingQueueReady flag are not shared resources, i.e. only one thread has an access to them.
// That's why no mutexes are required.
WritingTask *t = mWritingQueue.head();
log("writingQueuePop: url = " + t->url);
mWriter->setUrl(t->url);
#ifdef KCALDAV_DEBUG
const QString fout_path = "/tmp/kcaldav_upload_" + identifier() + ".tmp";
QFile fout(fout_path);
if (fout.open(IO_WriteOnly | IO_Append)) {
QTextStream sout(&fout);
sout << "---------- " << resourceName() << ": --------------------------------\n";
sout << "================== Added:\n" << t->added << "\n";
sout << "================== Changed:\n" << t->changed << "\n";
sout << "================== Deleted:\n" << t->deleted << "\n";
fout.close();
} else {
loadError(i18n("can't open file"));
}
#endif // debug
mWriter->setAddedObjects(t->added);
mWriter->setChangedObjects(t->changed);
mWriter->setDeletedObjects(t->deleted);
mWritingQueueReady = false;
log("starting actual write job");
mWriter->start(QThread::LowestPriority);
// if all ok, remove the task from the queue
mWritingQueue.dequeue();
delete t;
// FIXME
// Qt3 needs to wait here for the download to finish, as I am too
// lazy to set up the correct event mechanisms at this time
// The correct mechanism would be to have the thread call
// QApplication::postEvent(), have the GUI trap the event,
// and then call writingFinished()
while (mWriter->running() == true)
qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
writingFinished();
}
void ResourceCalDav::startWriting(const QString& url) {
log("startWriting: url = " + url);
WritingTask *t = new WritingTask;
Incidence::List added = addedIncidences();
Incidence::List changed = changedIncidences();
Incidence::List deleted = deletedIncidences();
t->url = url;
t->added = getICalString(added); // This crashes when an event is added from the remote server and save() is subsequently called
t->changed = getICalString(changed);
t->deleted = getICalString(deleted);
writingQueuePush(t);
}
void ResourceCalDav::writingFinished() {
log("writing finished");
if (!mWriter) {
log("mWriter is NULL");
return;
}
if (mWriter->error()) {
log("error: " + mWriter->errorString());
saveError(QString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString());
} else {
log("success");
// is there something to do here?
}
// Writing queue and mWritingQueueReady flag are not shared resources, i.e. only one thread has an access to them.
// That's why no mutexes are required.
mWritingQueueReady = true;
writingQueuePop();
}
// EOF ========================================================================

@ -0,0 +1,220 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Main interface to the KResource system.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#ifndef KCAL_RESOURCECALDAV_H
#define KCAL_RESOURCECALDAV_H
#include "preferences.h"
#include <qthread.h>
#include <qptrqueue.h>
#include <libkcal/resourcecached.h>
#include <kabc/locknull.h>
#include <kdepimmacros.h>
#include <kconfig.h>
namespace KCal {
class CalDavReader;
class CalDavWriter;
/*=========================================================================
| CLASS
========================================================================*/
/**
* This class provides a resource for accessing calendars via CalDAV protocol.
*/
class KDE_EXPORT ResourceCalDav : public ResourceCached
{
Q_OBJECT
public:
explicit ResourceCalDav( const KConfig *config );
virtual ~ResourceCalDav();
void readConfig( const KConfig *config );
void writeConfig( KConfig *config );
/**
* @return This resource preferences.
*/
CalDavPrefs* prefs() {
return mPrefs;
}
/**
* @return This resource preferences.
*/
const CalDavPrefs* prefs() const {
return mPrefs;
}
virtual void setReadOnly(bool v);
protected slots:
void loadFinished();
void writingFinished();
protected:
struct LoadingTask {
QString url;
};
struct WritingTask {
QString url;
QString added;
QString changed;
QString deleted;
};
// virtual bool doLoad( bool syncCache );
// virtual bool doSave( bool syncCache );
virtual bool doLoad();
virtual bool doSave();
virtual bool doSave( bool syncCache, Incidence *incidence );
virtual KABC::Lock* lock();
/**
* Creates prefs and configures them.
* @return a newly created preferences object. It should be removed by the caller.
*/
CalDavPrefs* createPrefs() const;
/**
* Initializes internal state.
* Particulary, sets save and reload policies to default values,
* creates writing and reading jobs and preferences objects.
*/
void init();
/**
* Initiates calendar loading process.
* @param url URL to load calendar data from.
*/
void startLoading(const QString& url);
/**
* Checks if the data is correct and can be parsed.
* @param data ical string to check.
* @return true if the data is correct, false otherwise.
*/
bool checkData(const QString& data);
/**
* Parses the data and adds events to the calendar.
* @param data calendar data.
* @return true on success, false on fail.
*/
bool parseData(const QString& data);
/**
* Initiates calendar writing process.
* @param url URL to save calendar data to.
*/
void startWriting(const QString& url);
/**
* Returns a list of incidences as a valid iCalendar string.
* @param inc list of incidences.
* @return a string in iCalendar format which describes the given incidences.
*/
QString getICalString(const Incidence::List& inc);
/**
* Changes read-only status of incidences from a given list.
* @param inc list of incidences.
* @param readOnly read-only status that all the incidences should have after the method finishes.
*/
static void setIncidencesReadOnly(Incidence::List& inc, bool readOnly);
/**
* Ensures incidences' read-only states are the same as the calendar's read-only state.
*/
void ensureReadOnlyFlagHonored();
/**
* If the loading queue is empty or the loader is not ready, does nothing.
* Otherwise, pops a head element and starts a loading process for it.
*/
void loadingQueuePop();
/**
* Pushes the given loading task to the loading queue.
* Then calls loadingQueuePop.
*/
void loadingQueuePush(const LoadingTask *task);
/**
* If the writing queue is empty or the writer is not ready, does nothing.
* Otherwise, pops a head element and starts a writing process for it.
*/
void writingQueuePop();
/**
* Pushes the given writing task to the writing queue.
* Then calls writingQueuePop.
*/
void writingQueuePush(const WritingTask *task);
private:
// constants: =============================================================
/// Termination waiting time in milliseconds. Used to terminate job threads.
static const unsigned long TERMINATION_WAITING_TIME;
/**
* Resource caches only events which are from the interval [-CACHE_DAYS, CACHE_DAYS].
*/
static const int CACHE_DAYS;
static const int DEFAULT_RELOAD_INTERVAL;
static const int DEFAULT_SAVE_INTERVAL;
static const int DEFAULT_RELOAD_POLICY;
static const int DEFAULT_SAVE_POLICY;
// members: ===============================================================
KABC::LockNull mLock;
CalDavPrefs* mPrefs;
CalDavReader* mLoader;
CalDavWriter* mWriter;
bool mLoadingQueueReady;
QPtrQueue<LoadingTask> mLoadingQueue;
bool mWritingQueueReady;
QPtrQueue<WritingTask> mWritingQueue;
};
} // namespace KCal
#endif // KCAL_RESOURCECALDAV_H

@ -0,0 +1,2 @@
[Desktop Entry]
Hidden=true

@ -0,0 +1,81 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Remote calendar writing class.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#include "writer.h"
#include <kdebug.h>
/*=========================================================================
| DEFINES
========================================================================*/
// Use caldav_modify_object() function.
// If it's not set, a pair of caldav_delete_object/caldav_add_object
// is used for modifying objects.
// It's done, because, for some reason, SOGo server returns an error
// on caldav_modify_object. DAViCAL works fine both ways.
//#define USE_CALDAV_MODIFY
/*=========================================================================
| NAMESPACE
========================================================================*/
using namespace KCal;
/*=========================================================================
| METHODS
========================================================================*/
void CalDavWriter::cleanJob() {
CalDavJob::cleanJob();
}
int CalDavWriter::runJob(runtime_info* RT) {
kdDebug() << "writer::run, url: " << url() << "\n";
int res = OK;
kdDebug() << "pushing added objects";
res = pushObjects(mAdded, caldav_add_object, OK, RT);
if (OK == res) {
#ifdef USE_CALDAV_MODIFY
kdDebug() << "pushing changed objects";
res = pushObjects(mChanged, caldav_modify_object, OK, RT);
if (OK == res) {
kdDebug() << "pushing deleted objects";
res = pushObjects(mDeleted, caldav_delete_object, OK, RT);
}
#else // if USE_CALDAV_MODIFY
kdDebug() << "pushing changed objects (delete)";
res = pushObjects(mChanged, caldav_delete_object, OK, RT);
if (OK == res) {
kdDebug() << "pushing changed objects (add)";
res = pushObjects(mChanged, caldav_add_object, OK, RT);
if (OK == res) {
kdDebug() << "pushing deleted objects";
res = pushObjects(mDeleted, caldav_delete_object, OK, RT);
}
}
#endif // if USE_CALDAV_MODIFY
}
if (OK != res) {
clearObjects();
}
return res;
}
// EOF ========================================================================

@ -0,0 +1,110 @@
/*=========================================================================
| KCalDAV
|--------------------------------------------------------------------------
| (c) 2010 Timothy Pearson
| (c) 2009 Kumaran Santhanam (initial KDE4 version)
|
| This project is released under the GNU General Public License.
| Please see the file COPYING for more details.
|--------------------------------------------------------------------------
| Remote calendar writing class.
========================================================================*/
/*=========================================================================
| INCLUDES
========================================================================*/
#ifndef KCALDAV_WRITER_H
#define KCALDAV_WRITER_H
#include "job.h"
#include <string>
#include <qstring.h>
#include <qdatetime.h>
namespace KCal {
/*=========================================================================
| CLASS
========================================================================*/
/**
* Calendar writer.
*/
class CalDavWriter : public CalDavJob {
public:
/**
* @param url URL to load.
*/
CalDavWriter(const QString& url = QString()) :
CalDavJob(url)
{
clearObjects();
}
/**
* Sets the information about added incidences writer should send to server.
* @param s icalendar-formatted string consists of all added incidences plus necessary calendar info.
* May be an empty string, which means there is no added incidences to send.
*/
void setAddedObjects(const QString& s) {
mAdded = s;
}
/**
* Sets the information about changed incidences writer should send to server.
* @param s icalendar-formatted string consists of all changed incidences plus necessary calendar info.
* May be an empty string, which means there is no changed incidences to send.
*/
void setChangedObjects(const QString& s) {
mChanged = s;
}
/**
* Sets the information about deleted incidences writer should send to server.
* @param s icalendar-formatted string consists of all deleted incidences plus necessary calendar info.
* May be an empty string, which means there is no deleted incidences to send.
*/
void setDeletedObjects(const QString& s) {
mDeleted = s;
}
/**
* Clear all the information previously set.
*/
void clearObjects() {
setAddedObjects("");
setChangedObjects("");
setDeletedObjects("");
}
protected:
virtual int runJob(runtime_info* caldavRuntime);
virtual void cleanJob();
/// Just a wrapper above libcaldav functions.
template<typename Operation>
int pushObjects(const QString& data, Operation op, int okCode, runtime_info* RT) {
int r = okCode;
if (!data.isNull() && !data.isEmpty()) {
r = op(std::string(data.ascii()).c_str(), std::string(url().ascii()).c_str(), RT);
}
return r;
}
private:
QString mAdded;
QString mChanged;
QString mDeleted;
};
} // namespace KCal
#endif // KCALDAV_WRITER_H
Loading…
Cancel
Save