[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-pim
Subject:    [Kde-pim] [PATCH] OpenXchange support
From:       Volker Krause <volker.krause () rwth-aachen ! de>
Date:       2005-07-31 20:10:19
Message-ID: 200507312211.16474.volker.krause () rwth-aachen ! de
[Download RAW message or body]

[Attachment #2 (multipart/signed)]

[Attachment #4 (multipart/mixed)]


Hi,

the attached patch + files (by Florian Schröder and myself) add support for 
the OpenXchange groupware server to the SLOX resource. Since the SLOX and OX 
protocols are very similar, it IMHO doesn't make sense to create a complete 
new resource for OX.

Additionally to the features of the SLOX resource, this adds:
- Folder listing and selection
- Reading of address data for contacts
- Reading of participant status
This will only work with OX servers, but should be easy to add for SLOX as 
well (given a SLOX protocol documentation).

The currently only known issue is that the reading of recurrences is far from 
perfect, it currently only covers the most basic cases.

It has been tested with a 0.8.0-4 OpenXchange server and SuSE's public SLOX 
evaluation server (openexchange.suse.de).

Ok to commit?

regards
Volker



["kabc_ox.desktop" (application/x-desktop)]
["sloxbase.cpp" (text/x-c++src)]

/*
    Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de>
    Copyright (c) 2005 by Florian Schr�er <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"},
  // incidence fields
  {"title", "title"},
  {"description", "note"},
  {"members", "participants"},
  {"member", "user"},
  {"reminder", "alarm"},
  // recurrence fields
  {"date_sequence", "recurrence_type"},
  {"ds_ends", "until"},
  // 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"},
  {"displayname", "displayname"}, // FIXME: what's this in SLOX?
  {"title", "title"},
  {"department", "company"},
  {"phone", "phone_business"},
  {"phone2", "phone_business2"},
  {"mobile", "mobile1"},
  {"mobile2", "mobile1"}, // OX only has two mobile phone fields, the other one is used below
  {"fax", "fax"},
  {"fax2", "fax_business"},
  {"privatephone", "phone_home"},
  {"privatephone2", "phone_home2"},
  {"privatemobile", "mobile2"},
  {"privatemobile2", "mobile2"}, // OX only has two mobile phone fiels, see above
  {"privatefax", "fax_home"},
  {"privatefax2", "fax_other"},
  {"email", "email1"},
  {"birthday", "birthday"},
  {"privateurl", "url"},
  {"comment", "note"}
};

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";
}

["kabc_slox.desktop" (application/x-desktop)]
["ox-support.diff" (text/x-diff)]

Index: kresources_kabc_slox.kcfg
===================================================================
--- kresources_kabc_slox.kcfg	(revision 441699)
+++ kresources_kabc_slox.kcfg	(working copy)
@@ -19,6 +19,10 @@
       <label>Only load data since last sync</label>
       <default>true</default>
     </entry>
+    <entry type="String" name="FolderId">
+      <label>Folder ID</label>
+      <default></default>
+    </entry>
   </group>
 
 </kcfg>
Index: kabcresourcesloxconfig.cpp
===================================================================
--- kabcresourcesloxconfig.cpp	(revision 441699)
+++ kabcresourcesloxconfig.cpp	(working copy)
@@ -22,6 +22,10 @@
 
 #include "kabcresourceslox.h"
 #include "kabcsloxprefs.h"
+#include "sloxbase.h"
+#include "sloxfolder.h"
+#include "sloxfolderdialog.h"
+#include "sloxfoldermanager.h"
 
 #include <kdebug.h>
 #include <kdialog.h>
@@ -35,9 +39,9 @@
 using namespace KABC;
 
 ResourceSloxConfig::ResourceSloxConfig( QWidget* parent,  const char* name )
-  : KRES::ConfigWidget( parent, name )
+  : KRES::ConfigWidget( parent, name ), mRes( 0 )
 {
-  QGridLayout *mainLayout = new QGridLayout( this, 4, 2, 0, KDialog::spacingHint() \
); +  QGridLayout *mainLayout = new QGridLayout( this, 5, 2, 0, \
KDialog::spacingHint() );  
   QLabel *label = new QLabel( i18n( "URL:" ), this );
   mURL = new KURLRequester( this );
@@ -57,26 +61,36 @@
 
   mainLayout->addWidget( label, 3, 0 );
   mainLayout->addWidget( mPassword, 3, 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() );
+  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;
@@ -85,6 +99,16 @@
   resource->prefs()->setUrl( mURL->url() );
   resource->prefs()->setUser( mUser->text() );
   resource->prefs()->setPassword( mPassword->text() );
+  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"
Index: webdavhandler.cpp
===================================================================
--- webdavhandler.cpp	(revision 441699)
+++ webdavhandler.cpp	(working copy)
@@ -19,6 +19,7 @@
 */
 
 #include "webdavhandler.h"
+#include "sloxbase.h"
 
 #ifdef HAVE_VALUES_H
 #include <values.h>
@@ -76,14 +77,14 @@
     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( const QDomDocument &doc )
+QValueList<SloxItem> WebdavHandler::getSloxItems( SloxBase *res, const QDomDocument \
&doc )  {
   kdDebug() << "getSloxItems" << endl;
 
@@ -108,7 +109,7 @@
         continue;
       }
 
-      QDomNode sloxIdNode = prop.namedItem( "sloxid" );
+      QDomNode sloxIdNode = prop.namedItem( res->fieldName( SloxBase::ObjectId ) );
       if ( sloxIdNode.isNull() ) {
         kdError() << "Unable to find SLOX id." << endl;
         continue;
@@ -116,7 +117,7 @@
       QDomElement sloxIdElement = sloxIdNode.toElement();
       QString sloxId = sloxIdElement.text();
 
-      QDomNode sloxStatus = prop.namedItem( "sloxstatus" );
+      QDomNode sloxStatus = prop.namedItem( res->fieldName( SloxBase::ObjectStatus ) \
);  if ( sloxStatus.isNull() ) {
         kdError() << "Unable to find SLOX status." << endl;
         continue;
@@ -136,7 +137,7 @@
       items.append( item );
     }
   }
-  
+
   return items;
 }
 
@@ -153,8 +154,8 @@
   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 
+  // 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();
@@ -208,19 +209,27 @@
   return el;
 }
 
-QDomElement WebdavHandler::addDavElement( QDomDocument &doc, QDomNode &node,
+QDomElement WebdavHandler::addDavElement( SloxBase *res,
+                                          QDomDocument &doc, QDomNode &node,
                                           const QString &tag )
 {
-  QDomElement el = doc.createElementNS( "DAV", tag );
+  QDomElement el = doc.createElementNS( "DAV:", tag );
+  if ( res->resType() == "ox" )
+    el.setAttribute("xmlns:ox","http://www.open-xchange.org");
   node.appendChild( el );
   return el;
 }
 
-QDomElement WebdavHandler::addSloxElement( QDomDocument &doc, QDomNode &node,
+QDomElement WebdavHandler::addSloxElement( SloxBase *res,
+                                           QDomDocument &doc, QDomNode &node,
                                            const QString &tag,
                                            const QString &text )
 {
-  QDomElement el = doc.createElementNS( "SLOX", tag );
+  QDomElement el;
+  if ( res->resType() == "ox" )
+    el = doc.createElement( "ox:" + tag );
+  else
+    el = doc.createElementNS( "SLOX", "S:" + tag );
   if ( !text.isEmpty() ) {
     QDomText textnode = doc.createTextNode( text );
     el.appendChild( textnode );
@@ -253,7 +262,10 @@
 
 void WebdavHandler::clearSloxAttributeStatus()
 {
-  mWritable = false;
+  if ( mRes->resType() == "ox" )
+    mWritable = true; // parseSloxAttribute() won't work for OX
+  else
+    mWritable = false;
 }
 
 void WebdavHandler::setSloxAttributes( KCal::Incidence *i )
Index: kabcresourcesloxconfig.h
===================================================================
--- kabcresourcesloxconfig.h	(revision 441699)
+++ kabcresourcesloxconfig.h	(working copy)
@@ -25,11 +25,14 @@
 
 class KLineEdit;
 class KURLRequester;
+class KPushButton;
 
+class SloxBase;
+
 namespace KABC {
 
 class KDE_EXPORT ResourceSloxConfig : public KRES::ConfigWidget
-{ 
+{
   Q_OBJECT
 
   public:
@@ -39,10 +42,16 @@
     void loadSettings( KRES::Resource* );
     void saveSettings( KRES::Resource* );
 
+  private slots:
+    void selectAddressFolder();
+
   private:
     KURLRequester *mURL;
     KLineEdit *mUser;
     KLineEdit *mPassword;
+    KPushButton *mFolderButton;
+    QString mFolderId;
+    SloxBase *mRes;
 };
 
 }
Index: webdavhandler.h
===================================================================
--- webdavhandler.h	(revision 441699)
+++ webdavhandler.h	(working copy)
@@ -32,12 +32,8 @@
 class Incidence;
 }
 
-#include <kabc/addressee.h>
+class SloxBase;
 
-namespace KCal {
-class Incidence;
-}
-
 class KDE_EXPORT SloxItem
 {
   public:
@@ -57,14 +53,17 @@
 
     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 &,
+    static QDomElement addDavElement( SloxBase *res,
+                                      QDomDocument &, QDomNode &,
                                       const QString &tag );
-    static QDomElement addSloxElement( QDomDocument &, QDomNode &,
+    static QDomElement addSloxElement( SloxBase *res,
+                                       QDomDocument &, QDomNode &,
                                        const QString &tag,
                                        const QString &text = QString::null );
 
@@ -75,7 +74,7 @@
     static QString qDateTimeToSlox( const QDateTime &dt,
                                     const QString &timeZoneId );
 
-    static QValueList<SloxItem> getSloxItems( const QDomDocument &doc );
+    static QValueList<SloxItem> getSloxItems( SloxBase *res, const QDomDocument &doc \
);  
     void clearSloxAttributeStatus();
     void parseSloxAttribute( const QDomElement & );
@@ -85,9 +84,10 @@
   private:
     QString mLogFile;
     int mLogCount;
+    SloxBase *mRes;
 
     QString mUserId;
-    
+
     bool mWritable;
 };
 
Index: kresources_kcal_slox.kcfg
===================================================================
--- kresources_kcal_slox.kcfg	(revision 441699)
+++ kresources_kcal_slox.kcfg	(working copy)
@@ -25,6 +25,14 @@
       <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>
Index: kcalresourcesloxconfig.cpp
===================================================================
--- kcalresourcesloxconfig.cpp	(revision 441699)
+++ kcalresourcesloxconfig.cpp	(working copy)
@@ -28,22 +28,25 @@
 #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 )
+KCalResourceSloxConfig::KCalResourceSloxConfig( QWidget* parent,  const char* name ) \
: +  KRES::ConfigWidget( parent, name ), mRes( 0 )
 {
-  resize( 245, 115 ); 
-  QGridLayout *mainLayout = new QGridLayout( this, 2, 2 );
+  resize( 245, 115 );
+  QGridLayout *mainLayout = new QGridLayout( this, 6, 2, KDialog::spacingHint(), \
KDialog::spacingHint() );  
-  // FIXME: Post 3.2: i18n("Download from:") ( bug 67330 )
-  QLabel *label = new QLabel( i18n( "Download URL:" ), this );
+  QLabel *label = new QLabel( i18n( "Download from:" ), this );
 
   mDownloadUrl = new KURLRequester( this );
   mDownloadUrl->setMode( KFile::File );
@@ -52,13 +55,13 @@
 
   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 );
@@ -67,21 +70,36 @@
                                   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, 5, 5, 0, 1 );
+  mainLayout->addMultiCellWidget( mReloadConfig, 6, 6, 0, 1 );
 
   mSaveConfig = new KCal::ResourceCachedSaveConfig( this );
-  mainLayout->addMultiCellWidget( mSaveConfig, 6, 6, 0, 1 );
+  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 {
@@ -97,6 +115,8 @@
     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 {
@@ -104,4 +124,22 @@
   }
 }
 
+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"
Index: kabcresourceslox.cpp
===================================================================
--- kabcresourceslox.cpp	(revision 441699)
+++ kabcresourceslox.cpp	(working copy)
@@ -40,7 +40,7 @@
 using namespace KABC;
 
 ResourceSlox::ResourceSlox( const KConfig *config )
-  : Resource( config )
+  : Resource( config ), SloxBase( this )
 {
   init();
 
@@ -53,7 +53,7 @@
 
 ResourceSlox::ResourceSlox( const KURL &url,
                             const QString &user, const QString &password )
-  : Resource( 0 )
+  : Resource( 0 ), SloxBase( this )
 {
   init();
 
@@ -67,12 +67,11 @@
 void ResourceSlox::init()
 {
   mPrefs = new SloxPrefs;
+  mWebdavHandler.setResource( this );
 
-  setType( "slox" );
-
   mDownloadJob = 0;
   mProgress = 0;
-  
+
   setReadOnly( true );
 }
 
@@ -154,11 +153,15 @@
   url.setPass( mPrefs->password() );
 
   QDomDocument doc;
-  QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" );
-  QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" );
-  WebdavHandler::addSloxElement( doc, prop, "lastsync", "0" );
-  WebdavHandler::addSloxElement( doc, prop, "folderid" );
-  WebdavHandler::addSloxElement( doc, prop, "objecttype", "all" );
+  QDomElement root = WebdavHandler::addDavElement( this, doc, doc, "d:propfind" );
+  QDomElement prop = WebdavHandler::addDavElement( this, doc, root, "d:prop" );
+  WebdavHandler::addSloxElement( this, doc, prop, fieldName( LastSync ), "0" );
+  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;
 
@@ -190,7 +193,7 @@
 
     mWebdavHandler.log( doc.toString( 2 ) );
 
-    QValueList<SloxItem> items = WebdavHandler::getSloxItems( doc );
+    QValueList<SloxItem> items = WebdavHandler::getSloxItems( this, doc );
 
     bool changed = false;
 
@@ -241,53 +244,75 @@
 
 void ResourceSlox::parseContactAttribute( const QDomElement &e, Addressee &a )
 {
-  // FIXME: Why is the text still UTF8 encoded?
-  QString text = QString::fromUtf8( e.text().latin1() );
+  QString text = decodeText( e.text() );
   if ( text.isEmpty() ) return;
   QString tag = e.tagName();
 
-  if ( tag == "birthday" ) {
+  if ( tag == fieldName( Birthday ) ) {
     QDateTime dt = WebdavHandler::sloxToQDateTime( text );
     a.setBirthday( dt.date() );
   } else if ( tag == "position" ) {
     a.setRole( text );
   } else if ( tag == "salutation" ) {
     a.setPrefix( text );
-  } else if ( tag == "title" ) {
+  } else if ( tag == fieldName( Title ) ) {
     a.setTitle( text );
-  } else if ( tag == "department" ) {
+  } else if ( tag == fieldName( Organization ) ) {
     a.setOrganization( text );
-  } else if ( tag == "lastname" ) {
+  } else if ( tag == fieldName( FamilyName ) ) {
     a.setFamilyName( text );
-  } else if ( tag == "firstname" ) {
+  } else if ( tag == fieldName( GivenName) ) {
     a.setGivenName( text );
-  } else if ( tag == "email" ) {
+  } else if ( tag == fieldName( DisplayName ) ) {
+    a.setFormattedName( text );
+  } else if ( tag == fieldName( PrimaryEmail ) ) {
     a.insertEmail( text, true );
-  } else if ( tag == "phone" || tag == "phone2" ) {
+  } else if ( tag == fieldName( WorkPhone1 ) || tag == fieldName( WorkPhone2 ) ) {
     a.insertPhoneNumber( PhoneNumber( text, PhoneNumber::Work ) );
-  } else if ( tag == "mobile" || tag == "mobile2" ) {
+  } else if ( tag == fieldName( WorkMobile1 ) || tag == fieldName( WorkMobile2 ) ) {
     a.insertPhoneNumber( PhoneNumber( text, PhoneNumber::Cell |
                                       PhoneNumber:: Work ) );
-  } else if ( tag == "fax" || tag == "fax2" ) {
+  } else if ( tag == fieldName( WorkFax1 ) || tag == fieldName( WorkFax2 ) ) {
     a.insertPhoneNumber( PhoneNumber( text, PhoneNumber::Fax |
                                       PhoneNumber::Work ) );
-  } else if ( tag == "privatephone" || tag == "privatephone2" ) {
+  } else if ( tag == fieldName( PrivatePhone1 ) || tag == fieldName( PrivatePhone2 ) \
) {  a.insertPhoneNumber( PhoneNumber( text, PhoneNumber::Home ) );
-  } else if ( tag == "privatemobile" || tag == "privatemobile2" ) {
+  } else if ( tag == fieldName( PrivateMobile1 ) || tag == fieldName( PrivateMobile2 \
) ) {  a.insertPhoneNumber( PhoneNumber( text, PhoneNumber::Home |
                                       PhoneNumber::Cell ) );
-  } else if ( tag == "privatefax" || tag == "privatefax2" ) {
+  } else if ( tag == fieldName( PrivateFax1 ) || tag == fieldName( PrivateFax2 ) ) {
     a.insertPhoneNumber( PhoneNumber( text, PhoneNumber::Fax |
                                       PhoneNumber::Home ) );
-  } else if ( tag == "comment" ) {
+  } else if ( tag == fieldName( Comment ) ) {
     a.setNote( text );
   } else if ( tag == "email2" || tag == "privateemail" ||
               tag == "privateemail2" ) {
     a.insertEmail( text );
-  } else if ( tag == "privateurl" ) {
+  } else if ( tag == fieldName( Url ) ) {
     a.setUrl( text );
+  } else if ( type() == "ox" ) { // FIXME: Address reading is missing for SLOX
+    // read addresses
+    Address addr;
+    if ( tag.startsWith( "business" ) ) {
+      addr = a.address( KABC::Address::Work );
+    } else if ( tag.startsWith( "second" ) ) {
+      addr = a.address( 0 ); // FIXME: other ??
+    } else {
+      addr = a.address( KABC::Address::Home );
+    }
+    if ( tag.endsWith( "street" ) ) {
+      addr.setStreet( text );
+    } else if ( tag.endsWith( "postal_code" ) ) {
+      addr.setPostalCode( text );
+    } else if ( tag.endsWith( "city" ) ) {
+      addr.setLocality( text );
+    } else if ( tag.endsWith( "state" ) ) {
+      addr.setRegion( text );
+    } else if ( tag.endsWith( "country" ) ) {
+      addr.setCountry( text );
+    }
+    a.insertAddress( addr );
   }
-  // FIXME: Read addresses
 }
 
 bool ResourceSlox::save( Ticket* )
Index: kcalresourcesloxconfig.h
===================================================================
--- kcalresourcesloxconfig.h	(revision 441699)
+++ kcalresourcesloxconfig.h	(working copy)
@@ -28,19 +28,22 @@
 
 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 );
@@ -49,14 +52,24 @@
     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;    
+    QCheckBox *mLastSyncCheck;
+    KPushButton *mCalButton;
+    KPushButton *mTaskButton;
+    QString mCalendarFolderId;
+    QString mTaskFolderId;
 
     KCal::ResourceCachedReloadConfig *mReloadConfig;
     KCal::ResourceCachedSaveConfig *mSaveConfig;
+
+    SloxBase *mRes;
 };
 
 #endif
Index: kabcresourceslox.h
===================================================================
--- kabcresourceslox.h	(revision 441699)
+++ kabcresourceslox.h	(working copy)
@@ -20,6 +20,7 @@
 #ifndef KABC_RESOURCESLOX_H
 #define KABC_RESOURCESLOX_H
 
+#include "sloxbase.h"
 #include "webdavhandler.h"
 
 #include <kabc/resource.h>
@@ -43,7 +44,7 @@
 
 class SloxPrefs;
 
-class KDE_EXPORT ResourceSlox : public Resource
+class KDE_EXPORT ResourceSlox : public Resource, public SloxBase
 {
     Q_OBJECT
   public:
Index: sloxaccounts.cpp
===================================================================
--- sloxaccounts.cpp	(revision 441699)
+++ sloxaccounts.cpp	(working copy)
@@ -7,18 +7,20 @@
     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>
 
@@ -26,14 +28,16 @@
 #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( const KURL &baseUrl )
-  : mBaseUrl( baseUrl )
+SloxAccounts::SloxAccounts( SloxBase *res, const KURL &baseUrl )
+  : mBaseUrl( baseUrl ), mRes( res )
 {
   kdDebug() << "SloxAccounts(): " << baseUrl << endl;
 
@@ -63,7 +67,7 @@
   mUsers.replace( id, a );
 
   QString email = a.preferredEmail();
-  
+
   QString url = "http://" + mBaseUrl.host() + "/servlet/webdav.freebusy?username=";
   url += id + "&server=" + mDomain;
 
@@ -109,13 +113,31 @@
     return;
   }
 
-  KURL url = mBaseUrl;
-  url.addPath( "/servlet/webdav.groupuser" );
-  url.setQuery( "?user=*&group=*&groupres=*&res=*&details=t" );
+  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;
+    kdDebug() << "SloxAccounts::requestAccounts() URL: " << url << endl;
 
-  mDownloadJob = KIO::file_copy( url, cacheFile(), -1, true );
+    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( mRes, doc, doc, "d:propfind" );
+    QDomElement prop = WebdavHandler::addDavElement( mRes, doc, root, "d: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 * ) ) );
 }
@@ -127,8 +149,16 @@
   if ( job->error() ) {
     job->showErrorDialog( 0 );
   } else {
-    kdDebug() << "SloxAccounts::slotResult() success" << endl;
-  
+    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();
   }
 
@@ -164,29 +194,27 @@
 
   QDomElement docElement = doc.documentElement();
 
-  mUsers.clear();  
+  mUsers.clear();
 
-  QDomNode node;
-  for( node = docElement.firstChild(); !node.isNull();
-       node = node.nextSibling() ) {
-    QDomElement element = node.toElement();
-    if ( element.isNull() ) continue;
-    if ( element.tagName() == "user" ) {
-      QString id;
-      KABC::Addressee a;
-      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 == "uid" ) id = value;
-        else if ( tag == "mail" ) a.insertEmail( value );
-        else if ( tag == "forename" ) a.setGivenName( value );
-        else if ( tag == "surename" ) a.setFamilyName( value );
-      }
-//      kdDebug() << "MAIL: " << a.preferredEmail() << endl;
-      insertUser( id, a );
+  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 );
+      else if ( tag == "forename" ) a.setGivenName( value );
+      else if ( tag == "surename" ) a.setFamilyName( value );
     }
+//     kdDebug() << "MAIL: " << a.preferredEmail() << endl;
+    insertUser( id, a );
   }
 }
 
Index: kcalresourceslox.cpp
===================================================================
--- kcalresourceslox.cpp	(revision 441699)
+++ kcalresourceslox.cpp	(working copy)
@@ -60,7 +60,7 @@
 using namespace KCal;
 
 KCalResourceSlox::KCalResourceSlox( const KConfig *config )
-  : ResourceCached( config )
+  : ResourceCached( config ), SloxBase( this )
 {
   init();
 
@@ -72,7 +72,7 @@
 }
 
 KCalResourceSlox::KCalResourceSlox( const KURL &url )
-  : ResourceCached( 0 )
+  : ResourceCached( 0 ), SloxBase( this )
 {
   init();
 
@@ -101,6 +101,7 @@
 void KCalResourceSlox::init()
 {
   mPrefs = new SloxPrefs;
+  mWebdavHandler.setResource( this );
 
   mLoadEventsJob = 0;
   mLoadTodosJob = 0;
@@ -112,8 +113,6 @@
 
   mAccounts = 0;
 
-  setType( "slox" );
-
   mLock = new KABC::LockNull( true );
 
   enableChangeNotification();
@@ -132,7 +131,7 @@
   url.setPass( mPrefs->password() );
 
   delete mAccounts;
-  mAccounts = new SloxAccounts( url ); 
+  mAccounts = new SloxAccounts( this, url );
 }
 
 void KCalResourceSlox::writeConfig( KConfig *config )
@@ -211,11 +210,15 @@
   }
 
   QDomDocument doc;
-  QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" );
-  QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" );
-  WebdavHandler::addSloxElement( doc, prop, "lastsync", lastsync );
-  WebdavHandler::addSloxElement( doc, prop, "folderid" );
-  WebdavHandler::addSloxElement( doc, prop, "objecttype", "all" );
+  QDomElement root = WebdavHandler::addDavElement( this, doc, doc, "d:propfind" );
+  QDomElement prop = WebdavHandler::addDavElement( this, doc, root, "d: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;
 
@@ -252,11 +255,15 @@
   }
 
   QDomDocument doc;
-  QDomElement root = WebdavHandler::addDavElement( doc, doc, "propfind" );
-  QDomElement prop = WebdavHandler::addDavElement( doc, root, "prop" );
-  WebdavHandler::addSloxElement( doc, prop, "lastsync", lastsync );
-  WebdavHandler::addSloxElement( doc, prop, "folderid" );
-  WebdavHandler::addSloxElement( doc, prop, "objecttype", "all" );
+  QDomElement root = WebdavHandler::addDavElement( this, doc, doc, "d:propfind" );
+  QDomElement prop = WebdavHandler::addDavElement( this, doc, root, "d: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;
 
@@ -278,8 +285,8 @@
 void KCalResourceSlox::uploadIncidences()
 {
   QDomDocument doc;
-  QDomElement ms = WebdavHandler::addDavElement( doc, doc, "D:multistatus" );
-  QDomElement pu = WebdavHandler::addDavElement( doc, ms, "D:propertyupdate" );
+  QDomElement ms = WebdavHandler::addDavElement( this, doc, doc, "D:multistatus" );
+  QDomElement pu = WebdavHandler::addDavElement( this, doc, ms, "D:propertyupdate" \
);  QDomElement set = WebdavHandler::addElement( doc, pu, "D:set" );
   QDomElement prop = WebdavHandler::addElement( doc, set, "D:prop" );
 
@@ -314,7 +321,7 @@
 
   QString sloxId = mUploadedIncidence->customProperty( "SLOX", "ID" );
   if ( !sloxId.isEmpty() ) {
-    WebdavHandler::addSloxElement( doc, prop, "S:sloxid", sloxId );
+    WebdavHandler::addSloxElement( this, doc, prop, fieldName( ObjectId ), sloxId );
   } else {
     if ( mUploadIsDelete ) {
       kdError() << "Incidence to delete doesn't have a SLOX id" << endl;
@@ -323,7 +330,7 @@
       return;
     }
   }
-  WebdavHandler::addSloxElement( doc, prop, "S:clientid",
+  WebdavHandler::addSloxElement( this, doc, prop, fieldName( ClientId ),
                                  mUploadedIncidence->uid() );
 
   if ( mUploadIsDelete ) {
@@ -337,9 +344,13 @@
       return;
     }
 
-    QDomElement remove = WebdavHandler::addElement( doc, pu, "D:remove" );
-    QDomElement prop = WebdavHandler::addElement( doc, remove, "D:prop" );
-    WebdavHandler::addSloxElement( doc, prop, "S:sloxid", sloxId );
+    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
@@ -380,23 +391,28 @@
                                                   QDomElement &parent,
                                                   Incidence *incidence )
 {
-  WebdavHandler::addSloxElement( doc, parent, "S:title",
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( IncidenceTitle ),
                                  incidence->summary() );
 
-  WebdavHandler::addSloxElement( doc, parent, "S:description",
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( Description ),
                                  incidence->description() );
 
-  WebdavHandler::addSloxElement( doc, parent, "S:folderid" );
-
   if ( incidence->attendeeCount() > 0 ) {
-    QDomElement members = WebdavHandler::addSloxElement( doc, parent,
-                                                          "S:members" );
+    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() );
-        WebdavHandler::addSloxElement( doc, members, "S:member", userId );
+        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;
       }
@@ -404,16 +420,18 @@
   }
 
   // set read attributes - if SecrecyPublic, set it to users
-  if ( incidence->secrecy() == Incidence::SecrecyPublic )
+  // TODO OX support
+  if ( incidence->secrecy() == Incidence::SecrecyPublic && type() != "ox" )
   {
-    QDomElement rights = WebdavHandler::addSloxElement( doc, parent, "S:readrights" \
                );
-    WebdavHandler::addSloxElement( doc, rights, "S:group", "users" );
+    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( doc, parent, "S:reminder", QString::number( \
alarms.first()->startOffset().asSeconds() / 60 ) );; +    \
WebdavHandler::addSloxElement( this, doc, parent, fieldName( Reminder ), +            \
QString::number( alarms.first()->startOffset().asSeconds() / 60 ) );  
 }
 
@@ -421,18 +439,20 @@
                                               QDomElement &parent,
                                               Event *event )
 {
-  WebdavHandler::addSloxElement( doc, parent, "S:begins",
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( FolderId ), \
mPrefs->calendarFolderId() ); +
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( EventBegin ),
       WebdavHandler::qDateTimeToSlox( event->dtStart(), timeZoneId() ) );
 
-  WebdavHandler::addSloxElement( doc, parent, "S:ends",
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( EventEnd ),
       WebdavHandler::qDateTimeToSlox( event->dtEnd(), timeZoneId() ) );
 
-  WebdavHandler::addSloxElement( doc, parent, "S:location", event->location() );
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( Location ), \
event->location() );  
   if ( event->doesFloat() ) {
-    WebdavHandler::addSloxElement( doc, parent, "S:full_time", "yes" );
+    WebdavHandler::addSloxElement( this, doc, parent, fieldName( FullTime ), \
boolToStr( true ) );  } else {
-    WebdavHandler::addSloxElement( doc, parent, "S:full_time", "no" );
+    WebdavHandler::addSloxElement( this, doc, parent, fieldName( FullTime ), \
boolToStr( false ) );  }
 }
 
@@ -440,35 +460,36 @@
                                              QDomElement &parent,
                                              Todo *todo )
 {
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( FolderId ), \
mPrefs->taskFolderId() ); +
   if ( todo->hasStartDate() ) {
-    WebdavHandler::addSloxElement( doc, parent, "S:startdate",
+    WebdavHandler::addSloxElement( this, doc, parent, fieldName( TaskBegin ),
         WebdavHandler::qDateTimeToSlox( todo->dtStart(), timeZoneId() ) );
   }
 
   if ( todo->hasDueDate() ) {
-    WebdavHandler::addSloxElement( doc, parent, "S:deadline",
+    WebdavHandler::addSloxElement( this, doc, parent, fieldName( TaskEnd ),
         WebdavHandler::qDateTimeToSlox( todo->dtDue(), timeZoneId() ) );
   }
 
   int priority = todo->priority();
   QString txt;
   switch ( priority ) {
-    case 5:
-    case 4:
+    case 9:
+    case 8:
       txt = "1";
       break;
-    default:
-    case 3:
-      txt = "2";
-      break;
     case 2:
     case 1:
       txt = "3";
       break;
+    default:
+      txt = "2";
+      break;
   }
-  WebdavHandler::addSloxElement( doc, parent, "S:priority", txt );
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( Priority ), txt );
 
-  WebdavHandler::addSloxElement( doc, parent, "S:status",
+  WebdavHandler::addSloxElement( this, doc, parent, fieldName( PercentComplete ),
                                  QString::number( todo->percentComplete() ) );
 }
 
@@ -480,7 +501,7 @@
   QDomNode n;
   for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) {
     QDomElement memberElement = n.toElement();
-    if ( memberElement.tagName() == "member" ) {
+    if ( memberElement.tagName() == fieldName( Participant ) ) {
       QString member = memberElement.text();
       KABC::Addressee account;
       if ( mAccounts ) account = mAccounts->lookupUser( member );
@@ -505,6 +526,16 @@
         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;
@@ -530,14 +561,14 @@
                                                 Incidence *incidence )
 {
   QString tag = e.tagName();
-  QString text = QString::fromUtf8( e.text().latin1() );
+  QString text = decodeText( e.text() );
   if ( text.isEmpty() ) return;
 
-  if ( tag == "title" ) {
+  if ( tag == fieldName( IncidenceTitle ) ) {
     incidence->setSummary( text );
-  } else if ( e.tagName() == "description" ) {
+  } else if ( e.tagName() == fieldName( Description ) ) {
     incidence->setDescription( text );
-  } else if ( tag == "reminder" ) {
+  } else if ( tag == fieldName( Reminder ) ) {
     int minutes = text.toInt();
     // FIXME: What exactly means a "0" reminder?
     if ( minutes != 0 ) {
@@ -552,7 +583,7 @@
       alarm->setStartOffset( d );
       alarm->setEnabled( true );
     }
-  } else if ( tag == "members" ) {
+  } else if ( tag == fieldName( Participants ) ) {
     parseMembersAttribute( e, incidence );
   } else if ( tag == "readrights" ) {
     parseReadRightsAttribute( e, incidence );
@@ -563,15 +594,15 @@
                                             Event *event )
 {
   QString tag = e.tagName();
-  QString text = QString::fromUtf8( e.text().latin1() );
+  QString text = decodeText( e.text() );
   if ( text.isEmpty() ) return;
 
-  if ( tag == "begins" ) {
+  if ( tag == fieldName( EventBegin ) ) {
     QDateTime dt;
     if ( event->doesFloat() ) dt = WebdavHandler::sloxToQDateTime( text );
     else dt = WebdavHandler::sloxToQDateTime( text, timeZoneId() );
     event->setDtStart( dt );
-  } else if ( tag == "ends" ) {
+  } else if ( tag == fieldName( EventEnd ) ) {
     QDateTime dt;
     if ( event->doesFloat() ) {
       dt = WebdavHandler::sloxToQDateTime( text );
@@ -579,7 +610,7 @@
     }
     else dt = WebdavHandler::sloxToQDateTime( text, timeZoneId() );
     event->setDtEnd( dt );
-  } else if ( tag == "location" ) {
+  } else if ( tag == fieldName( Location ) ) {
     event->setLocation( text );
   }
 }
@@ -593,33 +624,34 @@
 
   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;
 
   QDomNode n;
-  
+
   for( n = node.firstChild(); !n.isNull(); n = n.nextSibling() ) {
     QDomElement e = n.toElement();
     QString tag = e.tagName();
-    QString text = QString::fromUtf8( e.text().latin1() );
-    
-    if ( tag == "date_sequence" ) {
+    QString text = decodeText( e.text() );
+
+    if ( tag == fieldName( RecurrenceType ) ) {
       type = text;
     } else if ( tag == "daily_value" ) {
       dailyValue = text.toInt();
-    } else if ( tag == "ds_ends" ) {
+    } else if ( tag == fieldName( RecurrenceEnd ) ) {
       end = WebdavHandler::sloxToQDateTime( text );
     } else if ( tag == "weekly_value" ) {
       weeklyValue = text.toInt();
@@ -649,11 +681,36 @@
       yearly2Day = text.toInt();
     } else if ( tag == "yearly2_month" ) {
       yearly2Month = text.toInt();
+    } else if ( tag == "interval" ) {
+      dailyValue = text.toInt();
+      weeklyValue = text.toInt();
+      monthlyValueMonth = text.toInt();
+      monthly2ValueMonth = text.toInt();
+    } else if ( tag == "days" ) {
+      int tmp = text.toInt();
+      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();
+      yearly2Day = text.toInt();
+    } else if ( tag == "month" ) {
+      yearlyMonth = text.toInt() + 1; // starts at 0
+      yearly2Month = text.toInt() + 1;
     }
   }
-  
+
+  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" ) {
@@ -663,41 +720,41 @@
     r->addMonthlyDate( monthlyValueDay );
   } else if ( type == "yearly" ) {
     r->setYearly( 1 );
-		r->addYearlyDate( yearlyValueDay );
+    r->addYearlyDate( yearlyValueDay );
     r->addYearlyMonth( yearlyMonth );
   } else if ( type == "monthly2" ) {
     r->setMonthly( monthly2ValueMonth );
     QBitArray days( 7 );
     days.setBit( event->dtStart().date().dayOfWeek() );
     r->addMonthlyPos( monthly2Recurrency, days );
-  } else if ( type == "yearly2" ) {  
+  } else if ( type == "yearly2" ) {
     r->setYearly( 1 );
-		r->addYearlyDate( yearly2Day );
+    r->addYearlyDate( yearly2Day );
     r->addYearlyMonth( yearly2Month );
   }
-	r->setEndDate( end.date() );
+  r->setEndDate( end.date() );
 }
 
 void KCalResourceSlox::parseTodoAttribute( const QDomElement &e,
                                            Todo *todo )
 {
   QString tag = e.tagName();
-  QString text = QString::fromUtf8( e.text().latin1() );
+  QString text = decodeText( e.text() );
   if ( text.isEmpty() ) return;
 
-  if ( tag == "startdate" ) {
+  if ( tag == fieldName( TaskBegin ) ) {
     QDateTime dt = WebdavHandler::sloxToQDateTime( text );
     if ( dt.isValid() ) {
       todo->setDtStart( dt );
       todo->setHasStartDate( true );
     }
-  } else if ( tag == "deadline" ) {
+  } else if ( tag == fieldName( TaskEnd ) ) {
     QDateTime dt = WebdavHandler::sloxToQDateTime( text );
     if ( dt.isValid() ) {
       todo->setDtDue( dt );
       todo->setHasDueDate( true );
     }
-  } else if ( tag == "priority" ) {
+  } else if ( tag == fieldName( Priority ) ) {
     int p = text.toInt();
     if ( p < 1 || p > 3 ) {
       kdError() << "Unknown priority: " << text << endl;
@@ -705,11 +762,11 @@
       int priority;
       switch ( p ) {
         case 1:
-          priority = 5;
+          priority = 9;
           break;
         default:
         case 2:
-          priority = 3;
+          priority = 5;
           break;
         case 3:
           priority = 1;
@@ -717,7 +774,7 @@
       }
       todo->setPriority( priority );
     }
-  } else if ( tag == "status" ) {
+  } else if ( tag == fieldName( PercentComplete ) ) {
     int completed = text.toInt();
     todo->setPercentComplete( completed );
   }
@@ -736,7 +793,7 @@
 
     mWebdavHandler.log( doc.toString( 2 ) );
 
-    QValueList<SloxItem> items = WebdavHandler::getSloxItems( doc );
+    QValueList<SloxItem> items = WebdavHandler::getSloxItems( this, doc );
 
     bool changed = false;
 
@@ -810,7 +867,7 @@
 
     mWebdavHandler.log( doc.toString( 2 ) );
 
-    QValueList<SloxItem> items = WebdavHandler::getSloxItems( doc );
+    QValueList<SloxItem> items = WebdavHandler::getSloxItems( this, doc );
 
     bool changed = false;
 
@@ -838,8 +895,8 @@
 
         event->setCustomProperty( "SLOX", "ID", item.sloxId );
 
-        QDomNode n = item.domNode.namedItem( "full_time" );
-        event->setFloats( n.toElement().text() == "yes" );
+        QDomNode n = item.domNode.namedItem( fieldName( FullTime ) );
+        event->setFloats( n.toElement().text() == boolToStr( true ) );
 
         bool doesRecur = false;
 
@@ -850,7 +907,7 @@
           mWebdavHandler.parseSloxAttribute( e );
           parseIncidenceAttribute( e, event );
           parseEventAttribute( e, event );
-          if ( e.tagName() == "date_sequence" && e.text() != "no" ) {
+          if ( e.tagName() == fieldName( RecurrenceType ) && e.text() != "no" ) {
             doesRecur = true;
           }
         }
@@ -916,12 +973,12 @@
           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 != "HTTP/1.1 200 OK" ) {
+        if ( !response.contains( "200" ) ) {
             QString error = "'" + mUploadedIncidence->summary() + "'\n";
             error += response;
             QDomNode dn = propstat.namedItem( "responsedescription" );
@@ -938,7 +995,7 @@
           continue;
         }
 
-        QDomNode sloxIdNode = prop.namedItem( "sloxid" );
+        QDomNode sloxIdNode = prop.namedItem( fieldName( ObjectId ) );
         if ( sloxIdNode.isNull() ) {
           kdError() << "Unable to find SLOX id." << endl;
           continue;
@@ -950,7 +1007,7 @@
         if ( mUploadIsDelete ) {
           kdDebug() << "Incidence deleted" << endl;
         } else {
-          QDomNode clientIdNode = prop.namedItem( "clientid" );
+          QDomNode clientIdNode = prop.namedItem( fieldName( ClientId ) );
           if ( clientIdNode.isNull() ) {
             kdError() << "Unable to find client id." << endl;
             continue;
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 441699)
+++ Makefile.am	(working copy)
@@ -3,7 +3,9 @@
 
 lib_LTLIBRARIES = libkslox.la libkabc_slox.la libkcal_slox.la
 
-libkslox_la_SOURCES = sloxaccounts.cpp webdavhandler.cpp
+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
@@ -38,10 +40,10 @@
 
 
 kcal_servicedir = $(kde_servicesdir)/kresources/kcal
-kcal_service_DATA = kcal_slox.desktop
+kcal_service_DATA = kcal_slox.desktop kcal_ox.desktop
 
 kabc_servicedir = $(kde_servicesdir)/kresources/kabc
-kabc_service_DATA = kabc_slox.desktop
+kabc_service_DATA = kabc_slox.desktop kabc_ox.desktop
 
 METASOURCES = AUTO
 
Index: sloxaccounts.h
===================================================================
--- sloxaccounts.h	(revision 441699)
+++ sloxaccounts.h	(working copy)
@@ -7,12 +7,12 @@
     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.
@@ -28,17 +28,19 @@
 class Job;
 }
 
+class SloxBase;
+
 class KDE_EXPORT SloxAccounts : public QObject
 {
     Q_OBJECT
   public:
-    SloxAccounts( const KURL &baseUrl );
+    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:
@@ -46,10 +48,10 @@
     void readAccounts();
 
     QString cacheFile() const;
-    
+
   protected slots:
     void slotResult( KIO::Job * );
-  
+
   private:
     QString mDomain;
 
@@ -58,6 +60,7 @@
     QMap<QString, KABC::Addressee> mUsers; // map users ids to addressees.
 
     KURL mBaseUrl;
+    SloxBase *mRes;
 };
 
 #endif
Index: kcalresourceslox.h
===================================================================
--- kcalresourceslox.h	(revision 441699)
+++ kcalresourceslox.h	(working copy)
@@ -20,6 +20,7 @@
 #ifndef KCALRESOURCESLOX_H
 #define KCALRESOURCESLOX_H
 
+#include "sloxbase.h"
 #include "webdavhandler.h"
 
 #include <qptrlist.h>
@@ -57,7 +58,7 @@
 /**
   This class provides a calendar stored as a remote file.
 */
-class KDE_EXPORT KCalResourceSlox : public KCal::ResourceCached
+class KDE_EXPORT KCalResourceSlox : public KCal::ResourceCached, public SloxBase
 {
     Q_OBJECT
 
@@ -66,11 +67,11 @@
   public:
     /**
       Reload policy.
-      
+
       @see setReloadPolicy(), reloadPolicy()
     */
     enum { ReloadNever, ReloadOnStartup, ReloadOnceADay, ReloadAlways };
-  
+
     /**
       Create resource from configuration information stored in KConfig object.
     */
@@ -93,7 +94,7 @@
     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 );
@@ -111,7 +112,7 @@
     void requestTodos();
 
     void uploadIncidences();
- 
+
     void parseMembersAttribute( const QDomElement &e,
                                 KCal::Incidence *incidence );
     void parseReadRightsAttribute( const QDomElement &e,


["sloxbase.h" (text/x-c++hdr)]

/*
    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,
      IncidenceTitle, // incidence fields
      Description,
      Participants,
      Participant,
      Reminder,
      RecurrenceType, // recurrence fields
      RecurrenceEnd,
      EventBegin,   // event fields
      EventEnd,
      Location,
      FullTime,
      TaskBegin,    // task fields
      TaskEnd,
      Priority,
      PercentComplete,
      FamilyName,   // contact fields
      GivenName,
      DisplayName,
      Title,
      Organization,
      WorkPhone1,
      WorkPhone2,
      WorkMobile1,
      WorkMobile2,
      WorkFax1,
      WorkFax2,
      PrivatePhone1,
      PrivatePhone2,
      PrivateMobile1,
      PrivateMobile2,
      PrivateFax1,
      PrivateFax2,
      PrimaryEmail,
      Birthday,
      Url,
      Comment
    };

    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

["sloxfolder.cpp" (text/x-c++src)]

/*
    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;
}


["sloxfolder.h" (text/x-c++hdr)]

/*
    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


["sloxfolderdialog.h" (text/x-c++hdr)]

/*
    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


["sloxfolderdialog.cpp" (text/x-c++src)]

/*
    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() );
  switch ( folder->type() ) {
    case Calendar:
    case Tasks:
    case Contacts:
      // TODO: add folder icons (as kmails resource folder icons)
      folder->item->setPixmap( 0, SmallIcon( "folder_yellow" ) );
      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"


["sloxfoldermanager.cpp" (text/x-c++src)]

/*
    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( mRes, doc, doc, "d:propfind" );
  QDomElement prop = WebdavHandler::addDavElement( mRes, doc, root, "d: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"

["sloxfoldermanager.h" (text/x-c++hdr)]

/*
    Copyright (c) 2005 by Volker Krause <volker.krause@rwth-aachen.de>
    Copyright (c) 2005 by Florian Schr=F6der <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-130=
1, 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

[Attachment #18 (application/pgp-signature)]

_______________________________________________
kde-pim mailing list
kde-pim@kde.org
https://mail.kde.org/mailman/listinfo/kde-pim
kde-pim home page at http://pim.kde.org/

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic