diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-01-26 13:17:50 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-01-26 13:17:50 -0600 |
commit | b363d2579af0a11b77e698aed2e1021c2233b644 (patch) | |
tree | f4a47b87354b7a6a3b266c8121bd8ddaeb7accaa /tderesources/caldav | |
parent | 61bddfe3a7226b18c68a76124b727c736f431688 (diff) | |
download | tdepim-b363d2579af0a11b77e698aed2e1021c2233b644.tar.gz tdepim-b363d2579af0a11b77e698aed2e1021c2233b644.zip |
Rename a number of libraries and executables to avoid conflicts with KDE4
Diffstat (limited to 'tderesources/caldav')
23 files changed, 3795 insertions, 0 deletions
diff --git a/tderesources/caldav/CMakeLists.txt b/tderesources/caldav/CMakeLists.txt new file mode 100644 index 000000000..b43b5461f --- /dev/null +++ b/tderesources/caldav/CMakeLists.txt @@ -0,0 +1,54 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include( ConfigureChecks.cmake ) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/libtdepim + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} + ${CALDAV_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} + ${CALDAV_LIBRARY_DIRS} +) + + +##### other data ################################ + +install( + FILES kcal_caldav.desktop + DESTINATION ${SERVICES_INSTALL_DIR}/tderesources/kcal ) + + +##### kcal_caldav (module) ###################### + +tde_add_kpart( kcal_caldav AUTOMOC + SOURCES plugin.cpp + LINK kcal_caldav-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) + + +##### kcal_caldav (shared) ######################### + +tde_add_library( kcal_caldav SHARED AUTOMOC + SOURCES + resource.cpp config.cpp configwidgets.cpp preferences.cpp job.cpp + reader.cpp writer.cpp prefsskel.kcfgc + VERSION 1.0.0 + LINK tdepim-shared ${CALDAV_LIBRARIES} + DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/tderesources/caldav/ConfigureChecks.cmake b/tderesources/caldav/ConfigureChecks.cmake new file mode 100644 index 000000000..e98ff721d --- /dev/null +++ b/tderesources/caldav/ConfigureChecks.cmake @@ -0,0 +1,32 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +# FIXME we need to check for patched library + +# libcaldav +pkg_search_module( CALDAV libcaldav ) +if( CALDAV_FOUND ) + execute_process( + COMMAND pkg-config libcaldav --variable=pkgincludedir + OUTPUT_VARIABLE _incdir + RESULT_VARIABLE _result + OUTPUT_STRIP_TRAILING_WHITESPACE ) + execute_process( + COMMAND pkg-config libcaldav --variable=pkglibdir + OUTPUT_VARIABLE _libdir + RESULT_VARIABLE _result + OUTPUT_STRIP_TRAILING_WHITESPACE ) + list( APPEND CALDAV_INCLUDE_DIRS ${_incdir} ) + list( APPEND CALDAV_LIBRARY_DIRS ${_libdir} ) + list( APPEND CALDAV_LIBRARIES caldav ) +else( ) + tde_message_fatal( "libcaldav is requested, but was not found on your system" ) +endif( ) diff --git a/tderesources/caldav/Makefile.am b/tderesources/caldav/Makefile.am new file mode 100644 index 000000000..7749b022a --- /dev/null +++ b/tderesources/caldav/Makefile.am @@ -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)/libtdepim/libtdepim.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)/tderesources/kcal +kcal_service_DATA = kcal_caldav.desktop + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kres_caldav.pot diff --git a/tderesources/caldav/config.cpp b/tderesources/caldav/config.cpp new file mode 100644 index 000000000..0a07aafc9 --- /dev/null +++ b/tderesources/caldav/config.cpp @@ -0,0 +1,208 @@ +/*========================================================================= +| 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 <tqlabel.h> +#include <tqlayout.h> +#include <tqcheckbox.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" << '\n'; + } + + return res; +} + +CalDavPrefs* ResourceCalDavConfig::getPrefs(ResourceCalDav* res) { + CalDavPrefs* p = NULL; + + if (res) { + p = res->prefs(); + if (!p) { + kdDebug() << "CalDAV: res->prefs() returned NULL" << '\n'; + } + } + + return p; +} + +/*========================================================================= +| CONSTRUCTOR / DESTRUCTOR + ========================================================================*/ + +ResourceCalDavConfig::ResourceCalDavConfig( TQWidget *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()); + mTasksUrl->setText(p->tasksUrl()); + mJournalsUrl->setText(p->journalsUrl()); + mUseSTasks->setChecked(p->useSTasks()); + mUseSJournals->setChecked(p->useSJournals()); + + 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()); + p->setTasksUrl(mTasksUrl->text()); + p->setUseSTasks(mUseSTasks->isChecked()); + p->setJournalsUrl(mJournalsUrl->text()); + p->setUseSJournals(mUseSJournals->isChecked()); + } + } +} + +void ResourceCalDavConfig::setupUI() { + TQVBoxLayout *vertical = new TQVBoxLayout(this); + + TQGridLayout *mainLayout = new TQGridLayout( this ); + + // URL + TQLabel *label = new TQLabel( i18n( "URL:" ), this ); + mUrl = new TQLineEdit( this ); + mainLayout->addWidget( label, 1, 0 ); + mainLayout->addWidget( mUrl, 1, 1 ); + + // Tasks URL + TQLabel *tlabel = new TQLabel( i18n( "Tasks URL:" ), this ); + mTasksUrl = new TQLineEdit( this ); + mainLayout->addWidget( tlabel, 3, 0 ); + mainLayout->addWidget( mTasksUrl, 3, 1 ); + + // Use Task URL checkbox + mUseSTasks = new TQCheckBox( i18n("Use separate Tasks URL"), this ); + mainLayout->addWidget(mUseSTasks, 2, 0 ); + + // Journals URL + TQLabel *jlabel = new TQLabel( i18n( "Journals URL:" ), this ); + mJournalsUrl = new TQLineEdit( this ); + mainLayout->addWidget( jlabel, 5, 0 ); + mainLayout->addWidget( mJournalsUrl, 5, 1 ); + + // Use Journal URL checkbox + mUseSJournals = new TQCheckBox( i18n("Use separate Journals URL"), this ); + mainLayout->addWidget(mUseSJournals, 4, 0 ); + + // Username + label = new TQLabel( i18n( "Username:" ), this ); + mUsername = new TQLineEdit( this ); + mainLayout->addWidget( label, 6, 0 ); + mainLayout->addWidget( mUsername, 6, 1 ); + + // Password + label = new TQLabel( i18n( "Password:" ), this ); + mPassword = new TQLineEdit( this ); + mPassword->setEchoMode( TQLineEdit::Password ); + mainLayout->addWidget( label, 7, 0 ); + mainLayout->addWidget( mPassword, 7, 1 ); + + // Remember password checkbox + mRememberPassword = new TQCheckBox( i18n("Remember password"), this ); + mainLayout->addWidget(mRememberPassword, 8, 1); + + mTasksUrl->setEnabled(mUseSTasks->isChecked()); + connect( mUseSTasks, TQT_SIGNAL( toggled( bool ) ), + TQT_SLOT( slotSTasksToggled( bool ) ) ); + + mJournalsUrl->setEnabled(mUseSJournals->isChecked()); + connect( mUseSJournals, TQT_SIGNAL( toggled( bool ) ), + TQT_SLOT( slotSJournalsToggled( bool ) ) ); + + // configs + TQHBoxLayout* horizontal = new TQHBoxLayout(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); +} + +void ResourceCalDavConfig::slotSTasksToggled( bool enabled ) { + mTasksUrl->setEnabled(enabled); +} + +void ResourceCalDavConfig::slotSJournalsToggled( bool enabled ) { + mJournalsUrl->setEnabled(enabled); +} + +#include "config.moc" + +// EOF ======================================================================== diff --git a/tderesources/caldav/config.h b/tderesources/caldav/config.h new file mode 100644 index 000000000..fe03114c3 --- /dev/null +++ b/tderesources/caldav/config.h @@ -0,0 +1,88 @@ +/*========================================================================= +| 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 <tderesources/configwidget.h> + +class TQLineEdit; +class TQCheckBox; + +namespace KCal { + +class CalDavReloadConfig; +class CalDavSaveConfig; + +/*========================================================================= +| CLASS + ========================================================================*/ + +/** + * Configuration widget for CalDAV resource. + */ +class KDE_EXPORT ResourceCalDavConfig : public KRES::ConfigWidget +{ + Q_OBJECT + + +public: + + ResourceCalDavConfig(TQWidget *parent = 0); + +public slots: + + virtual void loadSettings(KRES::Resource *resource); + virtual void saveSettings(KRES::Resource *resource); + + void slotSTasksToggled( bool ); + void slotSJournalsToggled( bool ); + +protected: + + virtual void setupUI(); + +private: + + TQLineEdit *mUrl; + TQLineEdit *mTasksUrl; + TQLineEdit *mJournalsUrl; + TQLineEdit *mUsername; + TQLineEdit *mPassword; + TQCheckBox *mUseSTasks; + TQCheckBox *mUseSJournals; + TQCheckBox *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 + diff --git a/tderesources/caldav/configwidgets.cpp b/tderesources/caldav/configwidgets.cpp new file mode 100644 index 000000000..ab8c79050 --- /dev/null +++ b/tderesources/caldav/configwidgets.cpp @@ -0,0 +1,249 @@ +/*========================================================================= +| 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 <tqlabel.h> +#include <tqlayout.h> +#include <tqcheckbox.h> +#include <tqradiobutton.h> +#include <tqspinbox.h> +#include <tqbuttongroup.h> +#include <tqgroupbox.h> +#include <tqhbox.h> + +using namespace KCal; + +//@cond PRIVATE +class CalDavConfigPrivate +{ + public: + CalDavConfigPrivate() + : mGroup( 0 ), + mIntervalSpin( 0 ) {} + + TQButtonGroup *mGroup; + TQSpinBox *mIntervalSpin; +}; + +class CalDavReloadConfig::Private + : public CalDavConfigPrivate +{ +}; + +class CalDavSaveConfig::Private + : public CalDavConfigPrivate +{ +}; +//@endcond + +CalDavReloadConfig::CalDavReloadConfig( TQWidget *parent ) + : TQWidget( parent ), d( new KCal::CalDavReloadConfig::Private() ) +{ + TQBoxLayout *topLayout = new TQVBoxLayout( this ); + + //TQGroupBox *groupBox = new TQGroupBox( i18nc( "@title:group", "Automatic Reload" ), this ); + TQGroupBox *groupBox = new TQGroupBox( i18n( "Automatic Reload" ), this ); + topLayout->addWidget( groupBox ); + + TQRadioButton *noAutomaticReload = + new TQRadioButton( + //i18nc( "@option:radio never reload the cache", "Never" ), groupBox ); + i18n( "Never" ), groupBox ); + TQRadioButton *automaticReloadOnStartup = + new TQRadioButton( + //i18nc( "@option:radio reload the cache on startup", "Only on startup" ), groupBox ); + i18n( "Only on startup" ), groupBox ); + TQRadioButton *intervalRadio = + new TQRadioButton( +// i18nc( "@option:radio reload the cache at regular intervals", +// "Regular interval" ), groupBox ); + i18n( "Regular interval" ), groupBox ); + + d->mGroup = new TQButtonGroup( this ); + d->mGroup->hide(); + d->mGroup->insert( intervalRadio, 2 ); + d->mGroup->insert( automaticReloadOnStartup, 1 ); + d->mGroup->insert( noAutomaticReload, 0 ); + + connect( intervalRadio, TQT_SIGNAL( toggled( bool ) ), + TQT_SLOT( slotIntervalToggled( bool ) ) ); + + TQHBox *intervalBox = new TQHBox( groupBox ); + //new TQLabel( i18nc( "@label:spinbox", "Interval in minutes:" ), intervalBox ); + new TQLabel( i18n( "Interval in minutes:" ), intervalBox ); + d->mIntervalSpin = new TQSpinBox( intervalBox ); + d->mIntervalSpin->setRange( 1, 900 ); + d->mIntervalSpin->setEnabled( false ); + + groupBox->setColumnLayout(1, Qt::Vertical); + TQVBoxLayout *vbox = new TQVBoxLayout(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( TQWidget *parent ) + : TQWidget( parent ), d( new KCal::CalDavSaveConfig::Private() ) +{ + TQBoxLayout *topLayout = new TQVBoxLayout( this ); + + //TQGroupBox *groupBox = new TQGroupBox( i18nc( "@title:group", "Automatic Save" ), this ); + TQGroupBox *groupBox = new TQGroupBox( i18n( "Automatic Save" ), this ); + d->mGroup = new TQButtonGroup( this ); + d->mGroup->hide(); + topLayout->addWidget( groupBox ); + + TQRadioButton *never = + new TQRadioButton( + //i18nc( "@option:radio never save the cache automatically", "Never" ), groupBox ); + i18n( "Never" ), groupBox ); + TQRadioButton *onExit = + new TQRadioButton( + //i18nc( "@option:radio save the cache on exit", "Only on exit" ), groupBox ); + i18n( "Only on exit" ), groupBox ); + + TQRadioButton *intervalRadio = + new TQRadioButton( + //i18nc( "@option:radio save the cache at regular intervals", "Regular interval" ), groupBox ); + i18n( "Regular interval" ), groupBox ); + + d->mGroup = new TQButtonGroup( this ); + d->mGroup->hide(); + d->mGroup->insert( never, 0 ); + d->mGroup->insert( onExit, 1 ); + d->mGroup->insert( intervalRadio, 2 ); + + connect( intervalRadio, TQT_SIGNAL( toggled( bool ) ), + TQT_SLOT( slotIntervalToggled( bool ) ) ); + + TQHBox *intervalBox = new TQHBox( groupBox ); + //new TQLabel( i18nc( "@label:spinbox", "Interval in minutes:" ), intervalBox ); + new TQLabel( i18n( "Interval in minutes:" ), intervalBox ); + d->mIntervalSpin = new TQSpinBox( intervalBox ); + d->mIntervalSpin->setRange( 1, 900 ); + d->mIntervalSpin->setEnabled( false ); + + TQRadioButton *delay = + new TQRadioButton( +// i18nc( "@option:radio save the cache after some delay", +// "Delayed after changes" ), groupBox ); + i18n( "Delayed after changes" ), groupBox ); + TQRadioButton *every = + new TQRadioButton( +// 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); + TQVBoxLayout *vbox = new TQVBoxLayout(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 ); + } +} + +#include "configwidgets.moc" + +// EOF ======================================================================== diff --git a/tderesources/caldav/configwidgets.h b/tderesources/caldav/configwidgets.h new file mode 100644 index 000000000..1e5248446 --- /dev/null +++ b/tderesources/caldav/configwidgets.h @@ -0,0 +1,102 @@ +/*========================================================================= +| 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 <tqwidget.h> +#include <kdemacros.h> + +namespace KCal { + +class ResourceCached; + +/** + Configuration widget for reload policy + + @see ResourceCached +*/ +class KDE_EXPORT CalDavReloadConfig : public TQWidget +{ + Q_OBJECT + + public: + explicit CalDavReloadConfig( TQWidget *parent = 0 ); + ~CalDavReloadConfig(); + public slots: + void loadSettings( ResourceCached *resource ); + void saveSettings( ResourceCached *resource ); + + protected slots: + void slotIntervalToggled( bool ); + + private: + //@cond PRIVATE + //TQ_DISABLE_COPY( CalDavReloadConfig ) + class Private; + Private *const d; + //@endcond +}; + +/** + Configuration widget for save policy + + @see ResourceCached +*/ +class KDE_EXPORT CalDavSaveConfig : public TQWidget +{ + Q_OBJECT + + public: + explicit CalDavSaveConfig( TQWidget *parent = 0 ); + ~CalDavSaveConfig(); + + public slots: + void loadSettings( ResourceCached *resource ); + void saveSettings( ResourceCached *resource ); + + protected slots: + void slotIntervalToggled( bool ); + + private: + //@cond PRIVATE + //TQ_DISABLE_COPY( CalDavSaveConfig ) + class Private; + Private *const d; + //@endcond +}; + +} + +#endif // KCALDAV_AUTOWIDGETS_H diff --git a/tderesources/caldav/export.h b/tderesources/caldav/export.h new file mode 100644 index 000000000..c439f53f4 --- /dev/null +++ b/tderesources/caldav/export.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_TDEPIM_EXPORT_H +#define KRESOURCES_TDEPIM_EXPORT_H + +/** Exports a function returning tderesources 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() { TDEGlobal::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() { TDEGlobal::locale()->insertCatalogue(catalog1); \ + TDEGlobal::locale()->insertCatalogue(catalog2); } \ + }; \ + K_EXPORT_PLUGIN( Factory ) + +#endif diff --git a/tderesources/caldav/job.cpp b/tderesources/caldav/job.cpp new file mode 100644 index 000000000..93f91cd52 --- /dev/null +++ b/tderesources/caldav/job.cpp @@ -0,0 +1,173 @@ +/*========================================================================= +| 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 <klocale.h> + +#include <tqmutex.h> + +#define log(s) kdDebug() << s << '\n'; + +/*========================================================================= +| NAMESPACE + ========================================================================*/ + +using namespace KCal; + +/*========================================================================= +| STATIC + ========================================================================*/ + +/*========================================================================= +| CONSTRUCTOR AND DESTRUCTOR + ========================================================================*/ + +CalDavJob::CalDavJob(const TQString& 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 TQString& err, const long number) { + mError = true; + mErrorString = err; + mErrorNumber = number; +} + +void CalDavJob::setTasksErrorString(const TQString& err, const long number) { + mTasksError = true; + mTasksErrorString = err; + mTasksErrorNumber = number; +} + +void CalDavJob::setJournalsErrorString(const TQString& err, const long number) { + mJournalsError = true; + mJournalsErrorString = err; + mJournalsErrorNumber = number; +} + +void CalDavJob::processError(const caldav_error* err) { + TQString 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. Please ensure that the URL is a valid CalDAV resource.").arg(-code); + } else { + error_string = err->str; + } + + setErrorString(error_string, code); +} + +void CalDavJob::processTasksError(const caldav_error* err) { + TQString 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. Please ensure that the URL is a valid CalDAV resource.").arg(-code); + } else { + error_string = err->str; + } + + setTasksErrorString(error_string, code); +} + +void CalDavJob::processJournalsError(const caldav_error* err) { + TQString 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. Please ensure that the URL is a valid CalDAV resource.").arg(-code); + } else { + error_string = err->str; + } + + setJournalsErrorString(error_string, code); +} + + +void CalDavJob::run() { + log("cleaning job"); + cleanJob(); + + int res = OK; + int tasksres = OK; + int journalsres = 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 event job"); + res = runJob(caldav_runtime); + + if (OK != res) { + log("event job failed"); + processError(caldav_runtime->error); + } + + log("running tasks job"); + tasksres = runTasksJob(caldav_runtime); + + if (OK != tasksres) { + log("tasks job failed"); + processTasksError(caldav_runtime->error); + } + + log("running journals job"); + journalsres = runJournalsJob(caldav_runtime); + + if (OK != journalsres) { + log("journals job failed"); + processJournalsError(caldav_runtime->error); + } + + caldav_free_runtime_info(&caldav_runtime); + + // Signal done + // 1000 is read, 1001 is write + if (type() == 0) TQApplication::postEvent ( parent(), new TQEvent( static_cast<TQEvent::Type>(1000) ) ); + if (type() == 1) TQApplication::postEvent ( parent(), new TQEvent( static_cast<TQEvent::Type>(1001) ) ); +} + +// EOF ======================================================================== diff --git a/tderesources/caldav/job.h b/tderesources/caldav/job.h new file mode 100644 index 000000000..7d312d90b --- /dev/null +++ b/tderesources/caldav/job.h @@ -0,0 +1,290 @@ +/*========================================================================= +| 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 <tqthread.h> +#include <tqstring.h> +#include <tqdatetime.h> +#include <tqapplication.h> + +extern "C" { + #include <caldav.h> +} + +namespace KCal { + +/*========================================================================= +| CLASS + ========================================================================*/ + +/** + * Calendar job. + */ +class CalDavJob : public TQThread { + +public: + + /** + * @param url URL to load. + */ + CalDavJob(const TQString& url = TQString()); + + virtual ~CalDavJob(); + + /** + * Sets a new URL to load. + */ + virtual void setUrl(const TQString& s) { + mUrl = s; + } + + /** + * Sets a new Tasks URL to load. + */ + virtual void setTasksUrl(const TQString& s) { + mTasksUrl = s; + } + + /** + * Sets a new Journals URL to load. + */ + virtual void setJournalsUrl(const TQString& s) { + mJournalsUrl = s; + } + + /** + * Sets the parent qobject. + */ + virtual void setParent(TQObject *s) { + mParent = s; + } + + /** + * Sets the type (0==read, 1==write) + */ + virtual void setType(int s) { + mType = s; + } + + /** + * @return URL to load. + */ + virtual TQString url() const { + return mUrl; + } + + /** + * @return Tasks URL to load. + */ + virtual TQString tasksUrl() const { + return mTasksUrl; + } + + /** + * @return Journals URL to load. + */ + virtual TQString journalsUrl() const { + return mJournalsUrl; + } + + /** + * @return parent object + */ + virtual TQObject *parent() { + return mParent; + } + + /** + * @return type + */ + virtual int type() { + return mType; + } + + /** + * @return true if events downloading process failed. + */ + virtual bool error() const { + return mError; + } + + /** + * @return true if tasks downloading process failed. + */ + virtual bool tasksError() const { + return mTasksError; + } + + /** + * @return true if journals downloading process failed. + */ + virtual bool journalsError() const { + return mJournalsError; + } + + /** + * @return an event error string. + */ + virtual TQString errorString() const { + return mErrorString; + } + + /** + * @return a task error string. + */ + virtual TQString tasksErrorString() const { + return mTasksErrorString; + } + + /** + * @return a journal error string. + */ + virtual TQString journalsErrorString() const { + return mJournalsErrorString; + } + + /** + * @return an event error number. + */ + virtual long errorNumber() const { + return mErrorNumber; + } + + /** + * @return a task error number. + */ + virtual long tasksErrorNumber() const { + return mTasksErrorNumber; + } + + /** + * @return a journal error number. + */ + virtual long journalsErrorNumber() const { + return mJournalsErrorNumber; + } + +protected: + + virtual void run(); + + /** + * Main run method for event 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; + + /** + * Main run method for task 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 runTasksJob(runtime_info* caldavRuntime) = 0; + + /** + * Main run method for journal 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 runJournalsJob(runtime_info* caldavRuntime) = 0; + + /** + * Some cleaning. Jobs may (and usually should) override this method. + */ + virtual void cleanJob() { + mError = false; + mErrorString = ""; + mErrorNumber = 0; + mTasksError = false; + mTasksErrorString = ""; + mTasksErrorNumber = 0; + mJournalsError = false; + mJournalsErrorString = ""; + mJournalsErrorNumber = 0; + } + + /** + * Sets an event error string to @p err. Also sets an error flag. + */ + void setErrorString(const TQString& str, const long number); + + /** + * Sets a task error string to @p err. Also sets an error flag. + */ + void setTasksErrorString(const TQString& str, const long number); + + /** + * Sets a journal error string to @p err. Also sets an error flag. + */ + void setJournalsErrorString(const TQString& str, const long number); + + /** + * Process an event 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); + + /** + * Process a task 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 processTasksError(const caldav_error* err); + + /** + * Process a journal 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 processJournalsError(const caldav_error* err); + +private: + + TQString mUrl; + TQString mTasksUrl; + TQString mJournalsUrl; + bool mError; + bool mTasksError; + bool mJournalsError; + TQString mErrorString; + TQString mTasksErrorString; + TQString mJournalsErrorString; + long mErrorNumber; + long mTasksErrorNumber; + long mJournalsErrorNumber; + TQObject *mParent; + int mType; + + void enableCaldavDebug(runtime_info*); +}; + +} // namespace KCal + +#endif // KCALDAV_JOB_H + diff --git a/tderesources/caldav/kcal_caldav.desktop b/tderesources/caldav/kcal_caldav.desktop new file mode 100644 index 000000000..b237c04b4 --- /dev/null +++ b/tderesources/caldav/kcal_caldav.desktop @@ -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-TDE-Library=kcal_caldav +Type=Service +ServiceTypes=KResources/Plugin +X-TDE-ResourceFamily=calendar +X-TDE-ResourceType=caldav diff --git a/tderesources/caldav/plugin.cpp b/tderesources/caldav/plugin.cpp new file mode 100644 index 000000000..9ce6d60f6 --- /dev/null +++ b/tderesources/caldav/plugin.cpp @@ -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() + { + TDEGlobal::locale()->insertCatalogue( "libkcal" ); + TDEGlobal::locale()->insertCatalogue( "kres_caldav" ); + return new CalDavFactory; + } +} + +// EOF ======================================================================== diff --git a/tderesources/caldav/preferences.cpp b/tderesources/caldav/preferences.cpp new file mode 100644 index 000000000..5286d0220 --- /dev/null +++ b/tderesources/caldav/preferences.cpp @@ -0,0 +1,290 @@ +/*========================================================================= +| 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 <tdewallet.h> +#include <tqstring.h> +#include <tqurl.h> +#include <kdebug.h> + +/*========================================================================= +| NAMESPACES + ========================================================================*/ + +using namespace KCal; +using namespace KWallet; + +/*========================================================================= +| CONSTANTS + ========================================================================*/ + +const TQString CalDavPrefs::NO_PASSWORD = ""; +const TQString CalDavPrefs::WALLET_FOLDER = "CalDAV resource"; +const TQString CalDavPrefs::WALLET_PWD_SUFFIX = ":caldav_password"; + +/*========================================================================= +| METHODS + ========================================================================*/ + +bool CalDavPrefs::setWalletFolder(const TQString& 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 << '\n'; + + 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 TQString& prefix) { + TDEConfigSkeletonItem::List itemList = items(); + TDEConfigSkeletonItem::List::Iterator it; + + for ( it = itemList.begin(); it != itemList.end(); ++it ) { + (*it)->setGroup( prefix + ':' + (*it)->group() ); + } +} + +bool CalDavPrefs::writePasswordToWallet(const TQString& 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(TQString& password) { + Wallet* w = getWallet(); + + bool ret = false; + if (NULL != w) { + TQString 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 TQString& p) { + + mPassword = p; + + if (rememberPassword()) { + writePasswordToWallet(p); + } +} + +TQString CalDavPrefs::password() { + if (NO_PASSWORD == mPassword) { + readPasswordFromWallet(mPassword); + } + return mPassword; +} + +TQString CalDavPrefs::getusername() { + return username(); +} + +void CalDavPrefs::setRememberPassword(bool v) { + kdDebug() << "remember: " << v << '\n'; + + 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" << '\n'; + 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(); + }*/ +} + +TQString CalDavPrefs::getFullUrl() { + + TQUrl t(url()); + TQString safeURL; + int firstAt; + + t.setUser(username()); + t.setPassword(password()); + + safeURL = t.toString(); + + firstAt = safeURL.find("@") + 1; + while (safeURL.find("@", firstAt) != -1) { + safeURL.replace(safeURL.find("@", firstAt), 1, "%40"); + } + + // Unencode the username, as Zimbra stupidly rejects the %40 + safeURL.replace("%40", "@"); + + // Encode any spaces, as libcaldav stupidly fails otherwise + safeURL.replace(" ", "%20"); + + return safeURL; +} + +TQString CalDavPrefs::getFullTasksUrl() { + if (useSTasks() == 0) + return getFullUrl(); + + TQUrl t(tasksUrl()); + TQString safeURL; + int firstAt; + + t.setUser(username()); + t.setPassword(password()); + + safeURL = t.toString(); + + firstAt = safeURL.find("@") + 1; + while (safeURL.find("@", firstAt) != -1) { + safeURL.replace(safeURL.find("@", firstAt), 1, "%40"); + } + + // Unencode the username, as Zimbra stupidly rejects the %40 + safeURL.replace("%40", "@"); + + // Encode any spaces, as libcaldav stupidly fails otherwise + safeURL.replace(" ", "%20"); + + return safeURL; +} + +TQString CalDavPrefs::getFullJournalsUrl() { + if (useSJournals() == 0) + return getFullUrl(); + + TQUrl t(journalsUrl()); + TQString safeURL; + int firstAt; + + t.setUser(username()); + t.setPassword(password()); + + safeURL = t.toString(); + + firstAt = safeURL.find("@") + 1; + while (safeURL.find("@", firstAt) != -1) { + safeURL.replace(safeURL.find("@", firstAt), 1, "%40"); + } + + // Unencode the username, as Zimbra stupidly rejects the %40 + safeURL.replace("%40", "@"); + + // Encode any spaces, as libcaldav stupidly fails otherwise + safeURL.replace(" ", "%20"); + + return safeURL; +} + +// EOF ======================================================================== + diff --git a/tderesources/caldav/preferences.h b/tderesources/caldav/preferences.h new file mode 100644 index 000000000..0c4532cf9 --- /dev/null +++ b/tderesources/caldav/preferences.h @@ -0,0 +1,164 @@ +/*========================================================================= +| 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 <tdewallet.h> +#include <kdebug.h> + +class TQString; + +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 TQString& prefix) + : mWallet(NULL) + , mNoWallet(false) + , mPrefix(prefix) + , mPassword(NO_PASSWORD) + { + addPrefix(prefix); + } + + virtual ~CalDavPrefs() { + kdDebug() << "removing wallet" << '\n'; + 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 TQString& p); + + /** + * Returns password. The password is taken from the wallet. + * May return an empty string, if there is no password available. + */ + TQString password(); + + /** + * Returns the username. + */ + TQString getusername(); + + void setRememberPassword(bool v); + + /** + * @return A full URL to connect to CalDAV server (including username and password). + */ + TQString getFullUrl(); + + /** + * @return A full URL to connect to CalDAV Tasks server (including username and password). + */ + TQString getFullTasksUrl(); + + /** + * @return A full URL to connect to CalDAV Journals server (including username and password). + */ + TQString getFullJournalsUrl(); + +protected: + + /** + * Add an unique prefix to TDEConfigGroup, so that different instances of the resource + * can use the same config file. + * @param prefix Unique prefix of the resource instance. + */ + void addPrefix(const TQString& 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 TQString& 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 TQString& password); + + /** + * Extracts password from the wallet. + * @param password a variable to save read password to. + * @return true on success, false on failure + */ + bool readPasswordFromWallet(TQString& password); + + /** + * Clears password in the wallet. + * @return true on success, false on failure + */ + bool removePasswordFromWallet(); + +private: + + static const TQString NO_PASSWORD; + static const TQString WALLET_FOLDER; + static const TQString WALLET_PWD_SUFFIX; + + KWallet::Wallet* mWallet; + bool mNoWallet; + + TQString mPrefix; + TQString mPassword; +}; + +} // namespace KCal + +#endif // KCAL_CALDAVPREFS_H + + diff --git a/tderesources/caldav/prefsskel.kcfg b/tderesources/caldav/prefsskel.kcfg new file mode 100644 index 000000000..5f4cdc16a --- /dev/null +++ b/tderesources/caldav/prefsskel.kcfg @@ -0,0 +1,44 @@ +<?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="tderesources_caldavrc" /> + <group name="General" > + + <entry key="Url" type="String" > + <label>URL</label> + </entry> + + <entry key="TasksUrl" type="String" > + <label>URL</label> + </entry> + + <entry key="JournalsUrl" type="String" > + <label>URL</label> + </entry> + + <entry key="UseSTasks" type="Bool" > + <label>Use separate Tasks URL</label> + <default>false</default> + </entry> + + <entry key="UseSJournals" type="Bool" > + <label>Use separate Journals URL</label> + <default>false</default> + </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> diff --git a/tderesources/caldav/prefsskel.kcfgc b/tderesources/caldav/prefsskel.kcfgc new file mode 100644 index 000000000..b6b3aae0b --- /dev/null +++ b/tderesources/caldav/prefsskel.kcfgc @@ -0,0 +1,7 @@ +# Code generation options for kconfig_compiler +File=prefsskel.kcfg +ClassName=CalDavPrefsSkel +NameSpace=KCal +Singleton=false +Mutators=true +GlobalEnums=true diff --git a/tderesources/caldav/reader.cpp b/tderesources/caldav/reader.cpp new file mode 100644 index 000000000..92501e4f7 --- /dev/null +++ b/tderesources/caldav/reader.cpp @@ -0,0 +1,146 @@ +/*========================================================================= +| 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> +#include <string> + +/*========================================================================= +| NAMESPACE + ========================================================================*/ + +using namespace KCal; + +/*========================================================================= +| METHODS + ========================================================================*/ + +void CalDavReader::cleanJob() { + CalDavJob::cleanJob(); + mData = ""; +} + +void CalDavReader::cleanTasksJob() { + CalDavJob::cleanJob(); + mTasksData = ""; +} + +void CalDavReader::cleanJournalsJob() { + CalDavJob::cleanJob(); + mJournalsData = ""; +} + +int CalDavReader::runJob(runtime_info* RT) { + kdDebug() << "reader::run, url: " << url() << '\n'; + + response* result = caldav_get_response(); + CALDAV_RESPONSE res = OK; + + if ((OK == res) && (url() != "")) { + if (mGetAll) { + kdDebug() << "getting all objects" << '\n'; + res = caldav_getall_object(result, std::string(url().ascii()).c_str(), RT); + } else { + kdDebug() << "getting object from the specified time range" << '\n'; + res = caldav_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(url().ascii()).c_str(), RT); + } + + if (OK == res) { + kdDebug() << "success" << '\n'; + if (result->msg) { + mData = result->msg; + } else { + kdDebug() << "empty collection" << '\n'; + // empty collection + mData = ""; + } + } + } + + caldav_free_response(&result); + + return res; +} + +int CalDavReader::runTasksJob(runtime_info* RT) { + kdDebug() << "reader::run, tasksUrl: " << tasksUrl() << '\n'; + + response* result = caldav_get_response(); + CALDAV_RESPONSE tasksres = OK; + + if ((OK == tasksres) && (tasksUrl() != "")) { + kdDebug() << "reader::run, url: " << tasksUrl() << '\n'; + + if (mGetAll) { + kdDebug() << "getting all objects" << '\n'; + tasksres = caldav_tasks_getall_object(result, std::string(tasksUrl().ascii()).c_str(), RT); + } else { + kdDebug() << "getting object from the specified time range" << '\n'; + tasksres = caldav_tasks_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(tasksUrl().ascii()).c_str(), RT); + } + + if (OK == tasksres) { + kdDebug() << "success" << '\n'; + if (result->msg) { + mTasksData = result->msg; + } else { + kdDebug() << "empty collection" << '\n'; + // empty collection + mTasksData = ""; + } + } + + caldav_free_response(&result); + } + + return tasksres; +} + +int CalDavReader::runJournalsJob(runtime_info* RT) { + kdDebug() << "reader::run, journalsUrl: " << journalsUrl() << '\n'; + + response* result = caldav_get_response(); + CALDAV_RESPONSE journalsres = OK; + + if ((OK == journalsres) && (journalsUrl() != "")) { + kdDebug() << "reader::run, url: " << journalsUrl() << '\n'; + + if (mGetAll) { + kdDebug() << "getting all objects" << '\n'; + journalsres = caldav_tasks_getall_object(result, std::string(journalsUrl().ascii()).c_str(), RT); + } else { + kdDebug() << "getting object from the specified time range" << '\n'; + journalsres = caldav_tasks_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(journalsUrl().ascii()).c_str(), RT); + } + + if (OK == journalsres) { + kdDebug() << "success" << '\n'; + if (result->msg) { + mJournalsData = result->msg; + } else { + kdDebug() << "empty collection" << '\n'; + // empty collection + mJournalsData = ""; + } + } + + caldav_free_response(&result); + } + + return journalsres; +} + +// EOF ======================================================================== diff --git a/tderesources/caldav/reader.h b/tderesources/caldav/reader.h new file mode 100644 index 000000000..9bcc8c87a --- /dev/null +++ b/tderesources/caldav/reader.h @@ -0,0 +1,112 @@ +/*========================================================================= +| 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 <tqstring.h> +#include <tqdatetime.h> + +namespace KCal { + +/*========================================================================= +| CLASS + ========================================================================*/ + +/** + * Calendar Reader. + */ +class CalDavReader : public CalDavJob { + +public: + + /** + * @param url URL to load. + */ + CalDavReader(const TQString& url = TQString()) : + 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 TQDateTime& start, const TQDateTime& 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. + */ + TQString data() const { + return mData; + } + + /** + * @return downloaded task data in iCal format. + */ + TQString tasksData() const { + return mTasksData; + } + + /** + * @return downloaded journal data in iCal format. + */ + TQString journalsData() const { + return mJournalsData; + } + +protected: + + virtual int runJob(runtime_info* caldavRuntime); + virtual int runTasksJob(runtime_info* caldavRuntime); + virtual int runJournalsJob(runtime_info* caldavRuntime); + + virtual void cleanJob(); + virtual void cleanTasksJob(); + virtual void cleanJournalsJob(); + +private: + + TQString mData; + TQString mTasksData; + TQString mJournalsData; + bool mGetAll; + TQDateTime mTimeStart; + TQDateTime mTimeEnd; + +}; + +} // namespace KCal + +#endif // KCALDAV_LOADER_H + diff --git a/tderesources/caldav/resource.cpp b/tderesources/caldav/resource.cpp new file mode 100644 index 000000000..b9285e611 --- /dev/null +++ b/tderesources/caldav/resource.cpp @@ -0,0 +1,1011 @@ +/*========================================================================= +| 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 <unistd.h> + +#include <tqurl.h> +#include <tqmessagebox.h> +#include <tqapplication.h> +#include <tqeventloop.h> + +#include <libkcal/calendarlocal.h> +#include <libkcal/icalformat.h> + +#include <klocale.h> +#include <kpassdlg.h> + +#include <tqdatetime.h> +#include <tqmutex.h> +#include <tqthread.h> + +#ifdef KCALDAV_DEBUG + #include <tqfile.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) << '\n'; + +/*========================================================================= +| CONSTRUCTOR / DESTRUCTOR + ========================================================================*/ + +ResourceCalDav::ResourceCalDav( const TDEConfig *config ) : + ResourceCached(config) + , readLockout(false) + , mAllWritesComplete(false) + , mLock(true) + , mPrefs(NULL) + , mLoader(NULL) + , mWriter(NULL) + , mProgress(NULL) + , mLoadingQueueReady(true) + , mWritingQueueReady(true) + , mWriteRetryTimer(NULL) +{ + log("ResourceCalDav(config)"); + init(); + + if ( config ) { + readConfig( config ); + } +} + +ResourceCalDav::~ResourceCalDav() { + log("jobs termination"); + + if (mWriteRetryTimer != NULL) { + mWriteRetryTimer->stop(); // Unfortunately we cannot do anything at this point; if this timer is still running something is seriously wrong + } + + if (mLoader) { + readLockout = true; + mLoader->terminate(); + mLoader->wait(TERMINATION_WAITING_TIME); + mLoadingQueueReady = true; + } + + while ((mWriter->running() == true) || (mWritingQueue.isEmpty() == false) || !mWritingQueueReady) { + readLockout = true; + sleep(1); + tqApp->processEvents(TQEventLoop::ExcludeUserInput); + } + + 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; +} + +bool ResourceCalDav::isSaving() { + doSave(); + return (((mWriteRetryTimer != NULL) ? 1 : 0) || (mWriter->running() == true) || (mWritingQueue.isEmpty() == false) || !mWritingQueueReady || readLockout); +} + +/*========================================================================= +| GENERAL METHODS + ========================================================================*/ + +bool ResourceCalDav::doLoad() { + bool syncCache = true; + + if ((mLoadingQueueReady == false) || (mLoadingQueue.isEmpty() == false) || (mLoader->running() == true) || (isSaving() == true)) { + return true; // Silently fail; the user has obviously not responded to a dialog and we don't need to pop up more of them! + } + + log(TQString("doLoad(%1)").arg(syncCache)); + + clearCache(); + + log("loading from cache"); + disableChangeNotification(); + loadCache(); + enableChangeNotification(); + clearChanges(); // TODO: Determine if this really needs to be here, as it might clear out the calendar prematurely causing user confusion while the download process is running + emit resourceChanged(this); + emit resourceLoaded(this); + + log("starting download job"); + startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); + + return true; +} + +bool ResourceCalDav::doSave() { + bool syncCache = true; + + log(TQString("doSave(%1)").arg(syncCache)); + + if (!hasChanges()) { + log("no changes"); + return true; + } + + log("saving cache"); + saveCache(); + + // Delete any queued read jobs + mLoadingQueue.clear(); + + // See if there is a running read thread and terminate it + if (mLoader->running() == true) { + mLoader->terminate(); + mLoader->wait(TERMINATION_WAITING_TIME); + mLoadingQueueReady = true; + } + + log("start writing job"); + if (startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()) == true) { + 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(); + if (mWriteRetryTimer != NULL) { + if (mWriteRetryTimer->isActive() == false) { + disconnect( mWriteRetryTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(doSave()) ); + delete mWriteRetryTimer; + mWriteRetryTimer = NULL; + } + } + return true; + } + else return true; // We do not need to alert the user to this transient failure; a timer has been started to retry the save +} + + +KABC::Lock* ResourceCalDav::lock() { + log("lock()"); + return &mLock; +} + +void ResourceCalDav::readConfig( const TDEConfig *config ) { + log("readConfig"); + mPrefs->readConfig(); + ResourceCached::readConfig(config); +} + +void ResourceCalDav::writeConfig( TDEConfig *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 reader/writer instances + mLoader = new CalDavReader; + mWriter = new CalDavWriter; + + // creating jobs + // TQt4 handles this quite differently, as shown below, + // whereas TQt3 needs events (see ::event()) +// connect(mLoader, TQT_SIGNAL(finished()), this, TQT_SLOT(loadFinished())); +// connect(mWriter, TQT_SIGNAL(finished()), this, TQT_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(); +} + +void ResourceCalDav::updateProgressBar(int direction) { + int current_queued_events; + static int original_queued_events; + + // See if anything is in the queues + current_queued_events = mWritingQueue.count() + mLoadingQueue.count(); + if ((direction == 0) && (mLoader->running() == true)) current_queued_events++; + if ((direction == 1) && (mWriter->running() == true)) current_queued_events++; + if (current_queued_events > original_queued_events) { + original_queued_events = current_queued_events; + } + + if (current_queued_events == 0) { + if ( mProgress != NULL) { + mProgress->setComplete(); + mProgress = NULL; + original_queued_events = 0; + } + } + else { + if (mProgress == NULL) { + if (direction == 0) mProgress = KPIM::ProgressManager::createProgressItem(KPIM::ProgressManager::getUniqueID(), i18n("Downloading Calendar") ); + if (direction == 1) mProgress = KPIM::ProgressManager::createProgressItem(KPIM::ProgressManager::getUniqueID(), i18n("Uploading Calendar") ); + } + mProgress->setProgress( ((((float)original_queued_events-(float)current_queued_events)*100)/(float)original_queued_events) ); + } +} + +/*========================================================================= +| READING METHODS + ========================================================================*/ + +void ResourceCalDav::loadingQueuePush(const LoadingTask *task) { + if ((mLoadingQueue.isEmpty() == true) && (mLoader->running() == false)) { + mLoadingQueue.enqueue(task); + updateProgressBar(0); + loadingQueuePop(); + } +} + +void ResourceCalDav::loadingQueuePop() { + if (!mLoadingQueueReady || mLoadingQueue.isEmpty() || (isSaving() == true)) { + 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); + mLoader->setTasksUrl(t->tasksUrl); + mLoader->setJournalsUrl(t->journalsUrl); + mLoader->setParent(this); + mLoader->setType(0); + + TQDateTime dt(TQDate::currentDate()); + mLoader->setRange(dt.addDays(-CACHE_DAYS), dt.addDays(CACHE_DAYS)); + //mLoader->setGetAll(); + + mLoadingQueueReady = false; + + log("starting actual download job"); + mLoader->start(TQThread::LowestPriority); + + // if all ok, removing the task from the queue + mLoadingQueue.dequeue(); + updateProgressBar(0); + + delete t; +} + +void ResourceCalDav::startLoading(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl) { + LoadingTask *t = new LoadingTask; + t->url = url; + t->tasksUrl = tasksUrl; + t->journalsUrl = journalsUrl; + 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) { + TQCString newpass; + if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { + log("load error: " + loader->errorString() ); + loadError(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); + } + else { + // Set new password and try again + mPrefs->setPassword(TQString(newpass)); + startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); + } + } + else { + log("load error: " + loader->errorString() ); + loadError(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); + } + } + else { + log("load error: " + loader->errorString() ); + loadError(TQString("[%1] ").arg(abs(loader->errorNumber())) + loader->errorString()); + } + } else { + log("successful event load"); + TQString 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)) { + // FIXME: The agenda view can crash when a change is + // made on a remote server and a reload is requested! + log("... parsing is ok"); + log("clearing changes"); + enableChangeNotification(); + clearChanges(); + emit resourceChanged(this); + emit resourceLoaded(this); + } + } + } + + if (loader->tasksError()) { + if (loader->tasksErrorNumber() == -401) { + if (NULL != mPrefs) { +// TQCString newpass; +// if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { +// log("load error: " + loader->tasksErrorString() ); +// loadError(TQString("[%1] ").arg(abs(loader->tasksErrorNumber())) + loader->tasksErrorString()); +// } +// else { +// // Set new password and try again +// mPrefs->setPassword(TQString(newpass)); +// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); +// } + } + else { + log("load error: " + loader->tasksErrorString() ); + loadError(TQString("[%1] ").arg(abs(loader->tasksErrorNumber())) + loader->tasksErrorString()); + } + } + else { + log("load error: " + loader->tasksErrorString() ); + loadError(TQString("[%1] ").arg(abs(loader->tasksErrorNumber())) + loader->tasksErrorString()); + } + } else { + log("successful tasks load"); + TQString tasksData = loader->tasksData(); + + if (!tasksData.isNull() && !tasksData.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. + tasksData.replace("\r\n", "\n"); // to avoid \r\n becomes \n\n after the next line + tasksData.replace('\r', '\n'); + + log("trying to parse..."); + if (parseTasksData(tasksData)) { + // FIXME: The agenda view can crash when a change is + // made on a remote server and a reload is requested! + log("... parsing is ok"); + log("clearing changes"); + enableChangeNotification(); + clearChanges(); + emit resourceChanged(this); + emit resourceLoaded(this); + } + } + } + + if (loader->journalsError()) { + if (loader->journalsErrorNumber() == -401) { + if (NULL != mPrefs) { +// TQCString newpass; +// if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { +// log("load error: " + loader->journalsErrorString() ); +// loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString()); +// } +// else { +// // Set new password and try again +// mPrefs->setPassword(TQString(newpass)); +// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); +// } + } + else { + log("load error: " + loader->journalsErrorString() ); + loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString()); + } + } + else { + log("load error: " + loader->journalsErrorString() ); + loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString()); + } + } else { + log("successful journals load"); + TQString journalsData = loader->journalsData(); + + if (!journalsData.isNull() && !journalsData.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. + journalsData.replace("\r\n", "\n"); // to avoid \r\n becomes \n\n after the next line + journalsData.replace('\r', '\n'); + + log("trying to parse..."); + if (parseJournalsData(journalsData)) { + // FIXME: The agenda view can crash when a change is + // made on a remote server and a reload is requested! + log("... parsing is ok"); + log("clearing changes"); + enableChangeNotification(); + clearChanges(); + emit resourceChanged(this); + 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. + mLoader->terminate(); + mLoader->wait(TERMINATION_WAITING_TIME); + mLoadingQueueReady = true; + updateProgressBar(0); + loadingQueuePop(); +} + +bool ResourceCalDav::checkData(const TQString& 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 TQString& 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"); + clearEventsCache(); + + 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 TQString fout_path = "/tmp/kcaldav_download_" + identifier() + ".tmp"; + + TQFile fout(fout_path); + if (fout.open(IO_WriteOnly | IO_Append)) { + TQTextStream 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(); + } + + return ret; +} + +bool ResourceCalDav::parseTasksData(const TQString& data) { + log("parseTasksData()"); + + 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"); + clearTodosCache(); + + 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 TQString fout_path = "/tmp/kcaldav_download_" + identifier() + ".tmp"; + + TQFile fout(fout_path); + if (fout.open(IO_WriteOnly | IO_Append)) { + TQTextStream 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(); + } + + return ret; +} + +bool ResourceCalDav::parseJournalsData(const TQString& data) { + log("parseJournalsData()"); + + 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"); + clearJournalsCache(); + + 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 TQString fout_path = "/tmp/kcaldav_download_" + identifier() + ".tmp"; + + TQFile fout(fout_path); + if (fout.open(IO_WriteOnly | IO_Append)) { + TQTextStream 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(); + } + + return ret; +} + +/*========================================================================= +| WRITING METHODS + ========================================================================*/ + +TQString ResourceCalDav::getICalString(const Incidence::List& inc) { + if (inc.isEmpty()) { + return ""; + } + + CalendarLocal loc(timeZoneId()); + TQString data = ""; + TQString header = ""; + TQString footer = ""; + ICalFormat ical; + + // Get the iCal header and footer + header = ical.toString(&loc); + int location = header.find("END:VCALENDAR", 0, true); + footer = header.mid(location, 0xffffffff); + header.remove("END:VCALENDAR"); + + data = data + header; + // 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(); + data = data + ical.toString(i, &mCalendar); + } + data = data + footer; + + // Remove any line feeds/carriage returns/white spaces from the UID field as they WILL break libcaldav + int uidPos = data.find("UID:", 0) + 4; + int nextPos = data.findRev("\n", data.find(":", uidPos)); + TQString uidField = data.mid(uidPos, nextPos-uidPos); + data.remove(uidPos, nextPos-uidPos); + uidField.replace("\n", ""); + uidField.replace("\r", ""); + uidField.replace(" ", ""); + data.insert(uidPos, uidField); + 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); + updateProgressBar(1); + writingQueuePop(); +} + +void ResourceCalDav::writingQueuePop() { + 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); + mWriter->setTasksUrl(t->tasksUrl); + mWriter->setJournalsUrl(t->journalsUrl); + mWriter->setParent(this); + mWriter->setType(1); + +#ifdef KCALDAV_DEBUG + const TQString fout_path = "/tmp/kcaldav_upload_" + identifier() + ".tmp"; + + TQFile fout(fout_path); + if (fout.open(IO_WriteOnly | IO_Append)) { + TQTextStream 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); + + mWriter->setAddedTasksObjects(t->tasksAdded); + mWriter->setChangedTasksObjects(t->tasksChanged); + mWriter->setDeletedTasksObjects(t->tasksDeleted); + + mWriter->setAddedJournalsObjects(t->journalsAdded); + mWriter->setChangedJournalsObjects(t->journalsChanged); + mWriter->setDeletedJournalsObjects(t->journalsDeleted); + + mWritingQueueReady = false; + + log("starting actual write job"); + mWriter->start(TQThread::LowestPriority); + + // if all ok, remove the task from the queue + mWritingQueue.dequeue(); + updateProgressBar(1); + + delete t; +} + +bool ResourceCalDav::event ( TQEvent * e ) { + if (e->type() == 1000) { + // Read done + loadFinished(); + return TRUE; + } + else if (e->type() == 1001) { + // Write done + writingFinished(); + return TRUE; + } + else return FALSE; +} + +void ResourceCalDav::releaseReadLockout() { + readLockout = false; +} + +bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl) { + log("startWriting: url = " + url); + + // WARNING: This will segfault if a separate read or write thread + // modifies the calendar with clearChanges() or similar + // Before these calls are made any existing read (and maybe write) threads should be finished + if ((mLoader->running() == true) || (mLoadingQueue.isEmpty() == false) || (mWriter->running() == true) || (mWritingQueue.isEmpty() == false)) { + if (mWriteRetryTimer == NULL) { + mWriteRetryTimer = new TQTimer(this); + connect( mWriteRetryTimer, TQT_SIGNAL(timeout()), TQT_SLOT(doSave()) ); + } + mWriteRetryTimer->start(1000, TRUE); + return false; + } + + // If we don't lock the read out for a few seconds, it would be possible for the old calendar to be + // downloaded before our changes are committed, presenting a very bad image to the user as his/her appointments + // revert to the state they were in before the write (albiet temporarily) + readLockout = true; + + // This needs to send each event separately; i.e. if two events were added they need + // to be extracted and pushed on the stack independently (using two calls to writingQueuePush()) + + Incidence::List added = addedIncidences(); + Incidence::List changed = changedIncidences(); + Incidence::List deleted = deletedIncidences(); + + Incidence::List::ConstIterator it; + Incidence::List currentIncidence; + + for( it = added.begin(); it != added.end(); ++it ) { + WritingTask *t = new WritingTask; + + currentIncidence.clear(); + currentIncidence.append(*it); + + t->url = url; + t->tasksUrl = tasksUrl; + t->journalsUrl = journalsUrl; + t->added = ""; + t->changed = ""; + t->deleted = ""; + t->tasksAdded = ""; + t->tasksChanged = ""; + t->tasksDeleted = ""; + t->journalsAdded = ""; + t->journalsChanged = ""; + t->journalsDeleted = ""; + if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) + t->added = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) + t->tasksAdded = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VJOURNAL") > 0) + t->journalsAdded = getICalString(currentIncidence); + + writingQueuePush(t); + } + + for( it = changed.begin(); it != changed.end(); ++it ) { + WritingTask *t = new WritingTask; + + currentIncidence.clear(); + currentIncidence.append(*it); + + t->url = url; + t->tasksUrl = tasksUrl; + t->added = ""; + t->changed = ""; + t->deleted = ""; + t->tasksAdded = ""; + t->tasksChanged = ""; + t->tasksDeleted = ""; + t->journalsAdded = ""; + t->journalsChanged = ""; + t->journalsDeleted = ""; + + if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) + t->changed = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) + t->tasksChanged = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VJOURNAL") > 0) + t->journalsChanged = getICalString(currentIncidence); + + writingQueuePush(t); + } + + for( it = deleted.begin(); it != deleted.end(); ++it ) { + WritingTask *t = new WritingTask; + + currentIncidence.clear(); + currentIncidence.append(*it); + + t->url = url; + t->tasksUrl = tasksUrl; + t->added = ""; + t->changed = ""; + t->deleted = ""; + t->tasksAdded = ""; + t->tasksChanged = ""; + t->tasksDeleted = ""; + t->journalsAdded = ""; + t->journalsChanged = ""; + t->journalsDeleted = ""; + + if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0) + t->deleted = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0) + t->tasksDeleted = getICalString(currentIncidence); + else if (getICalString(currentIncidence).contains("BEGIN:VJOURNALS") > 0) + t->journalsDeleted = getICalString(currentIncidence); + + writingQueuePush(t); + } + + return true; +} + +void ResourceCalDav::writingFinished() { + log("writing finished"); + + if (!mWriter) { + log("mWriter is NULL"); + return; + } + + if (mWriter->error() && (abs(mWriter->errorNumber()) != 207)) { + if (mWriter->errorNumber() == -401) { + if (NULL != mPrefs) { + TQCString newpass; + if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) { + log("write error: " + mWriter->errorString()); + saveError(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); + } + else { + // Set new password and try again + mPrefs->setPassword(TQString(newpass)); + startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()); + } + } + else { + log("write error: " + mWriter->errorString()); + saveError(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); + } + } + else { + log("write error: " + mWriter->errorString()); + saveError(TQString("[%1] ").arg(abs(mWriter->errorNumber())) + mWriter->errorString()); + } + } else { + log("success"); + // is there something to do here? + } + + // Give the remote system a few seconds to process the data before we allow any read operations + TQTimer::singleShot( 3000, this, TQT_SLOT(releaseReadLockout()) ); + + // 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. + mWriter->terminate(); + mWriter->wait(TERMINATION_WAITING_TIME); + mWritingQueueReady = true; + updateProgressBar(1); + writingQueuePop(); +} + +#include "resource.moc" + +// EOF ======================================================================== diff --git a/tderesources/caldav/resource.h b/tderesources/caldav/resource.h new file mode 100644 index 000000000..ea04ef483 --- /dev/null +++ b/tderesources/caldav/resource.h @@ -0,0 +1,268 @@ +/*========================================================================= +| 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 <tqthread.h> +#include <tqptrqueue.h> + +#include <libkcal/resourcecached.h> +#include <libtdepim/progressmanager.h> + +#include <kabc/locknull.h> + +#include <tdepimmacros.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 TDEConfig *config ); + virtual ~ResourceCalDav(); + + void readConfig( const TDEConfig *config ); + void writeConfig( TDEConfig *config ); + + /** + * @return This resource preferences. + */ + CalDavPrefs* prefs() { + return mPrefs; + } + + /** + * @return This resource preferences. + */ + const CalDavPrefs* prefs() const { + return mPrefs; + } + + virtual void setReadOnly(bool v); + + bool isSaving(); + +protected slots: + + void loadFinished(); + + virtual bool doSave(); + + void writingFinished(); + + void releaseReadLockout(); + +protected: + + struct LoadingTask { + TQString url; + TQString tasksUrl; + TQString journalsUrl; + }; + + struct WritingTask { + TQString url; + TQString tasksUrl; + TQString journalsUrl; + + TQString added; + TQString changed; + TQString deleted; + + TQString tasksAdded; + TQString tasksChanged; + TQString tasksDeleted; + + TQString journalsAdded; + TQString journalsChanged; + TQString journalsDeleted; + }; + + + virtual bool doLoad(); +// virtual bool doSave(); + + 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(); + + /** + * Updates the progress bar + */ + void updateProgressBar(int direction); + + /** + * Initiates calendar loading process. + * @param url URL to load calendar data from. + * @param tasksUrl URL to load task data from. + * @param journalsUrl URL to load journal data from. + */ + void startLoading(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl); + + /** + * 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 TQString& data); + + /** + * Parses the data and adds events to the calendar. + * @param data calendar data. + * @return true on success, false on fail. + */ + bool parseData(const TQString& data); + + /** + * Parses the data and adds tasks to the calendar. + * @param data calendar data. + * @return true on success, false on fail. + */ + bool parseTasksData(const TQString& data); + + /** + * Parses the data and adds journals to the calendar. + * @param data calendar data. + * @return true on success, false on fail. + */ + bool parseJournalsData(const TQString& data); + + /** + * Initiates calendar writing process. + * @param url URL to save event data to. + * @param tasksUrl URL to save task data to. + * @param journalsUrl URL to save journal data to. + * @return true if write was queued successfully, false if not + */ + bool startWriting(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl); + + /** + * 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. + */ + TQString 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); + + virtual bool event ( TQEvent * e ); + +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; + + bool readLockout; + bool mAllWritesComplete; + + // members: =============================================================== + + KABC::LockNull mLock; + CalDavPrefs* mPrefs; + CalDavReader* mLoader; + CalDavWriter* mWriter; + KPIM::ProgressItem *mProgress; + + bool mLoadingQueueReady; + TQPtrQueue<LoadingTask> mLoadingQueue; + + bool mWritingQueueReady; + TQPtrQueue<WritingTask> mWritingQueue; + + TQTimer *mWriteRetryTimer; + +}; + + + +} // namespace KCal + +#endif // KCAL_RESOURCECALDAV_H + diff --git a/tderesources/caldav/uninstall.desktop b/tderesources/caldav/uninstall.desktop new file mode 100644 index 000000000..e1e3e1732 --- /dev/null +++ b/tderesources/caldav/uninstall.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Hidden=true diff --git a/tderesources/caldav/writer.cpp b/tderesources/caldav/writer.cpp new file mode 100644 index 000000000..d9a6b2f0e --- /dev/null +++ b/tderesources/caldav/writer.cpp @@ -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. +|-------------------------------------------------------------------------- +| Remote calendar writing class. + ========================================================================*/ + +/*========================================================================= +| INCLUDES + ========================================================================*/ + +#include "writer.h" +#include <kdebug.h> +#include <string> + +/*========================================================================= +| 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 +#define USE_CALDAV_TASKS_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; + + if ((OK == res) && (url() != "")) { + kdDebug() << "pushing added objects" << '\n'; + res = pushObjects(mAdded, caldav_add_object, OK, RT); + if (OK == res) { +#ifdef USE_CALDAV_MODIFY + kdDebug() << "pushing changed objects" << '\n'; + res = pushObjects(mChanged, caldav_modify_object, OK, RT); + if (OK == res) { + kdDebug() << "pushing deleted objects" << '\n'; + res = pushObjects(mDeleted, caldav_delete_object, OK, RT); + } +#else // if USE_CALDAV_MODIFY + kdDebug() << "pushing changed objects (delete)" << '\n'; + res = pushObjects(mChanged, caldav_delete_object, OK, RT); + if (OK == res) { + kdDebug() << "pushing changed objects (add)" << '\n'; + res = pushObjects(mChanged, caldav_add_object, OK, RT); + if (OK == res) { + kdDebug() << "pushing deleted objects" << '\n'; + res = pushObjects(mDeleted, caldav_delete_object, OK, RT); + } + } +#endif // if USE_CALDAV_MODIFY + } + } + + int tasksres = OK; + + if ((OK == tasksres) && (tasksUrl() != "")) { + kdDebug() << "pushing added tasks objects" << '\n'; + tasksres = pushTasksObjects(mTasksAdded, caldav_add_object, OK, RT); + if (OK == tasksres) { +#ifdef USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects" << '\n'; + tasksres = pushTasksObjects(mTasksChanged, caldav_tasks_modify_object, OK, RT); + if (OK == tasksres) { + kdDebug() << "pushing deleted objects" << '\n'; + tasksres = pushTasksObjects(mTasksDeleted, caldav_tasks_delete_object, OK, RT); + } +#else // if USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects (delete)" << '\n'; + tasksres = pushTasksObjects(mTasksChanged, caldav_tasks_delete_object, OK, RT); + if (OK == tasksres) { + kdDebug() << "pushing changed objects (add)" << '\n'; + tasksres = pushTasksObjects(mTasksChanged, caldav_add_object, OK, RT); + if (OK == tasksres) { + kdDebug() << "pushing deleted objects" << '\n'; + tasksres = pushTasksObjects(mTasksDeleted, caldav_tasks_delete_object, OK, RT); + } + } +#endif // if USE_CALDAV_TASKS_MODIFY + } + } + + int journalsres = OK; + + if ((OK == journalsres) && (tasksUrl() != "")) { + kdDebug() << "pushing added tasks objects" << '\n'; + journalsres = pushJournalsObjects(mJournalsAdded, caldav_add_object, OK, RT); + if (OK == journalsres) { +#ifdef USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects" << '\n'; + journalsres = pushJournalsObjects(mJournalsChanged, caldav_tasks_modify_object, OK, RT); + if (OK == journalsres) { + kdDebug() << "pushing deleted objects" << '\n'; + journalsres = pushJournalsObjects(mJournalsDeleted, caldav_tasks_delete_object, OK, RT); + } +#else // if USE_CALDAV_TASKS_MODIFY + kdDebug() << "pushing changed objects (delete)" << '\n'; + journalsres = pushJournalsObjects(mJournalsChanged, caldav_tasks_delete_object, OK, RT); + if (OK == journalsres) { + kdDebug() << "pushing changed objects (add)" << '\n'; + journalsres = pushJournalsObjects(mJournalsChanged, caldav_add_object, OK, RT); + if (OK == journalsres) { + kdDebug() << "pushing deleted objects" << '\n'; + journalsres = pushJournalsObjects(mJournalsDeleted, caldav_tasks_delete_object, OK, RT); + } + } +#endif // if USE_CALDAV_TASKS_MODIFY + } + } + + if ((OK != res) || (OK != tasksres)) { + clearObjects(); + } + + if (tasksres == OK) + return res; + else + return tasksres; +} + +int CalDavWriter::runTasksJob(runtime_info* RT) { + // Stub function as there is no reason to split the writing jobs like the reading jobs + return OK; +} + +void CalDavWriter::cleanTasksJob() { + // Stub function as there is no reason to split the writing jobs like the reading jobs +} + +int CalDavWriter::runJournalsJob(runtime_info* RT) { + // Stub function as there is no reason to split the writing jobs like the reading jobs + return OK; +} + +void CalDavWriter::cleanJournalsJob() { + // Stub function as there is no reason to split the writing jobs like the reading jobs +} + +// EOF ======================================================================== diff --git a/tderesources/caldav/writer.h b/tderesources/caldav/writer.h new file mode 100644 index 000000000..437eeed0e --- /dev/null +++ b/tderesources/caldav/writer.h @@ -0,0 +1,202 @@ +/*========================================================================= +| 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 <tqstring.h> +#include <tqdatetime.h> + +namespace KCal { + +/*========================================================================= +| CLASS + ========================================================================*/ + +/** + * Calendar writer. + */ +class CalDavWriter : public CalDavJob { + +public: + + /** + * @param url URL to load. + */ + CalDavWriter(const TQString& url = TQString()) : + CalDavJob(url) + { + clearObjects(); + } + + /** + * Sets the information about added events writer should send to server. + * @param s icalendar-formatted string consists of all added events plus necessary calendar info. + * May be an empty string, which means there are no added events to send. + */ + void setAddedObjects(const TQString& s) { + mAdded = s; + } + + /** + * Sets the information about changed events writer should send to server. + * @param s icalendar-formatted string consists of all changed events plus necessary calendar info. + * May be an empty string, which means there are no changed events to send. + */ + void setChangedObjects(const TQString& s) { + mChanged = s; + } + + /** + * Sets the information about deleted events writer should send to server. + * @param s icalendar-formatted string consists of all deleted events plus necessary calendar info. + * May be an empty string, which means there are no deleted events to send. + */ + void setDeletedObjects(const TQString& s) { + mDeleted = s; + } + + /** + * Sets the information about added tasks writer should send to server. + * @param s icalendar-formatted string consists of all added tasks plus necessary calendar info. + * May be an empty string, which means there are no added tasks to send. + */ + void setAddedTasksObjects(const TQString& s) { + mTasksAdded = s; + } + + /** + * Sets the information about added journals writer should send to server. + * @param s icalendar-formatted string consists of all added journals plus necessary calendar info. + * May be an empty string, which means there are no added journals to send. + */ + void setAddedJournalsObjects(const TQString& s) { + mJournalsAdded = s; + } + + /** + * Sets the information about changed tasks writer should send to server. + * @param s icalendar-formatted string consists of all changed tasks plus necessary calendar info. + * May be an empty string, which means there are no changed tasks to send. + */ + void setChangedTasksObjects(const TQString& s) { + mTasksChanged = s; + } + + /** + * Sets the information about changed journals writer should send to server. + * @param s icalendar-formatted string consists of all changed journals plus necessary calendar info. + * May be an empty string, which means there are no changed journals to send. + */ + void setChangedJournalsObjects(const TQString& s) { + mJournalsChanged = s; + } + + /** + * Sets the information about deleted tasks writer should send to server. + * @param s icalendar-formatted string consists of all deleted tasks plus necessary calendar info. + * May be an empty string, which means there are no deleted tasks to send. + */ + void setDeletedTasksObjects(const TQString& s) { + mTasksDeleted = s; + } + + /** + * Sets the information about deleted journals writer should send to server. + * @param s icalendar-formatted string consists of all deleted journals plus necessary calendar info. + * May be an empty string, which means there are no deleted journals to send. + */ + void setDeletedJournalsObjects(const TQString& s) { + mJournalsDeleted = s; + } + + /** + * Clear all the information previously set. + */ + void clearObjects() { + setAddedObjects(""); + setChangedObjects(""); + setDeletedObjects(""); + setAddedTasksObjects(""); + setChangedTasksObjects(""); + setDeletedTasksObjects(""); + setAddedJournalsObjects(""); + setChangedJournalsObjects(""); + setDeletedJournalsObjects(""); + } + +protected: + + virtual int runJob(runtime_info* caldavRuntime); + virtual int runTasksJob(runtime_info* caldavRuntime); + virtual int runJournalsJob(runtime_info* caldavRuntime); + + virtual void cleanJob(); + virtual void cleanTasksJob(); + virtual void cleanJournalsJob(); + + /// Just a wrapper above libcaldav event writing functions. + template<typename Operation> + int pushObjects(const TQString& 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; + } + + /// Just a wrapper above libcaldav task writing functions. + template<typename Operation> + int pushTasksObjects(const TQString& 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(tasksUrl().ascii()).c_str(), RT); + } + return r; + } + + /// Just a wrapper above libcaldav journal writing functions. + template<typename Operation> + int pushJournalsObjects(const TQString& 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(journalsUrl().ascii()).c_str(), RT); +// } + return r; + } + +private: + + TQString mAdded; + TQString mChanged; + TQString mDeleted; + + TQString mTasksAdded; + TQString mTasksChanged; + TQString mTasksDeleted; + + TQString mJournalsAdded; + TQString mJournalsChanged; + TQString mJournalsDeleted; +}; + +} // namespace KCal + +#endif // KCALDAV_WRITER_H + |