diff options
Diffstat (limited to 'kresources/egroupware')
34 files changed, 4890 insertions, 0 deletions
diff --git a/kresources/egroupware/Makefile.am b/kresources/egroupware/Makefile.am new file mode 100644 index 000000000..8325ed01c --- /dev/null +++ b/kresources/egroupware/Makefile.am @@ -0,0 +1,73 @@ +INCLUDES = -I$(top_srcdir)/libical/src/libical \ + -I$(top_srcdir)/libical/src/libicalss \ + -I$(top_builddir)/libical/src/libical \ + -I$(top_builddir)/libical/src/libicalss \ + -I$(srcdir)/versit -I$(top_srcdir)/ \ + -I$(top_srcdir)/knotes \ + -I$(top_builddir)/kaddressbook \ + -I$(top_builddir)/kaddressbook/common \ + -I$(top_srcdir)/kaddressbook/common \ + -I$(top_builddir)/kresources/egroupware \ + $(all_includes) + +noinst_HEADERS = kabc_resourcexmlrpcconfig.h kcal_resourcexmlrpcconfig.h \ + knotes_resourcexmlrpcconfig.h + +noinst_LTLIBRARIES = libegwcommon.la +libegwcommon_la_SOURCES = xmlrpciface.cpp synchronizer.cpp debugdialog.cpp + +lib_LTLIBRARIES = libkabc_xmlrpc.la libkcal_xmlrpc.la libknotes_xmlrpc.la +libkabc_xmlrpc_la_SOURCES = kabc_resourcexmlrpc.cpp kabc_resourcexmlrpcconfig.cpp \ + kabc_egroupwareprefs.kcfgc +libkabc_xmlrpc_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -version-info 1:0:0 -no-undefined +libkabc_xmlrpc_la_LIBADD = $(LIB_KIO) -lkabc $(top_builddir)/libkdepim/libkdepim.la \ + $(top_builddir)/kaddressbook/common/libkabcommon.la \ + libegwcommon.la + +libkcal_xmlrpc_la_SOURCES = kcal_resourcexmlrpc.cpp kcal_resourcexmlrpcconfig.cpp \ + todostatemapper.cpp kcal_egroupwareprefs.kcfgc +libkcal_xmlrpc_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -version-info 1:0:0 -no-undefined +libkcal_xmlrpc_la_LIBADD = $(top_builddir)/libkcal/libkcal.la \ + $(top_builddir)/libkdepim/libkdepim.la \ + libegwcommon.la + +libknotes_xmlrpc_la_SOURCES = knotes_resourcexmlrpc.cpp knotes_resourcexmlrpcconfig.cpp \ + knotes_egroupwareprefs.kcfgc +libknotes_xmlrpc_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -version-info 1:0:0 -no-undefined +libknotes_xmlrpc_la_LIBADD = $(top_builddir)/libkcal/libkcal.la -lkdeprint \ + $(top_builddir)/knotes/libknotesresources.la \ + $(top_builddir)/libkdepim/libkdepim.la \ + libegwcommon.la + +kabcincludedir = $(includedir)/kabc +kabcinclude_HEADERS = kabc_resourcexmlrpc.h kcal_resourcexmlrpc.h + +kde_module_LTLIBRARIES = kabc_xmlrpc.la kcal_xmlrpc.la knotes_xmlrpc.la + +kabc_xmlrpc_la_SOURCES = kabc_resourcexmlrpcplugin.cpp +kabc_xmlrpc_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kabc_xmlrpc_la_LIBADD = libkabc_xmlrpc.la + +kcal_xmlrpc_la_SOURCES = kcal_resourcexmlrpcplugin.cpp +kcal_xmlrpc_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kcal_xmlrpc_la_LIBADD = libkcal_xmlrpc.la + +knotes_xmlrpc_la_SOURCES = knotes_resourcexmlrpcplugin.cpp +knotes_xmlrpc_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +knotes_xmlrpc_la_LIBADD = libknotes_xmlrpc.la + +kabc_servicedir = $(kde_servicesdir)/kresources/kabc +kabc_service_DATA = kabc_xmlrpc.desktop + +kcal_servicedir = $(kde_servicesdir)/kresources/kcal +kcal_service_DATA = kcal_xmlrpc.desktop + +knotes_servicedir = $(kde_servicesdir)/kresources/knotes +knotes_service_DATA = knotes_xmlrpc.desktop + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kres_xmlrpc.pot + +kabc_resourcexmlrpc.lo: ../../kaddressbook/common/kabprefs_base.h diff --git a/kresources/egroupware/access.h b/kresources/egroupware/access.h new file mode 100644 index 000000000..8ed6a6afe --- /dev/null +++ b/kresources/egroupware/access.h @@ -0,0 +1,31 @@ +/* + This file is part of kdepim. + Copyright (c) 2005 Tobias Koenig <tokoe@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 ACCESS_H +#define ACCESS_H + +#define EGW_ACCESS_READ 1 +#define EGW_ACCESS_ADD 2 +#define EGW_ACCESS_EDIT 4 +#define EGW_ACCESS_DELETE 8 +#define EGW_ACCESS_PRIVATE 9 +#define EGW_ACCESS_ALL 15 + +#endif diff --git a/kresources/egroupware/debugdialog.cpp b/kresources/egroupware/debugdialog.cpp new file mode 100644 index 000000000..117db3243 --- /dev/null +++ b/kresources/egroupware/debugdialog.cpp @@ -0,0 +1,126 @@ +/* + This file is part of kdepim. + Copyright (c) 2005 Tobias Koenig <tokoe@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 <qfile.h> +#include <qfiledialog.h> +#include <qlayout.h> + +#include <ktextbrowser.h> +#include <kstaticdeleter.h> + +#include <stdlib.h> +#include <klocale.h> +#include "debugdialog.h" + +DebugDialog* DebugDialog::mSelf = 0; +static KStaticDeleter<DebugDialog> debugDialogDeleter; + +DebugDialog::DebugDialog() + : KDialogBase( Plain, WStyle_DialogBorder | WStyle_StaysOnTop, 0, + "Debug Dialog", false, i18n("Debug Dialog"), + User1 | User2 | Ok, Ok, true ) +{ + QWidget *page = plainPage(); + QVBoxLayout *layout = new QVBoxLayout( page, marginHint(), spacingHint() ); + + mView = new KTextBrowser( page ); + layout->addWidget( mView ); + + setButtonText( User1, "Save As..." ); + setButtonText( User2, "Clear" ); + + clear(); +} + +void DebugDialog::init() +{ + if ( !mSelf ) { + if ( getenv( "EGROUPWARE_DEBUG" ) != 0 ) { + debugDialogDeleter.setObject( mSelf, new DebugDialog ); + } + } + + if ( mSelf ) { + mSelf->show(); + mSelf->raise(); + } +} + +DebugDialog::~DebugDialog() +{ + mSelf = 0; +} + +void DebugDialog::addMessage( const QString &msg, Type type ) +{ + if ( mSelf ) + mSelf->addText( msg, type ); +} + +void DebugDialog::clear() +{ + mView->clear(); + mMessages.clear(); +} + +void DebugDialog::save() +{ + QString fileName = QFileDialog::getSaveFileName(); + if ( fileName.isEmpty() ) + return; + + QFile file( fileName ); + if ( !file.open( IO_WriteOnly ) ) { + qWarning( "Couldn't open file %s", file.name().latin1() ); + return; + } + + file.writeBlock( mMessages.join( "\n\n" ).utf8() ); + file.close(); +} + +void DebugDialog::slotUser1() +{ + save(); +} + +void DebugDialog::slotUser2() +{ + clear(); +} + +void DebugDialog::addText( const QString &text, Type type ) +{ + QString htmlCode( text ); + htmlCode.replace( "<", "<" ); + htmlCode.replace( ">", ">" ); + htmlCode.replace( "\n", "<br>" ); + + mMessages.append( text ); + if ( type == Input ) + mHTMLMessages.append( "<font color=\"green\">" + htmlCode + "</font>" ); + else + mHTMLMessages.append( "<font color=\"blue\">" + htmlCode + "</font>" ); + + mView->clear(); + mView->setText( mHTMLMessages.join( "<br>" ) ); +} + +#include "debugdialog.moc" diff --git a/kresources/egroupware/debugdialog.h b/kresources/egroupware/debugdialog.h new file mode 100644 index 000000000..c5f91377f --- /dev/null +++ b/kresources/egroupware/debugdialog.h @@ -0,0 +1,78 @@ +/* + This file is part of kdepim. + Copyright (c) 2005 Tobias Koenig <tokoe@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 DEBUGDIALOG_H +#define DEBUGDIALOG_H + +#include <kdialogbase.h> + +class KTextBrowser; + +/** + A dialog that parses chunks of XML documents and + displays them in a treeview. + */ +class DebugDialog : public KDialogBase +{ + Q_OBJECT + + public: + /** + The type of the message. + */ + enum Type { Input, Output }; + + /** + Starts the debug dialog depending on the presence + of the environment variable EGROUPWARE_DEBUG. + */ + static void init(); + + /** + Destructor. + */ + ~DebugDialog(); + + /** + Adds a message, which will be shown by the dialog. + */ + static void addMessage( const QString &msg, Type type ); + + private slots: + void clear(); + void save(); + + protected slots: + virtual void slotUser1(); + virtual void slotUser2(); + + private: + DebugDialog(); + static DebugDialog *mSelf; + + void addText( const QString&, Type ); + + QStringList mMessages; + QStringList mHTMLMessages; + + KTextBrowser *mView; +}; + +#endif diff --git a/kresources/egroupware/kabc_egroupwareprefs.kcfgc b/kresources/egroupware/kabc_egroupwareprefs.kcfgc new file mode 100644 index 000000000..0009334ac --- /dev/null +++ b/kresources/egroupware/kabc_egroupwareprefs.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=kresources_kabc_egroupware.kcfg +ClassName=EGroupwarePrefs +NameSpace=KABC +Singleton=false +Mutators=true +Inherits=KResourcePrefs +IncludeFiles=libkdepim/kresourceprefs.h +GlobalEnums=true +#ItemAccessors=true +#SetUserTexts=true diff --git a/kresources/egroupware/kabc_resourcexmlrpc.cpp b/kresources/egroupware/kabc_resourcexmlrpc.cpp new file mode 100644 index 000000000..eba630cc3 --- /dev/null +++ b/kresources/egroupware/kabc_resourcexmlrpc.cpp @@ -0,0 +1,771 @@ +/* + This file is part of kdepim. + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 <qapplication.h> + +#include <kabc/addressee.h> +#include <kabprefs.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmdcodec.h> +#include <kstandarddirs.h> +#include <kstringhandler.h> +#include <libkcal/freebusyurlstore.h> +#include <libkdepim/kpimprefs.h> + +#include "kabc_egroupwareprefs.h" +#include "kabc_resourcexmlrpc.h" +#include "kabc_resourcexmlrpcconfig.h" + +#include "access.h" +#include "synchronizer.h" +#include "xmlrpciface.h" + +using namespace KABC; + +static const QString SearchContactsCommand = "addressbook.boaddressbook.search"; +static const QString AddContactCommand = "addressbook.boaddressbook.write"; +static const QString DeleteContactCommand = "addressbook.boaddressbook.delete"; +static const QString LoadCategoriesCommand = "addressbook.boaddressbook.categories"; +static const QString LoadCustomFieldsCommand = "addressbook.boaddressbook.customfields"; + +static void setRights( KABC::Addressee &addr, int rights ) +{ + addr.insertCustom( "EGWRESOURCE", "RIGHTS", QString::number( rights ) ); +} + +static int rights( const KABC::Addressee &addr ) +{ + return addr.custom( "EGWRESOURCE", "RIGHTS" ).toInt(); +} + +ResourceXMLRPC::ResourceXMLRPC( const KConfig *config ) + : ResourceCached( config ), mServer( 0 ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + if ( config ) + mPrefs->readConfig(); + + initEGroupware(); +} + +ResourceXMLRPC::ResourceXMLRPC( const QString &url, const QString &domain, + const QString &user, const QString &password ) + : ResourceCached( 0 ), mServer( 0 ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + mPrefs->setUrl( url ); + mPrefs->setDomain( domain ); + mPrefs->setUser( user ); + mPrefs->setPassword( password ); + + initEGroupware(); +} + +void ResourceXMLRPC::init() +{ + setType( "xmlrpc" ); + + mSynchronizer = new Synchronizer; + + mPrefs = new EGroupwarePrefs; +} + +void ResourceXMLRPC::initEGroupware() +{ + KURL url( mPrefs->url() ); + + mAddrTypes.insert( "dom", Address::Dom ); + mAddrTypes.insert( "intl", Address::Intl ); + mAddrTypes.insert( "parcel", Address::Parcel ); + mAddrTypes.insert( "postal", Address::Postal ); +} + +ResourceXMLRPC::~ResourceXMLRPC() +{ + saveCache(); + + delete mServer; + mServer = 0; + + delete mPrefs; + mPrefs = 0; + + delete mSynchronizer; + mSynchronizer = 0; +} + +void ResourceXMLRPC::writeConfig( KConfig *config ) +{ + Resource::writeConfig( config ); + + mPrefs->writeConfig(); +} + +Ticket *ResourceXMLRPC::requestSaveTicket() +{ + if ( !addressBook() ) { + kdDebug(5700) << "no addressbook" << endl; + return 0; + } + + return createTicket( this ); +} + +void ResourceXMLRPC::releaseSaveTicket( Ticket *ticket ) +{ + delete ticket; +} + +bool ResourceXMLRPC::doOpen() +{ + if ( mServer ) + delete mServer; + + mServer = new KXMLRPC::Server( KURL(), this ); + mServer->setUrl( KURL( mPrefs->url() ) ); + mServer->setUserAgent( "KDE-AddressBook" ); + + QMap<QString, QVariant> args; + args.insert( "domain", mPrefs->domain() ); + args.insert( "username", mPrefs->user() ); + args.insert( "password", mPrefs->password() ); + + mServer->call( "system.login", QVariant( args ), + this, SLOT( loginFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mSynchronizer->start(); + + return true; +} + +void ResourceXMLRPC::doClose() +{ + QMap<QString, QVariant> args; + args.insert( "sessionid", mSessionID ); + args.insert( "kp3", mKp3 ); + + mServer->call( "system.logout", QVariant( args ), + this, SLOT( logoutFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mSynchronizer->start(); +} + +bool ResourceXMLRPC::load() +{ + mAddrMap.clear(); + + return true; +} + +bool ResourceXMLRPC::asyncLoad() +{ + if ( !mServer ) + return false; + + mAddrMap.clear(); + + loadCache(); + + QMap<QString, QVariant> args; + args.insert( "start", "0" ); + args.insert( "query", "" ); + args.insert( "filter", "" ); + args.insert( "sort", "" ); + args.insert( "order", "" ); + args.insert( "include_users", "calendar" ); + + mServer->call( SearchContactsCommand, args, + this, SLOT( listContactsFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mServer->call( LoadCategoriesCommand, QVariant( false, 0 ), + this, SLOT( loadCategoriesFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mServer->call( LoadCustomFieldsCommand, QVariant( QValueList<QVariant>() ), + this, SLOT( loadCustomFieldsFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + return true; +} + + +bool ResourceXMLRPC::save( Ticket *ticket ) +{ + return asyncSave( ticket ); +} + +bool ResourceXMLRPC::asyncSave( Ticket* ) +{ + KABC::Addressee::List::ConstIterator it; + + const KABC::Addressee::List addedList = addedAddressees(); + for ( it = addedList.begin(); it != addedList.end(); ++it ) { + addContact( *it ); + } + + const KABC::Addressee::List changedList = changedAddressees(); + for ( it = changedList.begin(); it != changedList.end(); ++it ) { + updateContact( *it ); + } + + const KABC::Addressee::List deletedList = deletedAddressees(); + for ( it = deletedList.begin(); it != deletedList.end(); ++it ) { + deleteContact( *it ); + } + + return true; +} + +void ResourceXMLRPC::addContact( const Addressee& addr ) +{ + QMap<QString, QVariant> args; + writeContact( addr, args ); + + mServer->call( AddContactCommand, args, + this, SLOT( addContactFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( addContactFault( int, const QString&, const QVariant& ) ), + QVariant( addr.uid() ) ); +} + +void ResourceXMLRPC::updateContact( const Addressee& addr ) +{ + if ( !(rights( addr ) & EGW_ACCESS_DELETE) && (rights( addr ) != -1) ) { + clearChange( addr.uid() ); + return; + } + + QMap<QString, QVariant> args; + writeContact( addr, args ); + + args.insert( "id", idMapper().remoteId( addr.uid() ) ); + mServer->call( AddContactCommand, args, + this, SLOT( updateContactFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( updateContactFault( int, const QString&, const QVariant& ) ), + QVariant( addr.uid() ) ); +} + +void ResourceXMLRPC::deleteContact( const Addressee& addr ) +{ + if ( !(rights( addr ) & EGW_ACCESS_DELETE) && rights( addr ) != -1 ) { + clearChange( addr.uid() ); + idMapper().removeRemoteId( idMapper().remoteId( addr.uid() ) ); + return; + } + + mServer->call( DeleteContactCommand, idMapper().remoteId( addr.uid() ), + this, SLOT( deleteContactFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( deleteContactFault( int, const QString&, const QVariant& ) ), + QVariant( addr.uid() ) ); +} + +void ResourceXMLRPC::loginFinished( const QValueList<QVariant> &variant, + const QVariant& ) +{ + QMap<QString, QVariant> map = variant[0].toMap(); + + KURL url( mPrefs->url() ); + if ( map[ "GOAWAY" ].toString() == "XOXO" ) { // failed + mSessionID = mKp3 = ""; + addressBook()->error( i18n( "Login failed, please check your username and password." ) ); + } else { + mSessionID = map[ "sessionid" ].toString(); + mKp3 = map[ "kp3" ].toString(); + } + + url.setUser( mSessionID ); + url.setPass( mKp3 ); + mServer->setUrl( url ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::logoutFinished( const QValueList<QVariant> &variant, + const QVariant& ) +{ + QMap<QString, QVariant> map = variant[0].toMap(); + + if ( map[ "GOODBYE" ].toString() != "XOXO" ) + addressBook()->error( i18n( "Logout failed, please check your username and password." ) ); + + KURL url( mPrefs->url() ); + mSessionID = mKp3 = ""; + url.setUser( mSessionID ); + url.setPass( mKp3 ); + mServer->setUrl( url ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::listContactsFinished( const QValueList<QVariant> &mapList, + const QVariant& ) +{ + const QValueList<QVariant> contactList = mapList[ 0 ].toList(); + QValueList<QVariant>::ConstIterator contactIt; + + KABC::Addressee::List serverContacts; + for ( contactIt = contactList.begin(); contactIt != contactList.end(); ++contactIt ) { + const QMap<QString, QVariant> map = (*contactIt).toMap(); + + Addressee addr; + QString uid; + + readContact( map, addr, uid ); + + if ( !addr.isEmpty() ) { + addr.setResource( this ); + addr.setChanged( false ); + + QString local = idMapper().localId( uid ); + if ( local.isEmpty() ) { // new entry + idMapper().setRemoteId( addr.uid(), uid ); + } else { + addr.setUid( local ); + } + + mAddrMap.insert( addr.uid(), addr ); + serverContacts.append( addr ); + } + } + + cleanUpCache( serverContacts ); + saveCache(); + + emit loadingFinished( this ); +} + +void ResourceXMLRPC::addContactFinished( const QValueList<QVariant> &list, + const QVariant &id ) +{ + clearChange( id.toString() ); + idMapper().setRemoteId( id.toString(), list[ 0 ].toString() ); + + saveCache(); +} + +void ResourceXMLRPC::updateContactFinished( const QValueList<QVariant>&, + const QVariant &id ) +{ + clearChange( id.toString() ); + + saveCache(); +} + +void ResourceXMLRPC::deleteContactFinished( const QValueList<QVariant>&, + const QVariant &id ) +{ + clearChange( id.toString() ); + idMapper().removeRemoteId( idMapper().remoteId( id.toString() ) ); + + saveCache(); +} + +void ResourceXMLRPC::fault( int error, const QString &errorMsg, + const QVariant& ) +{ + QString msg = i18n( "<qt>Server sent error %1: <b>%2</b></qt>" ).arg( error ).arg( errorMsg ); + if ( addressBook() ) + addressBook()->error( msg ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::addContactFault( int, const QString &errorMsg, + const QVariant &id ) +{ + KABC::Addressee addr = mAddrMap[ id.toString() ]; + + mAddrMap.remove( addr.uid() ); + + QString msg = i18n( "Unable to add contact %1 to server. (%2)" ); + addressBook()->error( msg.arg( addr.formattedName(), errorMsg ) ); +} + +void ResourceXMLRPC::updateContactFault( int, const QString &errorMsg, + const QVariant &id ) +{ + KABC::Addressee addr = mAddrMap[ id.toString() ]; + + QString msg = i18n( "Unable to update contact %1 on server. (%2)" ); + addressBook()->error( msg.arg( addr.formattedName(), errorMsg ) ); +} + +void ResourceXMLRPC::deleteContactFault( int, const QString &errorMsg, + const QVariant &id ) +{ + KABC::Addressee addr; + + const KABC::Addressee::List deletedList = deletedAddressees(); + KABC::Addressee::List::ConstIterator it; + for ( it = deletedList.begin(); it != deletedList.end(); ++it ) { + if ( (*it).uid() == id.toString() ) { + addr = *it; + break; + } + } + + mAddrMap.insert( addr.uid(), addr ); + + QString msg = i18n( "Unable to delete contact %1 from server. (%2)" ); + addressBook()->error( msg.arg( addr.formattedName(), errorMsg ) ); +} + +QString ResourceXMLRPC::addrTypesToTypeStr( int typeMask ) +{ + QStringList types; + QMap<QString, int>::ConstIterator it; + for ( it = mAddrTypes.begin(); it != mAddrTypes.end(); ++it ) + if ( it.data() & typeMask ) + types.append( it.key() ); + + return types.join( ";" ); +} + +void ResourceXMLRPC::writeContact( const Addressee &addr, QMap<QString, QVariant> &args ) +{ + args.insert( "access", ( addr.secrecy().type() == Secrecy::Private ? "private" : "public" ) ); + args.insert( "fn", addr.formattedName() ); + args.insert( "n_given", addr.givenName() ); + args.insert( "n_family", addr.familyName() ); + args.insert( "n_middle", addr.additionalName() ); + args.insert( "n_prefix", addr.prefix() ); + args.insert( "n_suffix", addr.suffix() ); +// args.insert( "sound", "sound" ); + args.insert( "bday", addr.birthday() ); + args.insert( "note", addr.note() ); + int hours = addr.timeZone().offset() / 60; + args.insert( "tz", hours ); +// args.insert( "geo", "geo" ); + args.insert( "url", addr.url().url() ); +// args.insert( "pubkey", "pubkey" ); + args.insert( "org_name", addr.organization() ); +// args.insert( "org_unit", "org_unit" ); + args.insert( "title", addr.title() ); + + // CATEGORIES + QStringList::ConstIterator catIt; + const QStringList categories = addr.categories(); + + QMap<QString, QVariant> catMap; + int counter = 0; + for ( catIt = categories.begin(); catIt != categories.end(); ++catIt ) { + QMap<QString, int>::ConstIterator it = mCategoryMap.find( *catIt ); + if ( it == mCategoryMap.end() ) // new category + catMap.insert( QString::number( counter-- ), *catIt ); + else + catMap.insert( QString::number( it.data() ), *catIt ); + } + args.insert( "cat_id", catMap ); + + Address workAddr = addr.address( Address::Work ); + if ( !workAddr.isEmpty() ) { + args.insert( "adr_one_street", workAddr.street() ); + args.insert( "adr_one_locality", workAddr.locality() ); + args.insert( "adr_one_region", workAddr.region() ); + args.insert( "adr_one_postalcode", workAddr.postalCode() ); + args.insert( "adr_one_countryname", workAddr.country() ); + + args.insert( "adr_one_type", addrTypesToTypeStr( workAddr.type() ) ); + args.insert( "label", workAddr.label() ); + } + + Address homeAddr = addr.address( Address::Home ); + if ( !homeAddr.isEmpty() ) { + args.insert( "adr_two_street", homeAddr.street() ); + args.insert( "adr_two_locality", homeAddr.locality() ); + args.insert( "adr_two_region", homeAddr.region() ); + args.insert( "adr_two_postalcode", homeAddr.postalCode() ); + args.insert( "adr_two_countryname", homeAddr.country() ); + args.insert( "adr_two_type", addrTypesToTypeStr( homeAddr.type() ) ); + } + + PhoneNumber phone = addr.phoneNumber( PhoneNumber::Work ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_work", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Home ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_home", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Voice ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_voice", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Fax ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_fax", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Msg ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_msg", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Cell ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_cell", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Pager ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_pager", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Bbs ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_bbs", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Modem ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_modem", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Car ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_car", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Isdn ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_isdn", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Video ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_video", phone.number() ); + + phone = addr.phoneNumber( PhoneNumber::Pref ); + if ( !phone.number().isEmpty() ) + args.insert( "tel_prefer", phone.number() ); + + if ( !addr.preferredEmail().isEmpty() ) { + args.insert( "email", addr.preferredEmail() ); + args.insert( "email_type", "INTERNET" ); + } + + if ( addr.emails().count() > 1 ) { + args.insert( "email_home", addr.emails()[ 1 ] ); + args.insert( "email_home_type", "INTERNET" ); + } + + + const QStringList customFields = addr.customs(); + QStringList::ConstIterator it; + for ( it = customFields.begin(); it != customFields.end(); ++it ) { + int colon = (*it).find( ":" ); + QString identifier = (*it).left( colon ); + int dash = identifier.find( "-" ); + QString app = identifier.left( dash ); + QString name = identifier.mid( dash + 1 ); + QString value = (*it).mid( colon + 1 ); + if ( value.isEmpty() ) + continue; + + if ( app == "XMLRPCResource" ) + args.insert( name, value ); + } + + QString url = KCal::FreeBusyUrlStore::self()->readUrl( addr.preferredEmail() ); + if ( !url.isEmpty() ) + args.insert( "freebusy_url", url ); +} + +void ResourceXMLRPC::readContact( const QMap<QString, QVariant> &args, Addressee &addr, QString &uid ) +{ + Address addrOne, addrTwo; + + QMap<QString, QVariant>::ConstIterator it; + for ( it = args.begin(); it != args.end(); ++it ) { + if ( it.key() == "id" ) { + uid = it.data().toString(); + } else if ( it.key() == "access" ) { + Secrecy secrecy; + if ( it.data().toString() == "private" ) + secrecy.setType( Secrecy::Private ); + else + secrecy.setType( Secrecy::Public ); + + addr.setSecrecy( secrecy ); + } else if ( it.key() == "fn" ) { + addr.setFormattedName( it.data().toString() ); + } else if ( it.key() == "n_given" ) { + addr.setGivenName( it.data().toString() ); + } else if ( it.key() == "n_family" ) { + addr.setFamilyName( it.data().toString() ); + } else if ( it.key() == "n_middle" ) { + addr.setAdditionalName( it.data().toString() ); + } else if ( it.key() == "n_prefix" ) { + addr.setPrefix( it.data().toString() ); + } else if ( it.key() == "n_suffix" ) { + addr.setSuffix( it.data().toString() ); + } else if ( it.key() == "sound" ) { + } else if ( it.key() == "bday" ) { + addr.setBirthday( it.data().toDateTime() ); + } else if ( it.key() == "note" ) { + addr.setNote( it.data().toString() ); + } else if ( it.key() == "tz" ) { + int hour = it.data().toInt(); + TimeZone timeZone( hour * 60 ); + addr.setTimeZone( timeZone ); + } else if ( it.key() == "geo" ) { + } else if ( it.key() == "url" ) { + addr.setUrl( KURL( it.data().toString() ) ); + } else if ( it.key() == "pubkey" ) { + } else if ( it.key() == "org_name" ) { + addr.setOrganization( it.data().toString() ); + } else if ( it.key() == "org_unit" ) { + } else if ( it.key() == "title" ) { + addr.setTitle( it.data().toString() ); + } else if ( it.key() == "adr_one_street" ) { + addrOne.setStreet( it.data().toString() ); + } else if ( it.key() == "adr_one_locality" ) { + addrOne.setLocality( it.data().toString() ); + } else if ( it.key() == "adr_one_region" ) { + addrOne.setRegion( it.data().toString() ); + } else if ( it.key() == "adr_one_postalcode" ) { + addrOne.setPostalCode( it.data().toString() ); + } else if ( it.key() == "adr_one_countryname" ) { + addrOne.setCountry( it.data().toString() ); + } else if ( it.key() == "adr_one_type" ) { + QStringList types = QStringList::split( ';', it.data().toString() ); + + int type = Address::Work; + for ( uint i = 0; i < types.count(); ++i ) + type += mAddrTypes[ types[ i ] ]; + + addrOne.setType( type ); + } else if ( it.key() == "label" ) { + addrOne.setLabel( it.data().toString() ); + } else if ( it.key() == "adr_two_street" ) { + addrTwo.setStreet( it.data().toString() ); + } else if ( it.key() == "adr_two_locality" ) { + addrTwo.setLocality( it.data().toString() ); + } else if ( it.key() == "adr_two_region" ) { + addrTwo.setRegion( it.data().toString() ); + } else if ( it.key() == "adr_two_postalcode" ) { + addrTwo.setPostalCode( it.data().toString() ); + } else if ( it.key() == "adr_two_countryname" ) { + addrTwo.setCountry( it.data().toString() ); + } else if ( it.key() == "adr_two_type" ) { + QStringList types = QStringList::split( ';', it.data().toString() ); + + int type = Address::Home; + for ( uint i = 0; i < types.count(); ++i ) + type += mAddrTypes[ types[ i ] ]; + + addrTwo.setType( type ); + } else if ( it.key() == "tel_work" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Work ) ); + } else if ( it.key() == "tel_home" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Home ) ); + } else if ( it.key() == "tel_voice" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Voice ) ); + } else if ( it.key() == "tel_fax" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Fax ) ); + } else if ( it.key() == "tel_msg" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Msg ) ); + } else if ( it.key() == "tel_cell" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Cell ) ); + } else if ( it.key() == "tel_pager" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Pager ) ); + } else if ( it.key() == "tel_bbs" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Bbs ) ); + } else if ( it.key() == "tel_modem" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Modem ) ); + } else if ( it.key() == "tel_car" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Car ) ); + } else if ( it.key() == "tel_isdn" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Isdn ) ); + } else if ( it.key() == "tel_video" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Video ) ); + } else if ( it.key() == "tel_prefer" ) { + addr.insertPhoneNumber( PhoneNumber( it.data().toString(), PhoneNumber::Pref ) ); + } else if ( it.key() == "email" ) { + addr.insertEmail( it.data().toString(), true ); + } else if ( it.key() == "email_type" ) { + } else if ( it.key() == "email_home" ) { + addr.insertEmail( it.data().toString(), false ); + } else if ( it.key() == "email_home_type" ) { + } else if ( it.key() == "cat_id" ) { + const QMap<QString, QVariant> categories = it.data().toMap(); + QMap<QString, QVariant>::ConstIterator it; + + for ( it = categories.begin(); it != categories.end(); ++it ) + addr.insertCategory( it.data().toString() ); + } else if ( it.key() == "rights" ) { + setRights( addr, it.data().toInt() ); + } + } + + QMap<QString, QString>::ConstIterator cfIt; + for ( cfIt = mCustomFieldsMap.begin(); cfIt != mCustomFieldsMap.end(); ++cfIt ) { + if ( args[ cfIt.key() ].toString().isEmpty() ) + continue; + + if ( cfIt.key() == "freebusy_url" ) { + KCal::FreeBusyUrlStore::self()->writeUrl( addr.preferredEmail(), + args[ cfIt.key() ].toString() ); + KCal::FreeBusyUrlStore::self()->sync(); + } else + addr.insertCustom( "XMLRPCResource", cfIt.key(), cfIt.data() ); + } + + if ( !addrOne.isEmpty() ) + addr.insertAddress( addrOne ); + if ( !addrTwo.isEmpty() ) + addr.insertAddress( addrTwo ); +} + +void ResourceXMLRPC::loadCategoriesFinished( const QValueList<QVariant> &mapList, + const QVariant& ) +{ + mCategoryMap.clear(); + + const QMap<QString, QVariant> map = mapList[ 0 ].toMap(); + QMap<QString, QVariant>::ConstIterator it; + + KABPrefs *prefs = KABPrefs::instance(); + for ( it = map.begin(); it != map.end(); ++it ) { + mCategoryMap.insert( it.data().toString(), it.key().toInt() ); + + QStringList categories = prefs->customCategories(); + if ( categories.find( it.data().toString() ) == categories.end() ) + categories.append( it.data().toString() ); + + prefs->mCustomCategories = categories; + } +} + +void ResourceXMLRPC::loadCustomFieldsFinished( const QValueList<QVariant> &mapList, + const QVariant& ) +{ + mCustomFieldsMap.clear(); + + const QMap<QString, QVariant> map = mapList[ 0 ].toMap(); + QMap<QString, QVariant>::ConstIterator it; + + for ( it = map.begin(); it != map.end(); ++it ) + mCustomFieldsMap.insert( it.key(), it.data().toString() ); +} + +#include "kabc_resourcexmlrpc.moc" diff --git a/kresources/egroupware/kabc_resourcexmlrpc.h b/kresources/egroupware/kabc_resourcexmlrpc.h new file mode 100644 index 000000000..57bbd903a --- /dev/null +++ b/kresources/egroupware/kabc_resourcexmlrpc.h @@ -0,0 +1,114 @@ +/* + This file is part of kdepim. + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 KABC_RESOURCEXMLRPC_H +#define KABC_RESOURCEXMLRPC_H + +#include <qmap.h> +#include <kdepimmacros.h> + +#include "libkdepim/kabcresourcecached.h" + +class KConfig; +class Synchronizer; + +namespace KXMLRPC { +class Server; +} + +namespace KABC { + +class EGroupwarePrefs; + +class KDE_EXPORT ResourceXMLRPC : public ResourceCached +{ + Q_OBJECT + + public: + ResourceXMLRPC( const KConfig* ); + ResourceXMLRPC( const QString &url, const QString &domain, + const QString &user, const QString &password ); + ~ResourceXMLRPC(); + + virtual void writeConfig( KConfig* ); + + EGroupwarePrefs *prefs() const { return mPrefs; } + + virtual bool doOpen(); + virtual void doClose(); + + virtual Ticket *requestSaveTicket(); + virtual void releaseSaveTicket( Ticket* ); + + virtual bool load(); + virtual bool asyncLoad(); + virtual bool save( Ticket * ); + virtual bool asyncSave( Ticket * ); + + protected: + void init(); + + protected slots: + void loginFinished( const QValueList<QVariant>&, const QVariant& ); + void logoutFinished( const QValueList<QVariant>&, const QVariant& ); + + void listContactsFinished( const QValueList<QVariant>&, const QVariant& ); + void addContactFinished( const QValueList<QVariant>&, const QVariant& ); + void updateContactFinished( const QValueList<QVariant>&, const QVariant& ); + void deleteContactFinished( const QValueList<QVariant>&, const QVariant& ); + void loadCategoriesFinished( const QValueList<QVariant>&, const QVariant& ); + void loadCustomFieldsFinished( const QValueList<QVariant>&, const QVariant& ); + + void fault( int, const QString&, const QVariant& ); + void addContactFault( int, const QString&, const QVariant& ); + void updateContactFault( int, const QString&, const QVariant& ); + void deleteContactFault( int, const QString&, const QVariant& ); + + void addContact( const KABC::Addressee& ); + void updateContact( const KABC::Addressee& ); + void deleteContact( const KABC::Addressee& ); + + private: + void initEGroupware(); + + QString addrTypesToTypeStr( int ); + + void writeContact( const Addressee&, QMap<QString, QVariant>& ); + void readContact( const QMap<QString, QVariant>&, Addressee &addr, QString& ); + + EGroupwarePrefs *mPrefs; + + QString mSessionID; + QString mKp3; + + QMap<QString, int> mCategoryMap; + QMap<QString, int> mAddrTypes; + QMap<QString, QString> mCustomFieldsMap; + + KXMLRPC::Server *mServer; + Synchronizer *mSynchronizer; + + class ResourceXMLRPCPrivate; + ResourceXMLRPCPrivate *d; +}; + +} + +#endif diff --git a/kresources/egroupware/kabc_resourcexmlrpcconfig.cpp b/kresources/egroupware/kabc_resourcexmlrpcconfig.cpp new file mode 100644 index 000000000..cd2075c71 --- /dev/null +++ b/kresources/egroupware/kabc_resourcexmlrpcconfig.cpp @@ -0,0 +1,97 @@ +/* + This file is part of kdepim. + Copyright (c) 2002 - 2004 Tobias Koenig <tokoe@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 <qlabel.h> +#include <qlayout.h> + +#include <kdebug.h> +#include <kdialog.h> +#include <klocale.h> +#include <klineedit.h> +#include <kurlrequester.h> + +#include "kabc_egroupwareprefs.h" +#include "kabc_resourcexmlrpc.h" +#include "kabc_resourcexmlrpcconfig.h" + +using namespace KABC; + +ResourceXMLRPCConfig::ResourceXMLRPCConfig( QWidget* parent, const char* name ) + : KRES::ConfigWidget( parent, name ) +{ + QGridLayout *mainLayout = new QGridLayout( this, 4, 2, 0, KDialog::spacingHint() ); + + QLabel *label = new QLabel( i18n( "URL:" ), this ); + mURL = new KURLRequester( this ); + + mainLayout->addWidget( label, 0, 0 ); + mainLayout->addWidget( mURL, 0, 1 ); + + label = new QLabel( i18n( "Domain:" ), this ); + mDomain = new KLineEdit( this ); + + mainLayout->addWidget( label, 1, 0 ); + mainLayout->addWidget( mDomain, 1, 1 ); + + label = new QLabel( i18n( "User:" ), this ); + mUser = new KLineEdit( this ); + + mainLayout->addWidget( label, 2, 0 ); + mainLayout->addWidget( mUser, 2, 1 ); + + label = new QLabel( i18n( "Password:" ), this ); + mPassword = new KLineEdit( this ); + mPassword->setEchoMode( QLineEdit::Password ); + + mainLayout->addWidget( label, 3, 0 ); + mainLayout->addWidget( mPassword, 3, 1 ); +} + +void ResourceXMLRPCConfig::loadSettings( KRES::Resource *res ) +{ + ResourceXMLRPC *resource = dynamic_cast<ResourceXMLRPC*>( res ); + + if ( !resource ) { + kdDebug(5700) << "ResourceXMLRPCConfig::loadSettings(): cast failed" << endl; + return; + } + + mURL->setURL( resource->prefs()->url() ); + mDomain->setText( resource->prefs()->domain() ); + mUser->setText( resource->prefs()->user() ); + mPassword->setText( resource->prefs()->password() ); +} + +void ResourceXMLRPCConfig::saveSettings( KRES::Resource *res ) +{ + ResourceXMLRPC *resource = dynamic_cast<ResourceXMLRPC*>( res ); + + if ( !resource ) { + kdDebug(5700) << "ResourceXMLRPCConfig::saveSettings(): cast failed" << endl; + return; + } + + resource->prefs()->setUrl( mURL->url() ); + resource->prefs()->setDomain( mDomain->text() ); + resource->prefs()->setUser( mUser->text() ); + resource->prefs()->setPassword( mPassword->text() ); +} + +#include "kabc_resourcexmlrpcconfig.moc" diff --git a/kresources/egroupware/kabc_resourcexmlrpcconfig.h b/kresources/egroupware/kabc_resourcexmlrpcconfig.h new file mode 100644 index 000000000..6e0ddfdb8 --- /dev/null +++ b/kresources/egroupware/kabc_resourcexmlrpcconfig.h @@ -0,0 +1,52 @@ +/* + This file is part of kdepim. + Copyright (c) 2002 - 2004 Tobias Koenig <tokoe@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 RESOURCEXMLRPCCONFIG_H +#define RESOURCEXMLRPCCONFIG_H + +#include <kresources/configwidget.h> +#include <kdepimmacros.h> + +class KLineEdit; +class KURLRequester; + +namespace KABC { + +class KDE_EXPORT ResourceXMLRPCConfig : public KRES::ConfigWidget +{ + Q_OBJECT + + public: + ResourceXMLRPCConfig( QWidget* parent = 0, const char* name = 0 ); + + public slots: + void loadSettings( KRES::Resource* ); + void saveSettings( KRES::Resource* ); + + private: + KURLRequester *mURL; + KLineEdit *mDomain; + KLineEdit *mUser; + KLineEdit *mPassword; +}; + +} + +#endif diff --git a/kresources/egroupware/kabc_resourcexmlrpcplugin.cpp b/kresources/egroupware/kabc_resourcexmlrpcplugin.cpp new file mode 100644 index 000000000..9fd5611e6 --- /dev/null +++ b/kresources/egroupware/kabc_resourcexmlrpcplugin.cpp @@ -0,0 +1,40 @@ +/* + This file is part of kdepim. + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 "kabc_resourcexmlrpc.h" +#include "kabc_resourcexmlrpcconfig.h" + +#include <kglobal.h> +#include <klocale.h> + +using namespace KABC; + +typedef KRES::PluginFactory< ResourceXMLRPC, ResourceXMLRPCConfig > XMLRPCFactory; + +// FIXME: Use K_EXPORT_COMPONENT_FACTORY( kabc_xmlrpc, XMLRPCFactory ); here +// Problem: How to insert the catalogue! +extern "C" +{ + void *init_kabc_xmlrpc() + { + KGlobal::locale()->insertCatalogue( "kres_xmlrpc" ); + return new XMLRPCFactory; + } +} diff --git a/kresources/egroupware/kabc_xmlrpc.desktop b/kresources/egroupware/kabc_xmlrpc.desktop new file mode 100644 index 000000000..c7386a593 --- /dev/null +++ b/kresources/egroupware/kabc_xmlrpc.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=eGroupware Server (via XML-RPC) +Name[af]=eGroupware Bediener (via XML-RPC) +Name[bg]=Сървър eGroupware (чрез XML-RPC) +Name[br]=Servijer eGroupware (gant XML-RPC) +Name[ca]=Servidor eGroupware (via XML-RPC) +Name[cs]=eGroupware Server (přes XML-RPC) +Name[da]=eGroupware server (via XML-RPC) +Name[el]=Εξυπηρετητής eGroupware (μέσω XML-RPC) +Name[es]=Servidor de eGroupware (por medio de XML-RPC) +Name[et]=eGroupware server (XML-RPC vahendusel) +Name[eu]=eGroupware zerbitzaria (XML-RPC bidez) +Name[fa]=کارساز eGroupware (از طریق XML-RPC) +Name[fi]=eGroupware-palvelin (XML-RPC kautta) +Name[fr]=Serveur eGroupware (via XML-RPC) +Name[fy]=eGroupware-tsjinner (fia XML-RPC) +Name[ga]=Freastalaí eGroupware (via XML-RPC) +Name[gl]=Servidor eGroupware (mediante XML-RPC) +Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül) +Name[is]=eGroupware þjónn (gegnum XML-RPC) +Name[it]=Server eGroupware (via XML-RPC) +Name[ja]=eGroupware サーバ (XML-RPC 経由) +Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით) +Name[kk]=eGroupware сервері (XML-RPC арқылы) +Name[km]=ម៉ាស៊ីនបម្រើ eGroupware (តាមរយៈ XML-RPC) +Name[lt]=eGroupware serveris (per XML-RPC) +Name[ms]=Pelayan eGroupware (melalui XML-RPC) +Name[nb]=eGroupware-tjener (via XML-RPPC) +Name[nds]=eGroupware-Server (över XML-RPC) +Name[ne]=(XML-RPC मार्फत) eGroupware सर्भर +Name[nl]=eGroupware-server (via XML-RPC) +Name[nn]=eGroupware-tenar (via XML-RPC) +Name[pl]=Serwer eGroupware (poprzez XML-RPC) +Name[pt]=Servidor eGroupware (via XML-RPC) +Name[pt_BR]=Servidor eGroupware (via XML-RPC) +Name[ru]=Сервер eGroupware (через XML-RPC) +Name[sk]=eGroupware Server (cez XML-RPC) +Name[sl]=Strežnik eGroupware (preko XML-RPC) +Name[sr]=eGroupware сервер (преко XML-RPC) +Name[sr@Latn]=eGroupware server (preko XML-RPC) +Name[sv]=eGroupware-server (via XML-RPC) +Name[ta]=eGroupware சேவகன் (via XML-RPC) +Name[tr]=eGroupware Sunucusu (XML-RPC ile) +Name[uk]=Сервер eGroupware (через XML-RPC) +Name[zh_CN]=eGroupware 服务器(通过 XML-RPC) +Name[zh_TW]=eGroupware 伺服器(透過 XML-RPC) +X-KDE-Library=kabc_xmlrpc +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=contact +X-KDE-ResourceType=xmlrpc diff --git a/kresources/egroupware/kcal_egroupwareprefs.kcfgc b/kresources/egroupware/kcal_egroupwareprefs.kcfgc new file mode 100644 index 000000000..6a278752b --- /dev/null +++ b/kresources/egroupware/kcal_egroupwareprefs.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=kresources_kcal_egroupware.kcfg +ClassName=EGroupwarePrefs +NameSpace=KCal +Singleton=false +Mutators=true +Inherits=KResourcePrefs +IncludeFiles=libkdepim/kresourceprefs.h +GlobalEnums=true +#ItemAccessors=true +#SetUserTexts=true diff --git a/kresources/egroupware/kcal_resourcexmlrpc.cpp b/kresources/egroupware/kcal_resourcexmlrpc.cpp new file mode 100644 index 000000000..af4f019c1 --- /dev/null +++ b/kresources/egroupware/kcal_resourcexmlrpc.cpp @@ -0,0 +1,1203 @@ +/* + This file is part of kdepim. + + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 <stdlib.h> +#include <typeinfo> + +#include <qapplication.h> +#include <qdatetime.h> +#include <qptrlist.h> +#include <qstringlist.h> +#include <qtimer.h> + +#include <kabc/locknull.h> +#include <kdebug.h> +#include <klocale.h> +#include <kresources/configwidget.h> +#include <kstandarddirs.h> +#include <kstringhandler.h> +#include <kurl.h> +#include <libkdepim/kpimprefs.h> + +#include "libkcal/vcaldrag.h" +#include "libkcal/vcalformat.h" +#include "libkcal/icalformat.h" +#include "libkcal/exceptions.h" +#include "libkcal/incidence.h" +#include "libkcal/event.h" +#include "libkcal/todo.h" +#include "libkcal/journal.h" +#include "libkcal/filestorage.h" +#include "libkcal/alarm.h" + +#include "kcal_egroupwareprefs.h" +#include "kcal_resourcexmlrpcconfig.h" +#include "kcal_resourcexmlrpc.h" + +#include "access.h" +#include "synchronizer.h" +#include "xmlrpciface.h" + +#define CAL_PRIO_LOW 1 +#define CAL_PRIO_NORMAL 2 +#define CAL_PRIO_HIGH 3 + +#define CAL_RECUR_NONE 0 +#define CAL_RECUR_DAILY 1 +#define CAL_RECUR_WEEKLY 2 +#define CAL_RECUR_MONTHLY_MDAY 3 +#define CAL_RECUR_MONTHLY_WDAY 4 +#define CAL_RECUR_YEARLY 5 +#define CAL_SUNDAY 1 +#define CAL_MONDAY 2 +#define CAL_TUESDAY 4 +#define CAL_WEDNESDAY 8 +#define CAL_THURSDAY 16 +#define CAL_FRIDAY 32 +#define CAL_SATURDAY 64 +#define CAL_WEEKDAYS 62 +#define CAL_WEEKEND 65 +#define CAL_ALLDAYS 127 + +using namespace KCal; + +typedef KRES::PluginFactory<ResourceXMLRPC, ResourceXMLRPCConfig> XMLRPCFactory; +K_EXPORT_COMPONENT_FACTORY( kcal_xmlrpc, XMLRPCFactory ) + + +static const QString SearchEventsCommand = "calendar.bocalendar.search"; +static const QString AddEventCommand = "calendar.bocalendar.write"; +static const QString DeleteEventCommand = "calendar.bocalendar.delete"; +static const QString LoadEventCategoriesCommand = "calendar.bocalendar.categories"; + +static const QString SearchTodosCommand = "infolog.boinfolog.search"; +static const QString AddTodoCommand = "infolog.boinfolog.write"; +static const QString DeleteTodoCommand = "infolog.boinfolog.delete"; +static const QString LoadTodoCategoriesCommand = "infolog.boinfolog.categories"; + +static void setRights( Incidence *incidence, int rights ) +{ + incidence->setCustomProperty( "EGWRESOURCE", "RIGHTS", QString::number( rights ) ); +} + +static int rights( Incidence *incidence ) +{ + return incidence->customProperty( "EGWRESOURCE", "RIGHTS" ).toInt(); +} + +ResourceXMLRPC::ResourceXMLRPC( const KConfig* config ) + : ResourceCached( config ), mServer( 0 ), mLock( 0 ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + if ( config ) + readConfig( config ); + + initEGroupware(); +} + +ResourceXMLRPC::ResourceXMLRPC( ) + : ResourceCached( 0 ), mServer( 0 ), mLock( 0 ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + initEGroupware(); +} + +ResourceXMLRPC::~ResourceXMLRPC() +{ + disableChangeNotification(); + + delete mServer; + mServer = 0; + + delete mLock; + mLock = 0; + + delete mPrefs; + mPrefs = 0; + + delete mSynchronizer; + mSynchronizer = 0; +} + +void ResourceXMLRPC::init() +{ + setType( "xmlrpc" ); + + mTodoStateMapper.setPath( "kcal/todostatemap/" ); + + mPrefs = new EGroupwarePrefs; + mLoaded = 0; + + mLock = new KABC::LockNull( true ); + mSynchronizer = new Synchronizer(); +} + +void ResourceXMLRPC::initEGroupware() +{ + KURL url( mPrefs->url() ); +} + +void ResourceXMLRPC::readConfig( const KConfig* config ) +{ + mPrefs->readConfig(); + + ResourceCached::readConfig( config ); +} + +void ResourceXMLRPC::writeConfig( KConfig* config ) +{ + ResourceCalendar::writeConfig( config ); + + mPrefs->writeConfig(); + + ResourceCached::writeConfig( config ); +} + +bool ResourceXMLRPC::doOpen() +{ + kdDebug(5800) << "ResourceXMLRPC::doOpen()" << endl; + + if ( mServer ) + delete mServer; + + mServer = new KXMLRPC::Server( KURL(), this ); + mServer->setUrl( KURL( mPrefs->url() ) ); + mServer->setUserAgent( "KDE-Calendar" ); + + QMap<QString, QVariant> args; + args.insert( "domain", mPrefs->domain() ); + args.insert( "username", mPrefs->user() ); + args.insert( "password", mPrefs->password() ); + + mServer->call( "system.login", QVariant( args ), + this, SLOT( loginFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mSynchronizer->start(); + + return true; +} + +void ResourceXMLRPC::doClose() +{ + kdDebug(5800) << "ResourceXMLRPC::doClose()" << endl; + + QMap<QString, QVariant> args; + args.insert( "sessionid", mSessionID ); + args.insert( "kp3", mKp3 ); + + mServer->call( "system.logout", QVariant( args ), + this, SLOT( logoutFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mSynchronizer->start(); +} + +bool ResourceXMLRPC::doLoad() +{ + kdDebug() << "ResourceXMLRPC::load()" << endl; + + mCalendar.close(); + + disableChangeNotification(); + loadCache(); + enableChangeNotification(); + + emit resourceChanged( this ); + + clearChanges(); + + loadCache(); + mTodoStateMapper.setIdentifier( type() + "_" + identifier() ); + mTodoStateMapper.load(); + + QMap<QString, QVariant> args, columns; + args.insert( "start", QDateTime( QDate::currentDate().addDays( -12 ) ) ); + args.insert( "end", QDateTime( QDate::currentDate().addDays( 2000 ) ) ); + + mServer->call( SearchEventsCommand, args, + this, SLOT( listEventsFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + args.clear(); + + columns.insert( "type", "task" ); + args.insert( "filter", "none" ); + args.insert( "col_filter", columns ); + args.insert( "order", "id_parent" ); + + mServer->call( SearchTodosCommand, args, + this, SLOT( listTodosFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mServer->call( LoadEventCategoriesCommand, QVariant( QMap<QString, QVariant>() ), + this, SLOT( loadEventCategoriesFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mServer->call( LoadTodoCategoriesCommand, QVariant( false, 0 ), + this, SLOT( loadTodoCategoriesFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + return true; +} + +bool ResourceXMLRPC::doSave() +{ + if ( readOnly() || !hasChanges() ) { + emit resourceSaved( this ); + return true; + } + + saveCache(); + + const Event::List events = mCalendar.rawEvents(); + Event::List::ConstIterator evIt; + + uint counter = 0; + for ( evIt = events.begin(); evIt != events.end(); ++evIt ) { + if ( !(*evIt)->isReadOnly() ) { + QMap<QString, QVariant> args; + writeEvent( (*evIt), args ); + + args.insert( "id", idMapper().remoteId( (*evIt)->uid() ).toInt() ); + mServer->call( AddEventCommand, QVariant( args ), + this, SLOT( updateEventFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + counter++; + } + } + + const Todo::List todos = mCalendar.rawTodos(); + Todo::List::ConstIterator todoIt; + + for ( todoIt = todos.begin(); todoIt != todos.end(); ++todoIt ) { + if ( !(*todoIt)->isReadOnly() ) { + QMap<QString, QVariant> args; + writeTodo( (*todoIt), args ); + + args.insert( "id", idMapper().remoteId( (*todoIt)->uid() ).toInt() ); + mServer->call( AddTodoCommand, QVariant( args ), + this, SLOT( updateTodoFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + counter++; + } + } + + if ( counter != 0 ) + mSynchronizer->start(); + + mTodoStateMapper.save(); + + return true; +} + +bool ResourceXMLRPC::isSaving() +{ + return false; +} + +KABC::Lock *ResourceXMLRPC::lock() +{ + return mLock; +} + + +bool ResourceXMLRPC::addEvent( Event* ev ) +{ + QMap<QString, QVariant> args; + + disableChangeNotification(); + + setRights( ev, EGW_ACCESS_ALL ); + Event *oldEvent = mCalendar.event( ev->uid() ); + if ( oldEvent ) { // already exists + if ( !oldEvent->isReadOnly() ) { + writeEvent( ev, args ); + args.insert( "id", idMapper().remoteId( ev->uid() ).toInt() ); + mServer->call( AddEventCommand, QVariant( args ), + this, SLOT( updateEventFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mCalendar.deleteIncidence( oldEvent ); + mCalendar.addIncidence( ev ); + saveCache(); + } + } else { // new event + writeEvent( ev, args ); + mServer->call( AddEventCommand, QVariant( args ), + this, SLOT( addEventFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ), + QVariant( ev->uid() ) ); + + mCalendar.addEvent( ev ); + saveCache(); + } + + enableChangeNotification(); + + return true; +} + +bool ResourceXMLRPC::deleteEvent( Event* ev ) +{ + if ( !(rights( ev ) & EGW_ACCESS_DELETE) && rights( ev ) != -1 ) + return false; + + mServer->call( DeleteEventCommand, idMapper().remoteId( ev->uid() ).toInt(), + this, SLOT( deleteEventFinished( const QValueList<QVariant>&, + const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ), + QVariant( ev->uid() ) ); + return true; +} + + +Event *ResourceXMLRPC::event( const QString& uid ) +{ + return mCalendar.event( uid ); +} + +Event::List ResourceXMLRPC::rawEventsForDate( const QDate& qd, + EventSortField sortField, + SortDirection sortDirection ) +{ + return mCalendar.rawEventsForDate( qd, sortField, sortDirection ); +} + + +Event::List ResourceXMLRPC::rawEvents( const QDate& start, const QDate& end, + bool inclusive ) +{ + return mCalendar.rawEvents( start, end, inclusive ); +} + +Event::List ResourceXMLRPC::rawEventsForDate( const QDateTime& qdt ) +{ + return mCalendar.rawEventsForDate( qdt.date() ); +} + +Event::List ResourceXMLRPC::rawEvents() +{ + return mCalendar.rawEvents(); +} + + +bool ResourceXMLRPC::addTodo( Todo *todo ) +{ + QMap<QString, QVariant> args; + + disableChangeNotification(); + + setRights( todo, EGW_ACCESS_ALL ); + Todo *oldTodo = mCalendar.todo( todo->uid() ); + if ( oldTodo ) { // already exists + if ( !oldTodo->isReadOnly() ) { + writeTodo( todo, args ); + args.insert( "id", idMapper().remoteId( todo->uid() ).toInt() ); + mServer->call( AddTodoCommand, QVariant( args ), + this, SLOT( updateTodoFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mCalendar.deleteIncidence( oldTodo ); + mCalendar.addIncidence( todo ); + saveCache(); + } + } else { // new todo + writeTodo( todo, args ); + mServer->call( AddTodoCommand, QVariant( args ), + this, SLOT( addTodoFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ), + QVariant( todo->uid() ) ); + + mCalendar.addTodo( todo ); + saveCache(); + } + + enableChangeNotification(); + + return true; +} + +bool ResourceXMLRPC::deleteTodo( Todo *todo ) +{ + if ( !(rights( todo ) & EGW_ACCESS_DELETE) && rights( todo ) != -1 ) + return false; + + mServer->call( DeleteTodoCommand, idMapper().remoteId( todo->uid() ).toInt(), + this, SLOT( deleteTodoFinished( const QValueList<QVariant>&, + const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ), + QVariant( todo->uid() ) ); + return true; +} + +Todo::List ResourceXMLRPC::rawTodos() +{ + return mCalendar.rawTodos(); +} + +Todo *ResourceXMLRPC::todo( const QString& uid ) +{ + return mCalendar.todo( uid ); +} + +Todo::List ResourceXMLRPC::rawTodosForDate( const QDate& date ) +{ + return mCalendar.rawTodosForDate( date ); +} + +bool ResourceXMLRPC::addJournal( Journal* journal ) +{ + return mCalendar.addJournal( journal ); +} + +bool ResourceXMLRPC::deleteJournal( Journal* journal ) +{ + return mCalendar.deleteJournal( journal ); +} + +Journal::List ResourceXMLRPC::journals( const QDate& date ) +{ + return mCalendar.journals( date ); +} + +Journal *ResourceXMLRPC::journal( const QString& uid ) +{ + return mCalendar.journal( uid ); +} + + +Alarm::List ResourceXMLRPC::alarmsTo( const QDateTime& to ) +{ + return mCalendar.alarmsTo( to ); +} + +Alarm::List ResourceXMLRPC::alarms( const QDateTime& from, const QDateTime& to ) +{ + return mCalendar.alarms( from, to ); +} + +void ResourceXMLRPC::dump() const +{ + ResourceCalendar::dump(); +} + +void ResourceXMLRPC::reload() +{ + load(); +} + + +void ResourceXMLRPC::loginFinished( const QValueList<QVariant>& variant, + const QVariant& ) +{ + QMap<QString, QVariant> map = variant[ 0 ].toMap(); + + KURL url = KURL( mPrefs->url() ); + if ( map[ "GOAWAY" ].toString() == "XOXO" ) { // failed + mSessionID = mKp3 = ""; + } else { + mSessionID = map[ "sessionid" ].toString(); + mKp3 = map[ "kp3" ].toString(); + } + + url.setUser( mSessionID ); + url.setPass( mKp3 ); + mServer->setUrl( url ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::logoutFinished( const QValueList<QVariant>& variant, + const QVariant& ) +{ + QMap<QString, QVariant> map = variant[ 0 ].toMap(); + + if ( map[ "GOODBYE" ].toString() != "XOXO" ) + kdError() << "logout failed" << endl; + + KURL url = KURL( mPrefs->url() ); + mSessionID = mKp3 = ""; + url.setUser( mSessionID ); + url.setPass( mKp3 ); + mServer->setUrl( url ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::listEventsFinished( const QValueList<QVariant>& list, + const QVariant& ) +{ + const QValueList<QVariant> eventList = list[ 0 ].toList(); + QValueList<QVariant>::ConstIterator eventIt; + + disableChangeNotification(); + + Event::List retrievedEvents; + + bool changed = false; + for ( eventIt = eventList.begin(); eventIt != eventList.end(); ++eventIt ) { + QMap<QString, QVariant> map = (*eventIt).toMap(); + + Event *event = new Event; + event->setFloats( false ); + + QString uid; + readEvent( map, event, uid ); + + // do we already have this event? + Event *oldEvent = 0; + QString localUid = idMapper().localId( uid ); + if ( !localUid.isEmpty() ) + oldEvent = mCalendar.event( localUid ); + + if ( oldEvent ) { + event->setUid( oldEvent->uid() ); + event->setCreated( oldEvent->created() ); + + if ( !(*oldEvent == *event) ) { + mCalendar.deleteEvent( oldEvent ); + mCalendar.addEvent( event ); + retrievedEvents.append( event ); + changed = true; + } else + delete event; + } else { + if ( !localUid.isEmpty() ) + event->setUid( localUid ); + idMapper().setRemoteId( event->uid(), uid ); + mCalendar.addEvent( event ); + retrievedEvents.append( event ); + changed = true; + } + } + + enableChangeNotification(); + + clearChanges(); + + + if ( changed ) { + cleanUpEventCache( retrievedEvents ); + saveCache(); + emit resourceChanged( this ); + } + + checkLoadingFinished(); +} + +void ResourceXMLRPC::deleteEventFinished( const QValueList<QVariant>&, + const QVariant& id ) +{ + idMapper().removeRemoteId( idMapper().remoteId( id.toString() ) ); + + Event *ev = mCalendar.event( id.toString() ); + + disableChangeNotification(); + mCalendar.deleteEvent( ev ); + saveCache(); + enableChangeNotification(); + + emit resourceChanged( this ); +} + +void ResourceXMLRPC::updateEventFinished( const QValueList<QVariant>&, + const QVariant& ) +{ + mSynchronizer->stop(); +} + +void ResourceXMLRPC::addEventFinished( const QValueList<QVariant>& list, + const QVariant& id ) +{ + idMapper().setRemoteId( id.toString(), list[ 0 ].toString() ); + + emit resourceChanged( this ); +} + +void ResourceXMLRPC::loadEventCategoriesFinished( const QValueList<QVariant> &mapList, const QVariant& ) +{ + mEventCategoryMap.clear(); + + const QMap<QString, QVariant> map = mapList[ 0 ].toMap(); + QMap<QString, QVariant>::ConstIterator it; + + KPimPrefs prefs( "korganizerrc" ); + for ( it = map.begin(); it != map.end(); ++it ) { + mEventCategoryMap.insert( it.data().toString(), it.key().toInt() ); + + if ( prefs.mCustomCategories.find( it.data().toString() ) == prefs.mCustomCategories.end() ) + prefs.mCustomCategories.append( it.data().toString() ); + } + + prefs.usrWriteConfig(); + prefs.config()->sync(); + + checkLoadingFinished(); +} + +void ResourceXMLRPC::listTodosFinished( const QValueList<QVariant>& list, + const QVariant& ) +{ + const QValueList<QVariant> todoList = list[ 0 ].toList(); + QValueList<QVariant>::ConstIterator todoIt; + + disableChangeNotification(); + + Todo::List retrievedTodos; + + bool changed = false; + for ( todoIt = todoList.begin(); todoIt != todoList.end(); ++todoIt ) { + QMap<QString, QVariant> map = (*todoIt).toMap(); + + Todo *todo = new Todo; + + QString uid; + readTodo( map, todo, uid ); + + // do we already have this todo? + Todo *oldTodo = 0; + QString localUid = idMapper().localId( uid ); + if ( !localUid.isEmpty() ) + oldTodo = mCalendar.todo( localUid ); + + if ( oldTodo ) { + todo->setUid( oldTodo->uid() ); + todo->setCreated( oldTodo->created() ); + + if ( !(*oldTodo == *todo) ) { + mCalendar.deleteTodo( oldTodo ); + mCalendar.addTodo( todo ); + retrievedTodos.append( todo ); + changed = true; + } else + delete todo; + } else { + idMapper().setRemoteId( todo->uid(), uid ); + mCalendar.addTodo( todo ); + retrievedTodos.append( todo ); + changed = true; + } + } + + enableChangeNotification(); + + if ( changed ) { + cleanUpTodoCache( retrievedTodos ); + saveCache(); + emit resourceChanged( this ); + } + + checkLoadingFinished(); +} + +void ResourceXMLRPC::deleteTodoFinished( const QValueList<QVariant>&, + const QVariant& id ) +{ + idMapper().removeRemoteId( idMapper().remoteId( id.toString() ) ); + mTodoStateMapper.remove( idMapper().remoteId( id.toString() ) ); + + Todo *todo = mCalendar.todo( id.toString() ); + disableChangeNotification(); + mCalendar.deleteTodo( todo ); + saveCache(); + enableChangeNotification(); + + emit resourceChanged( this ); +} + +void ResourceXMLRPC::addTodoFinished( const QValueList<QVariant>& list, + const QVariant& id ) +{ + idMapper().setRemoteId( id.toString(), list[ 0 ].toString() ); + + emit resourceChanged( this ); +} + +void ResourceXMLRPC::updateTodoFinished( const QValueList<QVariant>&, + const QVariant& ) +{ + mSynchronizer->stop(); +} + +void ResourceXMLRPC::loadTodoCategoriesFinished( const QValueList<QVariant> &mapList, const QVariant& ) +{ + mTodoCategoryMap.clear(); + + const QMap<QString, QVariant> map = mapList[ 0 ].toMap(); + QMap<QString, QVariant>::ConstIterator it; + + KPimPrefs prefs( "korganizerrc" ); + for ( it = map.begin(); it != map.end(); ++it ) { + mTodoCategoryMap.insert( it.data().toString(), it.key().toInt() ); + + if ( prefs.mCustomCategories.find( it.data().toString() ) == prefs.mCustomCategories.end() ) + prefs.mCustomCategories.append( it.data().toString() ); + } + + prefs.usrWriteConfig(); + prefs.config()->sync(); + + checkLoadingFinished(); +} + +void ResourceXMLRPC::fault( int error, const QString& errorMsg, + const QVariant& ) +{ + kdError() << "Server send error " << error << ": " << errorMsg << endl; + mSynchronizer->stop(); +} + +void ResourceXMLRPC::readEvent( const QMap<QString, QVariant> &args, Event *event, + QString &uid ) +{ + // for recurrence + int rType = CAL_RECUR_NONE; + int rInterval = 1; + int rData = 0; + int rights = 0; + QDateTime rEndDate; + QValueList<QDateTime> rExceptions; + + QMap<QString, QVariant>::ConstIterator it; + for ( it = args.begin(); it != args.end(); ++it ) { + if ( it.key() == "id" ) { + uid = it.data().toString(); + } else if ( it.key() == "rights" ) { + rights = it.data().toInt(); + } else if ( it.key() == "start" ) { + event->setDtStart( it.data().toDateTime() ); + } else if ( it.key() == "end" ) { + QDateTime start = args[ "start" ].toDateTime(); + QDateTime end = it.data().toDateTime(); + if ( start.time() == end.time() && + start.time().hour() == 0 && start.time().minute() == 0 && + start.time().second() == 0 ) { + event->setDtEnd( end.addDays( -1 ) ); + event->setFloats( true ); + } else { + event->setDtEnd( end ); + event->setHasEndDate( true ); + } + } else if ( it.key() == "modtime" ) { + event->setLastModified( it.data().toDateTime() ); + } else if ( it.key() == "title" ) { + event->setSummary( it.data().toString() ); + } else if ( it.key() == "description" ) { + event->setDescription( it.data().toString() ); + } else if ( it.key() == "location" ) { + event->setLocation( it.data().toString() ); + } else if ( it.key() == "access" ) { + event->setSecrecy( (it.data().toString() == "public" ? + Incidence::SecrecyPublic : Incidence::SecrecyPrivate) ); + } else if ( it.key() == "category" ) { + const QMap<QString, QVariant> categories = it.data().toMap(); + QMap<QString, QVariant>::ConstIterator catIt; + + QStringList eventCategories; + for ( catIt = categories.begin(); catIt != categories.end(); ++catIt ) { + mEventCategoryMap.insert( catIt.data().toString(), catIt.key().toInt() ); + eventCategories.append( catIt.data().toString() ); + } + + event->setCategories( eventCategories ); + } else if ( it.key() == "priority" ) { + int priority = 0; + + switch( it.data().toInt() ) { + case CAL_PRIO_LOW: + priority = 10; + break; + case CAL_PRIO_NORMAL: + priority = 5; + break; + case CAL_PRIO_HIGH: + priority = 1; + } + + event->setPriority( priority ); + } else if ( it.key() == "recur_type" ) { + rType = it.data().toInt(); + } else if ( it.key() == "recur_interval" ) { + rInterval = it.data().toInt(); + } else if ( it.key() == "recur_enddate" ) { + rEndDate = it.data().toDateTime(); + } else if ( it.key() == "recur_data" ) { + rData = it.data().toInt(); + } else if ( it.key() == "recur_exception" ) { + const QMap<QString, QVariant> dateList = it.data().toMap(); + QMap<QString, QVariant>::ConstIterator dateIt; + + for ( dateIt = dateList.begin(); dateIt != dateList.end(); ++dateIt ) + rExceptions.append( (*dateIt).toDateTime() ); + } else if ( it.key() == "participants" ) { + const QMap<QString, QVariant> persons = it.data().toMap(); + QMap<QString, QVariant>::ConstIterator personsIt; + + for ( personsIt = persons.begin(); personsIt != persons.end(); ++personsIt ) { + QMap<QString, QVariant> person = (*personsIt).toMap(); + Attendee::PartStat status = Attendee::InProcess; + if ( person[ "status" ] == "A" ) + status = Attendee::Accepted; + else if ( person[ "status" ] == "R" ) + status = Attendee::Declined; + else if ( person[ "status" ] == "T" ) + status = Attendee::Tentative; + else if ( person[ "status" ] == "N" ) + status = Attendee::InProcess; + + Attendee *attendee = new Attendee( person[ "name" ].toString(), + person[ "email" ].toString(), + false, status ); + attendee->setUid( personsIt.key() ); + event->addAttendee( attendee ); + } + } else if ( it.key() == "alarm" ) { + const QMap<QString, QVariant> alarmList = it.data().toMap(); + QMap<QString, QVariant>::ConstIterator alarmIt; + + for ( alarmIt = alarmList.begin(); alarmIt != alarmList.end(); ++alarmIt ) { + QMap<QString, QVariant> alarm = (*alarmIt).toMap(); + + Alarm *vAlarm = event->newAlarm(); + vAlarm->setText( event->summary() ); + vAlarm->setTime( alarm[ "time" ].toDateTime() ); + vAlarm->setStartOffset( alarm[ "offset" ].toInt() ); + vAlarm->setEnabled( alarm[ "enabled" ].toBool() ); + } + } + } + + if ( rType != CAL_RECUR_NONE && rInterval > 0 ) { + Recurrence *re = event->recurrence(); +// re->setRecurStart( event->dtStart() ); + + + if ( rInterval == 0 ) // libkcal crashes with rInterval == 0 + rInterval = 1; + + switch ( rType ) { + case CAL_RECUR_DAILY: + re->setDaily( rInterval ); + break; + case CAL_RECUR_WEEKLY: { + QBitArray weekMask( 7 ); + weekMask.setBit( 0, rData & CAL_MONDAY ); + weekMask.setBit( 1, rData & CAL_TUESDAY ); + weekMask.setBit( 2, rData & CAL_WEDNESDAY ); + weekMask.setBit( 3, rData & CAL_THURSDAY ); + weekMask.setBit( 4, rData & CAL_FRIDAY ); + weekMask.setBit( 5, rData & CAL_SATURDAY ); + weekMask.setBit( 6, rData & CAL_SUNDAY ); + + re->setWeekly( rInterval, weekMask ); + break; } + case CAL_RECUR_MONTHLY_MDAY: + re->setMonthly( rInterval ); + break; + case CAL_RECUR_MONTHLY_WDAY: + re->setMonthly( rInterval ); + // TODO: Set the correct monthly pos + break; + case CAL_RECUR_YEARLY: + re->setYearly( rInterval ); + break; + } + if ( rEndDate.date().isValid() ) + re->setEndDate( rEndDate.date() ); + + QValueList<QDateTime>::ConstIterator exIt; + for ( exIt = rExceptions.begin(); exIt != rExceptions.end(); ++exIt ) + re->addExDateTime( *exIt ); + } + + event->setReadOnly( !(rights & EGW_ACCESS_EDIT) ); + setRights( event, rights ); +} + +void ResourceXMLRPC::writeEvent( Event *event, QMap<QString, QVariant> &args ) +{ + args.insert( "start", event->dtStart() ); + + // handle all day events + if ( event->doesFloat() ) + args.insert( "end", event->dtEnd().addDays( 1 ) ); + else + args.insert( "end", event->dtEnd() ); + + args.insert( "modtime", event->lastModified() ); + args.insert( "title", event->summary() ); + args.insert( "description", event->description() ); + args.insert( "location", event->location() ); + + // SECRECY + args.insert( "access", (event->secrecy() == Incidence::SecrecyPublic ? "public" : "private") ); + + // CATEGORY + const QStringList categories = event->categories(); + QStringList::ConstIterator catIt; + QMap<QString, QVariant> catMap; + int counter = 0; + for ( catIt = categories.begin(); catIt != categories.end(); ++catIt ) { + QMap<QString, int>::Iterator it = mEventCategoryMap.find( *catIt ); + if ( it == mEventCategoryMap.end() ) // new category + catMap.insert( QString::number( counter-- ), *catIt ); + else + catMap.insert( QString::number( it.data() ), *catIt ); + } + args.insert( "category", catMap ); + + // PRIORITY + int priority = 0; + if ( event->priority() == 1 ) + priority = CAL_PRIO_HIGH; + else if ( event->priority() > 1 && event->priority() <= 5 ) + priority = CAL_PRIO_NORMAL; + else + priority = CAL_PRIO_LOW; + + args.insert( "priority", priority ); + + // RECURRENCE + Recurrence *rec = event->recurrence(); + if ( !rec->doesRecur() ) { + args.insert( "recur_type", int( 0 ) ); + args.insert( "recur_interval", int( 0 ) ); + args.insert( "recur_enddate", QDateTime() ); + args.insert( "recur_data", int( 0 ) ); + args.insert( "recur_exception", QMap<QString, QVariant>() ); + } else { + switch ( rec->recurrenceType() ) { + case Recurrence::rDaily: + args.insert( "recur_type", int( CAL_RECUR_DAILY ) ); + break; + case Recurrence::rWeekly: { + int weekMask = 0; + if ( rec->days().testBit( 0 ) ) + weekMask += CAL_MONDAY; + if ( rec->days().testBit( 1 ) ) + weekMask += CAL_TUESDAY; + if ( rec->days().testBit( 2 ) ) + weekMask += CAL_WEDNESDAY; + if ( rec->days().testBit( 3 ) ) + weekMask += CAL_THURSDAY; + if ( rec->days().testBit( 4 ) ) + weekMask += CAL_FRIDAY; + if ( rec->days().testBit( 5 ) ) + weekMask += CAL_SATURDAY; + if ( rec->days().testBit( 6 ) ) + weekMask += CAL_SUNDAY; + + args.insert( "recur_data", weekMask ); + args.insert( "recur_type", int( CAL_RECUR_WEEKLY ) ); + } + break; + case Recurrence::rMonthlyPos: + args.insert( "recur_type", int( CAL_RECUR_MONTHLY_MDAY ) ); + break; + case Recurrence::rMonthlyDay: + args.insert( "recur_type", int( CAL_RECUR_MONTHLY_WDAY ) ); + break; + case Recurrence::rYearlyDay: + args.insert( "recur_type", int( CAL_RECUR_YEARLY ) ); + break; + default: + break; + } + + args.insert( "recur_interval", rec->frequency() ); + args.insert( "recur_enddate", rec->endDateTime() ); + + // TODO: Also use exception dates! + const QValueList<QDateTime> dates = event->recurrence()->exDateTimes(); + QValueList<QDateTime>::ConstIterator dateIt; + QMap<QString, QVariant> exMap; + int counter = 0; + for ( dateIt = dates.begin(); dateIt != dates.end(); ++dateIt, ++counter ) + exMap.insert( QString::number( counter ), *dateIt ); + + args.insert( "recur_exception", exMap ); + } + + // PARTICIPANTS + const Attendee::List attendees = event->attendees(); + Attendee::List::ConstIterator attIt; + QMap<QString, QVariant> persons; + for ( attIt = attendees.begin(); attIt != attendees.end(); ++attIt ) { + QMap<QString, QVariant> person; + QString status; + + if ( (*attIt)->status() == Attendee::Accepted ) + status = "A"; + else if ( (*attIt)->status() == Attendee::Declined ) + status = "R"; + else if ( (*attIt)->status() == Attendee::Tentative ) + status = "T"; + else + status = "N"; + + person.insert( "status", status ); + person.insert( "name", (*attIt)->name() ); + person.insert( "email", (*attIt)->email() ); + + persons.insert( (*attIt)->uid(), person ); + } + args.insert( "participants", persons ); + + // ALARMS + const Alarm::List alarms = event->alarms(); + Alarm::List::ConstIterator alarmIt; + QMap<QString, QVariant> alarmMap; + for ( alarmIt = alarms.begin(); alarmIt != alarms.end(); ++alarmIt ) { + QMap<QString, QVariant> alarm; + alarm.insert( "time", (*alarmIt)->time() ); + alarm.insert( "offset", (*alarmIt)->startOffset().asSeconds() ); + alarm.insert( "enabled", ( (*alarmIt)->enabled() ? int( 1 ) : int( 0 ) ) ); + + alarmMap.insert( "id", alarm ); // that sucks... + } + + args.insert( "alarm", alarmMap ); +} + +void ResourceXMLRPC::writeTodo( Todo* todo, QMap<QString, QVariant>& args ) +{ + args.insert( "subject", todo->summary() ); + args.insert( "des", todo->description() ); + args.insert( "access", + (todo->secrecy() == Todo::SecrecyPublic ? "public" : "private" ) ); + + // CATEGORIES + QMap<QString, QVariant> catMap; + + const QStringList categories = todo->categories(); + QStringList::ConstIterator catIt; + int counter = 0; + for ( catIt = categories.begin(); catIt != categories.end(); ++catIt ) { + QMap<QString, int>::Iterator it = mTodoCategoryMap.find( *catIt ); + if ( it == mTodoCategoryMap.end() ) + catMap.insert( QString::number( counter-- ), *catIt ); + else + catMap.insert( QString::number( it.data() ), *catIt ); + } + args.insert( "category", catMap ); + + args.insert( "datemodified", todo->lastModified() ); + args.insert( "startdate", todo->dtStart() ); + args.insert( "enddate", todo->dtDue() ); + + // SUBTODO + Incidence *inc = todo->relatedTo(); + if ( inc ) { + QString parentUid = idMapper().remoteId( inc->uid() ); + args.insert( "id_parent", parentUid ); + } + + // STATE + QString remoteId = idMapper().remoteId( todo->uid() ); + QString status = mTodoStateMapper.remoteState( remoteId, todo->percentComplete() ); + args.insert( "status", status ); +} + +void ResourceXMLRPC::readTodo( const QMap<QString, QVariant>& args, Todo *todo, QString &uid ) +{ + uid = args[ "id" ].toString(); + +/* + info_from + info_addr + info_owner + info_responsible + info_modifier +*/ + + todo->setSummary( args[ "subject" ].toString() ); + todo->setDescription( args[ "des" ].toString() ); + todo->setSecrecy( args[ "access" ].toString() == "public" ? Todo::SecrecyPublic : Todo::SecrecyPrivate ); + + // CATEGORIES + const QMap<QString, QVariant> categories = args[ "category" ].toMap(); + QMap<QString, QVariant>::ConstIterator it; + + QStringList todoCategories; + for ( it = categories.begin(); it != categories.end(); ++it ) { + mTodoCategoryMap.insert( it.data().toString(), it.key().toInt() ); + todoCategories.append( it.data().toString() ); + } + + todo->setCategories( todoCategories ); + + todo->setLastModified( args[ "datemodified" ].toDateTime() ); + + todo->setFloats( true ); + QDateTime dateTime = args[ "startdate" ].toDateTime(); + if ( dateTime.isValid() ) { + todo->setDtStart( dateTime ); + todo->setHasStartDate( true ); + if ( !dateTime.time().isNull() ) + todo->setFloats( false ); + } + + dateTime = args[ "enddate" ].toDateTime(); + if ( dateTime.isValid() ) { + todo->setDtDue( dateTime ); + todo->setHasDueDate( true ); + if ( !dateTime.time().isNull() ) + todo->setFloats( false ); + } + + // SUBTODO + QString parentId = args[ "id_parent" ].toString(); + if ( parentId != "0" ) { // we are a sub todo + QString localParentUid = idMapper().localId( parentId ); + if ( !localParentUid.isEmpty() ) { // found parent todo + Todo *parent = mCalendar.todo( localParentUid ); + if ( parent ) + todo->setRelatedTo( parent ); + } + } + + // STATE + QString status = args[ "status" ].toString(); + int state = TodoStateMapper::toLocal( status ); + + mTodoStateMapper.addTodoState( uid, state, status ); + todo->setPercentComplete( state ); + + int rights = args[ "rights" ].toInt(); + todo->setReadOnly( !(rights & EGW_ACCESS_EDIT) ); + setRights( todo, rights ); +} + +void ResourceXMLRPC::checkLoadingFinished() +{ + mLoaded++; + if ( mLoaded == 4 ) { + mLoaded = 0; + emit resourceLoaded( this ); + } +} + +#include "kcal_resourcexmlrpc.moc" diff --git a/kresources/egroupware/kcal_resourcexmlrpc.h b/kresources/egroupware/kcal_resourcexmlrpc.h new file mode 100644 index 000000000..fd9ad6826 --- /dev/null +++ b/kresources/egroupware/kcal_resourcexmlrpc.h @@ -0,0 +1,236 @@ + /* + This file is part of kdepim. + + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 KCAL_RESOURCEXMLRPC_H +#define KCAL_RESOURCEXMLRPC_H + +#include <qdatetime.h> +#include <qptrlist.h> +#include <qstring.h> + +#include <kconfig.h> +#include <kurl.h> + +#include <kdepimmacros.h> + +#include "libkcal/calendarlocal.h" +#include "libkcal/incidence.h" +#include "libkcal/resourcecached.h" +#include "todostatemapper.h" + +namespace KXMLRPC { +class Server; +} + +class Synchronizer; +class QTimer; + +namespace KCal { + +class EGroupwarePrefs; + +/** + This class provides access to php/eGroupware calendar via XML-RPC. +*/ +class KDE_EXPORT ResourceXMLRPC : public ResourceCached +{ + Q_OBJECT + + public: + ResourceXMLRPC( const KConfig* ); + ResourceXMLRPC(); + virtual ~ResourceXMLRPC(); + + void readConfig( const KConfig* config ); + void writeConfig( KConfig* config ); + + EGroupwarePrefs *prefs() const { return mPrefs; } + + bool isSaving(); + + KABC::Lock *lock(); + + /** + Add Event to calendar. + */ + bool addEvent( Event* event ); + + /** + Deletes an event from this calendar. + */ + bool deleteEvent( Event* ); + + /** + Retrieves an event on the basis of the unique string ID. + */ + Event *event( const QString& uid ); + + /** + Return unfiltered list of all events in calendar. + */ + Event::List rawEvents(); + + /** + Builds and then returns a list of all events that match for the + date specified. useful for dayView, etc. etc. + */ + Event::List rawEventsForDate( + const QDate& date, + EventSortField sortField=EventSortUnsorted, + SortDirection sortDirection=SortDirectionAscending ); + + /** + Get unfiltered events for date \a qdt. + */ + Event::List rawEventsForDate( const QDateTime& qdt ); + + /** + Get unfiltered events in a range of dates. If inclusive is set to true, + only events are returned, which are completely included in the range. + */ + Event::List rawEvents( const QDate& start, const QDate& end, + bool inclusive = false ); + + + /** + Add a todo to the todolist. + */ + bool addTodo( Todo* todo ); + + /** + Remove a todo from the todolist. + */ + bool deleteTodo( Todo* todo ); + + /** + Searches todolist for an event with this unique string identifier, + returns a pointer or null. + */ + Todo *todo( const QString& uid ); + + /** + Return list of all todos. + */ + Todo::List rawTodos(); + + /** + Returns list of todos due on the specified date. + */ + Todo::List rawTodosForDate( const QDate& date ); + + /** + Add a Journal entry to calendar + */ + virtual bool addJournal( Journal* journal ); + + /** + Remove journal from the calendar. + */ + bool deleteJournal( Journal* journal ); + + /** + Return Journals for given date + */ + virtual Journal::List journals( const QDate& ); + + /** + Return Journal with given UID + */ + virtual Journal *journal( const QString& uid ); + + /** + Return all alarms, which ocur in the given time interval. + */ + Alarm::List alarms( const QDateTime& from, const QDateTime& to ); + + /** + Return all alarms, which ocur before given date. + */ + Alarm::List alarmsTo( const QDateTime& to ); + + /** + Public because needed in MultiCalendar::load() + */ + bool doOpen(); + void doClose(); + + void dump() const; + + void setTimeZoneId( const QString& ) {} + + protected slots: + void loginFinished( const QValueList<QVariant>&, const QVariant& ); + void logoutFinished( const QValueList<QVariant>&, const QVariant& ); + + void listEventsFinished( const QValueList<QVariant>&, const QVariant& ); + void addEventFinished( const QValueList<QVariant>&, const QVariant& ); + void updateEventFinished( const QValueList<QVariant>&, const QVariant& ); + void deleteEventFinished( const QValueList<QVariant>&, const QVariant& ); + void loadEventCategoriesFinished( const QValueList<QVariant>&, const QVariant& ); + + void listTodosFinished( const QValueList<QVariant>&, const QVariant& ); + void addTodoFinished( const QValueList<QVariant>&, const QVariant& ); + void updateTodoFinished( const QValueList<QVariant>&, const QVariant& ); + void deleteTodoFinished( const QValueList<QVariant>&, const QVariant& ); + void loadTodoCategoriesFinished( const QValueList<QVariant>&, const QVariant& ); + + void fault( int, const QString&, const QVariant& ); + + protected: + bool doLoad(); + bool doSave(); + + private slots: + void reload(); + + private: + void init(); + void initEGroupware(); + + void writeEvent( Event*, QMap<QString, QVariant>& ); + void readEvent( const QMap<QString, QVariant>&, Event*, QString& ); + + void writeTodo( Todo*, QMap<QString, QVariant>& ); + void readTodo( const QMap<QString, QVariant>&, Todo*, QString& ); + + void checkLoadingFinished(); + + KXMLRPC::Server *mServer; + + EGroupwarePrefs *mPrefs; + + QString mSessionID; + QString mKp3; + + QMap<QString, int> mEventCategoryMap; + QMap<QString, int> mTodoCategoryMap; + + TodoStateMapper mTodoStateMapper; + + Synchronizer *mSynchronizer; + + KABC::Lock *mLock; + int mLoaded; +}; + +} + +#endif diff --git a/kresources/egroupware/kcal_resourcexmlrpcconfig.cpp b/kresources/egroupware/kcal_resourcexmlrpcconfig.cpp new file mode 100644 index 000000000..450519aa4 --- /dev/null +++ b/kresources/egroupware/kcal_resourcexmlrpcconfig.cpp @@ -0,0 +1,98 @@ +/* + This file is part of kdepim. + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 <qlabel.h> +#include <qlayout.h> + +#include <kdebug.h> +#include <kdialog.h> +#include <klineedit.h> +#include <klocale.h> +#include <knuminput.h> +#include <kurlrequester.h> + +#include "kcal_egroupwareprefs.h" +#include "kcal_resourcexmlrpc.h" +#include "kcal_resourcexmlrpcconfig.h" + +using namespace KCal; + +ResourceXMLRPCConfig::ResourceXMLRPCConfig( QWidget* parent, const char* name ) + : KRES::ConfigWidget( parent, name ) +{ + QGridLayout *mainLayout = new QGridLayout( this, 4, 2, 0, KDialog::spacingHint() ); + + QLabel *label = new QLabel( i18n( "URL:" ), this ); + mURL = new KURLRequester( this ); + + mainLayout->addWidget( label, 0, 0 ); + mainLayout->addWidget( mURL, 0, 1 ); + + label = new QLabel( i18n( "Domain:" ), this ); + mDomain = new KLineEdit( this ); + + mainLayout->addWidget( label, 1, 0 ); + mainLayout->addWidget( mDomain, 1, 1 ); + + label = new QLabel( i18n( "User:" ), this ); + mUser = new KLineEdit( this ); + + mainLayout->addWidget( label, 2, 0 ); + mainLayout->addWidget( mUser, 2, 1 ); + + label = new QLabel( i18n( "Password:" ), this ); + mPassword = new KLineEdit( this ); + mPassword->setEchoMode( QLineEdit::Password ); + + mainLayout->addWidget( label, 3, 0 ); + mainLayout->addWidget( mPassword, 3, 1 ); +} + +void ResourceXMLRPCConfig::loadSettings( KRES::Resource *res ) +{ + ResourceXMLRPC *resource = dynamic_cast<ResourceXMLRPC*>( res ); + + if ( !resource ) { + kdDebug(5700) << "ResourceXMLRPCConfig::loadSettings(): cast failed" << endl; + return; + } + + mURL->setURL( resource->prefs()->url() ); + mDomain->setText( resource->prefs()->domain() ); + mUser->setText( resource->prefs()->user() ); + mPassword->setText( resource->prefs()->password() ); +} + +void ResourceXMLRPCConfig::saveSettings( KRES::Resource *res ) +{ + ResourceXMLRPC *resource = dynamic_cast<ResourceXMLRPC*>( res ); + + if ( !resource ) { + kdDebug(5700) << "ResourceXMLRPCConfig::saveSettings(): cast failed" << endl; + return; + } + + resource->prefs()->setUrl( mURL->url() ); + resource->prefs()->setDomain( mDomain->text() ); + resource->prefs()->setUser( mUser->text() ); + resource->prefs()->setPassword( mPassword->text() ); +} + +#include "kcal_resourcexmlrpcconfig.moc" diff --git a/kresources/egroupware/kcal_resourcexmlrpcconfig.h b/kresources/egroupware/kcal_resourcexmlrpcconfig.h new file mode 100644 index 000000000..c6a918f84 --- /dev/null +++ b/kresources/egroupware/kcal_resourcexmlrpcconfig.h @@ -0,0 +1,53 @@ +/* + This file is part of kdepim. + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 RESOURCEXMLRPCCONFIG_H +#define RESOURCEXMLRPCCONFIG_H + +#include <kresources/configwidget.h> +#include <kdepimmacros.h> + +class KIntSpinBox; +class KLineEdit; +class KURLRequester; + +namespace KCal { + +class KDE_EXPORT ResourceXMLRPCConfig : public KRES::ConfigWidget +{ + Q_OBJECT + + public: + ResourceXMLRPCConfig( QWidget* parent = 0, const char* name = 0 ); + + public slots: + void loadSettings( KRES::Resource* ); + void saveSettings( KRES::Resource* ); + + private: + KURLRequester *mURL; + KLineEdit *mDomain; + KLineEdit *mUser; + KLineEdit *mPassword; +}; + +} + +#endif diff --git a/kresources/egroupware/kcal_resourcexmlrpcplugin.cpp b/kresources/egroupware/kcal_resourcexmlrpcplugin.cpp new file mode 100644 index 000000000..1cc867b62 --- /dev/null +++ b/kresources/egroupware/kcal_resourcexmlrpcplugin.cpp @@ -0,0 +1,40 @@ +/* + This file is part of kdepim. + Copyright (c) 2003 - 2004 Tobias Koenig <tokoe@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 "kcal_resourcexmlrpc.h" +#include "kcal_resourcexmlrpcconfig.h" + +#include <kglobal.h> +#include <klocale.h> + +using namespace KCal; + +typedef KRES::PluginFactory<ResourceXMLRPC, ResourceXMLRPCConfig> XMLRPCFactory; + +// FIXME: Use K_EXPORT_COMPONENT_FACTORY( kcal_xmlrpc, XMLRPCFactory ); here +// Problem: How to insert the catalogue! +extern "C" +{ + void *init_kcal_xmlrpc() + { + KGlobal::locale()->insertCatalogue( "kres_xmlrpc" ); + return new XMLRPCFactory; + } +} diff --git a/kresources/egroupware/kcal_xmlrpc.desktop b/kresources/egroupware/kcal_xmlrpc.desktop new file mode 100644 index 000000000..5480d86b6 --- /dev/null +++ b/kresources/egroupware/kcal_xmlrpc.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=eGroupware Server (via XML-RPC) +Name[af]=eGroupware Bediener (via XML-RPC) +Name[bg]=Сървър eGroupware (чрез XML-RPC) +Name[br]=Servijer eGroupware (gant XML-RPC) +Name[ca]=Servidor eGroupware (via XML-RPC) +Name[cs]=eGroupware Server (přes XML-RPC) +Name[da]=eGroupware server (via XML-RPC) +Name[el]=Εξυπηρετητής eGroupware (μέσω XML-RPC) +Name[es]=Servidor de eGroupware (por medio de XML-RPC) +Name[et]=eGroupware server (XML-RPC vahendusel) +Name[eu]=eGroupware zerbitzaria (XML-RPC bidez) +Name[fa]=کارساز eGroupware (از طریق XML-RPC) +Name[fi]=eGroupware-palvelin (XML-RPC kautta) +Name[fr]=Serveur eGroupware (via XML-RPC) +Name[fy]=eGroupware-tsjinner (fia XML-RPC) +Name[ga]=Freastalaí eGroupware (via XML-RPC) +Name[gl]=Servidor eGroupware (mediante XML-RPC) +Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül) +Name[is]=eGroupware þjónn (gegnum XML-RPC) +Name[it]=Server eGroupware (via XML-RPC) +Name[ja]=eGroupware サーバ (XML-RPC 経由) +Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით) +Name[kk]=eGroupware сервері (XML-RPC арқылы) +Name[km]=ម៉ាស៊ីនបម្រើ eGroupware (តាមរយៈ XML-RPC) +Name[lt]=eGroupware serveris (per XML-RPC) +Name[ms]=Pelayan eGroupware (melalui XML-RPC) +Name[nb]=eGroupware-tjener (via XML-RPPC) +Name[nds]=eGroupware-Server (över XML-RPC) +Name[ne]=(XML-RPC मार्फत) eGroupware सर्भर +Name[nl]=eGroupware-server (via XML-RPC) +Name[nn]=eGroupware-tenar (via XML-RPC) +Name[pl]=Serwer eGroupware (poprzez XML-RPC) +Name[pt]=Servidor eGroupware (via XML-RPC) +Name[pt_BR]=Servidor eGroupware (via XML-RPC) +Name[ru]=Сервер eGroupware (через XML-RPC) +Name[sk]=eGroupware Server (cez XML-RPC) +Name[sl]=Strežnik eGroupware (preko XML-RPC) +Name[sr]=eGroupware сервер (преко XML-RPC) +Name[sr@Latn]=eGroupware server (preko XML-RPC) +Name[sv]=eGroupware-server (via XML-RPC) +Name[ta]=eGroupware சேவகன் (via XML-RPC) +Name[tr]=eGroupware Sunucusu (XML-RPC ile) +Name[uk]=Сервер eGroupware (через XML-RPC) +Name[zh_CN]=eGroupware 服务器(通过 XML-RPC) +Name[zh_TW]=eGroupware 伺服器(透過 XML-RPC) +X-KDE-Library=kcal_xmlrpc +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=calendar +X-KDE-ResourceType=xmlrpc diff --git a/kresources/egroupware/knotes_egroupwareprefs.kcfgc b/kresources/egroupware/knotes_egroupwareprefs.kcfgc new file mode 100644 index 000000000..782dd5673 --- /dev/null +++ b/kresources/egroupware/knotes_egroupwareprefs.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=kresources_knotes_egroupware.kcfg +ClassName=EGroupwarePrefs +NameSpace=KNotes +Singleton=false +Mutators=true +Inherits=KResourcePrefs +IncludeFiles=libkdepim/kresourceprefs.h +GlobalEnums=true +#ItemAccessors=true +#SetUserTexts=true diff --git a/kresources/egroupware/knotes_resourcexmlrpc.cpp b/kresources/egroupware/knotes_resourcexmlrpc.cpp new file mode 100644 index 000000000..c30da41f0 --- /dev/null +++ b/kresources/egroupware/knotes_resourcexmlrpc.cpp @@ -0,0 +1,333 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Tobias Koenig <tokoe@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 <qapplication.h> +#include <qstringlist.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kstringhandler.h> +#include <kurl.h> + +#include "libkcal/journal.h" + +#include "knotes/resourcemanager.h" + +#include "knotes_egroupwareprefs.h" +#include "knotes_resourcexmlrpc.h" +#include "knotes_resourcexmlrpcconfig.h" + +#include "synchronizer.h" +#include "xmlrpciface.h" + +using namespace KNotes; + +typedef KRES::PluginFactory< ResourceXMLRPC, ResourceXMLRPCConfig> XMLRPCFactory; +K_EXPORT_COMPONENT_FACTORY( knotes_xmlrpc, XMLRPCFactory ) + +static const QString SearchNotesCommand = "infolog.boinfolog.search"; +static const QString AddNoteCommand = "infolog.boinfolog.write"; +static const QString DeleteNoteCommand = "infolog.boinfolog.delete"; +static const QString LoadNoteCategoriesCommand = "infolog.boinfolog.categories"; + +ResourceXMLRPC::ResourceXMLRPC( const KConfig* config ) + : ResourceNotes( config ), mCalendar( QString::fromLatin1("UTC") ), + mServer( 0 ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + if ( config ) + readConfig( config ); +} + +ResourceXMLRPC::ResourceXMLRPC( ) + : ResourceNotes( 0 ), mCalendar( QString::fromLatin1("UTC") ), + mServer( 0 ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); +} + +ResourceXMLRPC::~ResourceXMLRPC() +{ + delete mServer; + mServer = 0; + + delete mPrefs; + mPrefs = 0; + + delete mSynchronizer; + mSynchronizer = 0; +} + +void ResourceXMLRPC::init() +{ + setType( "xmlrpc" ); + + mPrefs = new EGroupwarePrefs; + + mSynchronizer = new Synchronizer; +} + +void ResourceXMLRPC::readConfig( const KConfig* ) +{ + mPrefs->readConfig(); +} + +void ResourceXMLRPC::writeConfig( KConfig* config ) +{ + ResourceNotes::writeConfig( config ); + + mPrefs->writeConfig(); +} + +bool ResourceXMLRPC::load() +{ + mCalendar.close(); + + if ( mServer ) + delete mServer; + + mServer = new KXMLRPC::Server( KURL(), this ); + mServer->setUrl( KURL( mPrefs->url() ) ); + mServer->setUserAgent( "KDE-Notes" ); + + QMap<QString, QVariant> args, columns; + args.insert( "domain", mPrefs->domain() ); + args.insert( "username", mPrefs->user() ); + args.insert( "password", mPrefs->password() ); + + mServer->call( "system.login", QVariant( args ), + this, SLOT( loginFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mSynchronizer->start(); + + columns.insert( "type", "note" ); + args.clear(); + args.insert( "filter", "none" ); + args.insert( "col_filter", columns ); + args.insert( "order", "id_parent" ); + + mServer->call( SearchNotesCommand, args, + this, SLOT( listNotesFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + + mSynchronizer->start(); + + return true; +} + +bool ResourceXMLRPC::save() +{ + mCalendar.close(); + + return true; +} + +bool ResourceXMLRPC::addNote( KCal::Journal *journal ) +{ + QMap<QString, QVariant> args; + writeNote( journal, args ); + + KCal::Journal *oldJournal = mCalendar.journal( journal->uid() ); + + bool added = false; + if ( oldJournal ) { + if ( !oldJournal->isReadOnly() ) { + writeNote( journal, args ); + args.insert( "id", mUidMap[ journal->uid() ].toInt() ); + mServer->call( AddNoteCommand, QVariant( args ), + this, SLOT( updateNoteFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ) ); + mCalendar.addJournal( journal ); + added = true; + } + } else { + mServer->call( AddNoteCommand, QVariant( args ), + this, SLOT( addNoteFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ), + QVariant( journal->uid() ) ); + + mCalendar.addJournal( journal ); + added = true; + } + + if ( added ) + mSynchronizer->start(); + + return true; +} + +bool ResourceXMLRPC::deleteNote( KCal::Journal *journal ) +{ + int id = mUidMap[ journal->uid() ].toInt(); + + mServer->call( DeleteNoteCommand, id, + this, SLOT( deleteNoteFinished( const QValueList<QVariant>&, const QVariant& ) ), + this, SLOT( fault( int, const QString&, const QVariant& ) ), + QVariant( journal->uid() ) ); + mSynchronizer->start(); + + return true; +} + +KCal::Alarm::List ResourceXMLRPC::alarms( const QDateTime& from, const QDateTime& to ) +{ + KCal::Alarm::List alarms; + KCal::Journal::List notes = mCalendar.journals(); + KCal::Journal::List::ConstIterator note; + for ( note = notes.begin(); note != notes.end(); ++note ) + { + QDateTime preTime = from.addSecs( -1 ); + KCal::Alarm::List::ConstIterator it; + for( it = (*note)->alarms().begin(); it != (*note)->alarms().end(); ++it ) + { + if ( (*it)->enabled() ) + { + QDateTime dt = (*it)->nextRepetition( preTime ); + if ( dt.isValid() && dt <= to ) + alarms.append( *it ); + } + } + } + + return alarms; +} + +void ResourceXMLRPC::loginFinished( const QValueList<QVariant>& variant, + const QVariant& ) +{ + QMap<QString, QVariant> map = variant[ 0 ].toMap(); + + KURL url = KURL( mPrefs->url() ); + if ( map[ "GOAWAY" ].toString() == "XOXO" ) { // failed + mSessionID = mKp3 = ""; + } else { + mSessionID = map[ "sessionid" ].toString(); + mKp3 = map[ "kp3" ].toString(); + } + + url.setUser( mSessionID ); + url.setPass( mKp3 ); + mServer->setUrl( url ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::logoutFinished( const QValueList<QVariant>& variant, + const QVariant& ) +{ + QMap<QString, QVariant> map = variant[ 0 ].toMap(); + + if ( map[ "GOODBYE" ].toString() != "XOXO" ) + kdError() << "logout failed" << endl; + + KURL url = KURL( mPrefs->url() ); + mSessionID = mKp3 = ""; + url.setUser( mSessionID ); + url.setPass( mKp3 ); + mServer->setUrl( url ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::listNotesFinished( const QValueList<QVariant> &list, const QVariant& ) +{ + QMap<QString, QString>::Iterator uidIt; + for ( uidIt = mUidMap.begin(); uidIt != mUidMap.end(); ++uidIt ) { + KCal::Journal *journal = mCalendar.journal( uidIt.key() ); + mCalendar.deleteJournal( journal ); + } + + mUidMap.clear(); + + QValueList<QVariant> noteList = list[ 0 ].toList(); + QValueList<QVariant>::Iterator noteIt; + + for ( noteIt = noteList.begin(); noteIt != noteList.end(); ++noteIt ) { + QMap<QString, QVariant> map = (*noteIt).toMap(); + + KCal::Journal *journal = new KCal::Journal(); + + QString uid; + readNote( map, journal, uid ); + mUidMap.insert( journal->uid(), uid ); + + mCalendar.addJournal( journal ); + manager()->registerNote( this, journal ); + } + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::addNoteFinished( const QValueList<QVariant> &list, const QVariant &id ) +{ + int uid = list[ 0 ].toInt(); + mUidMap.insert( id.toString(), QString::number( uid ) ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::updateNoteFinished( const QValueList<QVariant>&, const QVariant& ) +{ + mSynchronizer->stop(); +} + +void ResourceXMLRPC::deleteNoteFinished( const QValueList<QVariant>&, const QVariant &id ) +{ + mUidMap.erase( id.toString() ); + + KCal::Journal *journal = mCalendar.journal( id.toString() ); + mCalendar.deleteJournal( journal ); + + mSynchronizer->stop(); +} + +void ResourceXMLRPC::fault( int error, const QString& errorMsg, const QVariant& ) +{ + kdError() << "Server send error " << error << ": " << errorMsg << endl; + mSynchronizer->stop(); +} + +void ResourceXMLRPC::writeNote( KCal::Journal* journal, QMap<QString, QVariant>& args ) +{ + args.insert( "subject", journal->summary() ); + args.insert( "des", journal->description() ); + args.insert( "access", + (journal->secrecy() == KCal::Journal::SecrecyPublic ? "public" : "private" ) ); +} + +void ResourceXMLRPC::readNote( const QMap<QString, QVariant>& args, KCal::Journal *journal, QString &uid ) +{ + uid = args[ "id" ].toString(); + + journal->setSummary( args[ "subject" ].toString() ); + journal->setDescription( args[ "des" ].toString() ); + journal->setSecrecy( args[ "access" ].toString() == "public" ? + KCal::Journal::SecrecyPublic : KCal::Journal::SecrecyPrivate ); +} + +#include "knotes_resourcexmlrpc.moc" diff --git a/kresources/egroupware/knotes_resourcexmlrpc.h b/kresources/egroupware/knotes_resourcexmlrpc.h new file mode 100644 index 000000000..2f2934320 --- /dev/null +++ b/kresources/egroupware/knotes_resourcexmlrpc.h @@ -0,0 +1,103 @@ + /* + This file is part of kdepim. + + Copyright (c) 2004 Tobias Koenig <tokoe@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 KNOTES_RESOURCEXMLRPC_H +#define KNOTES_RESOURCEXMLRPC_H + +#include <qptrlist.h> +#include <qstring.h> + +#include <kconfig.h> +#include <kurl.h> +#include <kdepimmacros.h> + +#include "libkcal/calendarlocal.h" +#include "libkcal/journal.h" +#include "knotes/resourcenotes.h" + +namespace KXMLRPC { +class Server; +} + +class Synchronizer; + +namespace KNotes { + +class EGroupwarePrefs; + +/** + This class provides access to eGroupware notes via XML-RPC. +*/ +class KDE_EXPORT ResourceXMLRPC : public ResourceNotes +{ + Q_OBJECT + + public: + ResourceXMLRPC( const KConfig* ); + ResourceXMLRPC(); + virtual ~ResourceXMLRPC(); + + void readConfig( const KConfig* config ); + void writeConfig( KConfig* config ); + + EGroupwarePrefs *prefs() const { return mPrefs; } + + bool load(); + bool save(); + + bool addNote( KCal::Journal* ); + bool deleteNote( KCal::Journal* ); + + KCal::Alarm::List alarms( const QDateTime& from, const QDateTime& to ); + + protected slots: + void loginFinished( const QValueList<QVariant>&, const QVariant& ); + void logoutFinished( const QValueList<QVariant>&, const QVariant& ); + + void listNotesFinished( const QValueList<QVariant>&, const QVariant& ); + void addNoteFinished( const QValueList<QVariant>&, const QVariant& ); + void updateNoteFinished( const QValueList<QVariant>&, const QVariant& ); + void deleteNoteFinished( const QValueList<QVariant>&, const QVariant& ); + + void fault( int, const QString&, const QVariant& ); + + private: + void init(); + void initEGroupware(); + + void writeNote( KCal::Journal*, QMap<QString, QVariant>& ); + void readNote( const QMap<QString, QVariant>&, KCal::Journal*, QString& ); + + KCal::CalendarLocal mCalendar; + KXMLRPC::Server *mServer; + + EGroupwarePrefs *mPrefs; + + QString mSessionID; + QString mKp3; + QMap<QString, QString> mUidMap; + + Synchronizer *mSynchronizer; +}; + +} + +#endif diff --git a/kresources/egroupware/knotes_resourcexmlrpcconfig.cpp b/kresources/egroupware/knotes_resourcexmlrpcconfig.cpp new file mode 100644 index 000000000..6eee548ce --- /dev/null +++ b/kresources/egroupware/knotes_resourcexmlrpcconfig.cpp @@ -0,0 +1,98 @@ +/* + This file is part of kdepim. + Copyright (c) 2004 Tobias Koenig <tokoe@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 <qlabel.h> +#include <qlayout.h> + +#include <kdebug.h> +#include <kdialog.h> +#include <klineedit.h> +#include <klocale.h> +#include <knuminput.h> +#include <kurlrequester.h> + +#include "knotes_egroupwareprefs.h" +#include "knotes_resourcexmlrpc.h" +#include "knotes_resourcexmlrpcconfig.h" + +using namespace KNotes; + +ResourceXMLRPCConfig::ResourceXMLRPCConfig( QWidget* parent, const char* name ) + : KRES::ConfigWidget( parent, name ) +{ + QGridLayout *mainLayout = new QGridLayout( this, 4, 2, 0, KDialog::spacingHint() ); + + QLabel *label = new QLabel( i18n( "URL:" ), this ); + mURL = new KURLRequester( this ); + + mainLayout->addWidget( label, 0, 0 ); + mainLayout->addWidget( mURL, 0, 1 ); + + label = new QLabel( i18n( "Domain:" ), this ); + mDomain = new KLineEdit( this ); + + mainLayout->addWidget( label, 1, 0 ); + mainLayout->addWidget( mDomain, 1, 1 ); + + label = new QLabel( i18n( "User:" ), this ); + mUser = new KLineEdit( this ); + + mainLayout->addWidget( label, 2, 0 ); + mainLayout->addWidget( mUser, 2, 1 ); + + label = new QLabel( i18n( "Password:" ), this ); + mPassword = new KLineEdit( this ); + mPassword->setEchoMode( QLineEdit::Password ); + + mainLayout->addWidget( label, 3, 0 ); + mainLayout->addWidget( mPassword, 3, 1 ); +} + +void ResourceXMLRPCConfig::loadSettings( KRES::Resource *res ) +{ + ResourceXMLRPC *resource = dynamic_cast<ResourceXMLRPC*>( res ); + + if ( !resource ) { + kdDebug(5700) << "ResourceXMLRPCConfig::loadSettings(): cast failed" << endl; + return; + } + + mURL->setURL( resource->prefs()->url() ); + mDomain->setText( resource->prefs()->domain() ); + mUser->setText( resource->prefs()->user() ); + mPassword->setText( resource->prefs()->password() ); +} + +void ResourceXMLRPCConfig::saveSettings( KRES::Resource *res ) +{ + ResourceXMLRPC *resource = dynamic_cast<ResourceXMLRPC*>( res ); + + if ( !resource ) { + kdDebug(5700) << "ResourceXMLRPCConfig::saveSettings(): cast failed" << endl; + return; + } + + resource->prefs()->setUrl( mURL->url() ); + resource->prefs()->setDomain( mDomain->text() ); + resource->prefs()->setUser( mUser->text() ); + resource->prefs()->setPassword( mPassword->text() ); +} + +#include "knotes_resourcexmlrpcconfig.moc" diff --git a/kresources/egroupware/knotes_resourcexmlrpcconfig.h b/kresources/egroupware/knotes_resourcexmlrpcconfig.h new file mode 100644 index 000000000..7b3edab2e --- /dev/null +++ b/kresources/egroupware/knotes_resourcexmlrpcconfig.h @@ -0,0 +1,53 @@ +/* + This file is part of kdepim. + Copyright (c) 2004 Tobias Koenig <tokoe@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 RESOURCEXMLRPCCONFIG_H +#define RESOURCEXMLRPCCONFIG_H + +#include <kresources/configwidget.h> +#include <kdepimmacros.h> + +class KIntSpinBox; +class KLineEdit; +class KURLRequester; + +namespace KNotes { + +class KDE_EXPORT ResourceXMLRPCConfig : public KRES::ConfigWidget +{ + Q_OBJECT + + public: + ResourceXMLRPCConfig( QWidget* parent = 0, const char* name = 0 ); + + public slots: + void loadSettings( KRES::Resource* ); + void saveSettings( KRES::Resource* ); + + private: + KURLRequester *mURL; + KLineEdit *mDomain; + KLineEdit *mUser; + KLineEdit *mPassword; +}; + +} + +#endif diff --git a/kresources/egroupware/knotes_resourcexmlrpcplugin.cpp b/kresources/egroupware/knotes_resourcexmlrpcplugin.cpp new file mode 100644 index 000000000..b3b6aabe3 --- /dev/null +++ b/kresources/egroupware/knotes_resourcexmlrpcplugin.cpp @@ -0,0 +1,40 @@ +/* + This file is part of kdepim. + Copyright (c) 2004 Tobias Koenig <tokoe@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 "knotes_resourcexmlrpc.h" +#include "knotes_resourcexmlrpcconfig.h" + +#include <kglobal.h> +#include <klocale.h> + +using namespace KNotes; + +typedef KRES::PluginFactory<ResourceXMLRPC, ResourceXMLRPCConfig> XMLRPCFactory; + +// FIXME: Use K_EXPORT_COMPONENT_FACTORY( knotes_xmlrpc, XMLRPCFactory ); here +// Problem: How to insert the catalogue! +extern "C" +{ + void *init_knotes_xmlrpc() + { + KGlobal::locale()->insertCatalogue( "kres_xmlrpc" ); + return new XMLRPCFactory; + } +} diff --git a/kresources/egroupware/knotes_xmlrpc.desktop b/kresources/egroupware/knotes_xmlrpc.desktop new file mode 100644 index 000000000..61411ce01 --- /dev/null +++ b/kresources/egroupware/knotes_xmlrpc.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=eGroupware Server (via XML-RPC) +Name[af]=eGroupware Bediener (via XML-RPC) +Name[bg]=Сървър eGroupware (чрез XML-RPC) +Name[br]=Servijer eGroupware (gant XML-RPC) +Name[ca]=Servidor eGroupware (via XML-RPC) +Name[cs]=eGroupware Server (přes XML-RPC) +Name[da]=eGroupware server (via XML-RPC) +Name[el]=Εξυπηρετητής eGroupware (μέσω XML-RPC) +Name[es]=Servidor de eGroupware (por medio de XML-RPC) +Name[et]=eGroupware server (XML-RPC vahendusel) +Name[eu]=eGroupware zerbitzaria (XML-RPC bidez) +Name[fa]=کارساز eGroupware (از طریق XML-RPC) +Name[fi]=eGroupware-palvelin (XML-RPC kautta) +Name[fr]=Serveur eGroupware (via XML-RPC) +Name[fy]=eGroupware-tsjinner (fia XML-RPC) +Name[ga]=Freastalaí eGroupware (via XML-RPC) +Name[gl]=Servidor eGroupware (mediante XML-RPC) +Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül) +Name[is]=eGroupware þjónn (gegnum XML-RPC) +Name[it]=Server eGroupware (via XML-RPC) +Name[ja]=eGroupware サーバ (XML-RPC 経由) +Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით) +Name[kk]=eGroupware сервері (XML-RPC арқылы) +Name[km]=ម៉ាស៊ីនបម្រើ eGroupware (តាមរយៈ XML-RPC) +Name[lt]=eGroupware serveris (per XML-RPC) +Name[ms]=Pelayan eGroupware (melalui XML-RPC) +Name[nb]=eGroupware-tjener (via XML-RPPC) +Name[nds]=eGroupware-Server (över XML-RPC) +Name[ne]=(XML-RPC मार्फत) eGroupware सर्भर +Name[nl]=eGroupware-server (via XML-RPC) +Name[nn]=eGroupware-tenar (via XML-RPC) +Name[pl]=Serwer eGroupware (poprzez XML-RPC) +Name[pt]=Servidor eGroupware (via XML-RPC) +Name[pt_BR]=Servidor eGroupware (via XML-RPC) +Name[ru]=Сервер eGroupware (через XML-RPC) +Name[sk]=eGroupware Server (cez XML-RPC) +Name[sl]=Strežnik eGroupware (preko XML-RPC) +Name[sr]=eGroupware сервер (преко XML-RPC) +Name[sr@Latn]=eGroupware server (preko XML-RPC) +Name[sv]=eGroupware-server (via XML-RPC) +Name[ta]=eGroupware சேவகன் (via XML-RPC) +Name[tr]=eGroupware Sunucusu (XML-RPC ile) +Name[uk]=Сервер eGroupware (через XML-RPC) +Name[zh_CN]=eGroupware 服务器(通过 XML-RPC) +Name[zh_TW]=eGroupware 伺服器(透過 XML-RPC) +X-KDE-Library=knotes_xmlrpc +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=notes +X-KDE-ResourceType=xmlrpc diff --git a/kresources/egroupware/kresources_kabc_egroupware.kcfg b/kresources/egroupware/kresources_kabc_egroupware.kcfg new file mode 100644 index 000000000..3655109b0 --- /dev/null +++ b/kresources/egroupware/kresources_kabc_egroupware.kcfg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kresources_kabc_egroupwarerc"/> + + <group name="General"> + <entry type="String" name="Url"> + <label>URL</label> + </entry> + <entry type="String" name="Domain"> + <label>Domain</label> + <default>default</default> + </entry> + <entry type="String" name="User"> + <label>User Name</label> + </entry> + <entry type="Password" name="Password"> + <label>Password</label> + </entry> + </group> + +</kcfg> diff --git a/kresources/egroupware/kresources_kcal_egroupware.kcfg b/kresources/egroupware/kresources_kcal_egroupware.kcfg new file mode 100644 index 000000000..91889d71e --- /dev/null +++ b/kresources/egroupware/kresources_kcal_egroupware.kcfg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kresources_kcal_egroupwarerc"/> + + <group name="General"> + <entry type="String" name="Url"> + <label>URL</label> + </entry> + <entry type="String" name="Domain"> + <label>Domain</label> + <default>default</default> + </entry> + <entry type="String" name="User"> + <label>User Name</label> + </entry> + <entry type="Password" name="Password"> + <label>Password</label> + </entry> + </group> + +</kcfg> diff --git a/kresources/egroupware/kresources_knotes_egroupware.kcfg b/kresources/egroupware/kresources_knotes_egroupware.kcfg new file mode 100644 index 000000000..2fbb84a09 --- /dev/null +++ b/kresources/egroupware/kresources_knotes_egroupware.kcfg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kresources_knotes_egroupwarerc"/> + + <group name="General"> + <entry type="String" name="Url"> + <label>URL</label> + </entry> + <entry type="String" name="Domain"> + <label>Domain</label> + <default>default</default> + </entry> + <entry type="String" name="User"> + <label>User Name</label> + </entry> + <entry type="Password" name="Password"> + <label>Password</label> + </entry> + </group> + +</kcfg> diff --git a/kresources/egroupware/synchronizer.cpp b/kresources/egroupware/synchronizer.cpp new file mode 100644 index 000000000..928fc7e1d --- /dev/null +++ b/kresources/egroupware/synchronizer.cpp @@ -0,0 +1,50 @@ +/* + This file is part of kdepim. + + Copyright (c) 2005 Tobias Koenig <tokoe@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 <kapplication.h> +#include <qeventloop.h> + +#include <unistd.h> + +#include "synchronizer.h" + +Synchronizer::Synchronizer() + : mBlocked( false ) +{ +} + +void Synchronizer::start() +{ + mBlocked = true; + + while ( mBlocked ) { + QApplication::eventLoop()->processEvents( QEventLoop::ExcludeUserInput ); + + // use sleep here to reduce cpu usage + usleep( 100 ); + } +} + +void Synchronizer::stop() +{ + mBlocked = false; +} + diff --git a/kresources/egroupware/synchronizer.h b/kresources/egroupware/synchronizer.h new file mode 100644 index 000000000..feac6bf31 --- /dev/null +++ b/kresources/egroupware/synchronizer.h @@ -0,0 +1,72 @@ +/* + This file is part of kdepim. + + Copyright (c) 2005 Tobias Koenig <tokoe@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 SYNCHRONIZER_H +#define SYNCHRONIZER_H + +#include <qobject.h> + +/** + A small helper class which blocks an asynchronous operation (e.g. a KIO request) + so that it can be used in a synchronous environment. + + Example: + + ... + + Synchronizer mSynchronizer; + + ... + + job = KIO::file_copy( url, file, -1, true ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotResult( KIO::Job * ) ) ); + + mSynchronizer.start(); // will block here until the slot was called + ... + + + void slotResult( KIO::Job* ) + { + mSynchronizer.stop(); + } + */ +class Synchronizer +{ + public: + Synchronizer(); + + /** + Blocks the execution until @ref stop() is called. + */ + void start(); + + /** + Unblocks the execution. + */ + void stop(); + + private: + bool mBlocked; +}; + +#endif + diff --git a/kresources/egroupware/todostatemapper.cpp b/kresources/egroupware/todostatemapper.cpp new file mode 100644 index 000000000..6c81ded33 --- /dev/null +++ b/kresources/egroupware/todostatemapper.cpp @@ -0,0 +1,167 @@ +/* + This file is part of kdepim. + + Copyright (c) 2005 Tobias Koenig <tokoe@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 <qdatastream.h> +#include <qfile.h> + +#include <kdebug.h> +#include <kstandarddirs.h> + +#include "todostatemapper.h" + +QDataStream& operator<<( QDataStream &stream, const TodoStateMapper::TodoStateMapEntry &entry ) +{ + stream << entry.uid << entry.localState << entry.remoteState; + + return stream; +} + +QDataStream& operator>>( QDataStream &stream, TodoStateMapper::TodoStateMapEntry &entry ) +{ + stream >> entry.uid >> entry.localState >> entry.remoteState; + + return stream; +} + +TodoStateMapper::TodoStateMapper() +{ +} + +TodoStateMapper::~TodoStateMapper() +{ +} + +void TodoStateMapper::setPath( const QString &path ) +{ + mPath = path; +} + +void TodoStateMapper::setIdentifier( const QString &identifier ) +{ + mIdentifier = identifier; +} + +bool TodoStateMapper::load() +{ + QFile file( filename() ); + if ( !file.open( IO_ReadOnly ) ) { + kdError() << "Can't read uid map file '" << filename() << "'" << endl; + return false; + } + + clear(); + + QDataStream stream; + stream.setVersion( 6 ); + stream.setDevice( &file ); + stream >> mTodoStateMap; + + file.close(); + + return true; +} + +bool TodoStateMapper::save() +{ + QFile file( filename() ); + if ( !file.open( IO_WriteOnly ) ) { + kdError() << "Can't write uid map file '" << filename() << "'" << endl; + return false; + } + + QDataStream stream; + stream.setVersion( 6 ); + stream.setDevice( &file ); + stream << mTodoStateMap; + + file.close(); + + return true; +} + +void TodoStateMapper::clear() +{ + mTodoStateMap.clear(); +} + +void TodoStateMapper::addTodoState( const QString &uid, int localState, const QString &remoteState ) +{ + TodoStateMapEntry entry; + entry.uid = uid; + entry.localState = localState; + entry.remoteState = remoteState; + + mTodoStateMap.insert( uid, entry ); +} + +QString TodoStateMapper::remoteState( const QString &uid, int localState ) +{ + if ( mTodoStateMap.find( uid ) == mTodoStateMap.end() ) + kdError() << "TodoStateMapper: no entry for " << uid << " found" << endl; + + TodoStateMapEntry entry = mTodoStateMap[ uid ]; + if ( entry.localState == localState ) + return entry.remoteState; + else + return toRemote( localState ); +} + +void TodoStateMapper::remove( const QString &uid ) +{ + mTodoStateMap.remove( uid ); +} + +int TodoStateMapper::toLocal( const QString &remoteState ) +{ + if ( remoteState == "offer" ) + return 0; + else if ( remoteState == "ongoing" ) + return 50; + else if ( remoteState == "done" || remoteState == "billed" ) + return 100; + else { + QString number( remoteState ); + number.replace( "%", "" ); + return number.toInt(); + } +} + +QString TodoStateMapper::toRemote( int localState ) +{ + if ( localState == 0 ) + return "offer"; + else if ( localState == 50 ) + return "ongoing"; + else if ( localState == 100 ) + return "done"; + else + return QString( "%1%" ).arg( localState ); +} + +QString TodoStateMapper::filename() +{ + QString file = mPath; + if ( !file.endsWith( "/" ) ) file += "/"; + file += mIdentifier; + + return locateLocal( "data", file ); +} + diff --git a/kresources/egroupware/todostatemapper.h b/kresources/egroupware/todostatemapper.h new file mode 100644 index 000000000..c5590ef25 --- /dev/null +++ b/kresources/egroupware/todostatemapper.h @@ -0,0 +1,75 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Tobias Koenig <tokoe@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 TODOSTATEMAPPER_H +#define TODOSTATEMAPPER_H + +#include <qdatastream.h> +#include <qmap.h> + +class TodoStateMapper +{ + public: + /** + Create Id mapper. You have to set path and identifier before you can call + load() or save(). + */ + TodoStateMapper(); + ~TodoStateMapper(); + + void setPath( const QString &path ); + void setIdentifier( const QString &identifier ); + + bool load(); + bool save(); + + void clear(); + + void addTodoState( const QString &uid, int localState, const QString &remoteState ); + + QString remoteState( const QString &uid, int localState ); + + void remove( const QString &uid ); + + static int toLocal( const QString &remoteState ); + static QString toRemote( int localState ); + + protected: + QString filename(); + + private: + QString mPath; + QString mIdentifier; + + typedef struct { + QString uid; + int localState; + QString remoteState; + } TodoStateMapEntry; + + typedef QMap<QString, TodoStateMapEntry> TodoStateMap; + TodoStateMap mTodoStateMap; + + friend QDataStream &operator<<( QDataStream&, const TodoStateMapEntry& ); + friend QDataStream &operator>>( QDataStream&, TodoStateMapEntry& ); +}; + +#endif diff --git a/kresources/egroupware/xmlrpciface.cpp b/kresources/egroupware/xmlrpciface.cpp new file mode 100644 index 000000000..0158e23d1 --- /dev/null +++ b/kresources/egroupware/xmlrpciface.cpp @@ -0,0 +1,464 @@ +/************************************************************************** +* Copyright (C) 2003 - 2004 by Frerich Raabe <raabe@kde.org> * +* Tobias Koenig <tokoe@kde.org> * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include <qfile.h> + +#include <kdebug.h> +#include <kio/job.h> +#include <klocale.h> +#include <kmdcodec.h> + +#include "debugdialog.h" +#include "xmlrpciface.h" + +using namespace KXMLRPC; + +namespace KXMLRPC +{ + class Result + { + friend class Query; + public: + Result() + { } + + bool success() const + { + return m_success; + } + int errorCode() const + { + return m_errorCode; + } + QString errorString() const + { + return m_errorString; + } + QValueList<QVariant> data() const + { + return m_data; + } + + private: + bool m_success; + int m_errorCode; + QString m_errorString; + QValueList<QVariant> m_data; + }; +} + +Query *Query::create( const QVariant &id, QObject *parent, const char *name ) +{ + return new Query( id, parent, name ); +} + +void Query::call( const QString &server, const QString &method, + const QValueList<QVariant> &args, const QString &userAgent ) +{ + const QString xmlMarkup = markupCall( method, args ); + DebugDialog::addMessage( xmlMarkup, DebugDialog::Output ); + + QByteArray postData; + QDataStream stream( postData, IO_WriteOnly ); + stream.writeRawBytes( xmlMarkup.utf8(), xmlMarkup.utf8().length() ); + + KIO::TransferJob *job = KIO::http_post( KURL( server ), postData, false ); + if ( !job ) { + kdWarning() << "Unable to create KIO job for " << server << endl; + return; + } + job->addMetaData( "UserAgent", userAgent ); + job->addMetaData( "content-type", "Content-Type: text/xml; charset=utf-8" ); + job->addMetaData( "ConnectTimeout", "50" ); + + connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ), + this, SLOT( slotData( KIO::Job *, const QByteArray & ) ) ); + connect( job, SIGNAL( result( KIO::Job * ) ), + this, SLOT( slotResult( KIO::Job * ) ) ); + + m_pendingJobs.append( job ); +} + +void Query::slotData( KIO::Job *, const QByteArray &data ) +{ + unsigned int oldSize = m_buffer.size(); + m_buffer.resize( oldSize + data.size() ); + memcpy( m_buffer.data() + oldSize, data.data(), data.size() ); +} + +void Query::slotResult( KIO::Job *job ) +{ + m_pendingJobs.remove( job ); + + if ( job->error() != 0 ) + { + emit fault( job->error(), job->errorString(), m_id ); + emit finished( this ); + return ; + } + + QString data = QString::fromUtf8( m_buffer.data(), m_buffer.size() ); + DebugDialog::addMessage( data, DebugDialog::Input ); + + QDomDocument doc; + QString errMsg; + int errLine, errCol; + if ( !doc.setContent( data, false, &errMsg, &errLine, &errCol ) ) + { + emit fault( -1, i18n( "Received invalid XML markup: %1 at %2:%3" ) + .arg( errMsg ).arg( errLine ).arg( errCol ), m_id ); + emit finished( this ); + return ; + } + + m_buffer.truncate( 0 ); + + if ( isMessageResponse( doc ) ) + emit message( parseMessageResponse( doc ).data(), m_id ); + else if ( isFaultResponse( doc ) ) + { + emit fault( parseFaultResponse( doc ).errorCode(), parseFaultResponse( doc ).errorString(), m_id ); + } + else + { + emit fault( 1, i18n( "Unknown type of XML markup received" ), m_id ); + } + + emit finished( this ); +} + +bool Query::isMessageResponse( const QDomDocument &doc ) const +{ + return doc.documentElement().firstChild().toElement().tagName().lower() == "params"; +} + +Result Query::parseMessageResponse( const QDomDocument &doc ) const +{ + Result response; + response.m_success = true; + + QDomNode paramNode = doc.documentElement().firstChild().firstChild(); + while ( !paramNode.isNull() ) + { + response.m_data << demarshal( paramNode.firstChild().toElement() ); + paramNode = paramNode.nextSibling(); + } + + return response; +} + +bool Query::isFaultResponse( const QDomDocument &doc ) const +{ + return doc.documentElement().firstChild().toElement().tagName().lower() == "fault"; +} + +Result Query::parseFaultResponse( const QDomDocument &doc ) const +{ + Result response; + response.m_success = false; + + QDomNode errorNode = doc.documentElement().firstChild().firstChild(); + const QVariant errorVariant = demarshal( errorNode.toElement() ); + response.m_errorCode = errorVariant.toMap() [ "faultCode" ].toInt(); + response.m_errorString = errorVariant.toMap() [ "faultString" ].toString(); + + return response; +} + +QString Query::markupCall( const QString &cmd, + const QValueList<QVariant> &args ) const +{ + QString markup = "<?xml version=\"1.0\" ?>\r\n<methodCall>\r\n"; + + markup += "<methodName>" + cmd + "</methodName>\r\n"; + + if ( !args.isEmpty() ) + { + markup += "<params>\r\n"; + QValueList<QVariant>::ConstIterator it = args.begin(); + QValueList<QVariant>::ConstIterator end = args.end(); + for ( ; it != end; ++it ) + markup += "<param>\r\n" + marshal( *it ) + "</param>\r\n"; + markup += "</params>\r\n"; + } + + markup += "</methodCall>\r\n"; + + return markup; +} + +QString Query::marshal( const QVariant &arg ) const +{ + switch ( arg.type() ) + { + case QVariant::String: + case QVariant::CString: + { + QString result = arg.toString(); + result = result.replace( "&", "&" ); + result = result.replace( "\"", """ ); + result = result.replace( "<", "<" ); + result = result.replace( ">", ">" ); + return "<value><string>" + result + "</string></value>\r\n"; + } + case QVariant::Int: + return "<value><int>" + QString::number( arg.toInt() ) + "</int></value>\r\n"; + case QVariant::Double: + return "<value><double>" + QString::number( arg.toDouble() ) + "</double></value>\r\n"; + case QVariant::Bool: + { + QString markup = "<value><boolean>"; + markup += arg.toBool() ? "1" : "0"; + markup += "</boolean></value>\r\n"; + return markup; + } + case QVariant::ByteArray: + return "<value><base64>" + KCodecs::base64Encode( arg.toByteArray() ) + "</base64></value>\r\n"; + case QVariant::DateTime: + return "<value><datetime.iso8601>" + arg.toDateTime().toString( Qt::ISODate ) + "</datetime.iso8601></value>\r\n"; + case QVariant::List: + { + QString markup = "<value><array><data>\r\n"; + const QValueList<QVariant> args = arg.toList(); + QValueList<QVariant>::ConstIterator it = args.begin(); + QValueList<QVariant>::ConstIterator end = args.end(); + for ( ; it != end; ++it ) + markup += marshal( *it ); + markup += "</data></array></value>\r\n"; + return markup; + } + case QVariant::Map: + { + QString markup = "<value><struct>\r\n"; + QMap<QString, QVariant> map = arg.toMap(); + QMap<QString, QVariant>::ConstIterator it = map.begin(); + QMap<QString, QVariant>::ConstIterator end = map.end(); + for ( ; it != end; ++it ) + { + markup += "<member>\r\n"; + markup += "<name>" + it.key() + "</name>\r\n"; + markup += marshal( it.data() ); + markup += "</member>\r\n"; + } + markup += "</struct></value>\r\n"; + return markup; + } + default: + kdWarning() << "Failed to marshal unknown variant type: " << arg.type() << endl; + }; + return QString::null; +} + +QVariant Query::demarshal( const QDomElement &elem ) const +{ + Q_ASSERT( elem.tagName().lower() == "value" ); + + const QDomElement typeElement = elem.firstChild().toElement(); + const QString typeName = typeElement.tagName().lower(); + + if ( typeName == "string" ) + return QVariant( typeElement.text() ); + else if ( typeName == "i4" || typeName == "int" ) + return QVariant( typeElement.text().toInt() ); + else if ( typeName == "double" ) + return QVariant( typeElement.text().toDouble() ); + else if ( typeName == "boolean" ) + { + if ( typeElement.text().lower() == "true" || typeElement.text() == "1" ) + return QVariant( true ); + else + return QVariant( false ); + } + else if ( typeName == "base64" ) + return QVariant( KCodecs::base64Decode( typeElement.text().latin1() ) ); + else if ( typeName == "datetime" || typeName == "datetime.iso8601" ) + return QVariant( QDateTime::fromString( typeElement.text(), Qt::ISODate ) ); + else if ( typeName == "array" ) + { + QValueList<QVariant> values; + QDomNode valueNode = typeElement.firstChild().firstChild(); + while ( !valueNode.isNull() ) + { + values << demarshal( valueNode.toElement() ); + valueNode = valueNode.nextSibling(); + } + return QVariant( values ); + } + else if ( typeName == "struct" ) + { + QMap<QString, QVariant> map; + QDomNode memberNode = typeElement.firstChild(); + while ( !memberNode.isNull() ) + { + const QString key = memberNode.toElement().elementsByTagName( "name" ).item( 0 ).toElement().text(); + const QVariant data = demarshal( memberNode.toElement().elementsByTagName( "value" ).item( 0 ).toElement() ); + map[ key ] = data; + memberNode = memberNode.nextSibling(); + } + return QVariant( map ); + } + else + kdWarning() << "Cannot demarshal unknown type " << typeName << endl; + + return QVariant(); +} + +Query::Query( const QVariant &id, QObject *parent, const char *name ) + : QObject( parent, name ), m_id( id ) +{} + +Query::~Query() +{ + QValueList<KIO::Job*>::Iterator it; + for ( it = m_pendingJobs.begin(); it != m_pendingJobs.end(); ++it ) + (*it)->kill(); +} + +Server::Server( const KURL &url, QObject *parent, const char *name ) + : QObject( parent, name ) +{ + if ( url.isValid() ) + m_url = url; + + m_userAgent = "KDE XMLRPC resources"; + + DebugDialog::init(); +} + +Server::~Server() +{ + QValueList<Query*>::Iterator it; + for ( it = mPendingQueries.begin(); it !=mPendingQueries.end(); ++it ) + (*it)->deleteLater(); + + mPendingQueries.clear(); +} + +void Server::queryFinished( Query *query ) +{ + mPendingQueries.remove( query ); + query->deleteLater(); +} + +void Server::setUrl( const KURL &url ) +{ + m_url = url.isValid() ? url : KURL(); +} + +void Server::call( const QString &method, const QValueList<QVariant> &args, + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, const QVariant &id ) +{ + if ( m_url.isEmpty() ) + kdWarning() << "Cannot execute call to " << method << ": empty server URL" << endl; + + Query *query = Query::create( id, this ); + connect( query, SIGNAL( message( const QValueList<QVariant> &, const QVariant& ) ), msgObj, messageSlot ); + connect( query, SIGNAL( fault( int, const QString&, const QVariant& ) ), faultObj, faultSlot ); + connect( query, SIGNAL( finished( Query* ) ), this, SLOT( queryFinished( Query* ) ) ); + mPendingQueries.append( query ); + + query->call( m_url.url(), method, args, m_userAgent ); +} + +void Server::call( const QString &method, const QVariant &arg, + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << arg ; + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Server::call( const QString &method, int arg, + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Server::call( const QString &method, bool arg, + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Server::call( const QString &method, double arg , + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Server::call( const QString &method, const QString &arg , + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Server::call( const QString &method, const QCString &arg, + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Server::call( const QString &method, const QByteArray &arg , + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << QVariant( arg ); + call( method, args, faultObj, faultSlot, msgObj, messageSlot, id ); +} + +void Server::call( const QString &method, const QDateTime &arg, + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + args << QVariant( arg ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +void Server::call( const QString &method, const QStringList &arg, + QObject* msgObj, const char* messageSlot, + QObject* faultObj, const char* faultSlot, + const QVariant &id ) +{ + QValueList<QVariant> args; + QStringList::ConstIterator it = arg.begin(); + QStringList::ConstIterator end = arg.end(); + for ( ; it != end; ++it ) + args << QVariant( *it ); + call( method, args, msgObj, messageSlot, faultObj, faultSlot, id ); +} + +#include "xmlrpciface.moc" diff --git a/kresources/egroupware/xmlrpciface.h b/kresources/egroupware/xmlrpciface.h new file mode 100644 index 000000000..0e5f6c927 --- /dev/null +++ b/kresources/egroupware/xmlrpciface.h @@ -0,0 +1,165 @@ +/************************************************************************** +* Copyright (C) 2003 - 2004 by Frerich Raabe <raabe@kde.org> * +* Tobias Koenig <tokoe@kde.org> * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +***************************************************************************/ +#ifndef KXMLRPCIFACE_H +#define KXMLRPCIFACE_H + +#include <kurl.h> + +#include <qbuffer.h> +#include <qdom.h> +#include <qobject.h> +#include <qvariant.h> +#include <qvaluelist.h> + +namespace KIO +{ + class Job; +} + +namespace KXMLRPC +{ + class Query; + class QueryResult; + class Server; + class Result; + + class Query : public QObject + { + Q_OBJECT + public: + + + static Query *create( const QVariant &id = QVariant(), + QObject *parent = 0, const char *name = 0 ); + + public slots: + void call( const QString &server, const QString &method, + const QValueList<QVariant> &args = QValueList<QVariant>(), + const QString &userAgent = "KDE-XMLRPC" ); + + signals: + void message( const QValueList<QVariant> &result, const QVariant &id ); + void fault( int, const QString&, const QVariant &id ); + void finished( Query* ); + + private slots: + void slotData( KIO::Job *job, const QByteArray &data ); + void slotResult( KIO::Job *job ); + + private: + bool isMessageResponse( const QDomDocument &doc ) const; + bool isFaultResponse( const QDomDocument &doc ) const; + + Result parseMessageResponse( const QDomDocument &doc ) const; + Result parseFaultResponse( const QDomDocument &doc ) const; + + QString markupCall( const QString &method, + const QValueList<QVariant> &args ) const; + QString marshal( const QVariant &v ) const; + QVariant demarshal( const QDomElement &e ) const; + + Query( const QVariant &id, QObject *parent = 0, const char *name = 0 ); + ~Query(); + + QByteArray m_buffer; + QVariant m_id; + + QValueList<KIO::Job*> m_pendingJobs; + }; + + class Server : public QObject + { + Q_OBJECT + public: + Server( const KURL &url = KURL(), + QObject *parent = 0, const char *name = 0 ); + ~Server(); + + const KURL &url() const { return m_url; } + void setUrl( const KURL &url ); + + QString userAgent() const { return m_userAgent; } + void setUserAgent( const QString &userAgent ) { m_userAgent = userAgent; } + + template <typename T> + void call( const QString &method, const QValueList<T> &arg, + QObject* obj1, const char* faultSlot, + QObject* obj2, const char* messageSlot, const QVariant &id = QVariant() ); + + + public slots: + void call( const QString &method, const QValueList<QVariant> &args, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, const QVariant &arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, int arg , + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, bool arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, double arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, const QString &arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, const QCString &arg , + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, const QByteArray &arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, const QDateTime &arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + void call( const QString &method, const QStringList &arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, + const QVariant &id = QVariant() ); + + private slots: + void queryFinished( Query* ); + + private: + KURL m_url; + QString m_userAgent; + + QValueList<Query*> mPendingQueries; + }; +} + +template <typename T> +void KXMLRPC::Server::call( const QString &method, const QValueList<T> &arg, + QObject* faultObj, const char* faultSlot, + QObject* msgObj, const char* messageSlot, const QVariant &id ) +{ + QValueList<QVariant> args; + + typename QValueList<T>::ConstIterator it = arg.begin(); + typename QValueList<T>::ConstIterator end = arg.end(); + for ( ; it != end; ++it ) + args << QVariant( *it ); + + return call( method, args, faultObj, faultSlot, msgObj, messageSlot, id ); +} + +#endif |