diff options
Diffstat (limited to 'kresources/slox')
32 files changed, 4616 insertions, 0 deletions
diff --git a/kresources/slox/Makefile.am b/kresources/slox/Makefile.am new file mode 100644 index 000000000..6cc95f1eb --- /dev/null +++ b/kresources/slox/Makefile.am @@ -0,0 +1,51 @@ +INCLUDES = -I$(top_srcdir) $(all_includes) + + +lib_LTLIBRARIES = libkslox.la libkabc_slox.la libkcal_slox.la + +libkslox_la_SOURCES = sloxaccounts.cpp webdavhandler.cpp \ + sloxfolder.cpp sloxfoldermanager.cpp \ + sloxfolderdialog.cpp sloxbase.cpp +libkslox_la_LDFLAGS = $(all_libraries) +libkslox_la_LIBADD = $(top_builddir)/libkcal/libkcal.la \ + $(top_builddir)/libkdepim/libkdepim.la + +libkcal_slox_la_SOURCES = kcalresourceslox.cpp kcalresourcesloxconfig.cpp \ + kcalsloxprefs.kcfgc +libkcal_slox_la_LDFLAGS = $(all_libraries) +libkcal_slox_la_LIBADD = libkslox.la $(top_builddir)/libkcal/libkcal.la + +libkabc_slox_la_SOURCES = kabcresourceslox.cpp kabcresourcesloxconfig.cpp \ + kabcsloxprefs.kcfgc +libkabc_slox_la_LDFLAGS = $(all_libraries) +libkabc_slox_la_LIBADD = libkslox.la -lkabc + + +kde_module_LTLIBRARIES = kcal_slox.la kabc_slox.la + +kcal_slox_la_SOURCES = kcalresourceslox_plugin.cpp +kcal_slox_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kcal_slox_la_LIBADD = libkcal_slox.la + +kabc_slox_la_SOURCES = kabcresourceslox_plugin.cpp +kabc_slox_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kabc_slox_la_LIBADD = libkabc_slox.la + + +EXTRA_PROGRAMS = testsloxaccounts + +testsloxaccounts_LDFLAGS = $(all_libraries) $(KDE_RPATH) +testsloxaccounts_LDADD = libkslox.la +testsloxaccounts_SOURCES = testsloxaccounts.cpp + + +kcal_servicedir = $(kde_servicesdir)/kresources/kcal +kcal_service_DATA = kcal_slox.desktop kcal_ox.desktop + +kabc_servicedir = $(kde_servicesdir)/kresources/kabc +kabc_service_DATA = kabc_slox.desktop kabc_ox.desktop + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kabc_slox.pot diff --git a/kresources/slox/kabc_ox.desktop b/kresources/slox/kabc_ox.desktop new file mode 100644 index 000000000..4f4fb8c22 --- /dev/null +++ b/kresources/slox/kabc_ox.desktop @@ -0,0 +1,47 @@ +[Desktop Entry] +Name=OpenXchange Server +Name[af]=OpenXchange bediener +Name[bg]=Сървър OpenXchange +Name[br]=Servijer OpenXchange +Name[ca]=Servidor OpenXchange +Name[da]=Openxchange-server +Name[el]=Εξυπηρετητής OpenXchange +Name[es]=Servidor OpenXchange +Name[et]=OpenXchange server +Name[eu]=OpenXchange zerbitzaria +Name[fa]=کارساز OpenXchange +Name[fi]=OpenXchange-palvelin +Name[fr]=Serveur OpenXchange +Name[fy]=OpenXchange-tsjinner +Name[ga]=Freastalaí Openexchange +Name[gl]=Servidor OpenXchange +Name[hu]=OpenXchange-kiszolgáló +Name[is]=OpenXchange þjónn +Name[ja]=OpenXchange サーバ +Name[ka]=Openexchange სერვერი +Name[kk]=OpenXchange сервері +Name[km]=ម៉ាស៊ីនបម្រើ OpenXchange +Name[lt]=OpenXchange serveris +Name[mk]=OpenXchange-сервер +Name[nb]=OpenExchange-tjener +Name[nds]=OpenXchange-Server +Name[ne]=ओपन एक्सचेन्ज सर्भर +Name[nl]=OpenXchange-server +Name[nn]=OpenXchange-tenar +Name[pl]=Server OpenXchange +Name[pt]=Servidor OpenXchange +Name[pt_BR]=Servidor OpenXchange +Name[ru]=Сервер OpenXchange +Name[sl]=Strežnik OpenXchange +Name[sr]=Openexchange сервер +Name[sr@Latn]=Openexchange server +Name[sv]=Openxchange-server +Name[tr]=OpenXchange Sunucusu +Name[uk]=Сервер OpenXchange +Name[zh_CN]=OpenXchange 服务器 +Name[zh_TW]=OpenXchange 伺服器 +X-KDE-Library=kabc_slox +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=contact +X-KDE-ResourceType=ox diff --git a/kresources/slox/kabc_slox.desktop b/kresources/slox/kabc_slox.desktop new file mode 100644 index 000000000..bdfce204e --- /dev/null +++ b/kresources/slox/kabc_slox.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=SUSE LINUX Openexchange Server +Name[af]=SuSE Linux OpenExchange bediener +Name[bg]=Сървър SUSE LINUX Openexchange +Name[br]=Servijer Openexchange SUSE LINUX +Name[ca]=Servidor SUSE LINUX Openexchange +Name[cs]=SUSE LINUX Openexchange server +Name[da]=SUSE Linux Openexchange-server +Name[de]=SUSE LINUX Openexchange-Server +Name[el]=Εξυπηρετητή SUSE LINUX Openexchange +Name[es]=Servidor Openexchange de SUSE LINUX +Name[et]=SUSE LINUX Openexchange server +Name[eu]=SUSE LINUX Openexchange zerbitzaria +Name[fa]=کارساز SUSE LINUX Openexchange +Name[fi]=Suse Linux Openexchange -palvelin +Name[fr]=Serveur SUSE Linux Openexchange +Name[fy]=SUSE LINUX Openexchange-tsjinner +Name[ga]=Freastalaí Openexchange SUSE LINUX +Name[gl]=Servidor SUSE LINUX Openexchange +Name[hu]=SUSE LINUX Openexchange-kiszolgáló +Name[is]=SUSE LINUX Openexchange þjónn +Name[it]=Server SUSE LINUX Openexchange +Name[ja]=SUSE LINUX Openexchange サーバ +Name[ka]= SUSE LINUX Openexchange სერვერი +Name[kk]=SUSE LINUX Openexchange сервері +Name[km]=ម៉ាស៊ីនបម្រើ Openexchange របស់ស៊ូស៊ីលីនីក +Name[lt]=SUSE LINUX Openexchange serveris +Name[mk]=SUSE LINUX Openexchange-сервер +Name[ms]=Pelayan SUSE LINUX Openexchange +Name[nb]=SUSE LINUX Openexchange-tjener +Name[nds]=SUSE-Openexchangeserver +Name[ne]=SUSE LINUX ओपन एक्सचेन्ज सर्भर +Name[nl]=SUSE LINUX Openexchange-server +Name[nn]=SUSE LINUX Openexchange-tenar +Name[pl]=Server SUSE LINUX Openexchange +Name[pt]=Servidor SUSE LINUX Openexchange +Name[pt_BR]=Servidor OpenExchange do SUSE Linux (SLOX) +Name[ru]=Сервер SUSE LINUX Openexchange +Name[sl]=Strežnik SUSE LINUX Openexchange +Name[sr]=Openexchange сервер SUSE-овог Linux-а +Name[sr@Latn]=Openexchange server SUSE-ovog Linux-a +Name[sv]=SUSE Linux Openexchange-server +Name[ta]=SUSE LINUX திறந்த பரிமாற்ற சேவகன் +Name[tr]=SUSE LINUX Openexchange Sunucusu +Name[uk]=Сервер SUSE LINUX Openexchange +Name[zh_CN]=SUSE LINUX Openexchange 服务器 +Name[zh_TW]=SUSE LINUX Openexchange 伺服器 +X-KDE-Library=kabc_slox +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=contact +X-KDE-ResourceType=slox diff --git a/kresources/slox/kabcresourceslox.cpp b/kresources/slox/kabcresourceslox.cpp new file mode 100644 index 000000000..e6bf326c3 --- /dev/null +++ b/kresources/slox/kabcresourceslox.cpp @@ -0,0 +1,673 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2005 Volker Krause <volker.krause@rwth-aachen.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <qapplication.h> + +#include <kabc/picture.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmdcodec.h> +#include <kstandarddirs.h> +#include <kstringhandler.h> +#include <libkdepim/kpimprefs.h> +#include <libkdepim/progressmanager.h> +#include <kio/davjob.h> + +#include "webdavhandler.h" +#include "sloxaccounts.h" +#include "kabcsloxprefs.h" + +#include "kabcresourceslox.h" + +using namespace KABC; + +ResourceSlox::ResourceSlox( const KConfig *config ) + : ResourceCached( config ), SloxBase( this ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + if ( config ) { + readConfig( config ); + } +} + +ResourceSlox::ResourceSlox( const KURL &url, + const QString &user, const QString &password ) + : ResourceCached( 0 ), SloxBase( this ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + mPrefs->setUrl( url.url() ); + mPrefs->setUser( user ); + mPrefs->setPassword( password ); +} + +void ResourceSlox::init() +{ + mPrefs = new SloxPrefs; + mWebdavHandler.setResource( this ); + + mDownloadJob = 0; + mUploadJob = 0; + mDownloadProgress = 0; + mUploadProgress = 0; + + // phone number mapping for SLOX + mPhoneNumberSloxMap[PhoneNumber::Work] << "phone" << "phone2"; + mPhoneNumberSloxMap[PhoneNumber::Home] << "privatephone" << "privatephone2"; + mPhoneNumberSloxMap[PhoneNumber::Cell | PhoneNumber::Work] << "mobile" << "mobile2"; + mPhoneNumberSloxMap[PhoneNumber::Cell | PhoneNumber::Home] << "privatemobile" << "privatemobile2"; + mPhoneNumberSloxMap[PhoneNumber::Fax | PhoneNumber::Work] << "fax" << "fax2"; + mPhoneNumberSloxMap[PhoneNumber::Fax | PhoneNumber::Home] << "privatefax" << "privatefax2"; + + // phone number mapping for OX (mapping partly taken from Kolab) + mPhoneNumberOxMap[PhoneNumber::Work] << "phone_business" << "phone_business2"; + mPhoneNumberOxMap[PhoneNumber::Home] << "phone_home" << "phone_home2"; + mPhoneNumberOxMap[PhoneNumber::Cell] << "mobile1"<< "mobile2"; + mPhoneNumberOxMap[PhoneNumber::Fax | PhoneNumber::Work] << "fax_business"; + mPhoneNumberOxMap[PhoneNumber::Fax | PhoneNumber::Home] << "fax_home"; + mPhoneNumberOxMap[PhoneNumber::Fax] << "fax_other"; + mPhoneNumberOxMap[PhoneNumber::Car] << "phone_car"; + mPhoneNumberOxMap[PhoneNumber::Isdn] << "isdn"; + mPhoneNumberOxMap[PhoneNumber::Pager] << "pager"; + mPhoneNumberOxMap[PhoneNumber::Pref] << "primary"; + mPhoneNumberOxMap[PhoneNumber::Voice] << "callback"; + mPhoneNumberOxMap[PhoneNumber::Video] << "radio"; + mPhoneNumberOxMap[PhoneNumber::Bbs] << "tty_tdd"; + mPhoneNumberOxMap[PhoneNumber::Modem] << "telex"; + mPhoneNumberOxMap[PhoneNumber::Pcs] << "phone_assistant"; + mPhoneNumberOxMap[PhoneNumber::Msg] << "phone_company"; +} + +ResourceSlox::~ResourceSlox() +{ + kdDebug() << "KABC::~ResourceSlox()" << endl; + + if ( mDownloadJob ) mDownloadJob->kill(); + + delete mPrefs; + + kdDebug() << "KABC::~ResourceSlox() done" << endl; +} + +void ResourceSlox::readConfig( const KConfig * ) +{ + mPrefs->readConfig(); +} + +void ResourceSlox::writeConfig( KConfig *config ) +{ + kdDebug() << "ResourceSlox::writeConfig() " << endl; + kdDebug() << mPrefs->url() << endl; + + Resource::writeConfig( config ); + + mPrefs->writeConfig(); +} + +Ticket *ResourceSlox::requestSaveTicket() +{ + if ( !addressBook() ) { + kdDebug(5700) << "no addressbook" << endl; + return 0; + } + + return createTicket( this ); +} + +void ResourceSlox::releaseSaveTicket( Ticket *ticket ) +{ + delete ticket; +} + +bool ResourceSlox::doOpen() +{ + return true; +} + +void ResourceSlox::doClose() +{ + cancelDownload(); + cancelUpload(); +} + +bool ResourceSlox::load() +{ + kdDebug() << "KABC::ResourceSlox::load()" << endl; + +#if 0 + return asyncLoad(); +#else + kdDebug() << "KABC::ResourceSlox::load() is a nop." << endl; + return true; +#endif +} + +bool ResourceSlox::asyncLoad() +{ + kdDebug() << "KABC::ResourceSlox::asyncLoad()" << endl; + + if ( mDownloadJob ) { + kdDebug() << "KABC::ResourceSlox::asyncLoad(): Loading still in progress." + << endl; + return true; + } + + loadCache(); + clearChanges(); + + KURL url = mPrefs->url(); + url.setPath( "/servlet/webdav.contacts/" ); + url.setUser( mPrefs->user() ); + url.setPass( mPrefs->password() ); + + QString lastsync = "0"; + if ( mPrefs->useLastSync() ) { + QDateTime dt = mPrefs->lastSync(); + if ( dt.isValid() ) + lastsync = WebdavHandler::qDateTimeToSlox( dt.addDays( -1 ) ); + } + + QDomDocument doc; + QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" ); + QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( LastSync ), lastsync ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( FolderId ), mPrefs->folderId() ); + if ( type() == "ox" ) { + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "NEW_AND_MODIFIED" ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "DELETED" ); + } else + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "all" ); + + kdDebug() << "REQUEST CONTACTS: \n" << doc.toString( 2 ) << endl; + + mDownloadJob = KIO::davPropFind( url, doc, "0", false ); + connect( mDownloadJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotResult( KIO::Job * ) ) ); + connect( mDownloadJob, SIGNAL( percent( KIO::Job *, unsigned long ) ), + SLOT( slotProgress( KIO::Job *, unsigned long ) ) ); + + mDownloadProgress = KPIM::ProgressManager::instance()->createProgressItem( + KPIM::ProgressManager::getUniqueID(), i18n("Downloading contacts") ); + connect( mDownloadProgress, + SIGNAL( progressItemCanceled( KPIM::ProgressItem * ) ), + SLOT( cancelDownload() ) ); + + mPrefs->setLastSync( QDateTime::currentDateTime() ); + + return true; +} + +void ResourceSlox::slotResult( KIO::Job *job ) +{ + kdDebug() << "ResourceSlox::slotResult()" << endl; + + if ( job->error() ) { + job->showErrorDialog( 0 ); + } else { + kdDebug() << "ResourceSlox::slotResult() success" << endl; + + QDomDocument doc = mDownloadJob->response(); + + mWebdavHandler.log( doc.toString( 2 ) ); + + QValueList<SloxItem> items = WebdavHandler::getSloxItems( this, doc ); + + bool changed = false; + + QValueList<SloxItem>::ConstIterator it; + for( it = items.begin(); it != items.end(); ++it ) { + SloxItem item = *it; + QString uid = "kresources_slox_kabc_" + item.sloxId; + if ( item.status == SloxItem::Delete ) { + QMap<QString,Addressee>::Iterator it; + it = mAddrMap.find( uid ); + if ( it != mAddrMap.end() ) { + mAddrMap.remove( it ); + changed = true; + } + } else if ( item.status == SloxItem::Create ) { + Addressee a; + a.setUid( uid ); + + mWebdavHandler.clearSloxAttributeStatus(); + + QDomNode n; + for( n = item.domNode.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e = n.toElement(); + mWebdavHandler.parseSloxAttribute( e ); + parseContactAttribute( e, a ); + } + + mWebdavHandler.setSloxAttributes( a ); + + a.setResource( this ); + a.setChanged( false ); + + mAddrMap.replace( a.uid(), a ); + + // TODO: Do we need to try to associate addressees with slox accounts? + + changed = true; + } + } + + clearChanges(); + saveCache(); + } + + mDownloadJob = 0; + mDownloadProgress->setComplete(); + mDownloadProgress = 0; + + emit loadingFinished( this ); +} + +void ResourceSlox::slotUploadResult( KIO::Job *job ) +{ + kdDebug() << "ResourceSlox::slotUploadResult()" << endl; + + if ( job->error() ) { + job->showErrorDialog( 0 ); + } else { + kdDebug() << "ResourceSlox::slotUploadResult() success" << endl; + + QDomDocument doc = mUploadJob->response(); + kdDebug() << k_funcinfo << "Upload result: " << endl; + kdDebug() << doc.toString() << endl; + + QValueList<SloxItem> items = WebdavHandler::getSloxItems( this, doc ); + + QValueList<SloxItem>::ConstIterator it; + for( it = items.begin(); it != items.end(); ++it ) { + SloxItem item = *it; + if ( !item.response.contains( "200" ) ) { + savingError( this, item.response + "\n" + item.responseDescription ); + continue; + } + if ( item.status == SloxItem::New ) { + QMap<QString,Addressee>::Iterator search_res; + search_res = mAddrMap.find( item.clientId ); + if ( search_res != mAddrMap.end() ) { + // use the id provided by the server + Addressee a = *search_res; + mAddrMap.remove( search_res ); + a.setUid( "kresources_slox_kabc_" + item.sloxId ); + a.setResource( this ); + a.setChanged( false ); + mAddrMap.replace( a.uid(), a ); + saveCache(); + } + } + } + } + + clearChange( mUploadAddressee ); + + mUploadJob = 0; + mUploadProgress->setComplete(); + mUploadProgress = 0; + + uploadContacts(); +} + +void ResourceSlox::parseContactAttribute( const QDomElement &e, Addressee &a ) +{ + QString text = decodeText( e.text() ); + if ( text.isEmpty() ) return; + QString tag = e.tagName(); + int pnType = 0; + + if ( tag == fieldName( Birthday ) ) { + QDateTime dt = WebdavHandler::sloxToQDateTime( text ); + a.setBirthday( dt.date() ); + } else if ( tag == fieldName( Role ) ) { + a.setRole( text ); + } else if ( tag == "salutation" ) { // what's this in OX? + a.setPrefix( text ); + } else if ( tag == fieldName( Title ) ) { + a.setTitle( text ); + } else if ( tag == fieldName( Organization ) ) { + a.setOrganization( text ); + } else if ( tag == fieldName( Department ) ) { + a.insertCustom( "KADDRESSBOOK", "X-Department", text ); + } else if ( tag == fieldName( FamilyName ) ) { + a.setFamilyName( text ); + } else if ( tag == fieldName( GivenName) ) { + a.setGivenName( text ); + } else if ( tag == fieldName( SecondName ) ) { + a.setAdditionalName( text ); + } else if ( tag == fieldName( DisplayName ) ) { + a.setFormattedName( text ); + } else if ( tag == fieldName( Suffix ) ) { + a.setSuffix( text ); + } else if ( tag == fieldName( PrimaryEmail ) ) { + a.insertEmail( text, true ); + } else if ( (pnType = phoneNumberType( tag )) ) { + a.insertPhoneNumber( PhoneNumber( text, pnType ) ); + } else if ( tag == fieldName( Comment ) ) { + a.setNote( text ); + } else if ( tag == fieldName( SecondaryEmail1 ) || tag == fieldName( SecondaryEmail2 ) || + tag == fieldName( SecondaryEmail3 ) ) { + a.insertEmail( text ); + } else if ( tag == fieldName( Url ) ) { + a.setUrl( text ); + } else if ( tag == fieldName( Image ) ) { + QByteArray decodedPicture; + KCodecs::base64Decode( text.utf8(), decodedPicture ); + a.setPhoto( Picture( QImage( decodedPicture ) ) ); + } else if ( tag == fieldName( NickName ) ) { + a.setNickName( text ); + } else if ( tag == fieldName( InstantMsg ) ) { + a.insertCustom( "KADDRESSBOOK", "X-IMAddress", text ); + } else if ( tag == fieldName( Office ) ) { + a.insertCustom( "KADDRESSBOOK", "X-Office", text ); + } else if ( tag == fieldName( Profession ) ) { + a.insertCustom( "KADDRESSBOOK", "X-Profession", text ); + } else if ( tag == fieldName( ManagersName ) ) { + a.insertCustom( "KADDRESSBOOK", "X-ManagersName", text ); + } else if ( tag == fieldName( AssistantsName ) ) { + a.insertCustom( "KADDRESSBOOK", "X-AssistantsName", text ); + } else if ( tag == fieldName( SpousesName ) ) { + a.insertCustom( "KADDRESSBOOK", "X-SpousesName", text ); + } else if ( tag == fieldName( Anniversary ) ) { + QDateTime dt = WebdavHandler::sloxToQDateTime( text ); + a.insertCustom( "KADDRESSBOOK", "X-Anniversary", dt.toString( Qt::ISODate ) ); + } else if ( tag == fieldName( Categories ) ) { + a.setCategories( QStringList::split( QRegExp(",\\s*"), text ) ); + } else if ( type() == "ox" ) { // FIXME: Address reading is missing for SLOX + // read addresses + Address addr; + if ( tag.startsWith( fieldName( BusinessPrefix ) ) ) { + addr = a.address( KABC::Address::Work ); + } else if ( tag.startsWith( fieldName( OtherPrefix ) ) ) { + addr = a.address( 0 ); + } else { + addr = a.address( KABC::Address::Home ); + } + if ( tag.endsWith( fieldName( Street ) ) ) { + addr.setStreet( text ); + } else if ( tag.endsWith( fieldName( PostalCode ) ) ) { + addr.setPostalCode( text ); + } else if ( tag.endsWith( fieldName( City ) ) ) { + addr.setLocality( text ); + } else if ( tag.endsWith( fieldName( State ) ) ) { + addr.setRegion( text ); + } else if ( tag.endsWith( fieldName( Country ) ) ) { + addr.setCountry( text ); + } + a.insertAddress( addr ); + } +} + +int ResourceSlox::phoneNumberType( const QString &fieldName ) const +{ + QMap<int, QStringList> pnmap; + if ( type() == "ox" ) + pnmap = mPhoneNumberOxMap; + else + pnmap = mPhoneNumberSloxMap; + QMap<int, QStringList>::ConstIterator it; + for ( it = pnmap.begin(); it != pnmap.end(); ++it ) { + QStringList l = it.data(); + QStringList::ConstIterator it2; + for ( it2 = l.begin(); it2 != l.end(); ++it2 ) + if ( (*it2) == fieldName ) + return it.key(); + } + return 0; +} + +bool ResourceSlox::save( Ticket* ) +{ + kdDebug() << k_funcinfo << endl; + + if ( readOnly() || !hasChanges() || type() != "ox" ) { + emit savingFinished( this ); + return true; + } + + if ( mDownloadJob ) { + kdWarning() << k_funcinfo << "download still in progress" << endl; + return false; + } + if ( mUploadJob ) { + kdWarning() << k_funcinfo << "upload still in progress" << endl; + return false; + } + + saveCache(); + uploadContacts(); + return true; +} + +bool ResourceSlox::asyncSave( Ticket* ) +{ + return false; // readonly +} + +void ResourceSlox::uploadContacts() +{ + QDomDocument doc; + QDomElement root = WebdavHandler::addDavElement( doc, doc, "propertyupdate" ); + QDomElement set = WebdavHandler::addDavElement( doc, root, "set" ); + QDomElement prop = WebdavHandler::addDavElement( doc, set, "prop" ); + + bool isDelete = false; + + KABC::Addressee::List addedAddr = addedAddressees(); + KABC::Addressee::List changedAddr = changedAddressees(); + KABC::Addressee::List deletedAddr = deletedAddressees(); + + if ( !addedAddr.isEmpty() ) { + mUploadAddressee = addedAddr.first(); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ClientId ), mUploadAddressee.uid() ); + } else if ( !changedAddr.isEmpty() ) { + mUploadAddressee = changedAddr.first(); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectId ), + mUploadAddressee.uid().remove( 0, sizeof("kresources_slox_kabc_") - 1) ); + } else if ( !deletedAddr.isEmpty() ) { + mUploadAddressee = deletedAddr.first(); + isDelete = true; + } else { + kdDebug() << k_funcinfo << "Upload finished." << endl; + emit savingFinished( this ); + return; + } + + if ( !isDelete ) { + createAddresseeFields( doc, prop, mUploadAddressee ); + } else { + QString tmp_uid = mUploadAddressee.uid().remove( 0, sizeof("kresources_slox_kabc_") - 1); // remove prefix from uid + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectId ), tmp_uid ); + WebdavHandler::addSloxElement( this, doc, prop, "method", "DELETE" ); + } + + kdDebug() << k_funcinfo << doc.toString() << endl; + + KURL url = mPrefs->url(); + url.setPath( "/servlet/webdav.contacts/" ); + url.setUser( mPrefs->user() ); + url.setPass( mPrefs->password() ); + + mUploadJob = KIO::davPropPatch( url, doc, false ); + connect( mUploadJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotUploadResult( KIO::Job * ) ) ); + connect( mUploadJob, SIGNAL( percent( KIO::Job *, unsigned long ) ), + SLOT( slotProgress( KIO::Job *, unsigned long ) ) ); + + mUploadProgress = KPIM::ProgressManager::instance()->createProgressItem( + KPIM::ProgressManager::getUniqueID(), i18n("Uploading contacts") ); + connect( mUploadProgress, + SIGNAL( progressItemCanceled( KPIM::ProgressItem * ) ), + SLOT( cancelUpload() ) ); +} + +void ResourceSlox::createAddresseeFields( QDomDocument &doc, QDomElement &prop, + const Addressee &a ) +{ + // choose addressbook + WebdavHandler::addSloxElement( this, doc, prop, fieldName( FolderId ), mPrefs->folderId() ); + + // person + WebdavHandler::addSloxElement( this, doc, prop, fieldName( GivenName ), a.givenName() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( FamilyName ), a.familyName() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Title ), a.title() ); + if ( !a.birthday().isNull() ) + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Birthday ), + WebdavHandler::qDateTimeToSlox( a.birthday() ) ); + else + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Birthday ) ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Role ), a.role() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Department ), + a.custom( "KADDRESSBOOK", "X-Department" ) ); + if ( type() == "ox" ) { // OX only fields + WebdavHandler::addSloxElement( this, doc, prop, fieldName( DisplayName ), a.formattedName() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( SecondName ), a.additionalName() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Suffix ), a.suffix() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Organization ), a.organization() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( NickName ), a.nickName() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( InstantMsg ), + a.custom( "KADDRESSBOOK", "X-IMAddress" ) ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Office ), + a.custom( "KADDRESSBOOK", "X-Office" ) ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Profession ), + a.custom( "KADDRESSBOOK", "X-Profession" ) ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ManagersName ), + a.custom( "KADDRESSBOOK", "X-ManagersName" ) ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( AssistantsName ), + a.custom( "KADDRESSBOOK", "X-AssistantsName" ) ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( SpousesName ), + a.custom( "KADDRESSBOOK", "X-SpousesName" ) ); + QString anniversary = a.custom( "KADDRESSBOOK", "X-Anniversary" ); + if ( !anniversary.isEmpty() ) + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Anniversary ), + WebdavHandler::qDateTimeToSlox( QDateTime::fromString( anniversary, Qt::ISODate ).date() ) ); + else + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Anniversary ) ); + } + + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Url ), a.url().url() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Comment ), a.note() ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( Categories ), a.categories().join( ", " ) ); + + // emails + QStringList email_list = a.emails(); + QStringList::const_iterator emails_it = email_list.begin(); + if ( emails_it != email_list.end() ) + WebdavHandler::addSloxElement( this, doc, prop, fieldName( PrimaryEmail ), *(emails_it++) ); + if ( emails_it != email_list.end() ) + WebdavHandler::addSloxElement( this, doc, prop, fieldName( SecondaryEmail1 ), *(emails_it++) ); + if ( emails_it != email_list.end() ) + WebdavHandler::addSloxElement( this, doc, prop, fieldName( SecondaryEmail2 ), *(emails_it++) ); + + // phone numbers + PhoneNumber::List pnlist = a.phoneNumbers(); + QMap<int, QStringList> pnSaveMap; + if ( type() == "ox" ) + pnSaveMap = mPhoneNumberOxMap; + else + pnSaveMap = mPhoneNumberSloxMap; + for ( PhoneNumber::List::ConstIterator it = pnlist.begin() ; it != pnlist.end(); ++it ) { + if ( pnSaveMap.contains( (*it).type() ) ) { + QStringList l = pnSaveMap[(*it).type()]; + QString fn = l.first(); + l.remove( l.begin() ); + if ( !l.isEmpty() ) + pnSaveMap[(*it).type()] = l; + else + pnSaveMap.remove( (*it).type() ); + WebdavHandler::addSloxElement( this, doc, prop, fn, (*it).number() ); + } else + kdDebug() << k_funcinfo << "Can't save phone number " << (*it).number() << " of type " << (*it).type() << endl; + } + // send empty fields for the remaining ohone number fields + // it's not possible to delete phone numbers otherwise + for ( QMap<int, QStringList>::ConstIterator it = pnSaveMap.begin(); it != pnSaveMap.end(); ++it ) { + QStringList l = it.data(); + for ( QStringList::ConstIterator it2 = l.begin(); it2 != l.end(); ++it2 ) + WebdavHandler::addSloxElement( this, doc, prop, (*it2) ); + } + + // write addresses + createAddressFields( doc, prop, fieldName( HomePrefix ), a.address( KABC::Address::Home ) ); + if ( type() == "ox" ) { + createAddressFields( doc, prop, fieldName( BusinessPrefix ), a.address( KABC::Address::Work ) ); + createAddressFields( doc, prop, fieldName( OtherPrefix ), a.address( 0 ) ); + } +} + +void KABC::ResourceSlox::createAddressFields( QDomDocument &doc, QDomElement &parent, + const QString &prefix, const KABC::Address &addr ) +{ + WebdavHandler::addSloxElement( this, doc, parent, prefix + fieldName( Street ), addr.street() ); + WebdavHandler::addSloxElement( this, doc, parent, prefix + fieldName( PostalCode ), addr.postalCode() ); + WebdavHandler::addSloxElement( this, doc, parent, prefix + fieldName( City ), addr.locality() ); + WebdavHandler::addSloxElement( this, doc, parent, prefix + fieldName( State ), addr.region() ); + WebdavHandler::addSloxElement( this, doc, parent, prefix + fieldName( Country ), addr.country() ); +} + +void ResourceSlox::slotProgress( KIO::Job *job, unsigned long percent ) +{ + if ( mDownloadProgress && job == mDownloadJob ) + mDownloadProgress->setProgress( percent ); + else if ( mUploadProgress && job == mUploadJob ) + mUploadProgress->setProgress( percent ); +} + +void ResourceSlox::cancelDownload() +{ + if ( mDownloadJob ) mDownloadJob->kill(); + mDownloadJob = 0; + if ( mDownloadProgress ) mDownloadProgress->setComplete(); + mDownloadProgress = 0; +} + +void ResourceSlox::cancelUpload() +{ + if ( mUploadJob ) mUploadJob->kill(); + mUploadJob = 0; + if ( mUploadProgress ) mUploadProgress->setComplete(); + mUploadProgress = 0; +} + +void ResourceSlox::setReadOnly( bool b ) +{ + if ( type() == "ox" ) + KABC::Resource::setReadOnly( b ); + else + KABC::Resource::setReadOnly( true ); +} + +bool ResourceSlox::readOnly() const +{ + if ( type() == "ox" ) + return KABC::Resource::readOnly(); + else + return true; +} + +#include "kabcresourceslox.moc" diff --git a/kresources/slox/kabcresourceslox.h b/kresources/slox/kabcresourceslox.h new file mode 100644 index 000000000..066fdeaa4 --- /dev/null +++ b/kresources/slox/kabcresourceslox.h @@ -0,0 +1,113 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef KABC_RESOURCESLOX_H +#define KABC_RESOURCESLOX_H + +#include "sloxbase.h" +#include "webdavhandler.h" + +#include <libkdepim/kabcresourcecached.h> +#include <kdepimmacros.h> +#include <kabc/addressee.h> + +#include <qmap.h> +#include <qdom.h> + +namespace KIO { +class DavJob; +class Job; +} + +namespace KPIM { +class ProgressItem; +} + +class KConfig; + +namespace KABC { + +class SloxPrefs; + +class KDE_EXPORT ResourceSlox : public ResourceCached, public SloxBase +{ + Q_OBJECT + public: + ResourceSlox( const KConfig * ); + ResourceSlox( const KURL &url, + const QString &user, const QString &password ); + ~ResourceSlox(); + + void readConfig( const KConfig * ); + void writeConfig( KConfig * ); + + SloxPrefs *prefs() const { return mPrefs; } + + bool doOpen(); + void doClose(); + + Ticket *requestSaveTicket(); + void releaseSaveTicket( Ticket* ); + + bool load(); + bool asyncLoad(); + bool save( Ticket * ); + bool asyncSave( Ticket * ); + + void setReadOnly( bool ); + bool readOnly() const; + + protected: + void init(); + + int phoneNumberType( const QString &fieldName ) const; + void parseContactAttribute( const QDomElement &e, Addressee &a ); + + void createAddresseeFields( QDomDocument &doc, QDomElement &prop, const Addressee &a ); + void createAddressFields( QDomDocument &doc, QDomElement &parent, + const QString &prefix, const KABC::Address &addr ); + + void uploadContacts(); + + protected slots: + void slotResult( KIO::Job *job ); + void slotUploadResult( KIO::Job *job ); + void slotProgress( KIO::Job *job, unsigned long percent ); + + void cancelDownload(); + void cancelUpload(); + + private: + SloxPrefs *mPrefs; + + KIO::DavJob *mDownloadJob; + KIO::DavJob *mUploadJob; + KPIM::ProgressItem *mDownloadProgress; + KPIM::ProgressItem *mUploadProgress; + + WebdavHandler mWebdavHandler; + + KABC::Addressee mUploadAddressee; + + QMap<int, QStringList> mPhoneNumberSloxMap, mPhoneNumberOxMap; +}; + +} + +#endif diff --git a/kresources/slox/kabcresourceslox_plugin.cpp b/kresources/slox/kabcresourceslox_plugin.cpp new file mode 100644 index 000000000..73152673a --- /dev/null +++ b/kresources/slox/kabcresourceslox_plugin.cpp @@ -0,0 +1,39 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "kabcresourceslox.h" +#include "kabcresourcesloxconfig.h" + +#include <kglobal.h> +#include <klocale.h> + +using namespace KABC; + +typedef KRES::PluginFactory< ResourceSlox, ResourceSloxConfig > SloxFactory; + +extern "C" +{ + void *init_kabc_slox() + { + KGlobal::locale()->insertCatalogue( "libkcal" ); + KGlobal::locale()->insertCatalogue( "kabc_slox" ); + return new SloxFactory; + } +} diff --git a/kresources/slox/kabcresourcesloxconfig.cpp b/kresources/slox/kabcresourcesloxconfig.cpp new file mode 100644 index 000000000..3df5636be --- /dev/null +++ b/kresources/slox/kabcresourcesloxconfig.cpp @@ -0,0 +1,121 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "kabcresourcesloxconfig.h" + +#include "kabcresourceslox.h" +#include "kabcsloxprefs.h" +#include "sloxbase.h" +#include "sloxfolder.h" +#include "sloxfolderdialog.h" +#include "sloxfoldermanager.h" + +#include <kdebug.h> +#include <kdialog.h> +#include <klocale.h> +#include <klineedit.h> +#include <kurlrequester.h> + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> + +using namespace KABC; + +ResourceSloxConfig::ResourceSloxConfig( QWidget* parent, const char* name ) + : KRES::ConfigWidget( parent, name ), mRes( 0 ) +{ + QGridLayout *mainLayout = new QGridLayout( this, 5, 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( "User:" ), this ); + mUser = new KLineEdit( this ); + + mainLayout->addWidget( label, 1, 0 ); + mainLayout->addWidget( mUser, 1, 1 ); + + label = new QLabel( i18n( "Password:" ), this ); + mPassword = new KLineEdit( this ); + mPassword->setEchoMode( QLineEdit::Password ); + + mainLayout->addWidget( label, 2, 0 ); + mainLayout->addWidget( mPassword, 2, 1 ); + + mLastSyncCheck = new QCheckBox( i18n("Only load data since last sync"), + this ); + mainLayout->addMultiCellWidget( mLastSyncCheck, 3, 3, 0, 1 ); + + mFolderButton = new KPushButton( i18n("Select Folder..."), this ); + mainLayout->addMultiCellWidget( mFolderButton, 4, 4, 0, 1 ); + connect( mFolderButton, SIGNAL( clicked() ), SLOT( selectAddressFolder() ) ); + +} + +void ResourceSloxConfig::loadSettings( KRES::Resource *res ) +{ + ResourceSlox *resource = dynamic_cast<ResourceSlox*>( res ); + mRes = resource; + + if ( !resource ) { + kdDebug(5700) << "ResourceSloxConfig::loadSettings(): cast failed" << endl; + return; + } + + if ( mRes->resType() == "slox" ) + mFolderButton->setEnabled( false ); // TODO folder selection for SLOX + + mURL->setURL( resource->prefs()->url() ); + mUser->setText( resource->prefs()->user() ); + mPassword->setText( resource->prefs()->password() ); + mLastSyncCheck->setChecked( resource->prefs()->useLastSync() ); + mFolderId = resource->prefs()->folderId(); +} + +void ResourceSloxConfig::saveSettings( KRES::Resource *res ) +{ + ResourceSlox *resource = dynamic_cast<ResourceSlox*>( res ); + + if ( !resource ) { + kdDebug(5700) << "ResourceSloxConfig::saveSettings(): cast failed" << endl; + return; + } + + resource->prefs()->setUrl( mURL->url() ); + resource->prefs()->setUser( mUser->text() ); + resource->prefs()->setPassword( mPassword->text() ); + resource->prefs()->setUseLastSync( mLastSyncCheck->isChecked() ); + resource->prefs()->setFolderId( mFolderId ); +} + +void KABC::ResourceSloxConfig::selectAddressFolder( ) +{ + SloxFolderManager *manager = new SloxFolderManager( mRes, mURL->url() ); + SloxFolderDialog *dialog = new SloxFolderDialog( manager, Contacts, this ); + dialog->setSelectedFolder( mFolderId ); + if ( dialog->exec() == QDialog::Accepted ) + mFolderId = dialog->selectedFolder(); +} + +#include "kabcresourcesloxconfig.moc" diff --git a/kresources/slox/kabcresourcesloxconfig.h b/kresources/slox/kabcresourcesloxconfig.h new file mode 100644 index 000000000..b55282a85 --- /dev/null +++ b/kresources/slox/kabcresourcesloxconfig.h @@ -0,0 +1,61 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef RESOURCESLOXCONFIG_H +#define RESOURCESLOXCONFIG_H + +#include <kresources/configwidget.h> +#include <kdepimmacros.h> + +class QCheckBox; +class KLineEdit; +class KURLRequester; +class KPushButton; + +class SloxBase; + +namespace KABC { + +class KDE_EXPORT ResourceSloxConfig : public KRES::ConfigWidget +{ + Q_OBJECT + + public: + ResourceSloxConfig( QWidget* parent = 0, const char* name = 0 ); + + public slots: + void loadSettings( KRES::Resource* ); + void saveSettings( KRES::Resource* ); + + private slots: + void selectAddressFolder(); + + private: + KURLRequester *mURL; + KLineEdit *mUser; + KLineEdit *mPassword; + QCheckBox *mLastSyncCheck; + KPushButton *mFolderButton; + QString mFolderId; + SloxBase *mRes; +}; + +} + +#endif diff --git a/kresources/slox/kabcsloxprefs.kcfgc b/kresources/slox/kabcsloxprefs.kcfgc new file mode 100644 index 000000000..50c7cbbb8 --- /dev/null +++ b/kresources/slox/kabcsloxprefs.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=kresources_kabc_slox.kcfg +ClassName=SloxPrefs +NameSpace=KABC +Singleton=false +Mutators=true +Inherits=KResourcePrefs +IncludeFiles=libkdepim/kresourceprefs.h +GlobalEnums=true +#ItemAccessors=true +#SetUserTexts=true diff --git a/kresources/slox/kcal_ox.desktop b/kresources/slox/kcal_ox.desktop new file mode 100644 index 000000000..e0eaa9224 --- /dev/null +++ b/kresources/slox/kcal_ox.desktop @@ -0,0 +1,47 @@ +[Desktop Entry] +Name=OpenXchange Server +Name[af]=OpenXchange bediener +Name[bg]=Сървър OpenXchange +Name[br]=Servijer OpenXchange +Name[ca]=Servidor OpenXchange +Name[da]=Openxchange-server +Name[el]=Εξυπηρετητής OpenXchange +Name[es]=Servidor OpenXchange +Name[et]=OpenXchange server +Name[eu]=OpenXchange zerbitzaria +Name[fa]=کارساز OpenXchange +Name[fi]=OpenXchange-palvelin +Name[fr]=Serveur OpenXchange +Name[fy]=OpenXchange-tsjinner +Name[ga]=Freastalaí Openexchange +Name[gl]=Servidor OpenXchange +Name[hu]=OpenXchange-kiszolgáló +Name[is]=OpenXchange þjónn +Name[ja]=OpenXchange サーバ +Name[ka]=Openexchange სერვერი +Name[kk]=OpenXchange сервері +Name[km]=ម៉ាស៊ីនបម្រើ OpenXchange +Name[lt]=OpenXchange serveris +Name[mk]=OpenXchange-сервер +Name[nb]=OpenExchange-tjener +Name[nds]=OpenXchange-Server +Name[ne]=ओपन एक्सचेन्ज सर्भर +Name[nl]=OpenXchange-server +Name[nn]=OpenXchange-tenar +Name[pl]=Server OpenXchange +Name[pt]=Servidor OpenXchange +Name[pt_BR]=Servidor OpenXchange +Name[ru]=Сервер OpenXchange +Name[sl]=Strežnik OpenXchange +Name[sr]=Openexchange сервер +Name[sr@Latn]=Openexchange server +Name[sv]=Openxchange-server +Name[tr]=OpenXchange Sunucusu +Name[uk]=Сервер OpenXchange +Name[zh_CN]=OpenXchange 服务器 +Name[zh_TW]=OpenXchange 伺服器 +X-KDE-Library=kcal_slox +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=calendar +X-KDE-ResourceType=ox diff --git a/kresources/slox/kcal_slox.desktop b/kresources/slox/kcal_slox.desktop new file mode 100644 index 000000000..0daca0b2c --- /dev/null +++ b/kresources/slox/kcal_slox.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=SUSE LINUX Openexchange Server +Name[af]=SuSE Linux OpenExchange bediener +Name[bg]=Сървър SUSE LINUX Openexchange +Name[br]=Servijer Openexchange SUSE LINUX +Name[ca]=Servidor SUSE LINUX Openexchange +Name[cs]=SUSE LINUX Openexchange server +Name[da]=SUSE Linux Openexchange-server +Name[de]=SUSE LINUX Openexchange-Server +Name[el]=Εξυπηρετητή SUSE LINUX Openexchange +Name[es]=Servidor Openexchange de SUSE LINUX +Name[et]=SUSE LINUX Openexchange server +Name[eu]=SUSE LINUX Openexchange zerbitzaria +Name[fa]=کارساز SUSE LINUX Openexchange +Name[fi]=Suse Linux Openexchange -palvelin +Name[fr]=Serveur SUSE Linux Openexchange +Name[fy]=SUSE LINUX Openexchange-tsjinner +Name[ga]=Freastalaí Openexchange SUSE LINUX +Name[gl]=Servidor SUSE LINUX Openexchange +Name[hu]=SUSE LINUX Openexchange-kiszolgáló +Name[is]=SUSE LINUX Openexchange þjónn +Name[it]=Server SUSE LINUX Openexchange +Name[ja]=SUSE LINUX Openexchange サーバ +Name[ka]= SUSE LINUX Openexchange სერვერი +Name[kk]=SUSE LINUX Openexchange сервері +Name[km]=ម៉ាស៊ីនបម្រើ Openexchange របស់ស៊ូស៊ីលីនីក +Name[lt]=SUSE LINUX Openexchange serveris +Name[mk]=SUSE LINUX Openexchange-сервер +Name[ms]=Pelayan SUSE LINUX Openexchange +Name[nb]=SUSE LINUX Openexchange-tjener +Name[nds]=SUSE-Openexchangeserver +Name[ne]=SUSE LINUX ओपन एक्सचेन्ज सर्भर +Name[nl]=SUSE LINUX Openexchange-server +Name[nn]=SUSE LINUX Openexchange-tenar +Name[pl]=Server SUSE LINUX Openexchange +Name[pt]=Servidor SUSE LINUX Openexchange +Name[pt_BR]=Servidor OpenExchange do SUSE Linux (SLOX) +Name[ru]=Сервер SUSE LINUX Openexchange +Name[sl]=Strežnik SUSE LINUX Openexchange +Name[sr]=Openexchange сервер SUSE-овог Linux-а +Name[sr@Latn]=Openexchange server SUSE-ovog Linux-a +Name[sv]=SUSE Linux Openexchange-server +Name[ta]=SUSE LINUX திறந்த பரிமாற்ற சேவகன் +Name[tr]=SUSE LINUX Openexchange Sunucusu +Name[uk]=Сервер SUSE LINUX Openexchange +Name[zh_CN]=SUSE LINUX Openexchange 服务器 +Name[zh_TW]=SUSE LINUX Openexchange 伺服器 +X-KDE-Library=kcal_slox +Type=Service +ServiceTypes=KResources/Plugin +X-KDE-ResourceFamily=calendar +X-KDE-ResourceType=slox diff --git a/kresources/slox/kcalresourceslox.cpp b/kresources/slox/kcalresourceslox.cpp new file mode 100644 index 000000000..d446494f6 --- /dev/null +++ b/kresources/slox/kcalresourceslox.cpp @@ -0,0 +1,1326 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2005 Volker Krause <volker.krause@rwth-aachen.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <typeinfo> +#include <stdlib.h> + +#include <qdatetime.h> +#include <qstring.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qregexp.h> + +#include <kdebug.h> +#include <kurl.h> +#include <kio/job.h> +#include <kio/davjob.h> +#include <klocale.h> +#include <kstandarddirs.h> + +#include <libkdepim/progressmanager.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/confirmsavedialog.h> + +#include <kabc/locknull.h> +#include <kabc/stdaddressbook.h> + +#include <kresources/configwidget.h> + +#include "webdavhandler.h" +#include "kcalsloxprefs.h" +#include "sloxaccounts.h" + +#include "kcalresourceslox.h" + +using namespace KCal; + +KCalResourceSlox::KCalResourceSlox( const KConfig *config ) + : ResourceCached( config ), SloxBase( this ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + if ( config ) { + readConfig( config ); + } +} + +KCalResourceSlox::KCalResourceSlox( const KURL &url ) + : ResourceCached( 0 ), SloxBase( this ) +{ + init(); + + mPrefs->addGroupPrefix( identifier() ); + + mPrefs->setUrl( url.url() ); +} + +KCalResourceSlox::~KCalResourceSlox() +{ + kdDebug() << "~KCalResourceSlox()" << endl; + + disableChangeNotification(); + + close(); + + if ( mLoadEventsJob ) mLoadEventsJob->kill(); + if ( mLoadTodosJob ) mLoadTodosJob->kill(); + if ( mUploadJob ) mUploadJob->kill(); + + delete mLock; + + kdDebug() << "~KCalResourceSlox() done" << endl; +} + +void KCalResourceSlox::init() +{ + mPrefs = new SloxPrefs; + mWebdavHandler.setResource( this ); + + mLoadEventsJob = 0; + mLoadTodosJob = 0; + + mUploadJob = 0; + + mLoadEventsProgress = 0; + mLoadTodosProgress = 0; + + mAccounts = 0; + + mLock = new KABC::LockNull( true ); + + enableChangeNotification(); +} + +void KCalResourceSlox::readConfig( const KConfig *config ) +{ + mPrefs->readConfig(); + + mWebdavHandler.setUserId( mPrefs->user() ); + + ResourceCached::readConfig( config ); + + KURL url = mPrefs->url(); + url.setUser( mPrefs->user() ); + url.setPass( mPrefs->password() ); + + delete mAccounts; + mAccounts = new SloxAccounts( this, url ); +} + +void KCalResourceSlox::writeConfig( KConfig *config ) +{ + kdDebug() << "KCalResourceSlox::writeConfig()" << endl; + + ResourceCalendar::writeConfig( config ); + + mPrefs->writeConfig(); + + ResourceCached::writeConfig( config ); +} + +bool KCalResourceSlox::doLoad() +{ + kdDebug() << "KCalResourceSlox::load() " << long( this ) << endl; + + if ( mLoadEventsJob || mLoadTodosJob ) { + kdDebug() << "KCalResourceSlox::load(): download still in progress." + << endl; + return true; + } + if ( mUploadJob ) { + kdWarning() << "KCalResourceSlox::load(): upload still in progress." + << endl; + loadError( "Upload still in progress." ); + return false; + } + + mCalendar.close(); + + disableChangeNotification(); + loadCache(); + enableChangeNotification(); + + emit resourceChanged( this ); + + clearChanges(); + + QString p = KURL( mPrefs->url() ).protocol(); + if ( p != "http" && p != "https" && p != "webdav" && p != "webdavs" ) { + QString err = i18n("Non-http protocol: '%1'").arg( p ); + kdDebug() << "KCalResourceSlox::load(): " << err << endl; + loadError( err ); + return false; + } + + // The SLOX contacts are loaded asynchronously, so make sure that they are + // actually loaded. + KABC::StdAddressBook::self( true )->asyncLoad(); + +#if 1 + requestEvents(); +#endif + requestTodos(); + + return true; +} + +void KCalResourceSlox::requestEvents() +{ + KURL url = mPrefs->url(); + url.setPath( "/servlet/webdav.calendar/" ); + url.setUser( mPrefs->user() ); + url.setPass( mPrefs->password() ); + + kdDebug() << "KCalResourceSlox::requestEvents(): " << url << endl; + + QString lastsync = "0"; + if ( mPrefs->useLastSync() ) { + QDateTime dt = mPrefs->lastEventSync(); + if ( dt.isValid() ) { + lastsync = WebdavHandler::qDateTimeToSlox( dt.addDays( -1 ) ); + } + } + + QDomDocument doc; + QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" ); + QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( LastSync ), lastsync ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( FolderId ), mPrefs->calendarFolderId() ); + if ( type() == "ox" ) { + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "NEW_AND_MODIFIED" ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "DELETED" ); + } else + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "all" ); + + kdDebug() << "REQUEST CALENDAR: \n" << doc.toString( 2 ) << endl; + + mLoadEventsJob = KIO::davPropFind( url, doc, "0", false ); + connect( mLoadEventsJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotLoadEventsResult( KIO::Job * ) ) ); + connect( mLoadEventsJob, SIGNAL( percent( KIO::Job *, unsigned long ) ), + SLOT( slotEventsProgress( KIO::Job *, unsigned long ) ) ); + + mLoadEventsProgress = KPIM::ProgressManager::instance()->createProgressItem( + KPIM::ProgressManager::getUniqueID(), i18n("Downloading events") ); + connect( mLoadEventsProgress, + SIGNAL( progressItemCanceled( KPIM::ProgressItem * ) ), + SLOT( cancelLoadEvents() ) ); + + mPrefs->setLastEventSync( QDateTime::currentDateTime() ); +} + +void KCalResourceSlox::requestTodos() +{ + KURL url = mPrefs->url(); + url.setPath( "/servlet/webdav.tasks/" ); + url.setUser( mPrefs->user() ); + url.setPass( mPrefs->password() ); + + kdDebug() << "KCalResourceSlox::requestTodos(): " << url << endl; + + QString lastsync = "0"; + if ( mPrefs->useLastSync() ) { + QDateTime dt = mPrefs->lastTodoSync(); + if ( dt.isValid() ) { + lastsync = WebdavHandler::qDateTimeToSlox( dt.addDays( -1 ) ); + } + } + + QDomDocument doc; + QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" ); + QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( LastSync ), lastsync ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( FolderId ), mPrefs->taskFolderId() ); + if ( type() == "ox" ) { + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "NEW_AND_MODIFIED" ); + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "DELETED" ); + } else + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectType ), "all" ); + + kdDebug() << "REQUEST TASKS: \n" << doc.toString( 2 ) << endl; + + mLoadTodosJob = KIO::davPropFind( url, doc, "0", false ); + connect( mLoadTodosJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotLoadTodosResult( KIO::Job * ) ) ); + connect( mLoadTodosJob, SIGNAL( percent( KIO::Job *, unsigned long ) ), + SLOT( slotTodosProgress( KIO::Job *, unsigned long ) ) ); + + mLoadTodosProgress = KPIM::ProgressManager::instance()->createProgressItem( + KPIM::ProgressManager::getUniqueID(), i18n("Downloading to-dos") ); + connect( mLoadTodosProgress, + SIGNAL( progressItemCanceled( KPIM::ProgressItem * ) ), + SLOT( cancelLoadTodos() ) ); + + mPrefs->setLastTodoSync( QDateTime::currentDateTime() ); +} + +void KCalResourceSlox::uploadIncidences() +{ + QDomDocument doc; + QDomElement ms = WebdavHandler::addDavElement( doc, doc, "multistatus" ); + QDomElement pu = WebdavHandler::addDavElement( doc, ms, "propertyupdate" ); + QDomElement set = WebdavHandler::addElement( doc, pu, "D:set" ); + QDomElement prop = WebdavHandler::addElement( doc, set, "D:prop" ); + + mUploadIsDelete = false; + Incidence::List added = addedIncidences(); + Incidence::List changed = changedIncidences(); + Incidence::List deleted = deletedIncidences(); + if ( !added.isEmpty() ) { + mUploadedIncidence = added.first(); + } else if ( !changed.isEmpty() ) { + mUploadedIncidence = changed.first(); + } else if ( !deleted.isEmpty() ) { + mUploadedIncidence = deleted.first(); + mUploadIsDelete = true; + } else { + mUploadedIncidence = 0; + kdDebug() << "uploadIncidences(): FINISHED" << endl; + emit resourceSaved( this ); + return; + } + + // Don't try to upload recurring incidences as long as the resource doesn't + // correctly write them in order to avoid corrupting data on the server. + // FIXME: Remove when recurrences are correctly written. + if ( mUploadedIncidence->doesRecur() && type() == "slox" ) { + clearChange( mUploadedIncidence ); + uploadIncidences(); + return; + } + + KURL url = mPrefs->url(); + + QString sloxId = mUploadedIncidence->customProperty( "SLOX", "ID" ); + if ( !sloxId.isEmpty() ) { + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectId ), sloxId ); + } else { + if ( mUploadIsDelete ) { + kdError() << "Incidence to delete doesn't have a SLOX id" << endl; + clearChange( mUploadedIncidence ); + uploadIncidences(); + return; + } + } + WebdavHandler::addSloxElement( this, doc, prop, fieldName( ClientId ), + mUploadedIncidence->uid() ); + + if ( mUploadIsDelete ) { + if ( mUploadedIncidence->type() == "Event" ) { + url.setPath( "/servlet/webdav.calendar/" + sloxId ); + } else if ( mUploadedIncidence->type() == "Todo" ) { + url.setPath( "/servlet/webdav.tasks/" + sloxId ); + } else { + kdWarning() << "uploadIncidences(): Unsupported incidence type: " + << mUploadedIncidence->type() << endl; + return; + } + + if ( type() == "ox" ) { + WebdavHandler::addSloxElement( this, doc, prop, "method", "DELETE" ); + } else { + QDomElement remove = WebdavHandler::addElement( doc, pu, "D:remove" ); + QDomElement prop = WebdavHandler::addElement( doc, remove, "D:prop" ); + WebdavHandler::addSloxElement( this, doc, prop, "sloxid", sloxId ); + } + } else { + createIncidenceAttributes( doc, prop, mUploadedIncidence ); + // FIXME: Use a visitor + if ( mUploadedIncidence->type() == "Event" ) { + url.setPath( "/servlet/webdav.calendar/file.xml" ); + createEventAttributes( doc, prop, static_cast<Event *>( mUploadedIncidence ) ); + // TODO: OX supports recurrences also for tasks + createRecurrenceAttributes( doc, prop, mUploadedIncidence ); + } else if ( mUploadedIncidence->type() == "Todo" ) { + url.setPath( "/servlet/webdav.tasks/file.xml" ); + createTodoAttributes( doc, prop, static_cast<Todo *>( mUploadedIncidence ) ); + } else { + kdWarning() << "uploadIncidences(): Unsupported incidence type: " + << mUploadedIncidence->type() << endl; + return; + } + } + + url.setUser( mPrefs->user() ); + url.setPass( mPrefs->password() ); + + kdDebug() << "KCalResourceSlox::uploadIncidences(): " << url << endl; + + kdDebug() << "UPLOAD: \n" << doc.toString( 2 ) << endl; + + mUploadJob = KIO::davPropPatch( url, doc, false ); + connect( mUploadJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotUploadResult( KIO::Job * ) ) ); + connect( mUploadJob, SIGNAL( percent( KIO::Job *, unsigned long ) ), + SLOT( slotUploadProgress( KIO::Job *, unsigned long ) ) ); + + mUploadProgress = KPIM::ProgressManager::instance()->createProgressItem( + KPIM::ProgressManager::getUniqueID(), i18n("Uploading incidence") ); + connect( mUploadProgress, + SIGNAL( progressItemCanceled( KPIM::ProgressItem * ) ), + SLOT( cancelUpload() ) ); +} + +void KCalResourceSlox::createIncidenceAttributes( QDomDocument &doc, + QDomElement &parent, + Incidence *incidence ) +{ + WebdavHandler::addSloxElement( this, doc, parent, fieldName( IncidenceTitle ), + incidence->summary() ); + + WebdavHandler::addSloxElement( this, doc, parent, fieldName( Description ), + incidence->description() ); + + if ( incidence->attendeeCount() > 0 ) { + QDomElement members = WebdavHandler::addSloxElement( this, doc, parent, + fieldName( Participants ) ); + Attendee::List attendees = incidence->attendees(); + Attendee::List::ConstIterator it; + for( it = attendees.begin(); it != attendees.end(); ++it ) { + if ( mAccounts ) { + QString userId = mAccounts->lookupId( (*it)->email() ); + QString status; + switch ( (*it)->status() ) { + case Attendee::Accepted: status = "accept"; break; + case Attendee::Declined: status = "decline"; break; + default: status = "none"; break; + } + QDomElement el = WebdavHandler::addSloxElement( this, doc, members, fieldName( Participant ), userId ); + el.setAttribute( "confirm", status ); + } else { + kdError() << "KCalResourceSlox: No accounts set." << endl; + } + } + } + + // set read attributes - if SecrecyPublic, set it to users + // TODO OX support + if ( incidence->secrecy() == Incidence::SecrecyPublic && type() != "ox" ) + { + QDomElement rights = WebdavHandler::addSloxElement( this, doc, parent, "readrights" ); + WebdavHandler::addSloxElement( this, doc, rights, "group", "users" ); + } + + // set reminder as the number of minutes to the start of the event + KCal::Alarm::List alarms = incidence->alarms(); + if ( !alarms.isEmpty() && alarms.first()->hasStartOffset() && alarms.first()->enabled() ) + WebdavHandler::addSloxElement( this, doc, parent, fieldName( Reminder ), + QString::number( (-1) * alarms.first()->startOffset().asSeconds() / 60 ) ); + else + WebdavHandler::addSloxElement( this, doc, parent, fieldName( Reminder ), "0" ); + + // categories + WebdavHandler::addSloxElement( this, doc, parent, fieldName( Categories ), incidence->categories().join( ", " ) ); +} + +void KCalResourceSlox::createEventAttributes( QDomDocument &doc, + QDomElement &parent, + Event *event ) +{ + QString folderId = mPrefs->calendarFolderId(); + if ( folderId.isEmpty() && type() == "ox" ) // SLOX and OX use diffrent default folders + folderId = "-1"; + WebdavHandler::addSloxElement( this, doc, parent, fieldName( FolderId ), folderId ); + + WebdavHandler::addSloxElement( this, doc, parent, fieldName( EventBegin ), + WebdavHandler::qDateTimeToSlox( event->dtStart(), timeZoneId() ) ); + + WebdavHandler::addSloxElement( this, doc, parent, fieldName( EventEnd ), + WebdavHandler::qDateTimeToSlox( event->dtEnd(), timeZoneId() ) ); + + WebdavHandler::addSloxElement( this, doc, parent, fieldName( Location ), event->location() ); + + if ( event->doesFloat() ) { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( FullTime ), boolToStr( true ) ); + } else { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( FullTime ), boolToStr( false ) ); + } +} + +void KCalResourceSlox::createTodoAttributes( QDomDocument &doc, + QDomElement &parent, + Todo *todo ) +{ + QString folderId = mPrefs->taskFolderId(); + if ( folderId.isEmpty() && type() == "ox" ) // SLOX and OX use diffrent default folders + folderId = "-1"; + WebdavHandler::addSloxElement( this, doc, parent, fieldName( FolderId ), folderId ); + + if ( todo->hasStartDate() ) { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( TaskBegin ), + WebdavHandler::qDateTimeToSlox( todo->dtStart(), timeZoneId() ) ); + } + + if ( todo->hasDueDate() ) { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( TaskEnd ), + WebdavHandler::qDateTimeToSlox( todo->dtDue(), timeZoneId() ) ); + } + + int priority = todo->priority(); + QString txt; + switch ( priority ) { + case 9: + case 8: + txt = "1"; + break; + case 2: + case 1: + txt = "3"; + break; + default: + txt = "2"; + break; + } + WebdavHandler::addSloxElement( this, doc, parent, fieldName( Priority ), txt ); + + WebdavHandler::addSloxElement( this, doc, parent, fieldName( PercentComplete ), + QString::number( todo->percentComplete() ) ); +} + +void KCalResourceSlox::createRecurrenceAttributes( QDomDocument &doc, + QDomElement &parent, + KCal::Incidence *incidence ) +{ + if ( !incidence->doesRecur() ) { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), + type() == "ox" ? "none" : "no" ); + return; + } + Recurrence *r = incidence->recurrence(); + int monthOffset = ( type() == "ox" ? -1 : 0 ); + switch ( r->recurrenceType() ) { + case Recurrence::rDaily: + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "daily" ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceDailyFreq ), + QString::number( r->frequency() ) ); + break; + case Recurrence::rWeekly: { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "weekly" ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceWeeklyFreq ), + QString::number( r->frequency() ) ); + // TODO: SLOX support + int oxDays = 0; + for ( int i = 0; i < 7; ++i ) { + if ( r->days()[i] ) + oxDays += 1 << ( ( i + 1 ) % 7 ); + } + if ( type() == "ox" ) + WebdavHandler::addSloxElement( this, doc, parent, "days", QString::number( oxDays ) ); + break; } + case Recurrence::rMonthlyDay: + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "monthly" ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthlyFreq ), + QString::number( r->frequency() ) ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthlyDay ), + QString::number( r->monthDays().first() ) ); + break; + case Recurrence::rMonthlyPos: { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), + type() == "ox" ? "monthly" : "monthly2" ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthly2Freq ), + QString::number( r->frequency() ) ); + RecurrenceRule::WDayPos wdp = r->monthPositions().first(); + // TODO: SLOX support + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthly2Day ), + QString::number( 1 << wdp.day() ) ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthly2Pos ), + QString::number( wdp.pos() ) ); + break; } + case Recurrence::rYearlyMonth: + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "yearly" ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearlyDay ), + QString::number( r->yearDates().first() ) ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearlyMonth ), + QString::number( r->yearMonths().first() + monthOffset ) ); + if ( type() == "ox" ) + WebdavHandler::addSloxElement( this, doc, parent, "interval", "1" ); + break; + case Recurrence::rYearlyPos: { + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), + type() == "ox" ? "yearly" : "yearly2" ); + RecurrenceRule::WDayPos wdp = r->monthPositions().first(); + // TODO: SLOX support + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearly2Day ), + QString::number( 1 << wdp.day() ) ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearly2Pos ), + QString::number( wdp.pos() ) ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearly2Month ), + QString::number( r->yearMonths().first() + monthOffset ) ); + if ( type() == "ox" ) + WebdavHandler::addSloxElement( this, doc, parent, "interval", "1" ); + break; } + default: + kdDebug() << k_funcinfo << "unsupported recurrence type: " << r->recurrenceType() << endl; + } + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceEnd ), + WebdavHandler::qDateTimeToSlox( r->endDateTime() ) ); + // delete exceptions + DateList exlist = r->exDates(); + QStringList res; + for ( DateList::Iterator it = exlist.begin(); it != exlist.end(); ++it ) + res.append( WebdavHandler::qDateTimeToSlox( *it ) ); + WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceDelEx ), res.join( "," ) ); +} + +void KCalResourceSlox::parseMembersAttribute( const QDomElement &e, + Incidence *incidence ) +{ + incidence->clearAttendees(); + + QDomNode n; + for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement memberElement = n.toElement(); + if ( memberElement.tagName() == fieldName( Participant ) ) { + QString member = memberElement.text(); + KABC::Addressee account; + if ( mAccounts ) account = mAccounts->lookupUser( member ); + else kdError() << "KCalResourceSlox: no accounts set" << endl; + QString name; + QString email; + Attendee *a = incidence->attendeeByUid( member ); + if ( account.isEmpty() ) { + if ( a ) continue; + + name = member; + email = member + "@" + KURL( mPrefs->url() ).host(); + } else { + name = account.realName(); + email = account.preferredEmail(); + } + if ( a ) { + a->setName( name ); + a->setEmail( email ); + } else { + a = new Attendee( name, email ); + a->setUid( member ); + incidence->addAttendee( a ); + } + QString status = memberElement.attribute( "confirm" ); + if ( !status.isEmpty() ) { + if ( status == "accept" ) { + a->setStatus( Attendee::Accepted ); + } else if ( status == "decline" ) { + a->setStatus( Attendee::Declined ); + } else { + a->setStatus( Attendee::NeedsAction ); + } + } + } else { + kdDebug() << "Unknown tag in members attribute: " + << memberElement.tagName() << endl; + } + } +} + +void KCalResourceSlox::parseReadRightsAttribute( const QDomElement &e, + Incidence *incidence ) +{ + QDomNode n; + for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement rightElement = n.toElement(); + if ( rightElement.tagName() == "group" ) { + QString groupName = rightElement.text(); + if ( groupName == "users" ) + incidence->setSecrecy( Incidence::SecrecyPublic ); + } + } +} + +void KCalResourceSlox::parseIncidenceAttribute( const QDomElement &e, + Incidence *incidence ) +{ + QString tag = e.tagName(); + QString text = decodeText( e.text() ); + if ( text.isEmpty() ) return; + + if ( tag == fieldName( IncidenceTitle ) ) { + incidence->setSummary( text ); + } else if ( e.tagName() == fieldName( Description ) ) { + incidence->setDescription( text ); + } else if ( tag == fieldName( Reminder ) ) { + int minutes = text.toInt(); + if ( minutes != 0 ) { + Alarm::List alarms = incidence->alarms(); + Alarm *alarm; + if ( alarms.isEmpty() ) alarm = incidence->newAlarm(); + else alarm = alarms.first(); + if ( alarm->type() == Alarm::Invalid ) { + alarm->setType( Alarm::Display ); + } + Duration d( minutes * -60 ); + alarm->setStartOffset( d ); + alarm->setEnabled( true ); + } else { + // 0 reminder -> disable alarm + incidence->clearAlarms(); + } + } else if ( tag == fieldName( CreatedBy ) ) { + KABC::Addressee a; + if ( mAccounts ) a = mAccounts->lookupUser( text ); + else kdDebug() << "KCalResourceSlox: no accounts set" << endl; + incidence->setOrganizer( Person( a.formattedName(), a.preferredEmail() ) ); + } else if ( tag == fieldName( Participants ) ) { + parseMembersAttribute( e, incidence ); + } else if ( tag == "readrights" ) { + parseReadRightsAttribute( e, incidence ); + } else if ( tag == fieldName( Categories ) ) { + incidence->setCategories( QStringList::split( QRegExp(",\\s*"), text ) ); + } +} + +void KCalResourceSlox::parseEventAttribute( const QDomElement &e, + Event *event ) +{ + QString tag = e.tagName(); + QString text = decodeText( e.text() ); + if ( text.isEmpty() ) return; + + if ( tag == fieldName( EventBegin ) ) { + QDateTime dt; + if ( event->doesFloat() ) { + if ( type() == "ox" ) + dt = WebdavHandler::sloxToQDateTime( text, timeZoneId() ); + else + dt = WebdavHandler::sloxToQDateTime( text ); // ### is this really correct for SLOX? + } else + dt = WebdavHandler::sloxToQDateTime( text, timeZoneId() ); + event->setDtStart( dt ); + } else if ( tag == fieldName( EventEnd ) ) { + QDateTime dt; + if ( event->doesFloat() ) { + dt = WebdavHandler::sloxToQDateTime( text ); + dt = dt.addSecs( -1 ); + } + else dt = WebdavHandler::sloxToQDateTime( text, timeZoneId() ); + event->setDtEnd( dt ); + } else if ( tag == fieldName( Location ) ) { + event->setLocation( text ); + } +} + +void KCalResourceSlox::parseRecurrence( const QDomNode &node, Event *event ) +{ + QString type; + + int dailyValue = -1; + QDateTime end; + + int weeklyValue = -1; + QBitArray days( 7 ); // days, starting with monday + bool daysSet = false; + + int monthlyValueDay = -1; + int monthlyValueMonth = -1; + + int yearlyValueDay = -1; + int yearlyMonth = -1; + + int monthly2Recurrency = 0; + int monthly2Day = 0; + int monthly2ValueMonth = -1; + + int yearly2Recurrency = 0; + int yearly2Day = 0; + int yearly2Month = -1; + + DateList deleteExceptions; + + QDomNode n; + + for( n = node.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e = n.toElement(); + QString tag = e.tagName(); + QString text = decodeText( e.text() ); + kdDebug() << k_funcinfo << tag << ": " << text << endl; + + if ( tag == fieldName( RecurrenceType ) ) { + type = text; + } else if ( tag == "daily_value" ) { + dailyValue = text.toInt(); + } else if ( tag == fieldName( RecurrenceEnd ) ) { + end = WebdavHandler::sloxToQDateTime( text ); + } else if ( tag == "weekly_value" ) { + weeklyValue = text.toInt(); + } else if ( tag.left( 11 ) == "weekly_day_" ) { + int day = tag.mid( 11, 1 ).toInt(); + int index; + if ( day == 1 ) index = 0; + else index = day - 2; + days.setBit( index ); + } else if ( tag == "monthly_value_day" ) { + monthlyValueDay = text.toInt(); + } else if ( tag == "monthly_value_month" ) { + monthlyValueMonth = text.toInt(); + } else if ( tag == "yearly_value_day" ) { + yearlyValueDay = text.toInt(); + } else if ( tag == "yearly_month" ) { + yearlyMonth = text.toInt(); + } else if ( tag == "monthly2_recurrency" ) { + monthly2Recurrency = text.toInt(); + } else if ( tag == "monthly2_day" ) { + monthly2Day = text.toInt(); + } else if ( tag == "monthly2_value_month" ) { + monthly2ValueMonth = text.toInt(); + } else if ( tag == "yearly2_reccurency" ) { // this is not a typo, this is what SLOX really sends! + yearly2Recurrency = text.toInt(); + } else if ( tag == "yearly2_day" ) { + yearly2Day = text.toInt(); + } else if ( tag == "yearly2_month" ) { + yearly2Month = text.toInt() + 1; + // OX recurrence fields + } else if ( tag == "interval" ) { + dailyValue = text.toInt(); + weeklyValue = text.toInt(); + monthlyValueMonth = text.toInt(); + monthly2ValueMonth = text.toInt(); + } else if ( tag == "days" ) { + int tmp = text.toInt(); // OX encodes days binary: 1=Su, 2=Mo, 4=Tu, ... + for ( int i = 0; i < 7; ++i ) { + if ( tmp & (1 << i) ) + days.setBit( (i + 6) % 7 ); + } + daysSet = true; + } else if ( tag == "day_in_month" ) { + monthlyValueDay = text.toInt(); + monthly2Recurrency = text.toInt(); + yearlyValueDay = text.toInt(); + yearly2Recurrency = text.toInt(); + } else if ( tag == "month" ) { + yearlyMonth = text.toInt() + 1; // starts at 0 + yearly2Month = text.toInt() + 1; + } else if ( tag == fieldName( RecurrenceDelEx ) ) { + QStringList exdates = QStringList::split( ",", text ); + QStringList::Iterator it; + for ( it = exdates.begin(); it != exdates.end(); ++it ) + deleteExceptions.append( WebdavHandler::sloxToQDateTime( *it ).date() ); + } + } + + if ( daysSet && type == "monthly" ) + type = "monthly2"; // HACK: OX doesn't cleanly distinguish between monthly and monthly2 + if ( daysSet && type == "yearly" ) + type = "yearly2"; + + Recurrence *r = event->recurrence(); + + if ( type == "daily" ) { + r->setDaily( dailyValue ); + } else if ( type == "weekly" ) { + r->setWeekly( weeklyValue, days ); + } else if ( type == "monthly" ) { + r->setMonthly( monthlyValueMonth ); + r->addMonthlyDate( monthlyValueDay ); + } else if ( type == "yearly" ) { + r->setYearly( 1 ); + r->addYearlyDate( yearlyValueDay ); + r->addYearlyMonth( yearlyMonth ); + } else if ( type == "monthly2" ) { + r->setMonthly( monthly2ValueMonth ); + QBitArray _days( 7 ); + if ( daysSet ) + _days = days; + else + _days.setBit( event->dtStart().date().dayOfWeek() ); + r->addMonthlyPos( monthly2Recurrency, _days ); + } else if ( type == "yearly2" ) { + r->setYearly( 1 ); + r->addYearlyMonth( yearly2Month ); + QBitArray _days( 7 ); + if ( daysSet ) + _days = days; + else + _days.setBit( ( yearly2Day + 5 ) % 7 ); + r->addYearlyPos( yearly2Recurrency, _days ); + } + r->setEndDate( end.date() ); + r->setExDates( deleteExceptions ); +} + +void KCalResourceSlox::parseTodoAttribute( const QDomElement &e, + Todo *todo ) +{ + QString tag = e.tagName(); + QString text = decodeText( e.text() ); + if ( text.isEmpty() ) return; + + if ( tag == fieldName( TaskBegin ) ) { + QDateTime dt = WebdavHandler::sloxToQDateTime( text ); + if ( dt.isValid() ) { + todo->setDtStart( dt ); + todo->setHasStartDate( true ); + } + } else if ( tag == fieldName( TaskEnd ) ) { + QDateTime dt = WebdavHandler::sloxToQDateTime( text ); + if ( dt.isValid() ) { + todo->setDtDue( dt ); + todo->setHasDueDate( true ); + } + } else if ( tag == fieldName( Priority ) ) { + int p = text.toInt(); + if ( p < 1 || p > 3 ) { + kdError() << "Unknown priority: " << text << endl; + } else { + int priority; + switch ( p ) { + case 1: + priority = 9; + break; + default: + case 2: + priority = 5; + break; + case 3: + priority = 1; + break; + } + todo->setPriority( priority ); + } + } else if ( tag == fieldName( PercentComplete ) ) { + int completed = text.toInt(); + todo->setPercentComplete( completed ); + } +} + +void KCalResourceSlox::slotLoadTodosResult( KIO::Job *job ) +{ + kdDebug() << "KCalResourceSlox::slotLoadTodosJobResult()" << endl; + + if ( job->error() ) { + loadError( job->errorString() ); + } else { + kdDebug() << "KCalResourceSlox::slotLoadTodosJobResult() success" << endl; + + QDomDocument doc = mLoadTodosJob->response(); + + mWebdavHandler.log( doc.toString( 2 ) ); + + QValueList<SloxItem> items = WebdavHandler::getSloxItems( this, doc ); + + bool changed = false; + + disableChangeNotification(); + + QValueList<SloxItem>::ConstIterator it; + for( it = items.begin(); it != items.end(); ++it ) { + SloxItem item = *it; + QString uid = sloxIdToTodoUid( item.sloxId ); + if ( item.status == SloxItem::Delete ) { + Todo *todo = mCalendar.todo( uid ); + if ( todo ) { + mCalendar.deleteTodo( todo ); + changed = true; + } + } else if ( item.status == SloxItem::Create ) { + Todo *newTodo = 0; + Todo *todo = mCalendar.todo( uid ); + if ( !todo ) { + newTodo = new Todo; + todo = newTodo; + todo->setUid( uid ); + todo->setSecrecy( Incidence::SecrecyPrivate ); + } + + todo->setCustomProperty( "SLOX", "ID", item.sloxId ); + + mWebdavHandler.clearSloxAttributeStatus(); + + QDomNode n; + for( n = item.domNode.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e = n.toElement(); + mWebdavHandler.parseSloxAttribute( e ); + parseIncidenceAttribute( e, todo ); + parseTodoAttribute( e, todo ); + } + + mWebdavHandler.setSloxAttributes( todo ); + + if ( newTodo ) mCalendar.addTodo( todo ); + + changed = true; + } + } + + enableChangeNotification(); + + clearChanges(); + + if ( changed ) emit resourceChanged( this ); + + emit resourceLoaded( this ); + } + + mLoadTodosJob = 0; + + if ( mLoadTodosProgress ) mLoadTodosProgress->setComplete(); + mLoadTodosProgress = 0; +} + +void KCalResourceSlox::slotLoadEventsResult( KIO::Job *job ) +{ + kdDebug() << "KCalResourceSlox::slotLoadEventsResult() " << long( this ) << endl; + + if ( job->error() ) { + loadError( job->errorString() ); + } else { + kdDebug() << "KCalResourceSlox::slotLoadEventsResult() success" << endl; + + QDomDocument doc = mLoadEventsJob->response(); + + mWebdavHandler.log( doc.toString( 2 ) ); + + QValueList<SloxItem> items = WebdavHandler::getSloxItems( this, doc ); + + bool changed = false; + + disableChangeNotification(); + + QValueList<SloxItem>::ConstIterator it; + for( it = items.begin(); it != items.end(); ++it ) { + SloxItem item = *it; + QString uid = sloxIdToEventUid( item.sloxId ); + if ( item.status == SloxItem::Delete ) { + Event *event = mCalendar.event( uid ); + if ( event ) { + mCalendar.deleteEvent( event ); + changed = true; + } + } else if ( item.status == SloxItem::Create ) { + Event *newEvent = 0; + Event *event = mCalendar.event( uid ); + if ( !event ) { + newEvent = new Event; + event = newEvent; + event->setUid( uid ); + event->setSecrecy( Incidence::SecrecyPrivate ); + } + + event->setCustomProperty( "SLOX", "ID", item.sloxId ); + + QDomNode n = item.domNode.namedItem( fieldName( FullTime ) ); + event->setFloats( n.toElement().text() == boolToStr( true ) ); + + bool doesRecur = false; + + mWebdavHandler.clearSloxAttributeStatus(); + + for( n = item.domNode.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e = n.toElement(); + mWebdavHandler.parseSloxAttribute( e ); + parseIncidenceAttribute( e, event ); + parseEventAttribute( e, event ); + if ( e.tagName() == fieldName( RecurrenceType ) && e.text() != "no" ) { + doesRecur = true; + } + } + + if ( doesRecur ) + parseRecurrence( item.domNode, event ); + else + event->recurrence()->unsetRecurs(); + + mWebdavHandler.setSloxAttributes( event ); + +// kdDebug() << "EVENT " << item.uid << " " << event->summary() << endl; + + if ( newEvent ) mCalendar.addEvent( event ); + + changed = true; + } + } + + enableChangeNotification(); + + saveCache(); + + clearChanges(); + + if ( changed ) emit resourceChanged( this ); + + emit resourceLoaded( this ); + } + + mLoadEventsJob = 0; + + if ( mLoadEventsProgress ) mLoadEventsProgress->setComplete(); + mLoadEventsProgress = 0; +} + +void KCalResourceSlox::slotUploadResult( KIO::Job *job ) +{ + kdDebug() << "KCalResourceSlox::slotUploadResult()" << endl; + + if ( job->error() ) { + saveError( job->errorString() ); + } else { + kdDebug() << "KCalResourceSlox::slotUploadResult() success" << endl; + + if ( !mUploadJob ) + { + kdDebug() << "KCalResourceSlox::slotUploadResult() - mUploadJob was 0" << endl; + return; + } + + QDomDocument doc = mUploadJob->response(); + + kdDebug() << "UPLOAD RESULT:" << endl; + kdDebug() << doc.toString( 2 ) << endl; + + QDomElement docElement = doc.documentElement(); + + QDomNode responseNode; + for( responseNode = docElement.firstChild(); !responseNode.isNull(); + responseNode = responseNode.nextSibling() ) { + QDomElement responseElement = responseNode.toElement(); + if ( responseElement.tagName() == "response" ) { + QDomNode propstat = responseElement.namedItem( "propstat" ); + if ( propstat.isNull() ) { + kdError() << "Unable to find propstat tag." << endl; + continue; + } + + QDomNode status = propstat.namedItem( "status" ); + if ( !status.isNull() ) { + QDomElement statusElement = status.toElement(); + QString response = statusElement.text(); + if ( !response.contains( "200" ) ) { + QString error = "'" + mUploadedIncidence->summary() + "'\n"; + error += response; + QDomNode dn = propstat.namedItem( "responsedescription" ); + QString d = dn.toElement().text(); + if ( !d.isEmpty() ) error += "\n" + d; + saveError( error ); + continue; + } + } + + QDomNode prop = propstat.namedItem( "prop" ); + if ( prop.isNull() ) { + kdError() << "Unable to find WebDAV property" << endl; + continue; + } + + QDomNode sloxIdNode = prop.namedItem( fieldName( ObjectId ) ); + if ( sloxIdNode.isNull() ) { + kdError() << "Unable to find SLOX id." << endl; + continue; + } + QDomElement sloxIdElement = sloxIdNode.toElement(); + QString sloxId = sloxIdElement.text(); + kdDebug() << "SLOXID: " << sloxId << endl; + + if ( mUploadIsDelete ) { + kdDebug() << "Incidence deleted" << endl; + } else { + QDomNode clientIdNode = prop.namedItem( fieldName( ClientId ) ); + if ( clientIdNode.isNull() ) { + kdError() << "Unable to find client id." << endl; + continue; + } + QDomElement clientidElement = clientIdNode.toElement(); + QString clientId = clientidElement.text(); + + kdDebug() << "CLIENTID: " << clientId << endl; + + Incidence *i = mUploadedIncidence->clone(); + QString uid; + if ( i->type() == "Event" ) uid = sloxIdToEventUid( sloxId ); + else if ( i->type() == "Todo" ) uid = sloxIdToTodoUid( sloxId ); + else { + kdError() << "KCalResourceSlox::slotUploadResult(): Unknown type: " + << i->type() << endl; + } + i->setUid( uid ); + i->setCustomProperty( "SLOX", "ID", sloxId ); + + disableChangeNotification(); + mCalendar.deleteIncidence( mUploadedIncidence ); + mCalendar.addIncidence( i ); + saveCache(); + enableChangeNotification(); + + emit resourceChanged( this ); + } + } + } + } + + mUploadJob = 0; + + mUploadProgress->setComplete(); + mUploadProgress = 0; + + clearChange( mUploadedIncidence ); + + uploadIncidences(); +} + +void KCalResourceSlox::slotEventsProgress( KIO::Job *job, + unsigned long percent ) +{ +#if 0 + kdDebug() << "PROGRESS: events " << int( job ) << ": " << percent << endl; +#else + Q_UNUSED( job ); + Q_UNUSED( percent ); +#endif + if ( mLoadEventsProgress ) mLoadEventsProgress->setProgress( percent ); +} + +void KCalResourceSlox::slotTodosProgress( KIO::Job *job, unsigned long percent ) +{ +#if 0 + kdDebug() << "PROGRESS: todos " << int( job ) << ": " << percent << endl; +#else + Q_UNUSED( job ); + Q_UNUSED( percent ); +#endif + if ( mLoadTodosProgress ) mLoadTodosProgress->setProgress( percent ); +} + +void KCalResourceSlox::slotUploadProgress( KIO::Job *job, unsigned long percent ) +{ +#if 0 + kdDebug() << "PROGRESS: upload " << int( job ) << ": " << percent << endl; +#else + Q_UNUSED( job ); + Q_UNUSED( percent ); +#endif + if ( mUploadProgress ) mUploadProgress->setProgress( percent ); +} + +bool KCalResourceSlox::confirmSave() +{ + if ( !hasChanges() ) return true; + + ConfirmSaveDialog dlg( resourceName(), 0 ); + + dlg.addIncidences( addedIncidences(), i18n("Added") ); + dlg.addIncidences( changedIncidences(), i18n("Changed") ); + dlg.addIncidences( deletedIncidences(), i18n("Deleted") ); + + int result = dlg.exec(); + return result == QDialog::Accepted; +} + +bool KCalResourceSlox::doSave() +{ + kdDebug() << "KCalResourceSlox::save()" << endl; + + if ( readOnly() || !hasChanges() ) { + emit resourceSaved( this ); + return true; + } + + if ( mLoadEventsJob || mLoadTodosJob ) { + kdWarning() << "KCalResourceSlox::save(): download still in progress." + << endl; + return false; + } + if ( mUploadJob ) { + kdWarning() << "KCalResourceSlox::save(): upload still in progress." + << endl; + return false; + } + + if ( !confirmSave() ) return false; + + saveCache(); + + uploadIncidences(); + + return true; +} + +bool KCalResourceSlox::isSaving() +{ + return mUploadJob; +} + +void KCalResourceSlox::doClose() +{ + kdDebug() << "KCalResourceSlox::doClose()" << endl; + + cancelLoadEvents(); + cancelLoadTodos(); + + if ( mUploadJob ) { + kdError() << "KCalResourceSlox::doClose() Still saving" << endl; + } else { + mCalendar.close(); + } +} + +KABC::Lock *KCalResourceSlox::lock() +{ + return mLock; +} + +void KCalResourceSlox::dump() const +{ + ResourceCalendar::dump(); + kdDebug(5800) << " Url: " << mPrefs->url() << endl; +} + +void KCalResourceSlox::cancelLoadEvents() +{ + if ( mLoadEventsJob ) mLoadEventsJob->kill(); + mLoadEventsJob = 0; + if ( mLoadEventsProgress ) mLoadEventsProgress->setComplete(); + mLoadEventsProgress = 0; +} + +void KCalResourceSlox::cancelLoadTodos() +{ + if ( mLoadTodosJob ) mLoadTodosJob->kill(); + mLoadTodosJob = 0; + if ( mLoadTodosProgress ) mLoadTodosProgress->setComplete(); + mLoadTodosProgress = 0; +} + +void KCalResourceSlox::cancelUpload() +{ + if ( mUploadJob ) mUploadJob->kill(); + mUploadJob = 0; + if ( mUploadProgress ) mUploadProgress->setComplete(); +} + +QString KCalResourceSlox::sloxIdToEventUid( const QString &sloxId ) +{ + return "KResources_SLOX_Event_" + sloxId; +} + +QString KCalResourceSlox::sloxIdToTodoUid( const QString &sloxId ) +{ + return "KResources_SLOX_Todo_" + sloxId; +} + +#include "kcalresourceslox.moc" diff --git a/kresources/slox/kcalresourceslox.h b/kresources/slox/kcalresourceslox.h new file mode 100644 index 000000000..2d0022cc7 --- /dev/null +++ b/kresources/slox/kcalresourceslox.h @@ -0,0 +1,167 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef KCALRESOURCESLOX_H +#define KCALRESOURCESLOX_H + +#include "sloxbase.h" +#include "webdavhandler.h" + +#include <qptrlist.h> +#include <qstring.h> +#include <qdatetime.h> +#include <qdom.h> + +#include <kurl.h> +#include <kconfig.h> +#include <kdirwatch.h> +#include <kdepimmacros.h> + +#include <libkcal/incidence.h> +#include <libkcal/todo.h> +#include <libkcal/calendarlocal.h> +#include <libkcal/icalformat.h> +#include <libkcal/resourcecached.h> + +namespace KIO { +class FileCopyJob; +class Job; +class DavJob; +} + +namespace KCal { +class SloxPrefs; +} + +namespace KPIM { +class ProgressItem; +} + +class SloxAccounts; + +/** + This class provides a calendar stored as a remote file. +*/ +class KDE_EXPORT KCalResourceSlox : public KCal::ResourceCached, public SloxBase +{ + Q_OBJECT + + friend class KCalResourceSloxConfig; + + public: + /** + Reload policy. + + @see setReloadPolicy(), reloadPolicy() + */ + enum { ReloadNever, ReloadOnStartup, ReloadOnceADay, ReloadAlways }; + + /** + Create resource from configuration information stored in KConfig object. + */ + KCalResourceSlox( const KConfig * ); + KCalResourceSlox( const KURL &url ); + ~KCalResourceSlox(); + + void readConfig( const KConfig *config ); + void writeConfig( KConfig *config ); + + KCal::SloxPrefs *prefs() const { return mPrefs; } + + KABC::Lock *lock(); + + bool isSaving(); + + void dump() const; + + protected slots: + void slotLoadEventsResult( KIO::Job * ); + void slotLoadTodosResult( KIO::Job * ); + void slotUploadResult( KIO::Job * ); + + void slotEventsProgress( KIO::Job *job, unsigned long percent ); + void slotTodosProgress( KIO::Job *job, unsigned long percent ); + void slotUploadProgress( KIO::Job *job, unsigned long percent ); + + void cancelLoadEvents(); + void cancelLoadTodos(); + void cancelUpload(); + + protected: + void doClose(); + bool doLoad(); + bool doSave(); + + void requestEvents(); + void requestTodos(); + + void uploadIncidences(); + + void parseMembersAttribute( const QDomElement &e, + KCal::Incidence *incidence ); + void parseReadRightsAttribute( const QDomElement &e, + KCal::Incidence *incidence ); + void parseIncidenceAttribute( const QDomElement &e, + KCal::Incidence *incidence ); + void parseTodoAttribute( const QDomElement &e, KCal::Todo *todo ); + void parseEventAttribute( const QDomElement &e, KCal::Event *event ); + void parseRecurrence( const QDomNode &n, KCal::Event *event ); + + void createIncidenceAttributes( QDomDocument &doc, + QDomElement &parent, + KCal::Incidence *incidence ); + void createEventAttributes( QDomDocument &doc, + QDomElement &parent, + KCal::Event *event ); + void createTodoAttributes( QDomDocument &doc, + QDomElement &parent, + KCal::Todo *todo ); + void createRecurrenceAttributes( QDomDocument &doc, + QDomElement &parent, + KCal::Incidence *incidence ); + + bool confirmSave(); + + QString sloxIdToEventUid( const QString &sloxId ); + QString sloxIdToTodoUid( const QString &sloxId ); + + private: + void init(); + + KCal::SloxPrefs *mPrefs; + + KIO::DavJob *mLoadEventsJob; + KIO::DavJob *mLoadTodosJob; + KIO::DavJob *mUploadJob; + + KPIM::ProgressItem *mLoadEventsProgress; + KPIM::ProgressItem *mLoadTodosProgress; + KPIM::ProgressItem *mUploadProgress; + + KCal::Incidence *mUploadedIncidence; + bool mUploadIsDelete; + + KABC::Lock *mLock; + + WebdavHandler mWebdavHandler; + + SloxAccounts *mAccounts; +}; + +#endif diff --git a/kresources/slox/kcalresourceslox_plugin.cpp b/kresources/slox/kcalresourceslox_plugin.cpp new file mode 100644 index 000000000..57aa9dc58 --- /dev/null +++ b/kresources/slox/kcalresourceslox_plugin.cpp @@ -0,0 +1,40 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "kcalresourcesloxconfig.h" +#include "kcalresourceslox.h" + +#include <kglobal.h> +#include <klocale.h> + +using namespace KCal; + +typedef KRES::PluginFactory<KCalResourceSlox,KCalResourceSloxConfig> SLOXFactory; +// FIXME: Use K_EXPORT_COMPONENT_FACTORY( kcal_slox, SLOXFactory ); here +// Problem: How do I insert the catalogue??? +extern "C" +{ + void *init_kcal_slox() + { + KGlobal::locale()->insertCatalogue( "libkcal" ); + KGlobal::locale()->insertCatalogue( "kabc_slox" ); + return new SLOXFactory; + } +} diff --git a/kresources/slox/kcalresourcesloxconfig.cpp b/kresources/slox/kcalresourcesloxconfig.cpp new file mode 100644 index 000000000..403a5e518 --- /dev/null +++ b/kresources/slox/kcalresourcesloxconfig.cpp @@ -0,0 +1,145 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <typeinfo> + +#include <qlabel.h> +#include <qlayout.h> +#include <qcheckbox.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <klineedit.h> +#include <kpushbutton.h> + +#include <libkcal/resourcecachedconfig.h> + +#include "kcalresourceslox.h" +#include "kcalsloxprefs.h" +#include "sloxfolder.h" +#include "sloxfolderdialog.h" +#include "sloxfoldermanager.h" + +#include "kcalresourcesloxconfig.h" + +KCalResourceSloxConfig::KCalResourceSloxConfig( QWidget* parent, const char* name ) : + KRES::ConfigWidget( parent, name ), mRes( 0 ) +{ + resize( 245, 115 ); + QGridLayout *mainLayout = new QGridLayout( this, 6, 2, KDialog::spacingHint(), KDialog::spacingHint() ); + + QLabel *label = new QLabel( i18n( "Download from:" ), this ); + + mDownloadUrl = new KURLRequester( this ); + mDownloadUrl->setMode( KFile::File ); + mainLayout->addWidget( label, 1, 0 ); + mainLayout->addWidget( mDownloadUrl, 1, 1 ); + + label = new QLabel( i18n("User:"), this ); + mainLayout->addWidget( label, 2, 0 ); + + mUserEdit = new KLineEdit( this ); + mainLayout->addWidget( mUserEdit, 2, 1 ); + + label = new QLabel( i18n("Password:"), this ); + mainLayout->addWidget( label, 3, 0 ); + + mPasswordEdit = new KLineEdit( this ); + mainLayout->addWidget( mPasswordEdit, 3, 1 ); + mPasswordEdit->setEchoMode( KLineEdit::Password ); + + mLastSyncCheck = new QCheckBox( i18n("Only load data since last sync"), + this ); + mainLayout->addMultiCellWidget( mLastSyncCheck, 4, 4, 0, 1 ); + + mCalButton = new KPushButton( i18n("Calendar Folder..."), this ); + mainLayout->addWidget( mCalButton, 5, 0 ); + connect( mCalButton, SIGNAL( clicked() ), SLOT( selectCalendarFolder() ) ); + + mTaskButton = new KPushButton( i18n("Task Folder..."), this ); + mainLayout->addWidget( mTaskButton, 5, 1 ); + connect( mTaskButton, SIGNAL( clicked() ), SLOT( selectTaskFolder() ) ); + + mReloadConfig = new KCal::ResourceCachedReloadConfig( this ); + mainLayout->addMultiCellWidget( mReloadConfig, 6, 6, 0, 1 ); + + mSaveConfig = new KCal::ResourceCachedSaveConfig( this ); + mainLayout->addMultiCellWidget( mSaveConfig, 7, 7, 0, 1 ); +} + +void KCalResourceSloxConfig::loadSettings( KRES::Resource *resource ) +{ + KCalResourceSlox *res = static_cast<KCalResourceSlox *>( resource ); + mRes = res; + if ( mRes->resType() == "slox" ) { // we don't have folder selection for SLOX + mCalButton->setEnabled( false ); + mTaskButton->setEnabled( false ); + } + if ( res ) { + mDownloadUrl->setURL( res->prefs()->url() ); + mLastSyncCheck->setChecked( res->prefs()->useLastSync() ); + mUserEdit->setText( res->prefs()->user() ); + mPasswordEdit->setText( res->prefs()->password() ); + mCalendarFolderId = res->prefs()->calendarFolderId(); + mTaskFolderId = res->prefs()->taskFolderId(); + mReloadConfig->loadSettings( res ); + mSaveConfig->loadSettings( res ); + } else { + kdError(5700) << "KCalResourceSloxConfig::loadSettings(): no KCalResourceSlox, cast failed" << endl; + } +} + +void KCalResourceSloxConfig::saveSettings( KRES::Resource *resource ) +{ + KCalResourceSlox *res = static_cast<KCalResourceSlox*>( resource ); + if ( res ) { + res->prefs()->setUrl( mDownloadUrl->url() ); + res->prefs()->setUseLastSync( mLastSyncCheck->isChecked() ); + res->prefs()->setUser( mUserEdit->text() ); + res->prefs()->setPassword( mPasswordEdit->text() ); + res->prefs()->setCalendarFolderId( mCalendarFolderId ); + res->prefs()->setTaskFolderId( mTaskFolderId ); + mReloadConfig->saveSettings( res ); + mSaveConfig->saveSettings( res ); + } else { + kdError(5700) << "KCalResourceSloxConfig::saveSettings(): no KCalResourceSlox, cast failed" << endl; + } +} + +void KCalResourceSloxConfig::selectCalendarFolder() +{ + SloxFolderManager *manager = new SloxFolderManager( mRes, mDownloadUrl->url() ); + SloxFolderDialog *dialog = new SloxFolderDialog( manager, ::Calendar, this ); + dialog->setSelectedFolder( mCalendarFolderId ); + if ( dialog->exec() == QDialog::Accepted ) + mCalendarFolderId = dialog->selectedFolder(); +} + +void KCalResourceSloxConfig::selectTaskFolder( ) +{ + SloxFolderManager *manager = new SloxFolderManager( mRes, mDownloadUrl->url() ); + SloxFolderDialog *dialog = new SloxFolderDialog( manager, Tasks, this ); + dialog->setSelectedFolder( mTaskFolderId ); + if ( dialog->exec() == QDialog::Accepted ) + mTaskFolderId = dialog->selectedFolder(); +} + +#include "kcalresourcesloxconfig.moc" diff --git a/kresources/slox/kcalresourcesloxconfig.h b/kresources/slox/kcalresourcesloxconfig.h new file mode 100644 index 000000000..a656478d2 --- /dev/null +++ b/kresources/slox/kcalresourcesloxconfig.h @@ -0,0 +1,75 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef KCALRESOURCESLOXCONFIG_H +#define KCALRESOURCESLOXCONFIG_H + +#include <kurlrequester.h> +#include <kdepimmacros.h> + +#include <kresources/resource.h> +#include <kresources/configwidget.h> + +class QCheckBox; +class KLineEdit; +class KPushButton; + +namespace KCal { +class ResourceCachedReloadConfig; +class ResourceCachedSaveConfig; +} + +class SloxBase; + +/** + Configuration widget for SLOX resource. + + @see KCalResourceSlox +*/ +class KDE_EXPORT KCalResourceSloxConfig : public KRES::ConfigWidget +{ + Q_OBJECT + public: + KCalResourceSloxConfig( QWidget *parent = 0, const char *name = 0 ); + + public slots: + virtual void loadSettings( KRES::Resource *resource ); + virtual void saveSettings( KRES::Resource *resource ); + + private slots: + void selectCalendarFolder(); + void selectTaskFolder(); + + private: + KURLRequester *mDownloadUrl; + KLineEdit *mUserEdit; + KLineEdit *mPasswordEdit; + QCheckBox *mLastSyncCheck; + KPushButton *mCalButton; + KPushButton *mTaskButton; + QString mCalendarFolderId; + QString mTaskFolderId; + + KCal::ResourceCachedReloadConfig *mReloadConfig; + KCal::ResourceCachedSaveConfig *mSaveConfig; + + SloxBase *mRes; +}; + +#endif diff --git a/kresources/slox/kcalsloxprefs.kcfgc b/kresources/slox/kcalsloxprefs.kcfgc new file mode 100644 index 000000000..0c1bff263 --- /dev/null +++ b/kresources/slox/kcalsloxprefs.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=kresources_kcal_slox.kcfg +ClassName=SloxPrefs +NameSpace=KCal +Singleton=false +Mutators=true +Inherits=KResourcePrefs +IncludeFiles=libkdepim/kresourceprefs.h +GlobalEnums=true +#ItemAccessors=true +#SetUserTexts=true diff --git a/kresources/slox/kresources_kabc_slox.kcfg b/kresources/slox/kresources_kabc_slox.kcfg new file mode 100644 index 000000000..159605ba3 --- /dev/null +++ b/kresources/slox/kresources_kabc_slox.kcfg @@ -0,0 +1,31 @@ +<?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_sloxrc"/> + + <group name="General"> + <entry type="String" name="Url"> + <label>Base Url</label> + </entry> + <entry type="String" name="User"> + <label>User Name</label> + </entry> + <entry type="Password" name="Password"> + <label>Password</label> + </entry> + <entry type="Bool" name="UseLastSync"> + <label>Only load data since last sync</label> + <default>true</default> + </entry> + <entry type="String" name="FolderId"> + <label>Folder ID</label> + <default></default> + </entry> + <entry type="DateTime" name="LastSync"> + <label>Last Sync</label> + </entry> + </group> + +</kcfg> diff --git a/kresources/slox/kresources_kcal_slox.kcfg b/kresources/slox/kresources_kcal_slox.kcfg new file mode 100644 index 000000000..9e4e6f4eb --- /dev/null +++ b/kresources/slox/kresources_kcal_slox.kcfg @@ -0,0 +1,38 @@ +<?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_sloxrc"/> + + <group name="General"> + <entry type="String" name="Url"> + <label>Base Url</label> + </entry> + <entry type="String" name="User"> + <label>User Name</label> + </entry> + <entry type="Password" name="Password"> + <label>Password</label> + </entry> + <entry type="DateTime" name="LastEventSync"> + <label>Last Event Sync</label> + </entry> + <entry type="DateTime" name="LastTodoSync"> + <label>Last To-do Sync</label> + </entry> + <entry type="Bool" name="UseLastSync"> + <label>Only load data since last sync</label> + <default>true</default> + </entry> + <entry type="String" name="CalendarFolderId"> + <label>Calendar Folder</label> + <default></default> + </entry> + <entry type="String" name="TaskFolderId"> + <label>Task Folder</label> + <default></default> + </entry> + </group> + +</kcfg> diff --git a/kresources/slox/sloxaccounts.cpp b/kresources/slox/sloxaccounts.cpp new file mode 100644 index 000000000..35203b06f --- /dev/null +++ b/kresources/slox/sloxaccounts.cpp @@ -0,0 +1,222 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2005 Volker Krause <volker.krause@rwth-aachen.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "sloxaccounts.h" +#include "sloxbase.h" +#include "webdavhandler.h" + +#include <libkcal/freebusyurlstore.h> + +#include <kstaticdeleter.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kio/job.h> +#include <kio/davjob.h> +#include <kstringhandler.h> +#include <kconfig.h> + +#include <qfile.h> +#include <qdom.h> +#include <qstring.h> + +SloxAccounts::SloxAccounts( SloxBase *res, const KURL &baseUrl ) + : mBaseUrl( baseUrl ), mRes( res ) +{ + kdDebug() << "SloxAccounts(): " << baseUrl << endl; + + mDownloadJob = 0; + + QString server = mBaseUrl.host(); + + QStringList l = QStringList::split( '.', server ); + + if ( l.count() < 2 ) mDomain = server; + else mDomain = l[ l.count() - 2 ] + "." + l[ l.count() - 1 ]; + + readAccounts(); +} + +SloxAccounts::~SloxAccounts() +{ + kdDebug() << "~SloxAccounts()" << endl; + + if ( mDownloadJob ) mDownloadJob->kill(); +} + +void SloxAccounts::insertUser( const QString &id, const KABC::Addressee &a ) +{ + kdDebug() << "SloxAccount::insertUser() " << id << endl; + + mUsers.replace( id, a ); + + QString email = a.preferredEmail(); + + QString url = "http://" + mBaseUrl.host() + "/servlet/webdav.freebusy?username="; + url += id + "&server=" + mDomain; + + KCal::FreeBusyUrlStore::self()->writeUrl( email, url ); +} + +KABC::Addressee SloxAccounts::lookupUser( const QString &id ) +{ + QMap<QString, KABC::Addressee>::ConstIterator it; + it = mUsers.find( id ); + if ( it == mUsers.end() ) { + requestAccounts(); + return KABC::Addressee(); + } else { + return *it; + } +} + +QString SloxAccounts::lookupId( const QString &email ) +{ + kdDebug() << "SloxAccounts::lookupId() " << email << endl; + + QMap<QString, KABC::Addressee>::ConstIterator it; + for( it = mUsers.begin(); it != mUsers.end(); ++it ) { + kdDebug() << "PREF: " << (*it).preferredEmail() << endl; + kdDebug() << "KEY: " << it.key() << endl; + if ( (*it).preferredEmail() == email ) return it.key(); + } + requestAccounts(); + + int pos = email.find( '@' ); + if ( pos < 0 ) return email; + else return email.left( pos ); +} + +void SloxAccounts::requestAccounts() +{ + kdDebug() << "SloxAccounts::requestAccounts()" << endl; + + if ( mDownloadJob ) { + kdDebug() << "SloxAccount::requestAccounts(): Download still in progress" + << endl; + return; + } + + if ( mRes->resType() == "slox" ) { + KURL url = mBaseUrl; + url.addPath( "/servlet/webdav.groupuser" ); + url.setQuery( "?user=*&group=*&groupres=*&res=*&details=t" ); + + kdDebug() << "SloxAccounts::requestAccounts() URL: " << url << endl; + + mDownloadJob = KIO::file_copy( url, cacheFile(), -1, true, false, false ); + } else if ( mRes->resType() == "ox" ) { + KURL url = mBaseUrl; + url.setPath( "/servlet/webdav.groupuser/" ); + + QDomDocument doc; + QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" ); + QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "user", "*" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "group", "*" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "resource", "*" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "resourcegroup", "*" ); + + kdDebug() << k_funcinfo << doc.toString( 2 ) << endl; + + mDownloadJob = KIO::davPropFind( url, doc, "0", false ); + } + + connect( mDownloadJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotResult( KIO::Job * ) ) ); +} + +void SloxAccounts::slotResult( KIO::Job *job ) +{ + kdDebug() << "SloxAccounts::slotResult()" << endl; + + if ( job->error() ) { + job->showErrorDialog( 0 ); + } else { + if ( mRes->resType() == "ox" ) { + QFile f( cacheFile() ); + if ( !f.open( IO_WriteOnly ) ) { + kdWarning() << "Unable to open '" << cacheFile() << "'" << endl; + return; + } + QTextStream stream ( &f ); + stream << static_cast<KIO::DavJob*>( mDownloadJob )->response(); + f.close(); + } + readAccounts(); + } + + mDownloadJob = 0; +} + +QString SloxAccounts::cacheFile() const +{ + QString host = mBaseUrl.host(); + + QString file = locateLocal( "cache", "slox/accounts_" + host ); + + kdDebug() << "SloxAccounts::cacheFile(): " << file << endl; + + return file; +} + +void SloxAccounts::readAccounts() +{ + kdDebug() << "SloxAccounts::readAccounts()" << endl; + + QFile f( cacheFile() ); + if ( !f.open( IO_ReadOnly ) ) { + kdDebug() << "Unable to open '" << cacheFile() << "'" << endl; + requestAccounts(); + return; + } + + QDomDocument doc; + doc.setContent( &f ); + +// kdDebug() << "SLOX ACCOUNTS: " << doc.toString( 2 ) << endl; + + QDomElement docElement = doc.documentElement(); + + mUsers.clear(); + + QDomNodeList nodes = doc.elementsByTagName( mRes->resType() == "ox" ? "ox:user" : "user" ); + for( uint i = 0; i < nodes.count(); ++i ) { + QDomElement element = nodes.item(i).toElement(); + QString id; + KABC::Addressee a; + QDomNode n; + for( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e = n.toElement(); + QString tag = e.tagName(); + // remove XML namespace + tag = tag.right( tag.length() - ( tag.find( ':' ) + 1 ) ); + QString value = e.text(); + if ( tag == "uid" ) id = value; + else if ( tag == "mail" ) a.insertEmail( value, true ); + else if ( tag == "forename" ) a.setGivenName( value ); + else if ( tag == "surename" ) a.setFamilyName( value ); + } +// kdDebug() << "MAIL: " << a.preferredEmail() << endl; + insertUser( id, a ); + } +} + +#include "sloxaccounts.moc" diff --git a/kresources/slox/sloxaccounts.h b/kresources/slox/sloxaccounts.h new file mode 100644 index 000000000..ea3e664e2 --- /dev/null +++ b/kresources/slox/sloxaccounts.h @@ -0,0 +1,66 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef SLOXACCOUNTS_H +#define SLOXACCOUNTS_H + +#include <kabc/addressee.h> +#include <kdepimmacros.h> +#include <qobject.h> + +namespace KIO { +class Job; +} + +class SloxBase; + +class KDE_EXPORT SloxAccounts : public QObject +{ + Q_OBJECT + public: + SloxAccounts( SloxBase *res, const KURL &baseUrl ); + ~SloxAccounts(); + + void insertUser( const QString &id, const KABC::Addressee &a ); + + KABC::Addressee lookupUser( const QString &id ); + + QString lookupId( const QString &email ); + + protected: + void requestAccounts(); + void readAccounts(); + + QString cacheFile() const; + + protected slots: + void slotResult( KIO::Job * ); + + private: + QString mDomain; + + KIO::Job *mDownloadJob; + + QMap<QString, KABC::Addressee> mUsers; // map users ids to addressees. + + KURL mBaseUrl; + SloxBase *mRes; +}; + +#endif diff --git a/kresources/slox/sloxbase.cpp b/kresources/slox/sloxbase.cpp new file mode 100644 index 000000000..c58990593 --- /dev/null +++ b/kresources/slox/sloxbase.cpp @@ -0,0 +1,139 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + Copyright (c) 2005 by Florian Schröder <florian@deltatauchi.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "sloxbase.h" + +#include <kdebug.h> +#include <kresources/resource.h> + +static QString mFieldNameMap[][2] = +{ + // SLOX, OX + {"sloxid", "object_id"}, // system fields + {"clientid", "client_id"}, + {"folderid", "folder_id"}, + {"lastsync", "lastsync"}, + {"objecttype", "objectmode"}, + {"sloxstatus", "object_status"}, + {"createfrom", "created_by"}, + {"categories", "categories"}, + // incidence fields + {"title", "title"}, + {"description", "note"}, + {"members", "participants"}, + {"member", "user"}, + {"reminder", "alarm"}, + // recurrence fields + {"date_sequence", "recurrence_type"}, + {"ds_ends", "until"}, + {"daily_value", "interval"}, + {"weekly_value", "interval"}, + {"monthly_value_month", "interval"}, + {"monthly_value_day", "day_in_month"}, + {"yearly_value_day", "day_in_month"}, + {"yearly_month", "month"}, + {"monthly2_value_month", "interval"}, + {"monthly2_day", "days"}, + {"monthly2_recurrency", "day_in_month"}, + {"yearly2_day", "days"}, + {"yearly2_reccurency", "day_in_month"}, // this is not a typo, this is what SLOX erally sends! + {"yearly2_month", "month"}, + {"deleteexceptions", "deleteexceptions"}, + // event fields + {"begins", "start_date"}, + {"ends", "end_date"}, + {"location", "location"}, + {"full_time", "full_time"}, + // task fields + {"startdate", "start_date"}, + {"deadline", "end_date"}, + {"priority", "priority"}, + {"status", "percent_complete"}, + // contact fields + {"lastname", "last_name"}, + {"firstname", "first_name"}, + {"n/a", "second_name"}, + {"displayname", "displayname"}, // FIXME: what's this in SLOX? + {"title", "title"}, + {"n/a", "suffix"}, + {"position", "position"}, + {"n/a", "company"}, // SLOX handles company separately + {"department", "department"}, + {"email", "email1"}, + {"email2", "email2"}, + {"privateemail", "email3"}, + {"privateemail2", "email3"}, // OX has only three email fields + {"birthday", "birthday"}, + {"privateurl", "url"}, + {"comment", "note"}, + {"n/a", "image1"}, // not supported by SLOX + {"n/a", "instant_messenger"}, + {"n/a", "room_number"}, + {"n/a", "profession"}, + {"n/a", "managers_name"}, + {"n/a", "assistants_name"}, + {"n/a", "spouse_name"}, + {"n/a", "anniversary"}, + {"n/a", "nickname"}, + {"street", "street"}, // address fields + {"zipcode", "postal_code"}, + {"city", "city"}, + {"state", "state"}, + {"country", "country"}, + {"private", ""}, // address type prefix + {"business_", "business_"}, // doesn't work with SLOX + {"second_", "second_"}, +}; + +SloxBase::SloxBase( KRES::Resource * res ) : + mRes( res ) +{ +} + +QString SloxBase::decodeText( const QString & text ) +{ + if ( mRes->type() == "ox" ) + return text; + return QString::fromUtf8( text.latin1() ); +} + +QString SloxBase::fieldName( Field f ) +{ + int t = 0; + if ( mRes->type() == "ox" ) + t = 1; + return mFieldNameMap[f][t]; +} + +QString SloxBase::resType( ) const +{ + return mRes->type(); +} + +QString SloxBase::boolToStr( bool b ) +{ + if ( mRes->type() == "ox" ) { + if ( b ) + return "true"; + return "false"; + } + if ( b ) + return "yes"; + return "no"; +} diff --git a/kresources/slox/sloxbase.h b/kresources/slox/sloxbase.h new file mode 100644 index 000000000..90afb16fa --- /dev/null +++ b/kresources/slox/sloxbase.h @@ -0,0 +1,115 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + Copyright (c) 2005 by Florian Schröder <florian@deltatauchi.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SLOXUTILS_H +#define SLOXUTILS_H + +#include <qstring.h> +#include <kdepimmacros.h> + +namespace KRES { +class Resource; +} + +class KDE_EXPORT SloxBase { + public: + enum Field { + ObjectId = 0, // system fields + ClientId, + FolderId, + LastSync, + ObjectType, + ObjectStatus, + CreatedBy, + Categories, + IncidenceTitle, // incidence fields + Description, + Participants, + Participant, + Reminder, + RecurrenceType, // recurrence fields + RecurrenceEnd, + RecurrenceDailyFreq, + RecurrenceWeeklyFreq, + RecurrenceMonthlyFreq, + RecurrenceMonthlyDay, + RecurrenceYearlyDay, + RecurrenceYearlyMonth, + RecurrenceMonthly2Freq, + RecurrenceMonthly2Day, + RecurrenceMonthly2Pos, + RecurrenceYearly2Day, + RecurrenceYearly2Pos, + RecurrenceYearly2Month, + RecurrenceDelEx, + EventBegin, // event fields + EventEnd, + Location, + FullTime, + TaskBegin, // task fields + TaskEnd, + Priority, + PercentComplete, + FamilyName, // contact fields + GivenName, + SecondName, + DisplayName, + Title, + Suffix, + Role, + Organization, + Department, + PrimaryEmail, + SecondaryEmail1, + SecondaryEmail2, + SecondaryEmail3, + Birthday, + Url, + Comment, + Image, + InstantMsg, + Office, + Profession, + ManagersName, + AssistantsName, + SpousesName, + Anniversary, + NickName, + Street, // address fields + PostalCode, + City, + State, + Country, + HomePrefix, // address type prefixes + BusinessPrefix, + OtherPrefix + }; + + SloxBase( KRES::Resource *res ); + + QString decodeText( const QString &text ); + QString fieldName( Field f ); + QString resType() const; + QString boolToStr( bool b ); + + private: + KRES::Resource *mRes; +}; + +#endif diff --git a/kresources/slox/sloxfolder.cpp b/kresources/slox/sloxfolder.cpp new file mode 100644 index 000000000..157463149 --- /dev/null +++ b/kresources/slox/sloxfolder.cpp @@ -0,0 +1,49 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + Copyright (c) 2005 by Florian Schröder <florian@deltatauchi.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "sloxfolder.h" + +SloxFolder::SloxFolder( const QString &id, const QString &parentId, const QString &type, const QString &name, bool def ) : + item( 0 ), + mId( id ), + mParentId( parentId ), + mName( name ), + mDefault( def ) +{ + if ( type == "calendar" ) + mType = Calendar; + else if ( type == "task" ) + mType = Tasks; + else if ( type == "contact" ) + mType = Contacts; + else + mType = Unbound; +} + +QString SloxFolder::name( ) const +{ + // special cases for system folders + if ( mName == "system_global" ) + return i18n( "Global Addressbook" ); + if ( mName == "system_ldap" ) + return i18n( "Internal Addressbook" ); + return mName; +} diff --git a/kresources/slox/sloxfolder.h b/kresources/slox/sloxfolder.h new file mode 100644 index 000000000..bda529ba4 --- /dev/null +++ b/kresources/slox/sloxfolder.h @@ -0,0 +1,55 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + Copyright (c) 2005 by Florian Schröder <florian@deltatauchi.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SLOXFOLDER_H +#define SLOXFOLDER_H + +#include <qstring.h> +#include <kdepimmacros.h> + +class KListViewItem; + +enum FolderType { + Unbound, + Calendar, + Tasks, + Contacts +}; + +class KDE_EXPORT SloxFolder +{ + public: + SloxFolder( const QString &id, const QString &parentId, const QString &type, const QString &name, bool def = false ); + + QString id() const { return mId; } + QString parentId() const { return mParentId; } + FolderType type() const { return mType; } + QString name() const; + bool isDefault() const { return mDefault; } + + KListViewItem *item; + + private: + QString mId, mParentId; + FolderType mType; + QString mName; + bool mDefault; +}; + +#endif diff --git a/kresources/slox/sloxfolderdialog.cpp b/kresources/slox/sloxfolderdialog.cpp new file mode 100644 index 000000000..b188fb2fa --- /dev/null +++ b/kresources/slox/sloxfolderdialog.cpp @@ -0,0 +1,125 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include <kiconloader.h> +#include <kguiitem.h> +#include <klistview.h> +#include <klocale.h> + +#include "sloxfolderdialog.h" +#include "sloxfoldermanager.h" + +SloxFolderDialog::SloxFolderDialog( SloxFolderManager *manager, FolderType type, QWidget *parent, const char *name ) : + KDialogBase( parent, name, true, i18n("Select Folder"), Ok|Cancel|User1, Ok, false, KGuiItem( i18n("Reload"), "reload" ) ), + mManager( manager ), + mFolderType( type ) +{ + mListView = new KListView( this ); + mListView->setRootIsDecorated( true ); + mListView->setShowSortIndicator( true ); + mListView->addColumn( i18n("Folder") ); + mListView->addColumn( i18n("Folder ID"), 0 ); + setMainWidget( mListView ); + updateFolderView(); + connect( manager, SIGNAL( foldersUpdated() ), SLOT( updateFolderView() ) ); +} + +SloxFolderDialog::~SloxFolderDialog() +{ + QMap<QString, SloxFolder*> folders = mManager->folders(); + QMap<QString, SloxFolder*>::Iterator it; + for ( it = folders.begin(); it != folders.end(); ++it ) + (*it)->item = 0; +} + +void SloxFolderDialog::updateFolderView() +{ + QString selected = selectedFolder(); + mListView->clear(); + QMap<QString, SloxFolder*> folders = mManager->folders(); + QMap<QString, SloxFolder*>::Iterator it; + for ( it = folders.begin(); it != folders.end(); ++it ) + createFolderViewItem( *it ); + setSelectedFolder( selected ); +} + +void SloxFolderDialog::slotUser1( ) +{ + mManager->requestFolders(); +} + +void SloxFolderDialog::createFolderViewItem( SloxFolder *folder ) +{ + if ( folder->item ) + return; + if ( folder->type() != mFolderType && folder->type() != Unbound ) + return; + if( mManager->folders().contains( folder->parentId() ) ) { + SloxFolder *parent = mManager->folders()[folder->parentId()]; + createFolderViewItem( parent ); + if ( parent->item ) + folder->item = new KListViewItem( parent->item ); + else + folder->item = new KListViewItem( mListView ); + } else { + folder->item = new KListViewItem( mListView ); + } + folder->item->setText( 0, folder->name() ); + folder->item->setText( 1, folder->id() ); + KGlobal::instance()->iconLoader()->addAppDir( "kmail" ); + switch ( folder->type() ) { + case Calendar: + folder->item->setPixmap( 0, SmallIcon( "kmgroupware_folder_calendar" ) ); + break; + case Tasks: + folder->item->setPixmap( 0, SmallIcon( "kmgroupware_folder_tasks" ) ); + break; + case Contacts: + folder->item->setPixmap( 0, SmallIcon( "kmgroupware_folder_contacts" ) ); + break; + default: + folder->item->setPixmap( 0, SmallIcon( "folder" ) ); + break; + } +} + +QString SloxFolderDialog::selectedFolder() const +{ + QListViewItem *item = mListView->selectedItem(); + if ( item ) + return item->text( 1 ); + return "-1"; // OX default folder +} + +void SloxFolderDialog::setSelectedFolder( const QString &id ) +{ + QMap<QString, SloxFolder*> folders = mManager->folders(); + QMap<QString, SloxFolder*>::Iterator it; + for ( it = folders.begin(); it != folders.end(); ++it ) { + if ( !(*it)->item ) + continue; + if ( (*it)->id() == id || ( ( id.isEmpty() || id == "-1" ) && (*it)->isDefault() ) ) { + mListView->setSelected( (*it)->item, true ); + mListView->ensureItemVisible( (*it)->item ); + break; + } + } +} + +#include "sloxfolderdialog.moc" diff --git a/kresources/slox/sloxfolderdialog.h b/kresources/slox/sloxfolderdialog.h new file mode 100644 index 000000000..37287d1b1 --- /dev/null +++ b/kresources/slox/sloxfolderdialog.h @@ -0,0 +1,55 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SLOXFOLDERDIALOG_H +#define SLOXFOLDERDIALOG_H + +#include <qstring.h> +#include <kdialogbase.h> + +#include "sloxfolder.h" + +class KListView; +class SloxFolder; +class SloxFolderManager; + +class SloxFolderDialog : public KDialogBase +{ + Q_OBJECT + public: + SloxFolderDialog( SloxFolderManager *manager, FolderType type, QWidget* parent = 0, const char *name = 0 ); + ~SloxFolderDialog(); + + QString selectedFolder() const; + void setSelectedFolder( const QString &id ); + + protected slots: + virtual void slotUser1(); + void updateFolderView(); + + private: + void createFolderViewItem( SloxFolder *folder ); + + private: + KListView *mListView; + SloxFolderManager *mManager; + QString mFolderId; + FolderType mFolderType; +}; + +#endif diff --git a/kresources/slox/sloxfoldermanager.cpp b/kresources/slox/sloxfoldermanager.cpp new file mode 100644 index 000000000..b693767ca --- /dev/null +++ b/kresources/slox/sloxfoldermanager.cpp @@ -0,0 +1,172 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + Copyright (c) 2005 by Florian Schröder <florian@deltatauchi.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <qfile.h> +#include <qdom.h> +#include <qstring.h> + +#include <kdebug.h> +#include <kio/job.h> +#include <kio/davjob.h> +#include <klocale.h> +#include <kstandarddirs.h> + +#include "sloxbase.h" +#include "sloxfolder.h" +#include "sloxfoldermanager.h" +#include "webdavhandler.h" + + +SloxFolderManager::SloxFolderManager( SloxBase *res, const KURL & baseUrl ) : + mDownloadJob( 0 ), + mBaseUrl( baseUrl ), + mRes( res ) +{ + kdDebug() << k_funcinfo << baseUrl << endl; + readFolders(); +} + +SloxFolderManager::~SloxFolderManager() +{ + if ( mDownloadJob ) + mDownloadJob->kill(); + QMap<QString, SloxFolder*>::Iterator it; + for ( it = mFolders.begin(); it != mFolders.end(); ++it ) + delete *it; + mFolders.clear(); +} + +void SloxFolderManager::requestFolders() +{ + kdDebug() << k_funcinfo << endl; + + if ( mDownloadJob ) { + kdDebug() << k_funcinfo << "Download still in progress" << endl; + return; + } + + KURL url = mBaseUrl; + url.setPath( "/servlet/webdav.folders/file.xml" ); + + QDomDocument doc; + QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" ); + QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "objectmode", "NEW_AND_MODIFIED" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "lastsync", "0" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "foldertype", "PRIVATE" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "foldertype", "PUBLIC" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "foldertype", "SHARED" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "foldertype", "GLOBALADDRESSBOOK" ); + WebdavHandler::addSloxElement( mRes, doc, prop, "foldertype", "INTERNALUSERS" ); + + kdDebug() << k_funcinfo << doc.toString( 2 ) << endl; + + mDownloadJob = KIO::davPropFind( url, doc, "0", false ); + + connect( mDownloadJob, SIGNAL( result( KIO::Job * ) ), + SLOT( slotResult( KIO::Job * ) ) ); +} + +void SloxFolderManager::slotResult( KIO::Job *job ) +{ + kdDebug() << k_funcinfo << endl; + + if ( job->error() ) { + job->showErrorDialog( 0 ); + } else { + kdDebug() << k_funcinfo << " success, writing to " << cacheFile() << endl; + QFile f( cacheFile() ); + if ( !f.open( IO_WriteOnly ) ) { + kdDebug() << "Unable to open '" << cacheFile() << "'" << endl; + return; + } + QTextStream stream ( &f ); + stream << mDownloadJob->response(); + f.close(); + readFolders(); + } + + mDownloadJob = 0; + emit foldersUpdated(); +} + +QString SloxFolderManager::cacheFile() const +{ + QString host = mBaseUrl.host(); + + QString file = locateLocal( "cache", "slox/folders_" + host ); + + kdDebug() << k_funcinfo << file << endl; + + return file; +} + +void SloxFolderManager::readFolders() +{ + kdDebug() << k_funcinfo << endl; + + QFile f( cacheFile() ); + if ( !f.open( IO_ReadOnly ) ) { + kdDebug() << "Unable to open '" << cacheFile() << "'" << endl; + requestFolders(); + return; + } + + QDomDocument doc; + doc.setContent( &f ); + + mFolders.clear(); + + QDomNodeList nodes = doc.elementsByTagName( "D:prop" ); + for( uint i = 0; i < nodes.count(); ++i ) { + QDomElement element = nodes.item(i).toElement(); + QString id = "-1", parentId = "-1"; // OX default folder + bool def = false; + QString name, type; + QDomNode n; + for( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e = n.toElement(); + QString tag = e.tagName(); + QString value = e.text(); + if ( tag == "ox:object_id" ) id = value; + else if ( tag == "ox:folder_id" ) parentId = value; + else if ( tag == "ox:title" ) name = value; + else if ( tag == "ox:module" ) type = value; + else if ( tag == "ox:defaultfolder" ) def = (value == "true"); + } + if ( id != "-1" && parentId != "-1" ) { + SloxFolder *folder = new SloxFolder( id, parentId, type, name, def ); + mFolders[id] = folder; + kdDebug() << k_funcinfo << "Found folder: " << folder->name() << endl; + } + } + + // add top-level system folders that are not contained in the folder listing + SloxFolder *folder = new SloxFolder( "1", "0", "unbound", i18n("Private Folder") ); + mFolders[folder->id()] = folder; + folder = new SloxFolder( "2", "0", "unbound", i18n("Public Folder") ); + mFolders[folder->id()] = folder; + folder = new SloxFolder( "3", "0", "unbound", i18n("Shared Folder") ); + mFolders[folder->id()] = folder; + folder = new SloxFolder( "4", "0", "unbound", i18n("System Folder") ); + mFolders[folder->id()] = folder; +} + + +#include "sloxfoldermanager.moc" diff --git a/kresources/slox/sloxfoldermanager.h b/kresources/slox/sloxfoldermanager.h new file mode 100644 index 000000000..3adac2061 --- /dev/null +++ b/kresources/slox/sloxfoldermanager.h @@ -0,0 +1,66 @@ +/* + Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de> + Copyright (c) 2005 by Florian Schröder <florian@deltatauchi.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SLOXFOLDERMANAGER_H +#define SLOXFOLDERMANAGER_H + +#include <qmap.h> +#include <qobject.h> + +#include <kurl.h> + +#include <kdepimmacros.h> + +namespace KIO { +class Job; +class DavJob; +} + +class SloxBase; +class SloxFolder; + +class KDE_EXPORT SloxFolderManager : public QObject +{ + Q_OBJECT + public: + SloxFolderManager( SloxBase *res, const KURL &baseUrl ); + ~SloxFolderManager(); + + QMap<QString, SloxFolder*> folders() const { return mFolders; } + void requestFolders(); + + signals: + void foldersUpdated(); + + protected: + void readFolders(); + + QString cacheFile() const; + + protected slots: + void slotResult( KIO::Job * ); + + private: + KIO::DavJob *mDownloadJob; + KURL mBaseUrl; + QMap<QString, SloxFolder*> mFolders; + SloxBase *mRes; +}; + +#endif diff --git a/kresources/slox/testsloxaccounts.cpp b/kresources/slox/testsloxaccounts.cpp new file mode 100644 index 000000000..c1cc75d3e --- /dev/null +++ b/kresources/slox/testsloxaccounts.cpp @@ -0,0 +1,61 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "sloxaccounts.h" + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kcmdlineargs.h> + +#include <qpushbutton.h> + +static const KCmdLineOptions options[] = +{ + {"verbose", "Verbose output", 0}, + KCmdLineLastOption +}; + +int main(int argc,char **argv) +{ + KAboutData aboutData( "textsloxaccounts", + "SUSE LINUX Openexchange Server Configuration Wizard", + "0.1" ); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + bool verbose = false; + if ( args->isSet( "verbose" ) ) verbose = true; + + QPushButton button( "Close", 0 ); + + SloxAccounts::setServer( "f85.suse.de" ); + SloxAccounts::self(); + + app.setMainWidget( &button ); + button.show(); + QObject::connect( &button, SIGNAL( clicked() ), &app, SLOT( quit() ) ); + + app.exec(); +} diff --git a/kresources/slox/webdavhandler.cpp b/kresources/slox/webdavhandler.cpp new file mode 100644 index 000000000..511373d51 --- /dev/null +++ b/kresources/slox/webdavhandler.cpp @@ -0,0 +1,295 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "webdavhandler.h" +#include "sloxbase.h" + +#ifdef HAVE_VALUES_H +#include <values.h> +#else +#ifdef HAVE_SYS_LIMITS_H +#include <sys/limits.h> +#endif +#endif + +#include <config.h> +#include <stdlib.h> + +#include <libkcal/incidence.h> + +#include <libkdepim/kpimprefs.h> + +#include <kdebug.h> +#include <kconfig.h> + +#include <qfile.h> + +SloxItem::SloxItem() + : status( Invalid ) +{ +} + +WebdavHandler::WebdavHandler() + : mLogCount( 0 ) +{ + KConfig cfg( "sloxrc" ); + + cfg.setGroup( "General" ); + mLogFile = cfg.readEntry( "LogFile" ); + + kdDebug() << "LOG FILE: " << mLogFile << endl; +} + +void WebdavHandler::setUserId( const QString &id ) +{ + mUserId = id; +} + +QString WebdavHandler::userId() const +{ + return mUserId; +} + + +void WebdavHandler::log( const QString &text ) +{ + if ( mLogFile.isEmpty() ) return; + + QString filename = mLogFile + "-" + QString::number( mLogCount ); + QFile file( filename ); + if ( !file.open( IO_WriteOnly ) ) { + kdWarning() << "Unable to open log file '" << filename << "'" << endl; + return; + } + + QCString textUtf8 = text.utf8(); + file.writeBlock( textUtf8.data(), textUtf8.size() - 1 ); + + if ( ++mLogCount > 5 ) mLogCount = 0; +} + +QValueList<SloxItem> WebdavHandler::getSloxItems( SloxBase *res, const QDomDocument &doc ) +{ + kdDebug() << "getSloxItems" << endl; + + QValueList<SloxItem> items; + + QDomElement docElement = doc.documentElement(); + + QDomNode responseNode; + for( responseNode = docElement.firstChild(); !responseNode.isNull(); + responseNode = responseNode.nextSibling() ) { + QDomElement responseElement = responseNode.toElement(); + if ( responseElement.tagName() == "response" ) { + SloxItem item; + + QDomNode propstat = responseElement.namedItem( "propstat" ); + if ( propstat.isNull() ) { + kdError() << "Unable to find propstat tag." << endl; + continue; + } + + QDomNode prop = propstat.namedItem( "prop" ); + if ( prop.isNull() ) { + kdError() << "Unable to find WebDAV property" << endl; + continue; + } + item.domNode = prop; + + QDomNode sloxIdNode = prop.namedItem( res->fieldName( SloxBase::ObjectId ) ); + if ( sloxIdNode.isNull() ) { + kdError() << "Unable to find SLOX id." << endl; + continue; + } + QDomElement sloxIdElement = sloxIdNode.toElement(); + item.sloxId = sloxIdElement.text(); + + QDomNode clientIdNode = prop.namedItem( res->fieldName( SloxBase::ClientId ) ); + if ( !clientIdNode.isNull() ) { + QDomElement clientIdElement = clientIdNode.toElement(); + item.clientId = clientIdElement.text(); + if ( item.clientId != item.sloxId ) + item.status = SloxItem::New; + } + + QDomNode sloxStatus = prop.namedItem( res->fieldName( SloxBase::ObjectStatus ) ); + if ( !sloxStatus.isNull() ) { + QDomElement sloxStatusElement = sloxStatus.toElement(); + if ( sloxStatusElement.text() == "DELETE" ) { + item.status = SloxItem::Delete; + } else if ( sloxStatusElement.text() == "CREATE" ) { + item.status = SloxItem::Create; + } + } + + QDomNode status = propstat.namedItem( "status" ); + if ( status.isNull() ) { + kdError() << "Unable to find WebDAV status" << endl; + continue; + } + item.response = status.toElement().text(); + + QDomNode desc = propstat.namedItem( "responsedescription" ); + if ( desc.isNull() ) { + kdError() << "Unable to find WebDAV responsedescription" << endl; + continue; + } + item.responseDescription = desc.toElement().text(); + + items.append( item ); + } + } + + return items; +} + +QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt ) +{ + uint ticks = -dt.secsTo( QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0 ) ) ); + + return QString::number( ticks ) + "000"; +} + +QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt, + const QString &timeZoneId ) +{ + QDateTime utc = KPimPrefs::localTimeToUtc( dt, timeZoneId ); + + // secsTo and toTime_t etc also perform a timezone conversion using the system timezone, + // but we want to use the calendar timezone, so we have to convert ourself and spoof the tz to UTC before + // converting to ticks to prevent this + QCString origTz = getenv("TZ"); + setenv( "TZ", "UTC", 1 ); + uint ticks = utc.toTime_t(); + if ( origTz.isNull() ) + unsetenv( "TZ" ); + else + setenv( "TZ", origTz, 1 ); + + return QString::number( ticks ) + "000"; +} + +QDateTime WebdavHandler::sloxToQDateTime( const QString &str ) +{ + QString s = str.mid( 0, str.length() - 3 ); + + bool preEpoch = s.startsWith("-"); + if (preEpoch) + s = s.mid(1); + + unsigned long ticks = s.toULong(); + + QDateTime dt; + + if (preEpoch) { + dt.setTime_t( 0, Qt::UTC ); + if (ticks > INT_MAX) { + dt = dt.addSecs(-INT_MAX); + ticks -= INT_MAX; + } + dt = dt.addSecs(-((long) ticks)); + } + else + { + dt.setTime_t( ticks, Qt::UTC ); + } + + return dt; +} + +QDateTime WebdavHandler::sloxToQDateTime( const QString &str, + const QString &timeZoneId ) +{ + return KPimPrefs::utcToLocalTime( sloxToQDateTime(str), timeZoneId ); +} + +QDomElement WebdavHandler::addElement( QDomDocument &doc, QDomNode &node, + const QString &tag ) +{ + QDomElement el = doc.createElement( tag ); + node.appendChild( el ); + return el; +} + +QDomElement WebdavHandler::addDavElement( QDomDocument &doc, QDomNode &node, + const QString &tag ) +{ + QDomElement el = doc.createElementNS( "DAV:", "D:" + tag ); + node.appendChild( el ); + return el; +} + +QDomElement WebdavHandler::addSloxElement( SloxBase *res, + QDomDocument &doc, QDomNode &node, + const QString &tag, + const QString &text ) +{ + QDomElement el; + if ( res->resType() == "ox" ) + el = doc.createElementNS( "http://www.open-xchange.org", "ox:" + tag ); + else + el = doc.createElementNS( "SLOX", "S:" + tag ); + if ( !text.isEmpty() ) { + QDomText textnode = doc.createTextNode( text ); + el.appendChild( textnode ); + } + node.appendChild( el ); + return el; +} + +void WebdavHandler::parseSloxAttribute( const QDomElement &e ) +{ +// kdDebug() << "parseSloxAttribute" << endl; + + QString tag = e.tagName(); + QString text = QString::fromUtf8( e.text().latin1() ); + if ( text.isEmpty() ) return; + + if ( tag == "owner" ) { + if ( text == mUserId ) mWritable = true; + } else if ( tag == "writerights" ) { + QDomNode n; + for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) { + QDomElement e2 = n.toElement(); + if ( e2.tagName() == "member" ) { + if ( e2.text() == mUserId ) mWritable = true; + } + // TODO: Process group write rights + } + } +} + +void WebdavHandler::clearSloxAttributeStatus() +{ + if ( mRes->resType() == "ox" ) + mWritable = true; // parseSloxAttribute() won't work for OX + else + mWritable = false; +} + +void WebdavHandler::setSloxAttributes( KCal::Incidence *i ) +{ + i->setReadOnly( !mWritable ); +} + +void WebdavHandler::setSloxAttributes( KABC::Addressee & ) +{ + // FIXME: libkabc doesn't allow to set an individual addressee to read-only +} diff --git a/kresources/slox/webdavhandler.h b/kresources/slox/webdavhandler.h new file mode 100644 index 000000000..b41499a4a --- /dev/null +++ b/kresources/slox/webdavhandler.h @@ -0,0 +1,96 @@ +/* + This file is part of kdepim. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef WEBDAVHANDLER_H +#define WEBDAVHANDLER_H + +#include <qvaluelist.h> +#include <qstring.h> +#include <qdatetime.h> +#include <qdom.h> + +#include <kdepimmacros.h> +#include <kabc/addressee.h> + +namespace KCal { +class Incidence; +} + +class SloxBase; + +class KDE_EXPORT SloxItem +{ + public: + enum Status { Invalid, Delete, Create, New }; + + SloxItem(); + + QDomNode domNode; + QString sloxId; + QString clientId; + Status status; + QString response; + QString responseDescription; +}; + +class KDE_EXPORT WebdavHandler +{ + public: + WebdavHandler(); + + void setUserId( const QString & ); + QString userId() const; + void setResource( SloxBase *res ) { mRes = res; } + + void log( const QString & ); + + static QDomElement addElement( QDomDocument &, QDomNode &, + const QString &tag ); + static QDomElement addDavElement( QDomDocument &, QDomNode &, + const QString &tag ); + static QDomElement addSloxElement( SloxBase *res, + QDomDocument &, QDomNode &, + const QString &tag, + const QString &text = QString::null ); + + static QDateTime sloxToQDateTime( const QString &str ); + static QDateTime sloxToQDateTime( const QString &str, + const QString &timeZoneId ); + static QString qDateTimeToSlox( const QDateTime &dt ); + static QString qDateTimeToSlox( const QDateTime &dt, + const QString &timeZoneId ); + + static QValueList<SloxItem> getSloxItems( SloxBase *res, const QDomDocument &doc ); + + void clearSloxAttributeStatus(); + void parseSloxAttribute( const QDomElement & ); + void setSloxAttributes( KCal::Incidence * ); + void setSloxAttributes( KABC::Addressee & ); + + private: + QString mLogFile; + int mLogCount; + SloxBase *mRes; + + QString mUserId; + + bool mWritable; +}; + +#endif |