4 commits - docs/syncroton.sql lib/ext lib/init.php lib/kolab_sync_backend_common.php lib/kolab_sync_backend_content.php lib/kolab_sync_backend_device.php lib/kolab_sync_backend_folder.php lib/kolab_sync_backend.php lib/kolab_sync_backend_policy.php lib/kolab_sync_backend_state.php lib/kolab_sync_data_email.php lib/kolab_sync_data.php lib/kolab_sync_db.php lib/kolab_sync.php

Aleksander Machniak machniak at kolabsys.com
Sun Aug 19 12:16:36 CEST 2012


 docs/syncroton.sql                                 |  148 ++-
 lib/ext/Roundcube/rcube_mdb2.php                   |  935 ---------------------
 lib/ext/Syncroton/Backend/ABackend.php             |  156 +++
 lib/ext/Syncroton/Backend/Content.php              |  129 --
 lib/ext/Syncroton/Backend/Device.php               |  103 --
 lib/ext/Syncroton/Backend/Folder.php               |  212 +---
 lib/ext/Syncroton/Backend/IBackend.php             |   50 +
 lib/ext/Syncroton/Backend/IContent.php             |   18 
 lib/ext/Syncroton/Backend/IDevice.php              |   34 
 lib/ext/Syncroton/Backend/IFolder.php              |   33 
 lib/ext/Syncroton/Backend/ISyncState.php           |   18 
 lib/ext/Syncroton/Backend/Policy.php               |   24 
 lib/ext/Syncroton/Backend/SyncState.php            |  199 +---
 lib/ext/Syncroton/Command/FolderCreate.php         |   76 -
 lib/ext/Syncroton/Command/FolderDelete.php         |   28 
 lib/ext/Syncroton/Command/FolderSync.php           |   74 -
 lib/ext/Syncroton/Command/FolderUpdate.php         |   50 -
 lib/ext/Syncroton/Command/ItemOperations.php       |    3 
 lib/ext/Syncroton/Command/Options.php              |    8 
 lib/ext/Syncroton/Command/Ping.php                 |    8 
 lib/ext/Syncroton/Command/Provision.php            |   64 -
 lib/ext/Syncroton/Command/Search.php               |   73 -
 lib/ext/Syncroton/Command/SendMail.php             |   23 
 lib/ext/Syncroton/Command/SmartForward.php         |    2 
 lib/ext/Syncroton/Command/SmartReply.php           |    2 
 lib/ext/Syncroton/Command/Sync.php                 |   69 -
 lib/ext/Syncroton/Command/Wbxml.php                |   51 -
 lib/ext/Syncroton/Data/AData.php                   |   24 
 lib/ext/Syncroton/Data/Calendar.php                |    6 
 lib/ext/Syncroton/Data/Contacts.php                |   54 +
 lib/ext/Syncroton/Data/Email.php                   |   30 
 lib/ext/Syncroton/Data/Factory.php                 |    9 
 lib/ext/Syncroton/Data/IDataEmail.php              |   21 
 lib/ext/Syncroton/Data/Tasks.php                   |    6 
 lib/ext/Syncroton/Exception/ProvisioningNeeded.php |    1 
 lib/ext/Syncroton/Model/AEntry.php                 |   83 +
 lib/ext/Syncroton/Model/Contact.php                |   84 -
 lib/ext/Syncroton/Model/Email.php                  |  122 --
 lib/ext/Syncroton/Model/EmailAttachment.php        |   85 -
 lib/ext/Syncroton/Model/EmailBody.php              |   34 
 lib/ext/Syncroton/Model/Event.php                  |  101 --
 lib/ext/Syncroton/Model/EventAttendee.php          |   77 -
 lib/ext/Syncroton/Model/EventException.php         |    3 
 lib/ext/Syncroton/Model/EventRecurrence.php        |   39 
 lib/ext/Syncroton/Model/FileReference.php          |   50 -
 lib/ext/Syncroton/Model/Folder.php                 |   61 +
 lib/ext/Syncroton/Model/IDevice.php                |    4 
 lib/ext/Syncroton/Model/IFolder.php                |   10 
 lib/ext/Syncroton/Model/IPolicy.php                |   32 
 lib/ext/Syncroton/Model/Policy.php                 |   75 +
 lib/ext/Syncroton/Model/StoreRequest.php           |   11 
 lib/ext/Syncroton/Model/StoreResponse.php          |    2 
 lib/ext/Syncroton/Model/StoreResponseResult.php    |   31 
 lib/ext/Syncroton/Model/SyncCollection.php         |    2 
 lib/ext/Syncroton/Model/Task.php                   |   72 -
 lib/ext/Syncroton/Registry.php                     |   18 
 lib/ext/Syncroton/Server.php                       |   13 
 lib/init.php                                       |    2 
 lib/kolab_sync.php                                 |    1 
 lib/kolab_sync_backend.php                         |    7 
 lib/kolab_sync_backend_common.php                  |  225 +++++
 lib/kolab_sync_backend_content.php                 |  100 --
 lib/kolab_sync_backend_device.php                  |  110 --
 lib/kolab_sync_backend_folder.php                  |  157 +--
 lib/kolab_sync_backend_policy.php                  |   33 
 lib/kolab_sync_backend_state.php                   |  144 +--
 lib/kolab_sync_data.php                            |   32 
 lib/kolab_sync_data_email.php                      |   23 
 lib/kolab_sync_db.php                              |    2 
 69 files changed, 1675 insertions(+), 2911 deletions(-)

New commits:
commit 5d4a085f7752376684a33df2aaa1461f102e9144
Author: Aleksander Machniak <alec at alec.pl>
Date:   Sun Aug 19 12:16:06 2012 +0200

    Perf. optimization: replace two similiar queries with one

diff --git a/lib/kolab_sync_backend_state.php b/lib/kolab_sync_backend_state.php
index dfd2127..b239d36 100644
--- a/lib/kolab_sync_backend_state.php
+++ b/lib/kolab_sync_backend_state.php
@@ -150,47 +150,46 @@ class kolab_sync_backend_state extends kolab_sync_backend_common implements Sync
         $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
         $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
 
+        // get sync data for current request and check if it's the last one
+        // by fetching synckey+1
+        $states = array();
+        $keys   = array($_syncKey, $_syncKey + 1);
+
         $where['device_id'] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
         $where['type']      = $this->db->quote_identifier('type')      . ' = ' . $this->db->quote($folderId);
-        $where['counter']   = $this->db->quote_identifier('counter')   . ' = ' . $this->db->quote($_syncKey);
+        $where['counter']   = $this->db->quote_identifier('counter')   . ' IN (' . $this->db->array2list($keys, 'int') . ')';
 
-        $select = $this->db->query('SELECT * FROM syncroton_synckey WHERE ' . implode(' AND ', $where));
-        $state  = $this->db->fetch_assoc($select);
+        $select = $this->db->query('SELECT * FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
 
-        if (empty($state)) {
-            return false;
+        while ($row = $this->db->fetch_assoc($select)) {
+            $states[$row['counter']] = $this->get_object($row);
         }
 
-        $state = $this->get_object($state);
-
-        // check if this was the latest syncKey
-        $where['counter'] = $this->db->quote_identifier('counter')   . ' = ' . $this->db->quote($_syncKey + 1);
-
-        $select = $this->db->query('SELECT * FROM syncroton_synckey WHERE ' . implode(' AND ', $where));
-
-        if ($moreRecentState = $this->db->fetch_assoc($select)) {
-            $moreRecentState = $this->get_object($moreRecentState);
+        if (empty($states) || empty($states[$_syncKey])) {
+            return false;
         }
 
+        $state = $states[$_syncKey];
+
         $where = array();
         $where['device_id']  = $this->db->quote_identifier('device_id')  . ' = ' . $this->db->quote($deviceId);
         $where['folder_id']  = $this->db->quote_identifier('folder_id')  . ' = ' . $this->db->quote($folderId);
         $where['is_deleted'] = $this->db->quote_identifier('is_deleted') . ' = 1';
 
         // found more recent synckey => the last sync repsonse got not received by the client
-        if ($moreRecentState instanceof Syncroton_Model_ISyncState) {
+        if (!empty($states[$_syncKey + 1])) {
             $where['synckey'] = $this->db->quote_identifier('creation_synckey') . ' = ' . $this->db->quote($state->counter);
-            // undelete entries marked as deleted in Syncroton_content table
+            // undelete entries marked as deleted in syncroton_content table
             $this->db->query('UPDATE syncroton_content SET is_deleted = 0 WHERE ' . implode(' AND ', $where));
 
-            // remove entries added during latest sync in Syncroton_content table
+            // remove entries added during latest sync in syncroton_content table
             unset($where['is_deleted']);
             $where['synckey'] = $this->db->quote_identifier('creation_synckey') . ' > ' . $this->db->quote($state->counter);
 
             $this->db->query('DELETE FROM syncroton_content WHERE ' . implode(' AND ', $where));
         }
         else {
-            // finaly delete all entries marked for removal in Syncroton_content table
+            // finaly delete all entries marked for removal in syncroton_content table
             $this->db->query('DELETE FROM syncroton_content WHERE ' . implode(' AND ', $where));
         }
 


commit 7cea6c3a5b21241376669e6d5dc8e31b50df197b
Author: Aleksander Machniak <alec at alec.pl>
Date:   Sun Aug 19 12:02:49 2012 +0200

    FIx for the last API change, email default folder wasn't detected properly

diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index 46ec0d6..fa4d82f 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -439,10 +439,10 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         $folder_id = $this->defaultRootFolder;
 
         return array(
-            'displayname' => 'Inbox',
+            'displayName' => 'Inbox',
             'realid'      => $real_id,
-            'folderid'    => $folder_id,
-            'parentid'    => 0,
+            'serverId'    => $folder_id,
+            'parentId'    => 0,
             'type'        => $this->defaultFolderType,
         );
     }


commit ab953c68a3579f12ac22851f0ff9425dedd98ce6
Author: Aleksander Machniak <alec at alec.pl>
Date:   Sun Aug 19 11:20:31 2012 +0200

    Perf. optimization: don't call SELECT after INSERT, check last_insert_id and return function argument

diff --git a/lib/kolab_sync_backend_common.php b/lib/kolab_sync_backend_common.php
index 34e9623..c7c3b58 100644
--- a/lib/kolab_sync_backend_common.php
+++ b/lib/kolab_sync_backend_common.php
@@ -85,7 +85,7 @@ class kolab_sync_backend_common implements Syncroton_Backend_IBackend
         $data   = $this->object_to_array($object);
         $insert = array();
 
-        $data['id'] = sha1(mt_rand(). microtime());
+        $data['id'] = $object->id = sha1(mt_rand(). microtime());
 
         foreach ($data as $key => $value) {
             $insert[$this->db->quote_identifier($key)] = $this->db->quote($value);
@@ -94,7 +94,11 @@ class kolab_sync_backend_common implements Syncroton_Backend_IBackend
         $this->db->query('INSERT INTO ' . $this->table_name
             . ' (' . implode(', ', array_keys($insert)) . ')' . ' VALUES(' . implode(', ', $insert) . ')');
 
-        return $this->get($data['id']);
+        if (!$this->db->insert_id($this->table_name)) {
+            // @TODO: throw exception
+        }
+
+        return $object;
     }
 
     /**
@@ -156,11 +160,11 @@ class kolab_sync_backend_common implements Syncroton_Backend_IBackend
         $this->db->query('UPDATE ' . $this->table_name . ' SET ' . implode(', ', $set)
             . ' WHERE ' . $this->db->quote_identifier('id') . ' = ' . $this->db->quote($object->id));
 
-        return $this->get($object->id);
+        return $object;
     }
 
     /**
-     *
+     * Convert array into model object
      */
     protected function get_object($data)
     {
@@ -177,6 +181,9 @@ class kolab_sync_backend_common implements Syncroton_Backend_IBackend
         return new $this->class_name($data);
     }
 
+    /**
+     * Converts model object into array
+     */
     protected function object_to_array($object)
     {
         $data = array();
@@ -194,6 +201,9 @@ class kolab_sync_backend_common implements Syncroton_Backend_IBackend
         return $data;
     }
 
+    /**
+     * Convert property name from camel-case to lower-case-with-underscore
+     */
     protected function from_camelcase($string)
     {
         $string = lcfirst($string);
@@ -201,6 +211,9 @@ class kolab_sync_backend_common implements Syncroton_Backend_IBackend
         return preg_replace_callback('/([A-Z])/', function ($string) { return '_' . strtolower($string[0]); }, $string);
     }
 
+    /**
+     * Convert property name from lower-case-with-underscore to camel-case
+     */
     protected function to_camelcase($string, $ucFirst = true)
     {
         if ($ucFirst) {


commit 2fe0cfb2ca77a6e28c73ba4708c2f49984a84581
Author: Aleksander Machniak <alec at alec.pl>
Date:   Sun Aug 19 09:46:06 2012 +0200

    Update Syncroton, update code for the new API

diff --git a/docs/syncroton.sql b/docs/syncroton.sql
index bcd97b7..5e140d9 100644
--- a/docs/syncroton.sql
+++ b/docs/syncroton.sql
@@ -1,57 +1,125 @@
+CREATE TABLE IF NOT EXISTS `syncroton_policy` (
+    `id` varchar(40) NOT NULL,
+    `name` varchar(255) NOT NULL,
+    `description` varchar(255) DEFAULT NULL,
+    `policy_key` varchar(64) NOT NULL,
+    `allow_bluetooth` int(11) DEFAULT NULL,
+    `allow_browser` int(11) DEFAULT NULL,
+    `allow_camera` int(11) DEFAULT NULL,
+    `allow_consumer_email` int(11) DEFAULT NULL,
+    `allow_desktop_sync` int(11) DEFAULT NULL,
+    `allow_h_t_m_l_email` int(11) DEFAULT NULL,
+    `allow_internet_sharing` int(11) DEFAULT NULL,
+    `allow_ir_d_a` int(11) DEFAULT NULL,
+    `allow_p_o_p_i_m_a_p_email` int(11) DEFAULT NULL,
+    `allow_remote_desktop` int(11) DEFAULT NULL,
+    `allow_simple_device_password` int(11) DEFAULT NULL,
+    `allow_s_m_i_m_e_encryption_algorithm_negotiation` int(11) DEFAULT NULL,
+    `allow_s_m_i_m_e_soft_certs` int(11) DEFAULT NULL,
+    `allow_storage_card` int(11) DEFAULT NULL,
+    `allow_text_messaging` int(11) DEFAULT NULL,
+    `allow_unsigned_applications` int(11) DEFAULT NULL,
+    `allow_unsigned_installation_packages` int(11) DEFAULT NULL,
+    `allow_wifi` int(11) DEFAULT NULL,
+    `alphanumeric_device_password_required` int(11) DEFAULT NULL,
+    `approved_application_list` varchar(255) DEFAULT NULL,
+    `attachments_enabled` int(11) DEFAULT NULL,
+    `device_password_enabled` int(11) DEFAULT NULL,
+    `device_password_expiration` int(11) DEFAULT NULL,
+    `device_password_history` int(11) DEFAULT NULL,
+    `max_attachment_size` int(11) DEFAULT NULL,
+    `max_calendar_age_filter` int(11) DEFAULT NULL,
+    `max_device_password_failed_attempts` int(11) DEFAULT NULL,
+    `max_email_age_filter` int(11) DEFAULT NULL,
+    `max_email_body_truncation_size` int(11) DEFAULT NULL,
+    `max_email_h_t_m_l_body_truncation_size` int(11) DEFAULT NULL,
+    `max_inactivity_time_device_lock` int(11) DEFAULT NULL,
+    `min_device_password_complex_characters` int(11) DEFAULT NULL,
+    `min_device_password_length` int(11) DEFAULT NULL,
+    `password_recovery_enabled` int(11) DEFAULT NULL,
+    `require_device_encryption` int(11) DEFAULT NULL,
+    `require_encrypted_s_m_i_m_e_messages` int(11) DEFAULT NULL,
+    `require_encryption_s_m_i_m_e_algorithm` int(11) DEFAULT NULL,
+    `require_manual_sync_when_roaming` int(11) DEFAULT NULL,
+    `require_signed_s_m_i_m_e_algorithm` int(11) DEFAULT NULL,
+    `require_signed_s_m_i_m_e_messages` int(11) DEFAULT NULL,
+    `require_storage_card_encryption` int(11) DEFAULT NULL,
+    `unapproved_in_r_o_m_application_list` varchar(255) DEFAULT NULL,
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB;
+
 CREATE TABLE IF NOT EXISTS `syncroton_device` (
     `id` varchar(40) NOT NULL,
     `deviceid` varchar(64) NOT NULL,
     `devicetype` varchar(64) NOT NULL,
-    `policykey` varchar(64) DEFAULT NULL,
-    `policy_id` varchar(40) NOT NULL,
     `owner_id` varchar(40) NOT NULL,
-    `useragent` varchar(255) NOT NULL,
     `acsversion` varchar(40) NOT NULL,
+    `policykey` varchar(64) DEFAULT NULL,
+    `policy_id` varchar(40) DEFAULT NULL,
+    `useragent` varchar(255) DEFAULT NULL,
+    `imei` varchar(255) DEFAULT NULL,
+    `model` varchar(255) DEFAULT NULL,
+    `friendlyname` varchar(255) DEFAULT NULL,
+    `os` varchar(255) DEFAULT NULL,
+    `oslanguage` varchar(255) DEFAULT NULL,
+    `phonenumber` varchar(255) DEFAULT NULL,
     `pinglifetime` int(11) DEFAULT NULL,
     `remotewipe` int(11) DEFAULT '0',
     `pingfolder` longblob,
-    PRIMARY KEY (`id`)
+    `contactsfilter_id` varchar(40) DEFAULT NULL,
+    `calendarfilter_id` varchar(40) DEFAULT NULL,
+    `tasksfilter_id` varchar(40) DEFAULT NULL,
+    `emailfilter_id` varchar(40) DEFAULT NULL,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `owner_id--deviceid` (`owner_id`, `deviceid`)
 ) ENGINE=InnoDB;
 
 CREATE TABLE IF NOT EXISTS `syncroton_folder` (
-  `id` varchar(40) NOT NULL,
-  `device_id` varchar(40) NOT NULL,
-  `class` varchar(64) NOT NULL,
-  `folderid` varchar(254) NOT NULL,
-  `parentid` varchar(254) DEFAULT NULL,
-  `displayname` varchar(254) NOT NULL,
-  `type` int(11) NOT NULL,
-  `creation_time` datetime NOT NULL,
-  `lastfiltertype` int(11) DEFAULT NULL,
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `device_id--class--folderid` (`device_id`,`class`,`folderid`),
-  CONSTRAINT `syncroton_folder::device_id--syncroton_device::id` FOREIGN KEY (`device_id`)
-    REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+    `id` varchar(40) NOT NULL,
+    `device_id` varchar(40) NOT NULL,
+    `class` varchar(64) NOT NULL,
+    `folderid` varchar(254) NOT NULL,
+    `parentid` varchar(254) DEFAULT NULL,
+    `displayname` varchar(254) NOT NULL,
+    `type` int(11) NOT NULL,
+    `creation_time` datetime NOT NULL,
+    `lastfiltertype` int(11) DEFAULT NULL,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `device_id--class--folderid` (`device_id`(40),`class`(40),`folderid`(40)),
+    KEY `folderstates::device_id--devices::id` (`device_id`),
+    CONSTRAINT `folderstates::device_id--devices::id` FOREIGN KEY (`device_id`) REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
 ) ENGINE=InnoDB;
 
-CREATE TABLE `syncroton_synckey` (
-  `id` varchar(40) NOT NULL,
-  `device_id` varchar(40) NOT NULL DEFAULT '',
-  `type` varchar(64) NOT NULL DEFAULT '',
-  `counter` int(11) unsigned NOT NULL DEFAULT '0',
-  `lastsync` datetime DEFAULT NULL,
-  `pendingdata` longblob,
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `device_id--type--counter` (`device_id`,`type`,`counter`),
-  CONSTRAINT `syncroton_synckey::device_id--syncroton_device::id` FOREIGN KEY (`device_id`)
-    REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+CREATE TABLE IF NOT EXISTS `syncroton_synckey` (
+    `id` varchar(40) NOT NULL,
+    `device_id` varchar(40) NOT NULL DEFAULT '',
+    `type` varchar(64) NOT NULL DEFAULT '',
+    `counter` int(11) NOT NULL DEFAULT '0',
+    `lastsync` datetime DEFAULT NULL,
+    `pendingdata` longblob,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `device_id--type--counter` (`device_id`,`type`,`counter`),
+    CONSTRAINT `syncroton_synckey::device_id--syncroton_device::id` FOREIGN KEY (`device_id`) REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
 ) ENGINE=InnoDB;
 
-CREATE TABLE `syncroton_content` (
-  `id` varchar(40) NOT NULL,
-  `device_id` varchar(40) DEFAULT NULL,
-  `folder_id` varchar(40) DEFAULT NULL,
-  `contentid` varchar(64) DEFAULT NULL,
-  `creation_time` datetime DEFAULT NULL,
-  `creation_synckey` int(11) NOT NULL,
-  `is_deleted` tinyint(1) unsigned DEFAULT '0',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `device_id--folder_id--contentid` (`device_id`,`folder_id`,`contentid`),
-  CONSTRAINT `syncroton_content::device_id--syncroton_device::id` FOREIGN KEY (`device_id`)
-    REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+CREATE TABLE IF NOT EXISTS `syncroton_content` (
+    `id` varchar(40) NOT NULL,
+    `device_id` varchar(40) DEFAULT NULL,
+    `folder_id` varchar(40) DEFAULT NULL,
+    `contentid` varchar(64) DEFAULT NULL,
+    `creation_time` datetime DEFAULT NULL,
+    `creation_synckey` int(11) NOT NULL,
+    `is_deleted` tinyint(1) DEFAULT '0',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `device_id--folder_id--contentid` (`device_id`(40),`folder_id`(40),`contentid`(40)),
+    KEY `syncroton_contents::device_id` (`device_id`),
+    CONSTRAINT `syncroton_contents::device_id--syncroton_device::id` FOREIGN KEY (`device_id`) REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB;
+
+CREATE TABLE IF NOT EXISTS `syncroton_data` (
+    `id` varchar(40) NOT NULL,
+    `type` varchar(40) NOT NULL,
+    `folder_id` varchar(40) NOT NULL,
+    `data` longblob,
+    PRIMARY KEY (`id`)
 ) ENGINE=InnoDB;
diff --git a/lib/ext/Roundcube/rcube_mdb2.php b/lib/ext/Roundcube/rcube_mdb2.php
deleted file mode 100644
index 721963b..0000000
--- a/lib/ext/Roundcube/rcube_mdb2.php
+++ /dev/null
@@ -1,935 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | program/include/rcube_mdb2.php                                        |
- |                                                                       |
- | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2005-2009, The Roundcube Dev Team                       |
- |                                                                       |
- | Licensed under the GNU General Public License version 3 or            |
- | any later version with exceptions for skins & plugins.                |
- | See the README file for a full license statement.                     |
- |                                                                       |
- | PURPOSE:                                                              |
- |   PEAR:DB wrapper class that implements PEAR MDB2 functions           |
- |   See http://pear.php.net/package/MDB2                                |
- |                                                                       |
- +-----------------------------------------------------------------------+
- | Author: Lukas Kahwe Smith <smith at pooteeweet.org>                      |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Database independent query interface
- *
- * This is a wrapper for the PEAR::MDB2 class
- *
- * @package    Database
- * @author     David Saez Padros <david at ols.es>
- * @author     Thomas Bruederli <roundcube at gmail.com>
- * @author     Lukas Kahwe Smith <smith at pooteeweet.org>
- * @version    1.18
- * @link       http://pear.php.net/package/MDB2
- */
-class rcube_mdb2
-{
-    public $db_dsnw;               // DSN for write operations
-    public $db_dsnr;               // DSN for read operations
-    public $db_connected = false;  // Already connected ?
-    public $db_mode = '';          // Connection mode
-    public $db_handle = 0;         // Connection handle
-    public $db_error = false;
-    public $db_error_msg = '';
-
-    private $debug_mode = false;
-    private $conn_failure = false;
-    private $a_query_results = array('dummy');
-    private $last_res_id = 0;
-    private $tables;
-    private $variables;
-
-
-    /**
-     * Object constructor
-     *
-     * @param  string $db_dsnw DSN for read/write operations
-     * @param  string $db_dsnr Optional DSN for read only operations
-     */
-    public function __construct($db_dsnw, $db_dsnr='', $pconn=false)
-    {
-        if (empty($db_dsnr)) {
-            $db_dsnr = $db_dsnw;
-        }
-
-        $this->db_dsnw = $db_dsnw;
-        $this->db_dsnr = $db_dsnr;
-        $this->db_pconn = $pconn;
-
-        $dsn_array = MDB2::parseDSN($db_dsnw);
-        $this->db_provider = $dsn_array['phptype'];
-    }
-
-
-    /**
-     * Connect to specific database
-     *
-     * @param  string $dsn  DSN for DB connections
-     * @return MDB2 PEAR database handle
-     * @access private
-     */
-    private function dsn_connect($dsn)
-    {
-        // Use persistent connections if available
-        $db_options = array(
-            'persistent'       => $this->db_pconn,
-            'emulate_prepared' => $this->debug_mode,
-            'debug'            => $this->debug_mode,
-            'debug_handler'    => array($this, 'debug_handler'),
-            'portability'      => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL,
-        );
-
-        if ($this->db_provider == 'pgsql') {
-            $db_options['disable_smart_seqname'] = true;
-            $db_options['seqname_format'] = '%s';
-        }
-        $this->db_error     = false;
-        $this->db_error_msg = null;
-
-        $dbh = MDB2::connect($dsn, $db_options);
-
-        if (MDB2::isError($dbh)) {
-            $this->db_error = true;
-            $this->db_error_msg = $dbh->getMessage();
-
-            rcube::raise_error(array('code' => 500, 'type' => 'db',
-                'line' => __LINE__, 'file' => __FILE__,
-                'message' => $dbh->getUserInfo()), true, false);
-        }
-        else if ($this->db_provider == 'sqlite') {
-            $dsn_array = MDB2::parseDSN($dsn);
-            if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) {
-                $this->sqlite_create_database($dbh, $this->sqlite_initials);
-            }
-        }
-        else if ($this->db_provider != 'mssql' && $this->db_provider != 'sqlsrv') {
-            $dbh->setCharset('utf8');
-        }
-
-        return $dbh;
-    }
-
-
-    /**
-     * Connect to appropiate database depending on the operation
-     *
-     * @param  string $mode Connection mode (r|w)
-     */
-    public function db_connect($mode)
-    {
-        // previous connection failed, don't attempt to connect again
-        if ($this->conn_failure) {
-            return;
-        }
-
-        // no replication
-        if ($this->db_dsnw == $this->db_dsnr) {
-            $mode = 'w';
-        }
-
-        // Already connected
-        if ($this->db_connected) {
-            // connected to db with the same or "higher" mode
-            if ($this->db_mode == 'w' || $this->db_mode == $mode) {
-                return;
-            }
-        }
-
-        $dsn = ($mode == 'r') ? $this->db_dsnr : $this->db_dsnw;
-
-        $this->db_handle    = $this->dsn_connect($dsn);
-        $this->db_connected = !PEAR::isError($this->db_handle);
-
-        // use write-master when read-only fails
-        if (!$this->db_connected && $mode == 'r') {
-            $mode = 'w';
-            $this->db_handle    = $this->dsn_connect($this->db_dsnw);
-            $this->db_connected = !PEAR::isError($this->db_handle);
-        }
-
-        if ($this->db_connected) {
-            $this->db_mode = $mode;
-        }
-        else {
-            $this->conn_failure = true;
-        }
-    }
-
-
-    /**
-     * Activate/deactivate debug mode
-     *
-     * @param boolean $dbg True if SQL queries should be logged
-     */
-    public function set_debug($dbg = true)
-    {
-        $this->debug_mode = $dbg;
-        if ($this->db_connected) {
-            $this->db_handle->setOption('debug', $dbg);
-            $this->db_handle->setOption('emulate_prepared', $dbg);
-        }
-    }
-
-
-    /**
-     * Getter for error state
-     *
-     * @param  boolean  True on error
-     */
-    public function is_error()
-    {
-        return $this->db_error ? $this->db_error_msg : false;
-    }
-
-
-    /**
-     * Connection state checker
-     *
-     * @param  boolean  True if in connected state
-     */
-    public function is_connected()
-    {
-        return PEAR::isError($this->db_handle) ? false : $this->db_connected;
-    }
-
-
-    /**
-     * Is database replication configured?
-     * This returns true if dsnw != dsnr
-     */
-    public function is_replicated()
-    {
-      return !empty($this->db_dsnr) && $this->db_dsnw != $this->db_dsnr;
-    }
-
-
-    /**
-     * Get database runtime variables
-     *
-     * @param string Variable name
-     * @param mixed  Default value if var is not set
-     * @return mixed Variable value or default
-     */
-    public function get_variable($varname, $default = null)
-    {
-        if (!isset($this->variables)) {
-            $this->variables = array();
-
-            // only mysql and postgres are know to support this
-            if ($this->db_provider == 'pgsql' || $this->db_provider == 'mysql' || $this->db_provider == 'mysqli') {
-                $this->db_connect('r');
-                $query = $this->db_provider == 'pgsql' ? 'SHOW ALL' : 'SHOW VARIABLES';
-                foreach ((array)$this->db_handle->queryAll($query) as $row)
-                    $this->variables[$row[0]] = $row[1];
-            }
-        }
-
-        return isset($this->variables[$varname]) ? $this->variables[$varname] : $default;
-    }
-
-
-    /**
-     * Execute a SQL query
-     *
-     * @param  string  SQL query to execute
-     * @param  mixed   Values to be inserted in query
-     *
-     * @return number  Query handle identifier
-     */
-    public function query()
-    {
-        $params = func_get_args();
-        $query = array_shift($params);
-
-        // Support one argument of type array, instead of n arguments
-        if (count($params) == 1 && is_array($params[0])) {
-            $params = $params[0];
-        }
-
-        return $this->_query($query, 0, 0, $params);
-    }
-
-
-    /**
-     * Execute a SQL query with limits
-     *
-     * @param  string  SQL query to execute
-     * @param  number  Offset for LIMIT statement
-     * @param  number  Number of rows for LIMIT statement
-     * @param  mixed   Values to be inserted in query
-     *
-     * @return number  Query handle identifier
-     */
-    public function limitquery()
-    {
-        $params  = func_get_args();
-        $query   = array_shift($params);
-        $offset  = array_shift($params);
-        $numrows = array_shift($params);
-
-        return $this->_query($query, $offset, $numrows, $params);
-    }
-
-
-    /**
-     * Execute a SQL query with limits
-     *
-     * @param  string $query   SQL query to execute
-     * @param  number $offset  Offset for LIMIT statement
-     * @param  number $numrows Number of rows for LIMIT statement
-     * @param  array  $params  Values to be inserted in query
-     * @return number  Query handle identifier
-     * @access private
-     */
-    private function _query($query, $offset, $numrows, $params)
-    {
-        // Read or write ?
-        $mode = (strtolower(substr(trim($query),0,6)) == 'select') ? 'r' : 'w';
-
-        $this->db_connect($mode);
-
-        // check connection before proceeding
-        if (!$this->is_connected()) {
-            return null;
-        }
-
-        if ($this->db_provider == 'sqlite') {
-            $this->sqlite_prepare();
-        }
-
-        if ($numrows || $offset) {
-            $result = $this->db_handle->setLimit($numrows,$offset);
-        }
-
-        if (empty($params)) {
-            $result = $mode == 'r' ? $this->db_handle->query($query) : $this->db_handle->exec($query);
-        }
-        else {
-            $params = (array)$params;
-            $q = $this->db_handle->prepare($query, null, $mode=='w' ? MDB2_PREPARE_MANIP : null);
-            if ($this->db_handle->isError($q)) {
-                $this->db_error = true;
-                $this->db_error_msg = $q->userinfo;
-
-                rcube::raise_error(array('code' => 500, 'type' => 'db',
-                    'line' => __LINE__, 'file' => __FILE__,
-                    'message' => $this->db_error_msg), true, false);
-
-                $result = false;
-            }
-            else {
-                $result = $q->execute($params);
-                $q->free();
-            }
-        }
-
-        // add result, even if it's an error
-        return $this->_add_result($result);
-    }
-
-
-    /**
-     * Get number of rows for a SQL query
-     * If no query handle is specified, the last query will be taken as reference
-     *
-     * @param  number $res_id  Optional query handle identifier
-     * @return mixed   Number of rows or false on failure
-     */
-    public function num_rows($res_id=null)
-    {
-        if (!$this->db_connected) {
-            return false;
-        }
-
-        if ($result = $this->_get_result($res_id)) {
-            return $result->numRows();
-        }
-
-        return false;
-    }
-
-
-    /**
-     * Get number of affected rows for the last query
-     *
-     * @param  number $res_id Optional query handle identifier
-     * @return mixed   Number of rows or false on failure
-     */
-    public function affected_rows($res_id = null)
-    {
-        if (!$this->db_connected) {
-            return false;
-        }
-
-        return $this->_get_result($res_id);
-    }
-
-
-    /**
-     * Get last inserted record ID
-     * For Postgres databases, a sequence name is required
-     *
-     * @param  string $table  Table name (to find the incremented sequence)
-     *
-     * @return mixed   ID or false on failure
-     */
-    public function insert_id($table = '')
-    {
-        if (!$this->db_connected || $this->db_mode == 'r') {
-            return false;
-        }
-
-        if ($table) {
-            if ($this->db_provider == 'pgsql') {
-                // find sequence name
-                $table = $this->sequence_name($table);
-            }
-            else {
-                // resolve table name
-                $table = $this->table_name($table);
-            }
-        }
-
-        $id = $this->db_handle->lastInsertID($table);
-
-        return $this->db_handle->isError($id) ? null : $id;
-    }
-
-
-    /**
-     * Get an associative array for one row
-     * If no query handle is specified, the last query will be taken as reference
-     *
-     * @param  number $res_id Optional query handle identifier
-     *
-     * @return mixed   Array with col values or false on failure
-     */
-    public function fetch_assoc($res_id = null)
-    {
-        $result = $this->_get_result($res_id);
-        return $this->_fetch_row($result, MDB2_FETCHMODE_ASSOC);
-    }
-
-
-    /**
-     * Get an index array for one row
-     * If no query handle is specified, the last query will be taken as reference
-     *
-     * @param  number $res_id  Optional query handle identifier
-     *
-     * @return mixed   Array with col values or false on failure
-     */
-    public function fetch_array($res_id = null)
-    {
-        $result = $this->_get_result($res_id);
-        return $this->_fetch_row($result, MDB2_FETCHMODE_ORDERED);
-    }
-
-
-    /**
-     * Get col values for a result row
-     *
-     * @param  MDB2_Result_Common Query $result result handle
-     * @param  number                   $mode   Fetch mode identifier
-     *
-     * @return mixed  Array with col values or false on failure
-     */
-    private function _fetch_row($result, $mode)
-    {
-        if ($result === false || PEAR::isError($result) || !$this->is_connected()) {
-            return false;
-        }
-
-        return $result->fetchRow($mode);
-    }
-
-
-    /**
-     * Wrapper for the SHOW TABLES command
-     *
-     * @return array List of all tables of the current database
-     * @since 0.4-beta
-     */
-    public function list_tables()
-    {
-        // get tables if not cached
-        if (!$this->tables) {
-            $this->db_handle->loadModule('Manager');
-            if (!PEAR::isError($result = $this->db_handle->listTables())) {
-                $this->tables = $result;
-            }
-            else {
-                $this->tables = array();
-            }
-        }
-
-        return $this->tables;
-    }
-
-
-    /**
-     * Wrapper for SHOW COLUMNS command
-     *
-     * @param string Table name
-     *
-     * @return array List of table cols
-     */
-    public function list_cols($table)
-    {
-        $this->db_handle->loadModule('Manager');
-        if (!PEAR::isError($result = $this->db_handle->listTableFields($table))) {
-            return $result;
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Formats input so it can be safely used in a query
-     *
-     * @param  mixed  $input  Value to quote
-     * @param  string $type   Type of data
-     *
-     * @return string  Quoted/converted string for use in query
-     */
-    public function quote($input, $type = null)
-    {
-        // handle int directly for better performance
-        if ($type == 'integer') {
-            return intval($input);
-        }
-
-        // create DB handle if not available
-        if (!$this->db_handle) {
-            $this->db_connect('r');
-        }
-
-        return $this->db_connected ? $this->db_handle->quote($input, $type) : addslashes($input);
-    }
-
-
-    /**
-     * Quotes a string so it can be safely used as a table or column name
-     *
-     * @param  string $str Value to quote
-     *
-     * @return string  Quoted string for use in query
-     * @deprecated     Replaced by rcube_MDB2::quote_identifier
-     * @see            rcube_mdb2::quote_identifier
-     */
-    public function quoteIdentifier($str)
-    {
-        return $this->quote_identifier($str);
-    }
-
-
-    /**
-     * Quotes a string so it can be safely used as a table or column name
-     *
-     * @param  string $str Value to quote
-     *
-     * @return string  Quoted string for use in query
-     */
-    public function quote_identifier($str)
-    {
-        if (!$this->db_handle) {
-            $this->db_connect('r');
-        }
-
-        return $this->db_connected ? $this->db_handle->quoteIdentifier($str) : $str;
-    }
-
-
-    /**
-     * Escapes a string
-     *
-     * @param  string $str The string to be escaped
-     *
-     * @return string  The escaped string
-     * @since  0.1.1
-     */
-    public function escapeSimple($str)
-    {
-        if (!$this->db_handle) {
-            $this->db_connect('r');
-        }
-
-        return $this->db_handle->escape($str);
-    }
-
-
-    /**
-     * Return SQL function for current time and date
-     *
-     * @return string SQL function to use in query
-     */
-    public function now()
-    {
-        switch ($this->db_provider) {
-            case 'mssql':
-            case 'sqlsrv':
-                return "getdate()";
-
-            default:
-                return "now()";
-        }
-    }
-
-
-    /**
-     * Return list of elements for use with SQL's IN clause
-     *
-     * @param  array  $arr  Input array
-     * @param  string $type Type of data
-     *
-     * @return string Comma-separated list of quoted values for use in query
-     */
-    public function array2list($arr, $type = null)
-    {
-        if (!is_array($arr)) {
-            return $this->quote($arr, $type);
-        }
-
-        foreach ($arr as $idx => $item) {
-            $arr[$idx] = $this->quote($item, $type);
-        }
-
-        return implode(',', $arr);
-    }
-
-
-    /**
-     * Return SQL statement to convert a field value into a unix timestamp
-     *
-     * This method is deprecated and should not be used anymore due to limitations
-     * of timestamp functions in Mysql (year 2038 problem)
-     *
-     * @param  string $field Field name
-     *
-     * @return string  SQL statement to use in query
-     * @deprecated
-     */
-    public function unixtimestamp($field)
-    {
-        switch($this->db_provider) {
-            case 'pgsql':
-                return "EXTRACT (EPOCH FROM $field)";
-
-            case 'mssql':
-            case 'sqlsrv':
-                return "DATEDIFF(second, '19700101', $field) + DATEDIFF(second, GETDATE(), GETUTCDATE())";
-
-            default:
-                return "UNIX_TIMESTAMP($field)";
-        }
-    }
-
-
-    /**
-     * Return SQL statement to convert from a unix timestamp
-     *
-     * @param  string $timestamp Field name
-     *
-     * @return string  SQL statement to use in query
-     */
-    public function fromunixtime($timestamp)
-    {
-        return date("'Y-m-d H:i:s'", $timestamp);
-    }
-
-
-    /**
-     * Return SQL statement for case insensitive LIKE
-     *
-     * @param  string $column  Field name
-     * @param  string $value   Search value
-     *
-     * @return string  SQL statement to use in query
-     */
-    public function ilike($column, $value)
-    {
-        // TODO: use MDB2's matchPattern() function
-        switch ($this->db_provider) {
-            case 'pgsql':
-                return $this->quote_identifier($column).' ILIKE '.$this->quote($value);
-            default:
-                return $this->quote_identifier($column).' LIKE '.$this->quote($value);
-        }
-    }
-
-
-    /**
-     * Abstract SQL statement for value concatenation
-     *
-     * @return string SQL statement to be used in query
-     */
-    public function concat(/* col1, col2, ... */)
-    {
-        $func = '';
-        $args = func_get_args();
-        if (is_array($args[0]))
-            $args = $args[0];
-
-        switch ($this->db_provider) {
-            case 'mysql':
-            case 'mysqli':
-                $func = 'CONCAT';
-                $delim = ', ';
-                break;
-            case 'mssql':
-            case 'sqlsrv':
-                $delim = ' + ';
-                // Modify arguments, because + operator requires them to be of type varchar (#1488505)
-                // with SQL Server 2012 we can use just CONCAT(), but we need to support older versions
-                foreach ($args as $idx => $arg) {
-                    $args[$idx] = "CAST($arg AS varchar)";
-                }
-                break;
-            default:
-                $delim = ' || ';
-        }
-
-        return $func . '(' . join($delim, $args) . ')';
-    }
-
-
-    /**
-     * Encodes non-UTF-8 characters in string/array/object (recursive)
-     *
-     * @param  mixed  $input Data to fix
-     *
-     * @return mixed  Properly UTF-8 encoded data
-     */
-    public static function encode($input)
-    {
-        if (is_object($input)) {
-            foreach (get_object_vars($input) as $idx => $value) {
-                $input->$idx = self::encode($value);
-            }
-            return $input;
-        }
-        else if (is_array($input)) {
-            foreach ($input as $idx => $value) {
-                $input[$idx] = self::encode($value);
-            }
-            return $input;
-        }
-
-        return utf8_encode($input);
-    }
-
-
-    /**
-     * Decodes encoded UTF-8 string/object/array (recursive)
-     *
-     * @param  mixed $input Input data
-     *
-     * @return mixed  Decoded data
-     */
-    public static function decode($input)
-    {
-        if (is_object($input)) {
-            foreach (get_object_vars($input) as $idx => $value) {
-                $input->$idx = self::decode($value);
-            }
-            return $input;
-        }
-        else if (is_array($input)) {
-            foreach ($input as $idx => $value) {
-                $input[$idx] = self::decode($value);
-            }
-            return $input;
-        }
-
-        return utf8_decode($input);
-    }
-
-
-    /**
-     * Adds a query result and returns a handle ID
-     *
-     * @param  object $res Query handle
-     *
-     * @return mixed   Handle ID
-     */
-    private function _add_result($res)
-    {
-        // sql error occured
-        if (PEAR::isError($res)) {
-            $this->db_error = true;
-            $this->db_error_msg = $res->getMessage();
-            rcube::raise_error(array('code' => 500, 'type' => 'db',
-                'line' => __LINE__, 'file' => __FILE__,
-                'message' => $res->getMessage() . " Query: " 
-                . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)),
-                true, false);
-        }
-
-        $res_id = sizeof($this->a_query_results);
-        $this->last_res_id = $res_id;
-        $this->a_query_results[$res_id] = $res;
-        return $res_id;
-    }
-
-
-    /**
-     * Resolves a given handle ID and returns the according query handle
-     * If no ID is specified, the last resource handle will be returned
-     *
-     * @param  number $res_id Handle ID
-     *
-     * @return mixed   Resource handle or false on failure
-     */
-    private function _get_result($res_id = null)
-    {
-        if ($res_id == null) {
-            $res_id = $this->last_res_id;
-        }
-
-        if (isset($this->a_query_results[$res_id])) {
-            if (!PEAR::isError($this->a_query_results[$res_id])) {
-                return $this->a_query_results[$res_id];
-            }
-        }
-
-        return false;
-    }
-
-
-    /**
-     * Create a sqlite database from a file
-     *
-     * @param  MDB2   $dbh       SQLite database handle
-     * @param  string $file_name File path to use for DB creation
-     */
-    private function sqlite_create_database($dbh, $file_name)
-    {
-        if (empty($file_name) || !is_string($file_name)) {
-            return;
-        }
-
-        $data = file_get_contents($file_name);
-
-        if (strlen($data)) {
-            if (!sqlite_exec($dbh->connection, $data, $error) || MDB2::isError($dbh)) {
-                rcube::raise_error(array('code' => 500, 'type' => 'db',
-                    'line' => __LINE__, 'file' => __FILE__,
-                    'message' => $error), true, false);
-            }
-        }
-    }
-
-
-    /**
-     * Add some proprietary database functions to the current SQLite handle
-     * in order to make it MySQL compatible
-     */
-    private function sqlite_prepare()
-    {
-        // we emulate via callback some missing MySQL functions
-        sqlite_create_function($this->db_handle->connection,
-            'unix_timestamp', array('rcube_mdb2', 'sqlite_unix_timestamp'));
-        sqlite_create_function($this->db_handle->connection,
-            'now', array('rcube_mdb2', 'sqlite_now'));
-    }
-
-
-    /**
-     * Debug handler for the MDB2
-     */
-    function debug_handler(&$db, $scope, $message, $context = array())
-    {
-        if ($scope != 'prepare') {
-            $debug_output = sprintf('%s(%d): %s;',
-                $scope, $db->db_index, rtrim($message, ';'));
-            rcube::write_log('sql', $debug_output);
-        }
-    }
-
-
-    /**
-     * Return correct name for a specific database table
-     *
-     * @param string $table Table name
-     *
-     * @return string Translated table name
-     */
-    public function table_name($table)
-    {
-        $rcube = rcube::get_instance();
-
-        // return table name if configured
-        $config_key = 'db_table_'.$table;
-
-        if ($name = $rcube->config->get($config_key)) {
-            return $name;
-        }
-
-        return $table;
-    }
-
-
-    /**
-     * Return correct name for a specific database sequence
-     * (used for Postgres only)
-     *
-     * @param string $sequence Secuence name
-     *
-     * @return string Translated sequence name
-     */
-    public function sequence_name($sequence)
-    {
-        $rcube = rcube::get_instance();
-
-        // return sequence name if configured
-        $config_key = 'db_sequence_'.$sequence;
-
-        if ($name = $rcube->config->get($config_key)) {
-            return $name;
-        }
-
-        return $sequence;
-    }
-
-
-    /**
-     * Callback for sqlite: unix_timestamp()
-     */
-    public static function sqlite_unix_timestamp($timestamp = '')
-    {
-        $timestamp = trim($timestamp);
-        if (!$timestamp) {
-            $ret = time();
-        }
-        else if (!preg_match('/^[0-9]+$/s', $timestamp)) {
-            $ret = strtotime($timestamp);
-        }
-        else {
-            $ret = $timestamp;
-        }
-
-        return $ret;
-    }
-
-
-    /**
-     * Callback for sqlite: now()
-     */
-    public static function sqlite_now()
-    {
-        return date("Y-m-d H:i:s");
-    }
-
-}
diff --git a/lib/ext/Syncroton/Backend/ABackend.php b/lib/ext/Syncroton/Backend/ABackend.php
new file mode 100644
index 0000000..d345d6d
--- /dev/null
+++ b/lib/ext/Syncroton/Backend/ABackend.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Syncroton
+ *
+ * @package     Command
+ * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
+ * @copyright   Copyright (c) 2012-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Lars Kneschke <l.kneschke at metaways.de>
+ */
+
+/**
+ * class to handle ActiveSync Sync command
+ *
+ * @package     Backend
+ */
+ 
+abstract class Syncroton_Backend_ABackend implements Syncroton_Backend_IBackend
+{
+    /**
+     * the database adapter
+     * 
+     * @var Zend_Db_Adapter_Abstract
+     */
+    protected $_db;
+    
+    protected $_tablePrefix;
+    
+    protected $_tableName;
+    
+    protected $_modelClassName;
+    
+    protected $_modelInterfaceName;
+    
+    public function __construct(Zend_Db_Adapter_Abstract $_db, $_tablePrefix = 'Syncroton_')
+    {
+        $this->_db          = $_db;
+        $this->_tablePrefix = $_tablePrefix;
+    }
+
+    /**
+     * create new device
+     * 
+     * @param Syncroton_Model_IDevice $_device
+     * @return Syncroton_Model_IDevice
+     */
+    public function create($model)
+    {
+        if (! $model instanceof $this->_modelInterfaceName) {
+            throw new InvalidArgumentException('$model must be instanace of ' . $this->_modelInterfaceName);
+        }
+        
+        $data = $this->_convertModelToArray($model);
+        
+        $data['id'] = sha1(mt_rand(). microtime());
+        
+        $this->_db->insert($this->_tablePrefix . $this->_tableName, $data);
+        
+        return $this->get($data['id']);
+    }
+    
+    protected function _convertModelToArray($model)
+    {
+        $data = array();
+        
+        foreach ($model as $key => $value) {
+            if ($value instanceof DateTime) {
+                $value = $value->format('Y-m-d H:i:s');
+            } elseif (is_object($value) && isset($value->id)) {
+                $value = $value->id;
+            }
+        
+            $data[$this->_fromCamelCase($key)] = $value;
+        }
+        
+        return $data;
+    }
+    
+    /**
+     * @param string  $_id
+     * @throws Syncroton_Exception_NotFound
+     * @return Syncroton_Model_IDevice
+     */
+    public function get($id)
+    {
+        $id = $id instanceof $this->_modelInterfaceName ? $id->id : $id;
+        
+        $select = $this->_db->select()
+            ->from($this->_tablePrefix . $this->_tableName)
+            ->where('id = ?', $id);
+            
+        $stmt = $this->_db->query($select);
+        $data = $stmt->fetch();
+        $stmt = null; # see https://bugs.php.net/bug.php?id=44081
+        
+        if ($data === false) {
+            throw new Syncroton_Exception_NotFound('id not found');
+        }
+
+        return $this->_getObject($data);
+    }
+    
+    protected function _getObject($data)
+    {
+        foreach ($data as $key => $value) {
+            unset($data[$key]);
+            
+            if (!empty($value) && preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $value)) { # 2012-08-12 07:43:26
+                $value = new DateTime($value, new DateTimeZone('utc'));
+            }
+            
+            $data[$this->_toCamelCase($key, false)] = $value;
+        }
+        
+        return new $this->_modelClassName($data);
+    }
+    
+    public function delete($id)
+    {
+        $id = $id instanceof $this->_modelInterfaceName ? $id->id : $id;
+        
+        $result = $this->_db->delete($this->_tablePrefix . $this->_tableName, array('id = ?' => $id));
+        
+        return (bool) $result;
+    }
+    
+    public function update($model)
+    {
+        if (! $model instanceof $this->_modelInterfaceName) {
+            throw new InvalidArgumentException('$model must be instanace of ' . $this->_modelInterfaceName);
+        }
+        
+        $data = $this->_convertModelToArray($model);
+        
+        $this->_db->update($this->_tablePrefix . $this->_tableName, $data, array(
+            'id = ?' => $model->id
+        ));
+        
+        return $this->get($model->id);
+    }
+
+    protected function _fromCamelCase($string)
+    {
+        $string = lcfirst($string);
+        
+        return preg_replace_callback('/([A-Z])/', function ($string) {return '_' . strtolower($string[0]);}, $string);
+    }
+    
+    protected function _toCamelCase($string, $ucFirst = true)
+    {
+        if ($ucFirst === true) {
+            $string = ucfirst($string);
+        }
+        
+        return preg_replace_callback('/_([a-z])/', function ($string) {return strtoupper($string[1]);}, $string);
+    }
+}
diff --git a/lib/ext/Syncroton/Backend/Content.php b/lib/ext/Syncroton/Backend/Content.php
index 2500a17..b186b00 100644
--- a/lib/ext/Syncroton/Backend/Content.php
+++ b/lib/ext/Syncroton/Backend/Content.php
@@ -16,48 +16,13 @@
  * @package     Syncroton
  * @subpackage  Backend
  */
-class Syncroton_Backend_Content implements Syncroton_Backend_IContent
+class Syncroton_Backend_Content extends Syncroton_Backend_ABackend implements Syncroton_Backend_IContent
 {
-    /**
-     * the database adapter
-     *
-     * @var Zend_Db_Adapter_Abstract
-     */
-    protected $_db;
-    
-    protected $_tablePrefix;
-    
-    public function __construct(Zend_Db_Adapter_Abstract $_db, $_tablePrefix = 'Syncroton_')
-    {
-        $this->_db          = $_db;
-        $this->_tablePrefix = $_tablePrefix;
-    }
-    
-    /**
-     * create new content state
-     *
-     * @param Syncroton_Model_IContent $_state
-     * @return Syncroton_Model_IContent
-     */
-    public function create(Syncroton_Model_IContent $_state)
-    {
-        $id = sha1(mt_rand(). microtime());
-        
-        $deviceId = $_state->device_id instanceof Syncroton_Model_IDevice ? $_state->device_id->id : $_state->device_id;
-        $folderId = $_state->folder_id instanceof Syncroton_Model_IFolder ? $_state->folder_id->id : $_state->folder_id;
-        
-        $this->_db->insert($this->_tablePrefix . 'content', array(
-            'id'               => $id, 
-            'device_id'        => $deviceId,
-            'folder_id'        => $folderId,
-            'contentid'        => $_state->contentid,
-            'creation_time'    => $_state->creation_time->format('Y-m-d H:i:s'),
-            'creation_synckey' => $_state->creation_synckey,
-            'is_deleted'       => isset($_state->is_deleted) ? (int)!!$_state->is_deleted : 0
-        ));
-        
-        return $this->get($id);
-    }
+    protected $_tableName = 'content';
+    
+    protected $_modelClassName = 'Syncroton_Model_Content';
+    
+    protected $_modelInterfaceName = 'Syncroton_Model_IContent';
     
     /**
      * mark state as deleted. The state gets removed finally, 
@@ -65,9 +30,9 @@ class Syncroton_Backend_Content implements Syncroton_Backend_IContent
      * 
      * @param Syncroton_Model_IContent|string $_id
      */
-    public function delete($_id)
+    public function delete($id)
     {
-        $id = $_id instanceof Syncroton_Model_IContent ? $_id->id : $_id;
+        $id = $id instanceof $this->_modelInterfaceName ? $id->id : $id;
         
         $this->_db->update($this->_tablePrefix . 'content', array(
             'is_deleted' => 1
@@ -78,73 +43,45 @@ class Syncroton_Backend_Content implements Syncroton_Backend_IContent
     }
     
     /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_IContent
-     */
-    public function get($_id)
-    {
-        $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'content')
-            ->where('id = ?', $_id);
-    
-        $stmt = $this->_db->query($select);
-        $state = $stmt->fetchObject('Syncroton_Model_Content');
-        
-        if (! $state instanceof Syncroton_Model_IContent) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-        
-        if (!empty($state->creation_time)) {
-            $state->creation_time = new DateTime($state->creation_time, new DateTimeZone('utc'));
-        }
-    
-        return $state;
-    }
-    
-    /**
-     * @param Syncroton_Model_IDevice|string $_deviceId
-     * @param Syncroton_Model_IFolder|string $_folderId
+     * @param Syncroton_Model_IDevice|string $deviceId
+     * @param Syncroton_Model_IFolder|string $folderId
      * @param string $_contentId
      * @return Syncroton_Model_IContent
      */
-    public function getContentState($_deviceId, $_folderId, $_contentId)
+    public function getContentState($deviceId, $folderId, $contentId)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
+        $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId;
     
         $select = $this->_db->select()
             ->from($this->_tablePrefix . 'content')
             ->where($this->_db->quoteIdentifier('device_id')  . ' = ?', $deviceId)
             ->where($this->_db->quoteIdentifier('folder_id')  . ' = ?', $folderId)
-            ->where($this->_db->quoteIdentifier('contentid')  . ' = ?', $_contentId)
+            ->where($this->_db->quoteIdentifier('contentid')  . ' = ?', $contentId)
             ->where($this->_db->quoteIdentifier('is_deleted') . ' = ?', 0);
     
-        $stmt = $this->_db->query($select);
-        $state = $stmt->fetchObject('Syncroton_Model_Content');
-        
-        if (! $state instanceof Syncroton_Model_IContent) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-        
-        if (!empty($state->creation_time)) {
-            $state->creation_time = new DateTime($state->creation_time, new DateTimeZone('utc'));
-        }
-    
-        return $state;
+        $stmt = $this->_db->query($select);
+        $data = $stmt->fetch();
+        $stmt = null; # see https://bugs.php.net/bug.php?id=44081
+        
+        if ($data === false) {
+            throw new Syncroton_Exception_NotFound('id not found');
+        }
+        
+        return $this->_getObject($data);        
     }
     
     /**
      * get array of ids which got send to the client for a given class
      *
-     * @param Syncroton_Model_IDevice|string $_deviceId
-     * @param Syncroton_Model_IFolder|string $_folderId
+     * @param Syncroton_Model_IDevice|string $deviceId
+     * @param Syncroton_Model_IFolder|string $folderId
      * @return array
      */
-    public function getFolderState($_deviceId, $_folderId)
+    public function getFolderState($deviceId, $folderId)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
+        $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId;
                 
         $select = $this->_db->select()
             ->from($this->_tablePrefix . 'content', 'contentid')
@@ -161,13 +98,13 @@ class Syncroton_Backend_Content implements Syncroton_Backend_IContent
     /**
      * reset list of stored id
      *
-     * @param Syncroton_Model_IDevice|string $_deviceId
-     * @param Syncroton_Model_IFolder|string $_folderId
+     * @param Syncroton_Model_IDevice|string $deviceId
+     * @param Syncroton_Model_IFolder|string $folderId
      */
-    public function resetState($_deviceId, $_folderId)
+    public function resetState($deviceId, $folderId)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
+        $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId;
          
         $where = array(
             $this->_db->quoteInto($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId),
diff --git a/lib/ext/Syncroton/Backend/Device.php b/lib/ext/Syncroton/Backend/Device.php
index 8176a02..f7646b9 100644
--- a/lib/ext/Syncroton/Backend/Device.php
+++ b/lib/ext/Syncroton/Backend/Device.php
@@ -14,68 +14,13 @@
  * @package     Backend
  */
  
-class Syncroton_Backend_Device implements Syncroton_Backend_IDevice
+class Syncroton_Backend_Device extends Syncroton_Backend_ABackend implements Syncroton_Backend_IDevice
 {
-    /**
-     * the database adapter
-     * 
-     * @var Zend_Db_Adapter_Abstract
-     */
-    protected $_db;
+    protected $_tableName = 'device';
     
-    protected $_tablePrefix;
+    protected $_modelClassName = 'Syncroton_Model_Device';
     
-    public function __construct(Zend_Db_Adapter_Abstract $_db, $_tablePrefix = 'Syncroton_')
-    {
-        $this->_db          = $_db;
-        $this->_tablePrefix = $_tablePrefix;
-    }
-
-    /**
-     * create new device
-     * 
-     * @param Syncroton_Model_IDevice $_device
-     * @return Syncroton_Model_IDevice
-     */
-    public function create(Syncroton_Model_IDevice $_device)
-    {
-        $id = sha1(mt_rand(). microtime());
-        
-        $this->_db->insert($this->_tablePrefix . 'device', array(
-            'id'         => $id, 
-            'deviceid'   => $_device->deviceid,
-            'devicetype' => $_device->devicetype,
-            'owner_id'   => $_device->owner_id,
-            'policy_id'  => isset($_device->policy_id)  ? $_device->policy_id  : 1,
-            'policykey'  => isset($_device->policykey)  ? $_device->policykey  : null,
-            'useragent'  => isset($_device->useragent)  ? $_device->useragent  : '',
-            'acsversion' => isset($_device->acsversion) ? $_device->acsversion : '',
-            'remotewipe' => isset($_device->remotewipe) ? $_device->remotewipe : null 
-        ));
-        
-        return $this->get($id);
-    }
-    
-    /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_IDevice
-     */
-    public function get($_id)
-    {
-        $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'device')
-            ->where('id = ?', $_id);
-            
-        $stmt = $this->_db->query($select);
-        $device = $stmt->fetchObject('Syncroton_Model_Device');
-        
-        if (! $device instanceof Syncroton_Model_IDevice) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-        
-        return $device;
-    }
+    protected $_modelInterfaceName = 'Syncroton_Model_IDevice';
     
     /**
      * return device for this user
@@ -88,42 +33,24 @@ class Syncroton_Backend_Device implements Syncroton_Backend_IDevice
     public function getUserDevice($ownerId, $deviceId)
     {
         $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'device')
+            ->from($this->_tablePrefix . $this->_tableName)
             ->where('owner_id = ?', $ownerId)
             ->where('deviceid = ?', $deviceId);
         
         $stmt = $this->_db->query($select);
-        $device = $stmt->fetchObject('Syncroton_Model_Device');
+        $data = $stmt->fetch();
         
-        if (! $device instanceof Syncroton_Model_IDevice) {
-            throw new Syncroton_Exception_NotFound('device not found');
+        if ($data === false) {
+            throw new Syncroton_Exception_NotFound('id not found');
+        }
+
+        foreach ($data as $key => $value) {
+            unset($data[$key]);
+            $data[$this->_toCamelCase($key, false)] = $value;
         }
         
-        return $device;
-    }
-    
-    public function delete($_id)
-    {
-        $id = $_id instanceof Syncroton_Model_IDevice ? $_id->id : $_id;
-        
-        $result = $this->_db->delete($this->_tablePrefix . 'device', array('id = ?' => $id));
-        
-        return (bool) $result;
-    }
-    
-    public function update(Syncroton_Model_IDevice $_device)
-    {
-        $this->_db->update($this->_tablePrefix . 'device', array(
-            'acsversion'   => $_device->acsversion,
-            'policykey'    => $_device->policykey,
-            'pingfolder'   => $_device->pingfolder,
-            'pinglifetime' => $_device->pinglifetime,
-            'remotewipe'   => $_device->remotewipe
-        ), array(
-            'id = ?' => $_device->id
-        ));
-        
-        return $this->get($_device->id);
+        $model = new $this->_modelClassName($data);
         
+        return $model;    
     }
 }
diff --git a/lib/ext/Syncroton/Backend/Folder.php b/lib/ext/Syncroton/Backend/Folder.php
index 98fd4f4..f42eb08 100644
--- a/lib/ext/Syncroton/Backend/Folder.php
+++ b/lib/ext/Syncroton/Backend/Folder.php
@@ -16,169 +16,121 @@
  * @package     Syncroton
  * @subpackage  Backend
  */
-class Syncroton_Backend_Folder implements Syncroton_Backend_IFolder
+class Syncroton_Backend_Folder extends Syncroton_Backend_ABackend implements Syncroton_Backend_IFolder
 {
-    /**
-     * the database adapter
-     *
-     * @var Zend_Db_Adapter_Abstract
-     */
-    protected $_db;
+    protected $_tableName = 'folder';
     
-    protected $_tablePrefix;
+    protected $_modelClassName = 'Syncroton_Model_Folder';
     
-    public function __construct(Zend_Db_Adapter_Abstract $_db, $_tablePrefix = 'Syncroton_')
-    {
-        $this->_db = $_db;
-        
-        $this->_tablePrefix = $_tablePrefix;
-    }
+    protected $_modelInterfaceName = 'Syncroton_Model_IFolder';
     
     /**
-     * create new folder state
-     *
-     * @param Syncroton_Model_IFolder $_folder
-     * @return Syncroton_Model_IFolder
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_IFolder::getFolder()
      */
-    public function create(Syncroton_Model_IFolder $_folder)
+    public function getFolder($deviceId, $folderId)
     {
-        $id = sha1(mt_rand(). microtime());
-        $deviceId = $_folder->device_id instanceof Syncroton_Model_IDevice ? $_folder->device_id->id : $_folder->device_id;
-    
-        $this->_db->insert($this->_tablePrefix . 'folder', array(
-            'id'             => $id, 
-            'device_id'      => $deviceId,
-            'class'          => $_folder->class,
-            'folderid'       => $_folder->folderid instanceof Syncroton_Model_IFolder ? $_folder->folderid->id : $_folder->folderid,
-            'parentid'       => $_folder->parentid,
-            'displayname'    => $_folder->displayname,
-            'type'           => $_folder->type,
-            'creation_time'  => $_folder->creation_time->format('Y-m-d H:i:s'),
-            'lastfiltertype' => $_folder->lastfiltertype
-        ));
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
         
-        return $this->get($id);
-    }
-    
-    public function delete($_id)
-    {
-        $id = $_id instanceof Syncroton_Model_IFolder ? $_id->id : $_id;
-    
-        $result = $this->_db->delete($this->_tablePrefix . 'folder', array('id = ?' => $id));
-    
-        return (bool) $result;
+        $select = $this->_db->select()
+            ->from($this->_tablePrefix . $this->_tableName)
+            ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
+            ->where($this->_db->quoteIdentifier('folderid')  . ' = ?', $folderId);
+        
+        $stmt = $this->_db->query($select);
+        $data = $stmt->fetch();
+        
+        if ($data === false) {
+            throw new Syncroton_Exception_NotFound('id not found');
+        }
+        
+        return $this->_getObject($data);
     }
     
     /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_IFolder
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_IFolder::getFolderState()
      */
-    public function get($_id)
+    public function getFolderState($deviceId, $class)
     {
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
+        
         $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'folder')
-            ->where('id = ?', $_id);
-    
-        $stmt = $this->_db->query($select);
-        $state = $stmt->fetchObject('Syncroton_Model_Folder');
+            ->from($this->_tablePrefix . $this->_tableName)
+            ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
+            ->where($this->_db->quoteIdentifier('class')     . ' = ?', $class);
         
-        if (! $state instanceof Syncroton_Model_IFolder) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
+        $result = array();
         
-        if (!empty($state->creation_time)) {
-            $state->creation_time = new DateTime($state->creation_time, new DateTimeZone('utc'));
+        $stmt = $this->_db->query($select);
+        while ($data = $stmt->fetch()) {
+            $result[$data['folderid']] = $this->_getObject($data); 
         }
-    
-        return $state;
+        
+        return $result;
     }
     
     /**
-     * delete all stored folderId's for given device
-     *
-     * @param Syncroton_Model_Device|string $_deviceId
-     * @param string $_class
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_IFolder::resetState()
      */
-    public function resetState($_deviceId)
+    public function resetState($deviceId)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
          
         $where = array(
             $this->_db->quoteInto($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
         );
         
-        $this->_db->delete($this->_tablePrefix . 'folder', $where);
-    }
-    
-    public function update(Syncroton_Model_IFolder $_folder)
-    {
-        $deviceId = $_folder->device_id instanceof Syncroton_Model_IDevice ? $_folder->device_id->id : $_folder->device_id;
-    
-        $this->_db->update($this->_tablePrefix . 'folder', array(
-            'lastfiltertype' => $_folder->lastfiltertype,
-            'displayname'    => $_folder->displayname,
-            'parentid'       => $_folder->parentid
-        ), array(
-            'id = ?' => $_folder->id
-        ));
-    
-        return $this->get($_folder->id);
+        $this->_db->delete($this->_tablePrefix . $this->_tableName, $where);
     }
     
     /**
-     * get array of ids which got send to the client for a given class
-     *
-     * @param Syncroton_Model_Device|string $_deviceId
-     * @param string $_class
-     * @return array
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_ABackend::_fromCamelCase()
      */
-    public function getFolderState($_deviceId, $_class)
+    protected function _fromCamelCase($string)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        
-        $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'folder')
-            ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
-            ->where($this->_db->quoteIdentifier('class') . ' = ?', $_class);
-        
-        $result = array();
-        
-        $stmt = $this->_db->query($select);
-        while ($row = $stmt->fetchObject("Syncroton_Model_Folder")) {
-            $result[$row->folderid] = $row; 
-        }
-        
-        return $result;
-    }
+        switch ($string) {
+            case 'displayName':
+            case 'parentId':
+                return strtolower($string);
+                break;
+                
+            case 'serverId':
+                return 'folderid';
+                break;
+                
+            default:
+                return parent::_fromCamelCase($string);
+                
+                break;
+        }
+    }
     
     /**
-     * get folder indentified by $_folderId
-     *
-     * @param  Syncroton_Model_Device|string  $_deviceId
-     * @param  string                       $_folderId
-     * @return Syncroton_Model_IFolder
-     */
-    public function getFolder($_deviceId, $_folderId)
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_ABackend::_toCamelCase()
+     */
+    protected function _toCamelCase($string, $ucFirst = true)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        
-        $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'folder')
-            ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
-            ->where($this->_db->quoteIdentifier('folderid') . ' = ?', $_folderId);
-        
-        $stmt = $this->_db->query($select);
-        $folder = $stmt->fetchObject('Syncroton_Model_Folder');
-        
-        if (! $folder instanceof Syncroton_Model_IFolder) {
-            throw new Syncroton_Exception_NotFound('folder not found');
-        }
-        
-        if (!empty($folder->creation_time)) {
-            $folder->creation_time = new DateTime($folder->creation_time, new DateTimeZone('utc'));
-        }
-        
-        return $folder;
-    }
+        switch ($string) {
+            case 'displayname':
+                return 'displayName';
+                break;
+                
+            case 'parentid':
+                return 'parentId';
+                break;
+                
+            case 'folderid':
+                return 'serverId';
+                break;
+            
+            default:
+                return parent::_toCamelCase($string, $ucFirst);
+                
+                break;
+        }
+    }
 }
diff --git a/lib/ext/Syncroton/Backend/IBackend.php b/lib/ext/Syncroton/Backend/IBackend.php
new file mode 100644
index 0000000..56979fb
--- /dev/null
+++ b/lib/ext/Syncroton/Backend/IBackend.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Syncroton
+ *
+ * @package     Command
+ * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
+ * @copyright   Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Lars Kneschke <l.kneschke at metaways.de>
+ */
+
+/**
+ * class to handle ActiveSync Sync command
+ *
+ * @package     Backend
+ */
+ 
+interface Syncroton_Backend_IBackend
+{
+    /**
+     * Create a new device
+     *
+     * @param  Syncroton_Model_IDevice $device
+     * @return Syncroton_Model_IDevice
+     */
+    public function create($model);
+    
+    /**
+     * Deletes one or more existing devices
+     *
+     * @param string|array $_id
+     * @return void
+     */
+    public function delete($id);
+    
+    /**
+     * Return a single device
+     *
+     * @param string $_id
+     * @return Syncroton_Model_IDevice
+     */
+    public function get($id);
+    
+    /**
+     * Upates an existing persistent record
+     *
+     * @param  Syncroton_Model_IDevice $_device
+     * @return Syncroton_Model_IDevice
+     */
+    public function update($model);    
+}
diff --git a/lib/ext/Syncroton/Backend/IContent.php b/lib/ext/Syncroton/Backend/IContent.php
index 32d217a..8974e49 100644
--- a/lib/ext/Syncroton/Backend/IContent.php
+++ b/lib/ext/Syncroton/Backend/IContent.php
@@ -16,25 +16,9 @@
  * @package     Syncroton
  * @subpackage  Backend
  */
-interface Syncroton_Backend_IContent
+interface Syncroton_Backend_IContent extends Syncroton_Backend_IBackend
 {
     /**
-     * create new content state
-     *
-     * @param Syncroton_Model_IContent $_contentState
-     * @return Syncroton_Model_IContent
-     */
-    public function create(Syncroton_Model_IContent $_contentState);
-
-    /**
-     * mark state as deleted. The state gets removed finally, 
-     * when the synckey gets validated during next sync.
-     *
-     * @param Syncroton_Model_IContent|string $_id
-     */
-    public function delete($_id);
-
-    /**
      * @param Syncroton_Model_IDevice|string $_deviceId
      * @param Syncroton_Model_IFolder|string $_folderId
      * @param string $_contentId
diff --git a/lib/ext/Syncroton/Backend/IDevice.php b/lib/ext/Syncroton/Backend/IDevice.php
index d6de9fa..27a3a55 100644
--- a/lib/ext/Syncroton/Backend/IDevice.php
+++ b/lib/ext/Syncroton/Backend/IDevice.php
@@ -14,44 +14,12 @@
  * @package     Backend
  */
  
-interface Syncroton_Backend_IDevice
+interface Syncroton_Backend_IDevice extends Syncroton_Backend_IBackend
 {
     /**
-    * Create a new device
-    *
-    * @param  Syncroton_Model_IDevice $_device
-    * @return Syncroton_Model_IDevice
-    */
-    public function create(Syncroton_Model_IDevice $_device);
-    
-    /**
-     * Deletes one or more existing devices
-     *
-     * @param string|array $_id
-     * @return void
-     */
-    public function delete($_id);
-    
-    /**
-     * Return a single device
-     *
-     * @param string $_id
-     * @return Syncroton_Model_IDevice
-     */
-    public function get($_id);
-    
-    /**
      * @param unknown_type $userId
      * @param unknown_type $deviceId
      * @return Syncroton_Model_IDevice
      */
     public function getUserDevice($userId, $deviceId);
-    
-    /**
-     * Upates an existing persistent record
-     *
-     * @param  Syncroton_Model_IDevice $_device
-     * @return Syncroton_Model_IDevice
-     */
-    public function update(Syncroton_Model_IDevice $_device);    
 }
diff --git a/lib/ext/Syncroton/Backend/IFolder.php b/lib/ext/Syncroton/Backend/IFolder.php
index 039c5ba..fc1d078 100755
--- a/lib/ext/Syncroton/Backend/IFolder.php
+++ b/lib/ext/Syncroton/Backend/IFolder.php
@@ -16,43 +16,30 @@
  * @package     Syncroton
  * @subpackage  Backend
  */
-interface Syncroton_Backend_IFolder
+interface Syncroton_Backend_IFolder extends Syncroton_Backend_IBackend
 {
     /**
-     * @param Syncroton_Model_IFolder $_folder
-     * @return Syncroton_Model_IFolder
-     */
-    public function create(Syncroton_Model_IFolder $_folder);
-    
-    public function delete($_id);
-    
-    public function get($_id);
-    
-    /**
-     * get folder indentified by $_folderId
+     * get folder indentified by $folderId
      *
-     * @param  Syncroton_Model_Device|string  $_deviceId
-     * @param  string                       $_folderId
+     * @param  Syncroton_Model_Device|string  $deviceId
+     * @param  string                         $folderId
      * @return Syncroton_Model_IFolder
      */
-    public function getFolder($_deviceId, $_folderId);
+    public function getFolder($deviceId, $folderId);
     
     /**
      * get array of ids which got send to the client for a given class
      *
-     * @param Syncroton_Model_Device $_deviceId
-     * @param string $_class
+     * @param  Syncroton_Model_Device|string  $deviceId
+     * @param  string                         $class
      * @return array
      */
-    public function getFolderState($_deviceId, $_class);
+    public function getFolderState($deviceId, $class);
     
     /**
      * delete all stored folderId's for given device
      *
-     * @param Syncroton_Model_Device $_deviceId
-     * @param string $_class
+     * @param  Syncroton_Model_Device|string  $deviceId
      */
-    public function resetState($_deviceId);
-    
-    public function update(Syncroton_Model_IFolder $_folder);
+    public function resetState($deviceId);
 }
diff --git a/lib/ext/Syncroton/Backend/ISyncState.php b/lib/ext/Syncroton/Backend/ISyncState.php
index d453665..144f61e 100644
--- a/lib/ext/Syncroton/Backend/ISyncState.php
+++ b/lib/ext/Syncroton/Backend/ISyncState.php
@@ -16,29 +16,27 @@
  * @package     Syncroton
  * @subpackage  Backend
  */
-interface Syncroton_Backend_ISyncState
+interface Syncroton_Backend_ISyncState extends Syncroton_Backend_IBackend
 {
     /**
      * create new sync state
-     *
-     * @param Syncroton_Model_ISyncState $_syncState
-     * @return Syncroton_Model_ISyncState
+     * 
+     * @param  Syncroton_Model_IDevice  $model
+     * @param  boolean                  $keepPreviousSyncState
      */
-    public function create(Syncroton_Model_ISyncState $_syncState);
+    #public function create($model, $keepPreviousSyncState = true);
 
     /**
      * always returns the latest syncstate
      *
-     * @param  Syncroton_Model_IDevice|string  $_deviceId
-     * @param  Syncroton_Model_IFolder|string  $_folderId
+     * @param  Syncroton_Model_IDevice|string  $deviceId
+     * @param  Syncroton_Model_IFolder|string  $folderId
      * @return Syncroton_Model_SyncState
      */
-    public function getSyncState($_deviceId, $_folderId);
+    public function getSyncState($deviceId, $folderId);
 
     public function resetState($_deviceId, $_type);
 
-    public function update(Syncroton_Model_ISyncState $_syncState);
-
     /**
      * get array of ids which got send to the client for a given class
      *
diff --git a/lib/ext/Syncroton/Backend/Policy.php b/lib/ext/Syncroton/Backend/Policy.php
new file mode 100644
index 0000000..5163359
--- /dev/null
+++ b/lib/ext/Syncroton/Backend/Policy.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Syncroton
+ *
+ * @package     Command
+ * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
+ * @copyright   Copyright (c) 2012-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Lars Kneschke <l.kneschke at metaways.de>
+ */
+
+/**
+ * class to handle ActiveSync Sync command
+ *
+ * @package     Backend
+ */
+ 
+class Syncroton_Backend_Policy extends Syncroton_Backend_ABackend #implements Syncroton_Backend_IDevice
+{
+    protected $_tableName = 'policy';
+    
+    protected $_modelClassName = 'Syncroton_Model_Policy';
+    
+    protected $_modelInterfaceName = 'Syncroton_Model_IPolicy';
+}
diff --git a/lib/ext/Syncroton/Backend/SyncState.php b/lib/ext/Syncroton/Backend/SyncState.php
index 078aacc..87dc39c 100644
--- a/lib/ext/Syncroton/Backend/SyncState.php
+++ b/lib/ext/Syncroton/Backend/SyncState.php
@@ -16,46 +16,23 @@
  * @package     Syncroton
  * @subpackage  Backend
  */
-class Syncroton_Backend_SyncState implements Syncroton_Backend_ISyncState
+class Syncroton_Backend_SyncState extends Syncroton_Backend_ABackend implements Syncroton_Backend_ISyncState
 {
-    /**
-     * the database adapter
-     *
-     * @var Zend_Db_Adapter_Abstract
-     */
-    protected $_db;
-    
-    protected $_tablePrefix;
-    
-    public function __construct(Zend_Db_Adapter_Abstract $_db, $_tablePrefix = 'Syncroton_')
-    {
-        $this->_db          = $_db;
-        $this->_tablePrefix = $_tablePrefix;
-    }
+    protected $_tableName = 'synckey';
+    
+    protected $_modelClassName = 'Syncroton_Model_SyncState';
+
+    protected $_modelInterfaceName = 'Syncroton_Model_ISyncState';
     
     /**
-     * create new sync state
-     *
-     * @param Syncroton_Model_ISyncState $_syncState
-     * @return Syncroton_Model_SyncState
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_ISyncState::create()
      */
-    public function create(Syncroton_Model_ISyncState $_syncState, $_keepPreviousSyncState = true)
+    public function create($model, $keepPreviousSyncState = true)
     {
-        $id = sha1(mt_rand(). microtime());
-        $deviceId = $_syncState->device_id instanceof Syncroton_Model_IDevice ? $_syncState->device_id->id : $_syncState->device_id;
-    
-        $this->_db->insert($this->_tablePrefix . 'synckey', array(
-            'id'          => $id, 
-            'device_id'   => $deviceId,
-            'type'        => $_syncState->type instanceof Syncroton_Model_IFolder ? $_syncState->type->id : $_syncState->type,
-            'counter'     => $_syncState->counter,
-            'lastsync'    => $_syncState->lastsync->format('Y-m-d H:i:s'),
-            'pendingdata' => isset($_syncState->pendingdata) && is_array($_syncState->pendingdata) ? Zend_Json::encode($_syncState->pendingdata) : null
-        ));
-        
-        $state = $this->get($id);
+        $state = parent::create($model);
         
-        if ($_keepPreviousSyncState !== true) {
+        if ($keepPreviousSyncState !== true) {
             // remove all other synckeys
             $this->_deleteOtherStates($state);
         }
@@ -63,162 +40,140 @@ class Syncroton_Backend_SyncState implements Syncroton_Backend_ISyncState
         return $state;
     }
     
-    protected function _deleteOtherStates(Syncroton_Model_ISyncState $_state)
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_ABackend::_convertModelToArray()
+     */
+    protected function _convertModelToArray($model)
+    {
+        $model = parent::_convertModelToArray($model);
+        
+        $model['pendingdata'] = isset($model['pendingdata']) && is_array($model['pendingdata']) ? Zend_Json::encode($model['pendingdata']) : null;
+        
+        return $model;
+    }
+    
+    /**
+     * 
+     * @param Syncroton_Model_ISyncState $state
+     */
+    protected function _deleteOtherStates(Syncroton_Model_ISyncState $state)
     {
         // remove all other synckeys
         $where = array(
-            'device_id = ?' => $_state->device_id,
-            'type = ?'      => $_state->type,
-            'counter != ?'  => $_state->counter
+            'device_id = ?' => $state->deviceId,
+            'type = ?'      => $state->type,
+            'counter != ?'  => $state->counter
         );
     
-        $this->_db->delete($this->_tablePrefix . 'synckey', $where);
+        $this->_db->delete($this->_tablePrefix . $this->_tableName, $where);
     
         return true;
     
     }
     
     /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_SyncState
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_ABackend::_getObject()
      */
-    public function get($_id)
+    protected function _getObject($data)
     {
-        $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'synckey')
-            ->where('id = ?', $_id);
-    
-        $stmt = $this->_db->query($select);
-        $state = $stmt->fetchObject('Syncroton_Model_SyncState');
-        $stmt = null; # see https://bugs.php.net/bug.php?id=44081
+        $model = parent::_getObject($data);
         
-        if (! $state instanceof Syncroton_Model_ISyncState) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-        
-        $this->_convertFields($state);
-        
-        return $state;
-    }
-    
-    protected function _convertFields(Syncroton_Model_SyncState $state)
-    {
-        if (!empty($state->lastsync)) {
-            $state->lastsync = new DateTime($state->lastsync, new DateTimeZone('utc'));
-        }
-        if ($state->pendingdata !== NULL) {
-            $state->pendingdata = Zend_Json::decode($state->pendingdata);
+        if ($model->pendingdata !== NULL) {
+            $model->pendingdata = Zend_Json::decode($model->pendingdata);
         }
+        
+        return $model;
     }
     
     /**
-     * always returns the latest syncstate
-     * 
-     * @param  Syncroton_Model_IDevice|string  $_deviceId
-     * @param  Syncroton_Model_IFolder|string  $_folderId
-     * @return Syncroton_Model_SyncState
+     * (non-PHPdoc)
+     * @see Syncroton_Backend_ISyncState::getSyncState()
      */
-    public function getSyncState($_deviceId, $_folderId)
+    public function getSyncState($deviceId, $folderId)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
+        $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId;
     
         $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'synckey')
+            ->from($this->_tablePrefix . $this->_tableName)
             ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
             ->where($this->_db->quoteIdentifier('type')      . ' = ?', $folderId)
             ->order('counter DESC')
             ->limit(1);
         
-        $stmt = $this->_db->query($select);
-        $state = $stmt->fetchObject('Syncroton_Model_SyncState');
-        $stmt = null; # see https://bugs.php.net/bug.php?id=44081
-        
-        if (! $state instanceof Syncroton_Model_ISyncState) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-        
-        $this->_convertFields($state);
-        
-        return $state;
+        $stmt = $this->_db->query($select);
+        $data = $stmt->fetch();
+        $stmt = null; # see https://bugs.php.net/bug.php?id=44081
+        
+        if ($data === false) {
+            throw new Syncroton_Exception_NotFound('id not found');
+        }
+        
+        return $this->_getObject($data);
     }
     
     /**
      * delete all stored synckeys for given type
      *
-     * @param  Syncroton_Model_IDevice|string  $_deviceId
-     * @param  Syncroton_Model_IFolder|string  $_folderId
+     * @param  Syncroton_Model_IDevice|string  $deviceId
+     * @param  Syncroton_Model_IFolder|string  $folderId
      */
-    public function resetState($_deviceId, $_folderId)
+    public function resetState($deviceId, $folderId)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
+        $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId;
          
         $where = array(
             $this->_db->quoteInto($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId),
             $this->_db->quoteInto($this->_db->quoteIdentifier('type') . ' = ?',      $folderId)
         );
     
-        $this->_db->delete($this->_tablePrefix . 'synckey', $where);
-    }
-    
-    public function update(Syncroton_Model_ISyncState $_syncState)
-    {
-        $deviceId = $_syncState->device_id instanceof Syncroton_Model_IDevice ? $_syncState->device_id->id : $_syncState->device_id;
-        
-        $this->_db->update($this->_tablePrefix . 'synckey', array(
-            'counter'     => $_syncState->counter,
-            'lastsync'    => $_syncState->lastsync->format('Y-m-d H:i:s'),
-            'pendingdata' => isset($_syncState->pendingdata) && is_array($_syncState->pendingdata) ? Zend_Json::encode($_syncState->pendingdata) : null
-        ), array(
-            'id = ?' => $_syncState->id
-        ));
-        
-        return $this->get($_syncState->id);
+        $this->_db->delete($this->_tablePrefix . $this->_tableName, $where);
     }
     
     /**
      * get array of ids which got send to the client for a given class
      *
-     * @param  Syncroton_Model_IDevice|string  $_deviceId
-     * @param  Syncroton_Model_IFolder|string  $_folderId
+     * @param  Syncroton_Model_IDevice|string  $deviceId
+     * @param  Syncroton_Model_IFolder|string  $folderId
      * @return Syncroton_Model_SyncState
      */
-    public function validate($_deviceId, $_folderId, $_syncKey)
+    public function validate($deviceId, $folderId, $syncKey)
     {
-        $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
-        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+        $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId;
+        $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId;
         
         $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'synckey')
+            ->from($this->_tablePrefix . $this->_tableName)
             ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
-            ->where($this->_db->quoteIdentifier('counter')   . ' = ?', $_syncKey)
+            ->where($this->_db->quoteIdentifier('counter')   . ' = ?', $syncKey)
             ->where($this->_db->quoteIdentifier('type')      . ' = ?', $folderId);
         
         $stmt = $this->_db->query($select);
-        $state = $stmt->fetchObject('Syncroton_Model_SyncState');
+        $data = $stmt->fetch();
         $stmt = null; # see https://bugs.php.net/bug.php?id=44081
         
-        if (! $state instanceof Syncroton_Model_ISyncState) {
+        if ($data === false) {
             return false;
         }
 
-        $this->_convertFields($state);
+        $state = $this->_getObject($data);
         
         // check if this was the latest syncKey
         $select = $this->_db->select()
-            ->from($this->_tablePrefix . 'synckey')
+            ->from($this->_tablePrefix . $this->_tableName)
             ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId)
-            ->where($this->_db->quoteIdentifier('counter') . ' = ?', $_syncKey + 1)
-            ->where($this->_db->quoteIdentifier('type') . ' = ?', $folderId);
+            ->where($this->_db->quoteIdentifier('counter')   . ' = ?', $syncKey + 1)
+            ->where($this->_db->quoteIdentifier('type')      . ' = ?', $folderId);
         
         $stmt = $this->_db->query($select);
-        $moreRecentState = $stmt->fetchObject('Syncroton_Model_SyncState');
+        $moreRecentStateData = $stmt->fetch();
         $stmt = null; # see https://bugs.php.net/bug.php?id=44081
         
         // found more recent synckey => the last sync repsone got not received by the client
-        if ($moreRecentState instanceof Syncroton_Model_ISyncState) {
+        if ($moreRecentStateData !== false) {
             // undelete entries marked as deleted in Syncroton_content table
             $this->_db->update($this->_tablePrefix . 'content', array(
                 'is_deleted'  => 0,
diff --git a/lib/ext/Syncroton/Command/FolderCreate.php b/lib/ext/Syncroton/Command/FolderCreate.php
index 47aefcb..1932848 100644
--- a/lib/ext/Syncroton/Command/FolderCreate.php
+++ b/lib/ext/Syncroton/Command/FolderCreate.php
@@ -28,14 +28,10 @@ class Syncroton_Command_FolderCreate extends Syncroton_Command_Wbxml
     );
     
     /**
-     * synckey sent from client
-     *
-     * @var string
+     * 
+     * @var Syncroton_Model_Folder
      */
-    protected $_syncKey;
-    protected $_parentId;
-    protected $_displayName;
-    protected $_type;
+    protected $_folder;
     
     /**
      * parse FolderCreate request
@@ -45,29 +41,38 @@ class Syncroton_Command_FolderCreate extends Syncroton_Command_Wbxml
     {
         $xml = simplexml_import_dom($this->_requestBody);
         
-        $this->_syncKey     = (int)$xml->SyncKey;
-        $this->_parentId    = (string)$xml->ParentId;
-        $this->_displayName = (string)$xml->DisplayName;
-        $this->_type        = (int)$xml->Type;
-        
+        $syncKey = (int)$xml->SyncKey;
+
         if ($this->_logger instanceof Zend_Log) 
-            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $this->_syncKey");        
+            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey");
+        
+        if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) {
+        
+            $this->_syncStateBackend->resetState($this->_device, 'FolderSync');
+        
+            return;
+        }
         
-        switch((int)$xml->Type) {
+        $folder   = new Syncroton_Model_Folder($xml);
+        
+        if ($this->_logger instanceof Zend_Log)
+            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " parentId: {$folder->parentId} displayName: {$folder->displayName}");
+        
+        switch($folder->type) {
             case Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR_USER_CREATED:
-                $this->_class = Syncroton_Data_Factory::CLASS_CALENDAR;
+                $folder->class = Syncroton_Data_Factory::CLASS_CALENDAR;
                 break;
                 
             case Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED:
-                $this->_class = Syncroton_Data_Factory::CLASS_CONTACTS;
+                $folder->class = Syncroton_Data_Factory::CLASS_CONTACTS;
                 break;
                 
             case Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED:
-                $this->_class = Syncroton_Data_Factory::CLASS_EMAIL;
+                $folder->class = Syncroton_Data_Factory::CLASS_EMAIL;
                 break;
                 
             case Syncroton_Command_FolderSync::FOLDERTYPE_TASK_USER_CREATED:
-                $this->_class = Syncroton_Data_Factory::CLASS_TASKS;
+                $folder->class = Syncroton_Data_Factory::CLASS_TASKS;
                 break;
                 
             default:
@@ -75,7 +80,14 @@ class Syncroton_Command_FolderCreate extends Syncroton_Command_Wbxml
                 break;
         }
         
-        $this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $this->_syncKey);
+        $folder->deviceId     = $this->_device;
+        $folder->creationTime = $this->_syncTimeStamp;
+        
+        $dataController = Syncroton_Data_Factory::factory($folder->class, $this->_device, $this->_syncTimeStamp);
+        
+        $this->_folder = $dataController->createFolder($folder);
+        
+        $this->_folderBackend->create($this->_folder);
     }
     
     /**
@@ -85,34 +97,22 @@ class Syncroton_Command_FolderCreate extends Syncroton_Command_Wbxml
     {
         $folderCreate = $this->_outputDom->documentElement;
         
-        if($this->_syncState == false) {
+        if (!$this->_syncState instanceof Syncroton_Model_SyncState) {
             if ($this->_logger instanceof Zend_Log) 
-                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " INVALID synckey");
+                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed.");
             $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY));
+            
         } else {
             $this->_syncState->counter++;
+            $this->_syncState->lastsync = $this->_syncTimeStamp;
             
-            $dataController = Syncroton_Data_Factory::factory($this->_class, $this->_device, $this->_syncTimeStamp);
-            
-            $folder = $dataController->createFolder(new Syncroton_Model_Folder(array(
-                'device_id'         => $this->_device,
-                'class'             => $this->_class,
-                'parentid'          => $this->_parentId,
-                'displayname'       => $this->_displayName,
-                'type'              => $this->_type,
-                'creation_time'     => $this->_syncTimeStamp,
-                'lastfiltertype'    => null
-            )));
+            // store folder in state backend
+            $this->_syncStateBackend->update($this->_syncState);
             
             // create xml output
             $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status',   Syncroton_Command_FolderSync::STATUS_SUCCESS));
             $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey',  $this->_syncState->counter));
-            $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ServerId', $folder->folderid));
-
-            // store folder in state backend
-            $this->_folderBackend->create($folder);            
-            
-            $this->_syncStateBackend->update($this->_syncState);
+            $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ServerId', $this->_folder->serverId));
         }
         
         return $this->_outputDom;
diff --git a/lib/ext/Syncroton/Command/FolderDelete.php b/lib/ext/Syncroton/Command/FolderDelete.php
index e390105..4259ea8 100644
--- a/lib/ext/Syncroton/Command/FolderDelete.php
+++ b/lib/ext/Syncroton/Command/FolderDelete.php
@@ -42,16 +42,22 @@ class Syncroton_Command_FolderDelete extends Syncroton_Command_Wbxml
     {
         $xml = simplexml_import_dom($this->_requestBody);
         
-        $syncKey  = (int)$xml->SyncKey;
-        $folderId = (string)$xml->ServerId;
+        $syncKey = (int)$xml->SyncKey;
         
         if ($this->_logger instanceof Zend_Log) 
-            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey");        
+            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey");
         
-        $this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey);
+        if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) {
+        
+            $this->_syncStateBackend->resetState($this->_device, 'FolderSync');
+        
+            return;
+        }
+        
+        $serverId = (string)$xml->ServerId;
         
         try {
-            $this->_folder = $this->_folderBackend->getFolder($this->_device, $folderId);
+            $this->_folder = $this->_folderBackend->getFolder($this->_device, $serverId);
             
             $dataController = Syncroton_Data_Factory::factory($this->_folder->class, $this->_device, $this->_syncTimeStamp);
             
@@ -73,19 +79,23 @@ class Syncroton_Command_FolderDelete extends Syncroton_Command_Wbxml
     {
         $folderDelete = $this->_outputDom->documentElement;
         
-        if($this->_syncState == false) {
+        if (!$this->_syncState instanceof Syncroton_Model_SyncState) {
             if ($this->_logger instanceof Zend_Log)
-                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " INVALID synckey");
+                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed.");
             $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY));
+            
         } else {
             if ($this->_folder instanceof Syncroton_Model_IFolder) {
                 $this->_syncState->counter++;
+                $this->_syncState->lastsync = $this->_syncTimeStamp;
+                
+                // store folder in state backend
+                $this->_syncStateBackend->update($this->_syncState);
                 
                 // create xml output
                 $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_SUCCESS));
                 $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter));
-                
-                $this->_syncStateBackend->update($this->_syncState);
+
             } else {
                 // create xml output
                 $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_FOLDER_NOT_FOUND));
diff --git a/lib/ext/Syncroton/Command/FolderSync.php b/lib/ext/Syncroton/Command/FolderSync.php
index df82ca4..9017798 100644
--- a/lib/ext/Syncroton/Command/FolderSync.php
+++ b/lib/ext/Syncroton/Command/FolderSync.php
@@ -73,21 +73,13 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
      */
     public function handle()
     {
-        #if ($this->_statusProvisioning = $this->_checkProvisioningNeeded() !== false) {
-        #    if (version_compare($this->_device->acsversion, '14.0', '<')) {
-        #        throw new Syncroton_Exception_ProvisioningNeeded();
-        #    } else {
-        #        return;
-        #    }
-        #}
-        
         $xml = simplexml_import_dom($this->_requestBody);
         $syncKey = (int)$xml->SyncKey;
         
         if ($this->_logger instanceof Zend_Log) 
             $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey");
         
-        if ($syncKey == 0) {
+        if ($syncKey === 0) {
             $this->_syncState = new Syncroton_Model_SyncState(array(
                 'device_id' => $this->_device,
                 'counter'   => 0,
@@ -97,12 +89,12 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
             
             // reset state of foldersync
             $this->_syncStateBackend->resetState($this->_device, 'FolderSync');
-        } else {
-            if (($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) {
-                $this->_syncState->lastsync = $this->_syncTimeStamp;
-            } else  {
-                $this->_syncStateBackend->resetState($this->_device, 'FolderSync');
-            }
+            
+            return;
+        } 
+        
+        if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) {
+            $this->_syncStateBackend->resetState($this->_device, 'FolderSync');
         }
     }
     
@@ -115,19 +107,10 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
     {
         $folderSync = $this->_outputDom->documentElement;
         
-        // provioning needed?
-        #if ($this->_statusProvisioning !== false) {
-        #    if ($this->_logger instanceof Zend_Log) 
-        #        $this->_logger->info(__METHOD__ . '::' . __LINE__ . " provisiong needed or remote wipe requested");
-        #    $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', $this->_statusProvisioning));
-        #    
-        #    return $this->_outputDom;
-        #}
-        
         // invalid synckey provided
-        if($this->_syncState === false) {
+        if (!$this->_syncState instanceof Syncroton_Model_SyncState) {
             if ($this->_logger instanceof Zend_Log) 
-                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " INVALID synckey provided");
+                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed.");
             $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', self::STATUS_INVALID_SYNC_KEY));
 
             return $this->_outputDom;
@@ -141,7 +124,7 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
         foreach($this->_classes as $class) {
             try {
                 $dataController = Syncroton_Data_Factory::factory($class, $this->_device, $this->_syncTimeStamp);
-            } catch (Zend_Exception $ze) {
+            } catch (Exception $e) {
                 // backend not defined
                 if ($this->_logger instanceof Zend_Log)
                     $this->_logger->info(__METHOD__ . '::' . __LINE__ . " no data backend defined for class: " . $class);
@@ -150,6 +133,7 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
             
             // retrieve all folders available in data backend
             $serverFolders = $dataController->getAllFolders();
+            
             // retrieve all folders sent to client
             $clientFolders = $this->_folderBackend->getFolderState($this->_device, $class);
             
@@ -161,24 +145,22 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
             } else {
                 $clientFoldersIds = array_keys($clientFolders);
             } 
-                           
+            
             // calculate added entries
             $serverDiff = array_diff($serverFoldersIds, $clientFoldersIds);
             foreach($serverDiff as $serverFolderId) {
+                // have we created a folderObject in syncroton_folder before?
                 if (isset($clientFolders[$serverFolderId])) {
-                    $adds[] = $clientFolders[$serverFolderId];
+                    $add = $clientFolders[$serverFolderId];
                 } else {
-                    $adds[] = new Syncroton_Model_Folder(array(
-                        'device_id'         => $this->_device,
-                        'class'             => $class,
-                        'folderid'          => $serverFolders[$serverFolderId]->folderid,
-                        'parentid'          => $serverFolders[$serverFolderId]->parentid,
-                        'displayname'       => $serverFolders[$serverFolderId]->displayname,
-                        'type'              => $serverFolders[$serverFolderId]->type,
-                        'creation_time'     => $this->_syncTimeStamp,
-                        'lastfiltertype'    => null
-                    ));
+                    $add = $serverFolders[$serverFolderId];
+                    $add->creationTime = $this->_syncTimeStamp;
+                    $add->deviceId     = $this->_device;
+                    unset($add->id);
                 }
+                $add->class = $class;
+                
+                $adds[] = $add;
             }
             
             // calculate deleted entries
@@ -191,6 +173,7 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
         $count = count($adds) + /*count($changes) + */count($deletes);
         if($count > 0) {
             $this->_syncState->counter++;
+            $this->_syncState->lastsync = $this->_syncTimeStamp;
         }
         
         // create xml output
@@ -200,17 +183,10 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
         $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Count', $count));
         
         foreach($adds as $folder) {
-            
             $add = $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Add'));
-            $add->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ServerId', $folder->folderid));
-            $add->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ParentId', $folder->parentid));
-            
-            $displayName = $this->_outputDom->createElementNS('uri:FolderHierarchy', 'DisplayName');
-            $displayName->appendChild($this->_outputDom->createTextNode($folder->displayname));
-            $add->appendChild($displayName);
-            
-            $add->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Type', $folder->type));
             
+            $folder->appendXML($add);
+
             // store folder in backend
             if (empty($folder->id)) {
                 $this->_folderBackend->create($folder);
@@ -219,7 +195,7 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
         
         foreach($deletes as $folder) {
             $delete = $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Delete'));
-            $delete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ServerId', $folder->folderid));
+            $delete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ServerId', $folder->serverId));
             
             $this->_folderBackend->delete($folder);
         }
diff --git a/lib/ext/Syncroton/Command/FolderUpdate.php b/lib/ext/Syncroton/Command/FolderUpdate.php
index 5089bd7..d219ede 100644
--- a/lib/ext/Syncroton/Command/FolderUpdate.php
+++ b/lib/ext/Syncroton/Command/FolderUpdate.php
@@ -20,17 +20,11 @@ class Syncroton_Command_FolderUpdate extends Syncroton_Command_Wbxml
     protected $_defaultNameSpace    = 'uri:FolderHierarchy';
     protected $_documentElement     = 'FolderUpdate';
     
-    protected $_classes             = array('Contacts', 'Tasks', 'Email');
-    
     /**
-     * synckey sent from client
-     *
-     * @var string
+     * 
+     * @var Syncroton_Model_Folder
      */
-    protected $_syncKey;
-    protected $_parentId;
-    protected $_displayName;
-    protected $_serverId;
+    protected $_folderUpdate;
     
     /**
      * parse FolderUpdate request
@@ -40,23 +34,34 @@ class Syncroton_Command_FolderUpdate extends Syncroton_Command_Wbxml
     {
         $xml = simplexml_import_dom($this->_requestBody);
         
-        $this->_syncKey     = (int)$xml->SyncKey;
-        $this->_serverId    = (string)$xml->ServerId;
+        $syncKey = (int)$xml->SyncKey;
         
         if ($this->_logger instanceof Zend_Log) 
-            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $this->_syncKey parentId $this->_parentId name $this->_displayName");
+            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey");
 
-        $this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $this->_syncKey);
+        if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) {
+            
+            $this->_syncStateBackend->resetState($this->_device, 'FolderSync');
+            
+            return;
+        }
+        
+        $folderUpdate = new Syncroton_Model_Folder($xml);
+        
+        if ($this->_logger instanceof Zend_Log)
+            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " parentId: {$folderUpdate->parentId} displayName: {$folderUpdate->displayName}");
         
         try {
-            $folder = $this->_folderBackend->getFolder($this->_device, $this->_serverId);
+            $folder = $this->_folderBackend->getFolder($this->_device, $folderUpdate->serverId);
             
-            $folder->displayname = (string)$xml->DisplayName;
-            $folder->parentid    = (string)$xml->ParentId;
+            $folder->displayName = $folderUpdate->displayName;
+            $folder->parentId    = $folderUpdate->parentId;
             
             $dataController = Syncroton_Data_Factory::factory($folder->class, $this->_device, $this->_syncTimeStamp);
             
+            // update folder in data backend
             $dataController->updateFolder($folder);
+            // update folder status in Syncroton backend
             $this->_folderBackend->update($folder);
             
         } catch (Syncroton_Exception_NotFound $senf) {
@@ -74,18 +79,21 @@ class Syncroton_Command_FolderUpdate extends Syncroton_Command_Wbxml
     {
         $folderUpdate = $this->_outputDom->documentElement;
         
-        if($this->_syncState == false) {
+        if (!$this->_syncState instanceof Syncroton_Model_SyncState) {
             if ($this->_logger instanceof Zend_Log) 
-                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " INVALID synckey");
-            $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY));
+                $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed.");
+            $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status',  Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY));
+            
         } else {
             $this->_syncState->counter++;
+            $this->_syncState->lastsync = $this->_syncTimeStamp;
             
+            // store folder in state backend
+            $this->_syncStateBackend->update($this->_syncState);
+                        
             // create xml output
             $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status',  Syncroton_Command_FolderSync::STATUS_SUCCESS));
             $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter));
-            
-            $this->_syncStateBackend->update($this->_syncState);
         }
         
         return $this->_outputDom;
diff --git a/lib/ext/Syncroton/Command/ItemOperations.php b/lib/ext/Syncroton/Command/ItemOperations.php
index 12fd0ea..7692970 100644
--- a/lib/ext/Syncroton/Command/ItemOperations.php
+++ b/lib/ext/Syncroton/Command/ItemOperations.php
@@ -127,10 +127,9 @@ class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
                     $fetchTag->appendChild($properties);
                 }
             } catch (Syncroton_Exception_NotFound $e) {
-            //echo __LINE__;
                 $response->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_ITEM_FAILED_CONVERSION));
             } catch (Exception $e) {
-            //echo __LINE__; echo $e->getMessage(); echo $e->getTraceAsString();
+                //echo __LINE__; echo $e->getMessage(); echo $e->getTraceAsString();
                 $response->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SERVER_ERROR));
             }
         }
diff --git a/lib/ext/Syncroton/Command/Options.php b/lib/ext/Syncroton/Command/Options.php
index cbb68c1..35a98e7 100644
--- a/lib/ext/Syncroton/Command/Options.php
+++ b/lib/ext/Syncroton/Command/Options.php
@@ -24,15 +24,9 @@ class Syncroton_Command_Options
      */
     public function getResponse()
     {
-        // same header like Exchange 2003
-        #header("MS-Server-ActiveSync: 8.3");
-        #header("MS-ASProtocolVersions: 2.5,12.0");
-        #header("MS-ASProtocolCommands: CreateCollection,DeleteCollection,FolderCreate,FolderDelete,FolderSync,FolderUpdate,GetAttachment,GetItemEstimate,ItemOperations,MeetingResponse,MoveCollection,MoveItems,Provision,ResolveRecipients,Ping,SendMail,Search,Settings,SmartForward,SmartReply,Sync");
-        
         // same header like Exchange 2xxx???
         header('MS-Server-ActiveSync:  14.00.0536.000');
-        header("MS-ASProtocolVersions: 2.5,12.0,12.1,14.0,14.1");
+        header("MS-ASProtocolVersions: 12.0,12.1,14.0,14.1");
         header("MS-ASProtocolCommands: CreateCollection,DeleteCollection,FolderCreate,FolderDelete,FolderSync,FolderUpdate,GetAttachment,GetHierarchy,GetItemEstimate,ItemOperations,MeetingResponse,MoveCollection,MoveItems,Provision,ResolveRecipients,Ping,SendMail,Search,Settings,SmartForward,SmartReply,Sync,ValidateCert");
-        header('MS-ASProtocolRevisions: 12.1r1');
     }    
 }
diff --git a/lib/ext/Syncroton/Command/Ping.php b/lib/ext/Syncroton/Command/Ping.php
index a2c88b6..e0c101e 100644
--- a/lib/ext/Syncroton/Command/Ping.php
+++ b/lib/ext/Syncroton/Command/Ping.php
@@ -55,7 +55,7 @@ class Syncroton_Command_Ping extends Syncroton_Command_Wbxml
     {
         $intervalStart = time();
         $status = self::STATUS_NO_CHANGES_FOUND;
-
+        
         // the client does not send a wbxml document, if the Ping parameters did not change compared with the last request
         if($this->_requestBody instanceof DOMDocument) {
             $xml = simplexml_import_dom($this->_requestBody);
@@ -113,7 +113,7 @@ class Syncroton_Command_Ping extends Syncroton_Command_Wbxml
                         if ($this->_logger instanceof Zend_Log) 
                             $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage());
                         if ($this->_logger instanceof Zend_Log) 
-                            $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' syncstate not found. enforce sync for folder: ' . $folder->folderid);
+                            $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' syncstate not found. enforce sync for folder: ' . $folder->serverId);
                         
                         $foundChanges = true;
                     }
@@ -151,9 +151,9 @@ class Syncroton_Command_Ping extends Syncroton_Command_Wbxml
             $folders = $ping->appendChild($this->_outputDom->createElementNS('uri:Ping', 'Folders'));
             
             foreach($this->_foldersWithChanges as $changedFolder) {
-                $folder = $folders->appendChild($this->_outputDom->createElementNS('uri:Ping', 'Folder', $changedFolder->folderid));
+                $folder = $folders->appendChild($this->_outputDom->createElementNS('uri:Ping', 'Folder', $changedFolder->serverId));
                 if ($this->_logger instanceof Zend_Log) 
-                    $this->_logger->info(__METHOD__ . '::' . __LINE__ . " DeviceId: " . $this->_device->deviceid . " changes in folder: " . $changedFolder->folderid);
+                    $this->_logger->info(__METHOD__ . '::' . __LINE__ . " DeviceId: " . $this->_device->deviceid . " changes in folder: " . $changedFolder->serverId);
             }
         }                
     }
diff --git a/lib/ext/Syncroton/Command/Provision.php b/lib/ext/Syncroton/Command/Provision.php
index 7cf53a2..b4ddf41 100644
--- a/lib/ext/Syncroton/Command/Provision.php
+++ b/lib/ext/Syncroton/Command/Provision.php
@@ -35,6 +35,7 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
     
     protected $_policyType;
     protected $_sendPolicyKey;
+    protected $_deviceInformationSet = false;
     
     /**
      * process the XML file and add, change, delete or fetches data 
@@ -53,6 +54,12 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
             $this->_device = $this->_deviceBackend->update($this->_device);
         }
         
+        // try to fetch element from Settings namespace
+        $settings = $xml->children('uri:Settings');
+        if (isset($settings->DeviceInformation) && isset($settings->DeviceInformation->Set)) {
+            // @todo update device informations
+            $this->_deviceInformationSet = true;
+        }
     }
     
     /**
@@ -61,6 +68,8 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
      */
     public function getResponse()
     {
+        $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Settings', 'uri:Settings');
+        
         // should we wipe the device
         if ($this->_device->remotewipe >= self::REMOTEWIPE_REQUESTED) {
             $this->_sendRemoteWipe();
@@ -70,7 +79,7 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
             
             if($this->_sendPolicyKey === NULL) {
                 $this->_sendPolicy();
-            } else {
+            } elseif ($this->_sendPolicyKey == $this->_device->policykey) {
                 $this->_acknowledgePolicy();
             }       
         } 
@@ -96,49 +105,28 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
         if ($this->_logger instanceof Zend_Log) 
             $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' send policy to device');
         
-        $policyData = '<wap-provisioningdoc>
-            <characteristic type="SecurityPolicy">
-                <parm name="4131" value="0"/>
-                <parm name="4133" value="0"/>
-            </characteristic>
-            <characteristic type="Registry">
-                <characteristic type="HKLM\Comm\Security\Policy\LASSD\AE\{50C13377-C66D-400C-889E-C316FC4AB374}">
-                    <parm name="AEFrequencyType" value="1"/>
-                    <parm name="AEFrequencyValue" value="3"/>
-                </characteristic>
-                <characteristic type="HKLM\Comm\Security\Policy\LASSD">
-                    <parm name="DeviceWipeThreshold" value="6"/>
-                </characteristic>
-                <characteristic type="HKLM\Comm\Security\Policy\LASSD">
-                    <parm name="CodewordFrequency" value="3"/>
-                </characteristic>
-                <characteristic type="HKLM\Comm\Security\Policy\LASSD\LAP\lap_pw">
-                    <parm name="MinimumPasswordLength" value="5"/>
-                </characteristic>
-                <characteristic type="HKLM\Comm\Security\Policy\LASSD\LAP\lap_pw">
-                    <parm name="PasswordComplexity" value="2"/>
-                </characteristic>
-            </characteristic>
-        </wap-provisioningdoc>';
-        
         $this->_device->policykey = $this->generatePolicyKey();
                 
         $provision = $sync = $this->_outputDom->documentElement;
+        if ($this->_deviceInformationSet === true) {
+            $deviceInformation = $provision->appendChild($this->_outputDom->createElementNS('uri:Settings', 'DeviceInformation'));
+            $deviceInformation->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Status', 1));
+        }
         $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1));
+        
         $policies = $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Policies'));
         $policy = $policies->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Policy'));
         $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyType', $this->_policyType));
         $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1));
         $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyKey', $this->_device->policykey));
         if ($this->_policyType == self::POLICYTYPE_XML) {
-            $data = $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Data', $policyData));
+            $data = $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Data'));
         } else {
             $data = $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Data'));
             $easProvisionDoc = $data->appendChild($this->_outputDom->createElementNS('uri:Provision', 'EASProvisionDoc'));
-            $easProvisionDoc->appendChild($this->_outputDom->createElementNS('uri:Provision', 'DevicePasswordEnabled', 1));
-            #$easProvisionDoc->appendChild($this->_outputDom->createElementNS('uri:Provision', 'MinDevicePasswordLength', 4));
-            #$easProvisionDoc->appendChild($this->_outputDom->createElementNS('uri:Provision', 'MaxDevicePasswordFailedAttempts', 4));
-            #$easProvisionDoc->appendChild($this->_outputDom->createElementNS('uri:Provision', 'MaxInactivityTimeDeviceLock', 60));
+            $this->_policyBackend
+                ->get($this->_device->policyId)
+                ->appendXML($easProvisionDoc);
         }
         
         $this->_deviceBackend->update($this->_device);
@@ -162,7 +150,7 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
         if ($this->_logger instanceof Zend_Log) 
             $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' acknowledge policy');
         
-        $this->_device->policykey = $this->generatePolicyKey();
+        $policykey = $this->_policyBackend->get($this->_device->policyId)->policyKey;
         
         $provision = $sync = $this->_outputDom->documentElement;
         $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1));
@@ -170,15 +158,17 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
         $policy = $policies->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Policy'));
         $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyType', $this->_policyType));
         $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1));
-        $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyKey', $this->_device->policykey));
+        $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyKey', $policykey));
 
+        $this->_device->policykey = null;
         $this->_deviceBackend->update($this->_device);
     }
-    
+
+    /**
+     * generate a random string used as PolicyKey
+     */
     public static function generatePolicyKey()
     {
-        $policyKey = mt_rand(1, mt_getrandmax());
-        
-        return $policyKey;
+        return sha1(mt_rand(). microtime());
     }
 }
diff --git a/lib/ext/Syncroton/Command/Search.php b/lib/ext/Syncroton/Command/Search.php
index 4f5f667..7febe29 100644
--- a/lib/ext/Syncroton/Command/Search.php
+++ b/lib/ext/Syncroton/Command/Search.php
@@ -50,51 +50,52 @@ class Syncroton_Command_Search extends Syncroton_Command_Wbxml
      */
     public function getResponse()
     {
+        $dataController = Syncroton_Data_Factory::factory($this->_store->name, $this->_device, new DateTime());
+        
+        if (! $dataController instanceof Syncroton_Data_IDataSearch) {
+            throw new RuntimeException('class must be instanceof Syncroton_Data_IDataSearch');
+        }
+        
         $storeResponse = new Syncroton_Model_StoreResponse(array(
            'Status' => self::STATUS_SUCCESS,
         ));
+        
+        try {
+            $options = $this->_store->options;
+            
+            // Search
+            $results = $dataController->search($this->_store->query, $options);
+
+            // Calculate requested range
+            $start = $options['range'][0];
+            $limit = $options['range'][1] + 1;
+            $total = count($results);
+            $storeResponse->Total = $total;
+
+            if ($total) {
+                if ($start > $total) {
+                    $start = $total;
+                }
+                if ($limit > $total) {
+                    $limit = max($start+1, $total);
+                }
 
-        if ($this->_store->name == Syncroton_Data_Factory::STORE_GAL || $this->_store->name == Syncroton_Data_Factory::STORE_EMAIL) {
-            $timestamp      = new DateTime();
-            $dataController = Syncroton_Data_Factory::factory($this->_store->name, $this->_device, $timestamp);
-
-            try {
-                $options = $this->_store->options;
-                // Search
-                $results = $dataController->search($this->_store->query, $options);
-
-                // Calculate requested range
-                $start = $options['range'][0];
-                $limit = $options['range'][1] + 1;
-                $total = count($results);
-                $storeResponse->Total = $total;
-
-                if ($total) {
-                    if ($start > $total) {
-                        $start = $total;
-                    }
-                    if ($limit > $total) {
-                        $limit = max($start+1, $total);
-                    }
-
-                    if ($start > 0 || $limit < $total) {
-                        $results = array_slice($results, $start, $limit-$start);
-                    }
-
-                    $storeResponse->Range = array($start, $start + count($results) - 1);
+                if ($start > 0 || $limit < $total) {
+                    $results = array_slice($results, $start, $limit-$start);
                 }
 
-                foreach ($results as $result) {
-                    if (empty($result->Properties)) {
-                        $result->Properties = $dataController->getSearchEntry($result->LongId, $this->_store->options);
-                    }
+                $storeResponse->Range = array($start, $start + count($results) - 1);
+            }
 
-                    $storeResponse->Result[] = $result;
+            foreach ($results as $result) {
+                if (empty($result->Properties)) {
+                    $result->Properties = $dataController->getSearchEntry($result->LongId, $this->_store->options);
                 }
+
+                $storeResponse->Result[] = $result;
             }
-            catch (Exception $e) {
-                $storeResponse->Status = self::STATUS_SERVER_ERROR;
-            }
+        } catch (Exception $e) {
+            $storeResponse->Status = self::STATUS_SERVER_ERROR;
         }
 
         $search = $this->_outputDom->documentElement;
diff --git a/lib/ext/Syncroton/Command/SendMail.php b/lib/ext/Syncroton/Command/SendMail.php
index 768eda4..773e27f 100644
--- a/lib/ext/Syncroton/Command/SendMail.php
+++ b/lib/ext/Syncroton/Command/SendMail.php
@@ -21,9 +21,8 @@ class Syncroton_Command_SendMail extends Syncroton_Command_Wbxml
     protected $_documentElement     = 'Sendmail';
 
     protected $_saveInSent;
-    protected $_itemId;
-    protected $_collectionId;
-    protected $_mime;
+    protected $_source;
+    protected $_replaceMime = false;
     
     /**
      * process the XML file and add, change, delete or fetches data 
@@ -34,20 +33,28 @@ class Syncroton_Command_SendMail extends Syncroton_Command_Wbxml
     {
         if ($this->_requestParameters['contentType'] == 'message/rfc822') {
             $this->_mime          = $this->_requestBody;
-            $this->_saveInSent    = $this->_requestParameters['SaveInSent'] == 'T';
+            $this->_saveInSent    = $this->_requestParameters['saveInSent'] == 'T';
             
-            $this->_collectionId  = $this->_requestParameters['CollectionId'];
-            $this->_itemId        = $this->_requestParameters['ItemId'];
+            $this->_collectionId  = $this->_requestParameters['collectionId'];
+            $this->_itemId        = $this->_requestParameters['itemId'];
             
         } else {
             $xml = simplexml_import_dom($this->_requestBody);
             
             $this->_mime          = (string) $xml->Mime;
             $this->_saveInSent    = isset($xml->SaveInSentItems);
+            $this->_replaceMime   = isset($xml->ReplaceMime);
             
             if (isset ($xml->Source)) {
-                $this->_collectionId  = (string)$xml->Source->FolderId;
-                $this->_itemId        = (string)$xml->Source->ItemId;
+                if ($xml->Source->LongId) {
+                    $this->_source = $xml->Source->LongId;
+                } else {
+                    $this->_source = array(
+                        'collectionId' => (string)$xml->Source->FolderId,
+                        'itemId'       => (string)$xml->Source->ItemId,
+                        'instanceId'   => isset($xml->Source->InstanceId) ? (string)$xml->Source->InstanceId : null
+                    );
+                }
             }
         }
         
diff --git a/lib/ext/Syncroton/Command/SmartForward.php b/lib/ext/Syncroton/Command/SmartForward.php
index 3ee31e7..e5ce2d1 100644
--- a/lib/ext/Syncroton/Command/SmartForward.php
+++ b/lib/ext/Syncroton/Command/SmartForward.php
@@ -28,6 +28,6 @@ class Syncroton_Command_SmartForward extends Syncroton_Command_SmartReply
     {
         $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_EMAIL, $this->_device, $this->_syncTimeStamp);
     
-        $dataController->forwardEmail($this->_collectionId, $this->_itemId, $this->_mime, $this->_saveInSent);
+        $dataController->forwardEmail($this->_source, $this->_mime, $this->_saveInSent, $this->_replaceMime);
     }
 }
diff --git a/lib/ext/Syncroton/Command/SmartReply.php b/lib/ext/Syncroton/Command/SmartReply.php
index 0f03341..f17d16d 100644
--- a/lib/ext/Syncroton/Command/SmartReply.php
+++ b/lib/ext/Syncroton/Command/SmartReply.php
@@ -29,6 +29,6 @@ class Syncroton_Command_SmartReply extends Syncroton_Command_SendMail
     {
         $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_EMAIL, $this->_device, $this->_syncTimeStamp);
     
-        $dataController->replyEmail($this->_collectionId, $this->_itemId, $this->_mime, $this->_saveInSent);
+        $dataController->replyEmail($this->_source, $this->_mime, $this->_saveInSent, $this->_replaceMime);
     }
 }
diff --git a/lib/ext/Syncroton/Command/Sync.php b/lib/ext/Syncroton/Command/Sync.php
index 426b739..e9fead9 100644
--- a/lib/ext/Syncroton/Command/Sync.php
+++ b/lib/ext/Syncroton/Command/Sync.php
@@ -84,11 +84,11 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
     protected $_modifications = array();
 
     /**
-     * total count of items in all collections
+     * the global WindowSize
      *
      * @var integer
      */
-    protected $_totalCount;
+    protected $_globalWindowSize;
     
     /**
      * there are more entries than WindowSize available
@@ -108,17 +108,11 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
      */
     public function handle()
     {
-        #if ($this->_statusProvisioning = $this->_checkProvisioningNeeded() !== false) {
-        #    if (version_compare($this->_device->acsversion, '14.0', '<')) {
-        #       throw new Syncroton_Exception_ProvisioningNeeded();
-        #    } else {
-        #        return;
-        #    }
-        #}
-        
         // input xml
         $xml = simplexml_import_dom($this->_requestBody);
         
+        $this->_globalWindowSize = isset($xml->WindowSize) ? (int)$xml->WindowSize : 100;
+        
         foreach ($xml->Collections->Collection as $xmlCollection) {
             $collectionData = new Syncroton_Model_SyncCollection($xmlCollection);
             
@@ -134,8 +128,8 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                 // to avoid a syncloop for the iPhone
                 if ($collectionData->syncKey > 0) {
                     $collectionData->folder    = new Syncroton_Model_Folder(array(
-                        'device_id' => $this->_device,
-                        'folderid'  => $collectionData->collectionId
+                        'deviceId' => $this->_device,
+                        'serverId'  => $collectionData->collectionId
                     ));
                 }
                 
@@ -364,18 +358,14 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
     {
         $sync = $this->_outputDom->documentElement;
         
-        // provioning needed?
-        #if ($this->_statusProvisioning !== false) {
-        #    if ($this->_logger instanceof Zend_Log)
-        #        $this->_logger->info(__METHOD__ . '::' . __LINE__ . " provisiong needed or remote wipe requested");
-        #    $sync->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', $this->_statusProvisioning));
-        # 
-        #    return $this->_outputDom;
-        #}
-        
         $collections = $sync->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collections'));
 
+        $totalChanges = 0;
+        
         foreach($this->_collections as $collectionData) {
+            $moreAvailable     = false;
+            $collectionChanges = 0;
+            
             // invalid collectionid provided
             if (! ($collectionData->folder instanceof Syncroton_Model_IFolder)) {
                 $collection = $collections->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collection'));
@@ -416,8 +406,6 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                     'deleted' => array(),
                 );
                 
-                $moreAvailable = false;
-                
                 if($collectionData->getChanges === true) {
                     // continue sync session?
                     if(is_array($collectionData->syncState->pendingdata)) {
@@ -550,21 +538,15 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                     $collection->appendChild($responses);
                 }
                 
-                if ((count($serverModifications['added']) + count($serverModifications['changed']) + count($serverModifications['deleted'])) > $collectionData->windowSize ) {
-                    $moreAvailable = true;
-                    $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'MoreAvailable'));
-                }
-                
                 $commands = $this->_outputDom->createElementNS('uri:AirSync', 'Commands');
                 
-                
                 /**
                  * process entries added on server side
                  */
                 $newContentStates = array();
                 
                 foreach($serverModifications['added'] as $id => $serverId) {
-                    if($this->_totalCount === $collectionData->windowSize) {
+                    if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges === $this->_globalWindowSize) {
                         break;
                     }
                     
@@ -600,7 +582,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                         
                         $commands->appendChild($add);
                         
-                        $this->_totalCount++;
+                        $collectionChanges++;
                     } catch (Exception $e) {
                         if ($this->_logger instanceof Zend_Log) 
                             $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage());
@@ -621,10 +603,10 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                  * process entries changed on server side
                  */
                 foreach($serverModifications['changed'] as $id => $serverId) {
-                    if($this->_totalCount === $collectionData->windowSize) {
+                    if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges === $this->_globalWindowSize) {
                         break;
                     }
-
+                    
                     try {
                         $change = $this->_outputDom->createElementNS('uri:AirSync', 'Change');
                         $change->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId));
@@ -638,7 +620,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
 
                         $commands->appendChild($change);
                         
-                        $this->_totalCount++;
+                        $collectionChanges++;
                     } catch (Exception $e) {
                         if ($this->_logger instanceof Zend_Log) 
                             $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage());
@@ -653,10 +635,10 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                 $deletedContentStates = array();
                 
                 foreach($serverModifications['deleted'] as $id => $serverId) {
-                    if($this->_totalCount === $collectionData->windowSize) {
+                    if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges === $this->_globalWindowSize) {
                         break;
                     }
-                                                
+                    
                     try {
                         // check if we have sent this entry to the phone
                         $state = $this->_contentStateBackend->getContentState($this->_device, $collectionData->folder, $serverId);
@@ -668,21 +650,30 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                         
                         $commands->appendChild($delete);
                         
-                        $this->_totalCount++;
+                        $collectionChanges++;
                     } catch (Exception $e) {
                         if ($this->_logger instanceof Zend_Log) 
                             $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage());
                     }
                     
-                    unset($serverModifications['deleted'][$id]);    
+                    unset($serverModifications['deleted'][$id]);
                 }
                 
                 if ($commands->hasChildNodes() === true) {
+                    
+                    $countOfPendingChanges = (count($serverModifications['added']) + count($serverModifications['changed']) + count($serverModifications['deleted'])); 
+                    if ($countOfPendingChanges > 0) {
+                        $moreAvailable = true;
+                        $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'MoreAvailable'));
+                    }
+                
                     $collection->appendChild($commands);
                 }
                 
+                $totalChanges += $collectionChanges;
+                
                 if ($this->_logger instanceof Zend_Log) 
-                    $this->_logger->info(__METHOD__ . '::' . __LINE__ . " new synckey is ". $collectionData->syncState->counter);                
+                    $this->_logger->info(__METHOD__ . '::' . __LINE__ . " new synckey is ". $collectionData->syncState->counter);
             }
             
             if (isset($collectionData->syncState) && $collectionData->syncState instanceof Syncroton_Model_ISyncState && 
diff --git a/lib/ext/Syncroton/Command/Wbxml.php b/lib/ext/Syncroton/Command/Wbxml.php
index 0b69857..537900a 100644
--- a/lib/ext/Syncroton/Command/Wbxml.php
+++ b/lib/ext/Syncroton/Command/Wbxml.php
@@ -50,6 +50,12 @@ abstract class Syncroton_Command_Wbxml implements Syncroton_Command_ICommand
     protected $_contentStateBackend;
     
     /**
+     * 
+     * @var Syncroton_Backend_IPolicy
+     */
+    protected $_policyBackend;
+    
+    /**
      * the domDocument containing the xml response from the server
      *
      * @var DOMDocument
@@ -129,24 +135,11 @@ abstract class Syncroton_Command_Wbxml implements Syncroton_Command_ICommand
         $this->_folderBackend       = Syncroton_Registry::getFolderBackend();
         $this->_syncStateBackend    = Syncroton_Registry::getSyncStateBackend();
         $this->_contentStateBackend = Syncroton_Registry::getContentStateBackend();
+        $this->_policyBackend       = Syncroton_Registry::getPolicyBackend();
         if (Syncroton_Registry::isRegistered('loggerBackend')) {
             $this->_logger          = Syncroton_Registry::get('loggerBackend');
         }
         
-        if ($this->_skipValidatePolicyKey !== true && $this->_policyKey === null) {
-            #throw new Syncroton_Exception_PolicyKeyMissing();
-        }
-        
-        if ($this->_skipValidatePolicyKey !== true && ($this->_policyKey === 0 || $this->_device->policykey != $this->_policyKey)) {
-            #throw new Syncroton_Exception_ProvisioningNeeded();
-        }
-        
-        // should we wipe the mobile phone?
-        if ($this->_skipValidatePolicyKey !== true && !empty($this->_policyKey) && $this->_device->remotewipe >= Syncroton_Command_Provision::REMOTEWIPE_REQUESTED) {
-            throw new Syncroton_Exception_ProvisioningNeeded();
-        }
-        
-        
         $this->_syncTimeStamp = new DateTime(null, new DateTimeZone('UTC'));
         
         if ($this->_logger instanceof Zend_Log) 
@@ -163,5 +156,33 @@ abstract class Syncroton_Command_Wbxml implements Syncroton_Command_ICommand
         $this->_outputDom->formatOutput = false;
         $this->_outputDom->encoding     = 'utf-8';
         
-    }    
+        if ($this->_skipValidatePolicyKey != true) {
+            if (!empty($this->_device->policyId)) {
+                if ($this->_policyKey === null) {
+                    throw new Syncroton_Exception_PolicyKeyMissing();
+                } 
+                
+                $policy = $this->_policyBackend->get($this->_device->policyId);
+                
+                if($policy->policyKey != $this->_policyKey) {
+                    $this->_outputDom->documentElement->appendChild($this->_outputDom->createElementNS($this->_defaultNameSpace, 'Status', 142));
+                    
+                    $sepn = new Syncroton_Exception_ProvisioningNeeded();
+                    $sepn->domDocument = $this->_outputDom;
+                    
+                    throw $sepn;
+                }
+                
+                // should we wipe the mobile phone?
+                if ($this->_device->remotewipe >= Syncroton_Command_Provision::REMOTEWIPE_REQUESTED) {
+                    $this->_outputDom->documentElement->appendChild($this->_outputDom->createElementNS($this->_defaultNameSpace, 'Status', 140));
+                    
+                    $sepn = new Syncroton_Exception_ProvisioningNeeded();
+                    $sepn->domDocument = $this->_outputDom;
+                    
+                    throw $sepn;
+                }
+            }
+        }
+    }
 }
diff --git a/lib/ext/Syncroton/Data/AData.php b/lib/ext/Syncroton/Data/AData.php
index 8a9b3b6..4e02ef5 100644
--- a/lib/ext/Syncroton/Data/AData.php
+++ b/lib/ext/Syncroton/Data/AData.php
@@ -47,11 +47,11 @@ abstract class Syncroton_Data_AData implements Syncroton_Data_IData
         $folder->id = sha1(mt_rand(). microtime());
         
         // normaly generated on server backend
-        $folder->folderid = sha1(mt_rand(). microtime());
+        $folder->serverId = sha1(mt_rand(). microtime());
     
-        Syncroton_Data_AData::$folders[get_class($this)][$folder->folderid] = $folder;
+        Syncroton_Data_AData::$folders[get_class($this)][$folder->serverId] = $folder;
     
-        return Syncroton_Data_AData::$folders[get_class($this)][$folder->folderid];
+        return Syncroton_Data_AData::$folders[get_class($this)][$folder->serverId];
     }
     
     public function createEntry($_folderId, Syncroton_Model_IEntry $_entry)
@@ -72,7 +72,7 @@ abstract class Syncroton_Data_AData implements Syncroton_Data_IData
     
     public function deleteEntry($_folderId, $_serverId, $_collectionData)
     {
-        #$folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->folderid : $_folderId;
+        #$folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->serverId : $_folderId;
         
         $result = $this->_db->delete($this->_tablePrefix . 'data', array('id = ?' => $_serverId));
         
@@ -83,7 +83,7 @@ abstract class Syncroton_Data_AData implements Syncroton_Data_IData
     
     public function deleteFolder($_folderId)
     {
-        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->folderid : $_folderId;
+        $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->serverId : $_folderId;
     
         unset(Syncroton_Data_AData::$folders[get_class($this)][$folderId]);
         unset(Syncroton_Data_AData::$entries[get_class($this)][$folderId]);
@@ -129,11 +129,11 @@ abstract class Syncroton_Data_AData implements Syncroton_Data_IData
     public function getCountOfChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState)
     {
         $allClientEntries = $contentBackend->getFolderState($this->_device, $folder);
-        $allServerEntries = $this->getServerEntries($folder->folderid, $folder->lastfiltertype);
+        $allServerEntries = $this->getServerEntries($folder->serverId, $folder->lastfiltertype);
         
         $addedEntries       = array_diff($allServerEntries, $allClientEntries);
         $deletedEntries     = array_diff($allClientEntries, $allServerEntries);
-        $changedEntries     = $this->getChangedEntries($folder->folderid, $syncState->lastsync);
+        $changedEntries     = $this->getChangedEntries($folder->serverId, $syncState->lastsync);
         
         return count($addedEntries) + count($deletedEntries) + count($changedEntries);
     }
@@ -161,14 +161,6 @@ abstract class Syncroton_Data_AData implements Syncroton_Data_IData
         }
         
         return unserialize($entry);
-        
-        #if (!isset(Syncroton_Data_AData::$entries[get_class($this)][$collection->collectionId][$serverId])) {
-        #    throw new OutOfBoundsException("entry $serverId not found in folder {$collection->collectionId}");
-        #}
-        
-        #return Syncroton_Data_AData::$entries[get_class($this)][$collection->collectionId][$serverId];
-
-        
     }
     
     public function moveItem($_srcFolderId, $_serverId, $_dstFolderId)
@@ -195,7 +187,7 @@ abstract class Syncroton_Data_AData implements Syncroton_Data_IData
     
     public function updateFolder(Syncroton_Model_IFolder $folder)
     {
-        Syncroton_Data_AData::$folders[get_class($this)][$folder->folderid] = $folder;
+        Syncroton_Data_AData::$folders[get_class($this)][$folder->serverId] = $folder;
     }
     
     
diff --git a/lib/ext/Syncroton/Data/Calendar.php b/lib/ext/Syncroton/Data/Calendar.php
index 539d9c2..9f24590 100644
--- a/lib/ext/Syncroton/Data/Calendar.php
+++ b/lib/ext/Syncroton/Data/Calendar.php
@@ -24,9 +24,9 @@ class Syncroton_Data_Calendar extends Syncroton_Data_AData
         Syncroton_Data_AData::$folders[get_class($this)] = array(
                 'calendarFolderId' => new Syncroton_Model_Folder(array(
                     'id'          => sha1(mt_rand(). microtime()),
-                    'folderid'    => 'calendarFolderId',
-                    'parentid'    => null,
-                    'displayname' => 'Default Contacts Folder',
+                    'serverId'    => 'calendarFolderId',
+                    'parentId'    => 0,
+                    'displayName' => 'Default Contacts Folder',
                     'type'        => Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR
                 ))
         );
diff --git a/lib/ext/Syncroton/Data/Contacts.php b/lib/ext/Syncroton/Data/Contacts.php
index 5ba8560..133ae00 100644
--- a/lib/ext/Syncroton/Data/Contacts.php
+++ b/lib/ext/Syncroton/Data/Contacts.php
@@ -14,8 +14,48 @@
  * @package     Model
  */
 
-class Syncroton_Data_Contacts extends Syncroton_Data_AData
+class Syncroton_Data_Contacts extends Syncroton_Data_AData implements Syncroton_Data_IDataSearch
 {
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IDataSearch::getSearchEntry()
+     */
+    public function getSearchEntry($longId, $options)
+    {
+        list($collectionId, $serverId) = explode('-', $longId, 2);
+        
+        $contact = $this->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $collectionId)), $serverId);
+        
+        return new Syncroton_Model_GAL(array(
+            'FirstName' => $contact->FirstName,
+            'LastName'  => $contact->LastName
+        ));
+    }
+    
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IDataSearch::search()
+     */
+    public function search($query, $options)
+    {
+        $found = array();
+        
+        $serverIds = $this->getServerEntries('addressbookFolderId', Syncroton_Command_Sync::FILTER_NOTHING);
+        
+        foreach ($serverIds as $serverId) {
+            $contact = $this->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => 'addressbookFolderId')), $serverId);
+            
+            if ($contact->FirstName == $query) {
+                $found[] = new Syncroton_Model_StoreResponseResult(array(
+                    'LongId' => 'addressbookFolderId-' .  $serverId,
+                    'Properties' => $this->getSearchEntry('addressbookFolderId-' .  $serverId, $options)
+                ));
+            }
+        }
+        
+        return $found;
+    }
+    
     protected function _initData()
     {
         /**
@@ -25,16 +65,16 @@ class Syncroton_Data_Contacts extends Syncroton_Data_AData
             Syncroton_Data_AData::$folders[get_class($this)] = array(
                 'addressbookFolderId' => new Syncroton_Model_Folder(array(
                     'id'          => sha1(mt_rand(). microtime()),
-                    'folderid'    => 'addressbookFolderId',
-                    'parentid'    => null,
-                    'displayname' => 'Default Contacts Folder',
+                    'serverId'    => 'addressbookFolderId',
+                    'parentId'    => 0,
+                    'displayName' => 'Default Contacts Folder',
                     'type'        => Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT
                 )),
                 'anotherAddressbookFolderId' => new Syncroton_Model_Folder(array(
                     'id'          => sha1(mt_rand(). microtime()),
-                    'folderid'    => 'anotherAddressbookFolderId',
-                    'parentid'    => null,
-                    'displayname' => 'Another Contacts Folder',
+                    'serverId'    => 'anotherAddressbookFolderId',
+                    'parentId'    => 0,
+                    'displayName' => 'Another Contacts Folder',
                     'type'        => Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED
                 ))
             );
diff --git a/lib/ext/Syncroton/Data/Email.php b/lib/ext/Syncroton/Data/Email.php
index 73c280f..9765a7b 100644
--- a/lib/ext/Syncroton/Data/Email.php
+++ b/lib/ext/Syncroton/Data/Email.php
@@ -22,7 +22,11 @@ class Syncroton_Data_Email extends Syncroton_Data_AData implements Syncroton_Dat
     public static $entries = array(
     );
     
-    public function forwardEmail($collectionId, $itemId, $inputStream, $saveInSent)
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IDataEmail::forwardEmail()
+     */
+    public function forwardEmail($source, $inputStream, $saveInSent, $replaceMime)
     {
         // forward email
     }
@@ -36,12 +40,16 @@ class Syncroton_Data_Email extends Syncroton_Data_AData implements Syncroton_Dat
     
         // example code
         return new Syncroton_Model_FileReference(array(
-                'ContentType' => 'text/plain',
-                'Data'        => 'Lars'
+            'ContentType' => 'text/plain',
+            'Data'        => 'Lars'
         ));
     }
-    
-    public function replyEmail($collectionId, $itemId, $inputStream, $saveInSent)
+    
+    /**
+     * (non-PHPdoc)
+     * @see Syncroton_Data_IDataEmail::replyEmail()
+     */
+    public function replyEmail($source, $inputStream, $saveInSent, $replaceMime)
     {
         // forward email
     }
@@ -68,16 +76,16 @@ class Syncroton_Data_Email extends Syncroton_Data_AData implements Syncroton_Dat
         Syncroton_Data_AData::$folders[get_class($this)] = array(
             'emailInboxFolderId' => new Syncroton_Model_Folder(array(
                 'id'          => sha1(mt_rand(). microtime()),
-                'folderid'    => 'emailInboxFolderId',
-                'parentid'    => null,
-                'displayname' => 'Inbox',
+                'serverId'    => 'emailInboxFolderId',
+                'parentId'    => 0,
+                'displayName' => 'Inbox',
                 'type'        => Syncroton_Command_FolderSync::FOLDERTYPE_INBOX
             )),
             'emailSentFolderId' => new Syncroton_Model_Folder(array(
                 'id'          => sha1(mt_rand(). microtime()),
-                'folderid'    => 'emailSentFolderId',
-                'parentid'    => null,
-                'displayname' => 'Sent',
+                'serverId'    => 'emailSentFolderId',
+                'parentId'    => 0,
+                'displayName' => 'Sent',
                 'type'        => Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL
             ))
         );
diff --git a/lib/ext/Syncroton/Data/Factory.php b/lib/ext/Syncroton/Data/Factory.php
index 29c2bdd..1be6946 100644
--- a/lib/ext/Syncroton/Data/Factory.php
+++ b/lib/ext/Syncroton/Data/Factory.php
@@ -58,18 +58,13 @@ class Syncroton_Data_Factory
                 break;
 
             default:
-                throw new InvalidArgumentException('invalid class type provided');
+                throw new Syncroton_Exception_UnexpectedValue('invalid class type provided');
                 breeak;
         }
         
         $class = new $className($_device, $_timeStamp);
         
-        if ($_classFactory == STORE_EMAIL || $_classFactory == STORE_GAL) {
-            if (! $class instanceof Syncroton_Data_IDataSearch) {
-                throw new RuntimeException('class must be instanceof Syncroton_Data_IDataSearch');
-            }
-        }
-        else if (! $class instanceof Syncroton_Data_IData) {
+        if (! $class instanceof Syncroton_Data_IData) {
             throw new RuntimeException('class must be instanceof Syncroton_Data_IData');
         }
                     
diff --git a/lib/ext/Syncroton/Data/IDataEmail.php b/lib/ext/Syncroton/Data/IDataEmail.php
index 731d187..7ecbb37 100644
--- a/lib/ext/Syncroton/Data/IDataEmail.php
+++ b/lib/ext/Syncroton/Data/IDataEmail.php
@@ -1,5 +1,4 @@
 <?php
-
 /**
  * Syncroton
  *
@@ -10,7 +9,7 @@
  */
 
 /**
- * class to handle ActiveSync Sync command
+ * intace for email backend
  *
  * @package     Model
  */
@@ -27,21 +26,19 @@ interface Syncroton_Data_IDataEmail
     /**
      * forward an email
      * 
-     * @param  string  $collectionId
-     * @param  string  $itemId
-     * @param  string  $inputStream
-     * @param  string  $saveInSent
+     * @param  string|array  $source       is either a string(LongId) or an arrey with following properties collectionId, itemId and instanceId
+     * @param  string        $inputStream
+     * @param  string        $saveInSent
      */
-    public function forwardEmail($collectionId, $itemId, $inputStream, $saveInSent);
+    public function forwardEmail($source, $inputStream, $saveInSent, $replaceMime);
 
     /**
      * reply to an email
      * 
-     * @param  string  $collectionId
-     * @param  string  $itemId
-     * @param  string  $inputStream
-     * @param  string  $saveInSent
+     * @param  string|array  $source       is either a string(LongId) or an arrey with following properties collectionId, itemId and instanceId
+     * @param  string        $inputStream
+     * @param  string        $saveInSent
      */
-    public function replyEmail($collectionId, $itemId, $inputStream, $saveInSent);
+    public function replyEmail($source, $inputStream, $saveInSent, $replaceMime);
 }
 
diff --git a/lib/ext/Syncroton/Data/Tasks.php b/lib/ext/Syncroton/Data/Tasks.php
index 6fc6f4d..30a80d2 100644
--- a/lib/ext/Syncroton/Data/Tasks.php
+++ b/lib/ext/Syncroton/Data/Tasks.php
@@ -24,9 +24,9 @@ class Syncroton_Data_Tasks extends Syncroton_Data_AData
         Syncroton_Data_AData::$folders[get_class($this)] = array(
             'tasksFolderId' => new Syncroton_Model_Folder(array(
                 'id'          => sha1(mt_rand(). microtime()),
-                'folderid'    => 'tasksFolderId',
-                'parentid'    => null,
-                'displayname' => 'Default Tasks Folder',
+                'serverId'    => 'tasksFolderId',
+                'parentId'    => 0,
+                'displayName' => 'Default Tasks Folder',
                 'type'        => Syncroton_Command_FolderSync::FOLDERTYPE_TASK
             ))
         );
diff --git a/lib/ext/Syncroton/Exception/ProvisioningNeeded.php b/lib/ext/Syncroton/Exception/ProvisioningNeeded.php
index f2cd5f2..10db726 100644
--- a/lib/ext/Syncroton/Exception/ProvisioningNeeded.php
+++ b/lib/ext/Syncroton/Exception/ProvisioningNeeded.php
@@ -17,4 +17,5 @@
  */
 class Syncroton_Exception_ProvisioningNeeded extends Syncroton_Exception
 {
+    public $domDocument;
 }
diff --git a/lib/ext/Syncroton/Model/AEntry.php b/lib/ext/Syncroton/Model/AEntry.php
index 029118a..7667d11 100644
--- a/lib/ext/Syncroton/Model/AEntry.php
+++ b/lib/ext/Syncroton/Model/AEntry.php
@@ -18,10 +18,14 @@
 
 abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, IteratorAggregate, Countable
 {
+    protected $_xmlBaseElement;
+    
     protected $_elements = array();
     
     protected $_properties = array();
     
+    protected $_dateTimeFormat = "Y-m-d\TH:i:s.000\Z";
+    
     public function __construct($properties = null)
     {
         if ($properties instanceof SimpleXMLElement) {
@@ -33,6 +37,51 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
     
     /**
      * (non-PHPdoc)
+     * @see Syncroton_Model_IEntry::appendXML()
+     */
+    public function appendXML(DOMElement $_domParrent)
+    {
+        $this->_addXMLNamespaces($_domParrent);
+        
+        foreach($this->_elements as $elementName => $value) {
+            // skip empty values
+            if($value === null || $value === '' || (is_array($value) && empty($value))) {
+                continue;
+            }
+            
+            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
+            
+            if ($nameSpace == 'Internal') {
+                continue;
+            }
+            
+            $nameSpace = 'uri:' . $nameSpace;
+            
+            // strip off any non printable control characters
+            if (!ctype_print($value)) {
+                #$value = $this->removeControlChars($value);
+            }
+            
+            $element = $_domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName));
+            
+            if (is_array($value)) {
+                foreach($value as $subValue) {
+                    $subElement = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementProperties['childName']);
+                    
+                    $this->_appendXMLElement($subElement, array(), $subValue);
+                    
+                    $element->appendChild($subElement);
+                }
+            } else {
+                $this->_appendXMLElement($element, $elementProperties, $value);
+            }
+            
+            $_domParrent->appendChild($element);
+        }
+    }
+    
+    /**
+     * (non-PHPdoc)
      * @see Countable::count()
      */    
     public function count()
@@ -87,13 +136,16 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
      */
     public function setFromSimpleXMLElement(SimpleXMLElement $properties)
     {
-        if ($properties->getName() !== $this->_xmlBaseElement) {
+        if (!in_array($properties->getName(), (array) $this->_xmlBaseElement)) {
             throw new InvalidArgumentException('Unexpected element name: ' . $properties->getName());
         }
     
         $this->_elements = array();
     
-        foreach (array_keys($this->_properties) as $namespace) {
+        foreach (array_keys($this->_properties) as $namespace) {
+            if ($namespace == 'Internal') {
+                continue;
+            }
             $functionName = '_parse' . $namespace . 'Namespace';
             $this->$functionName($properties);
         }
@@ -112,6 +164,27 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
             $_domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:'.$namespace, 'uri:'.$namespace);
         }
     }
+    
+    protected function _appendXMLElement($element, $elementProperties, $value)
+    {
+        if ($value instanceof Syncroton_Model_IEntry) {
+            $value->appendXML($element);
+        } else {
+            if ($value instanceof DateTime) {
+                $value = $value->format($this->_dateTimeFormat);
+                
+            } elseif (isset($elementProperties['encoding']) && $elementProperties['encoding'] == 'base64') {
+                if (is_resource($value)) {
+                    stream_filter_append($value, 'convert.base64-encode');
+                    $value = stream_get_contents($value);
+                } else {
+                    $value = base64_encode($value);
+                }
+            }
+            
+            $element->appendChild($element->ownerDocument->createTextNode($value));
+        }
+    }
     
     /**
      * 
@@ -120,13 +193,13 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
      * @return multitype:unknown
      */
     protected function _getElementProperties($element)
-    {
-        foreach($this->_properties as $namespace => $namespaceProperties) {
+    {
+        foreach($this->_properties as $namespace => $namespaceProperties) {
             if (array_key_exists($element, $namespaceProperties)) {
                 return array($namespace, $namespaceProperties[$element]);
             }
         }
-    
+        
         throw new InvalidArgumentException("$element is no valid property of this object");
     }
     
diff --git a/lib/ext/Syncroton/Model/Contact.php b/lib/ext/Syncroton/Model/Contact.php
index 31e2bdc..d5f20e4 100644
--- a/lib/ext/Syncroton/Model/Contact.php
+++ b/lib/ext/Syncroton/Model/Contact.php
@@ -49,9 +49,9 @@ class Syncroton_Model_Contact extends Syncroton_Model_AEntry
             'BusinessFaxNumber'      => array('type' => 'string'),
             'BusinessPhoneNumber'    => array('type' => 'string'),
             'CarPhoneNumber'         => array('type' => 'string'),
-            'Categories'             => array('type' => 'container'),
+            'Categories'             => array('type' => 'container', 'childName' => 'Category'),
             //'Category'              => array('type' => 'string'),
-            'Children'               => array('type' => 'container'),
+            'Children'               => array('type' => 'container', 'childName' => 'Child'),
             //'Child'                 => array('type' => 'string'),
             'CompanyName'            => array('type' => 'string'),
             'Department'             => array('type' => 'string'),
@@ -105,86 +105,6 @@ class Syncroton_Model_Contact extends Syncroton_Model_AEntry
         )
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-                
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-            
-            $nameSpace = 'uri:' . $nameSpace;
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                case 'Body':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    $value->appendXML($element);
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Categories':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $category) {
-                        $categoryElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Category');
-                        $categoryElement->appendChild($_domParrent->ownerDocument->createTextNode($category));
-                        
-                        $element->appendChild($categoryElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Children':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $child) {
-                        $childElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Child');
-                        $childElement->appendChild($_domParrent->ownerDocument->createTextNode($child));
-                        
-                        $element->appendChild($childElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Y-m-d\TH:i:s.000\Z");
-                    }
-                    
-                    if (isset($elementProperties['encoding']) && $elementProperties['encoding'] == 'base64') {
-                        if (is_resource($value)) {
-                            stream_filter_append($value, 'convert.base64-encode');
-                            $value = stream_get_contents($value);
-                        } else {
-                            $value = base64_encode($value);
-                        }
-                    }
-                        
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-    }
-    
     protected function _parseContactsNamespace(SimpleXMLElement $properties)
     {
         // fetch data from Contacts namespace
diff --git a/lib/ext/Syncroton/Model/Email.php b/lib/ext/Syncroton/Model/Email.php
index 9985d81..e3aa3ce 100644
--- a/lib/ext/Syncroton/Model/Email.php
+++ b/lib/ext/Syncroton/Model/Email.php
@@ -26,21 +26,20 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
     
     protected $_properties = array(
         'AirSyncBase' => array(
-            'Attachments'             => array('type' => 'container'),
+            'Attachments'             => array('type' => 'container', 'childName' => 'Attachment'),
             'ContentType'             => array('type' => 'string'),
             'Body'                    => array('type' => 'container'),
             'NativeBodyType'          => array('type' => 'number'),
         ),
         'Email' => array(
             'BusyStatus'              => array('type' => 'number'),
-            'Categories'              => array('type' => 'container'),
-            'Category'                => array('type' => 'string'),
+            'Categories'              => array('type' => 'container', 'childName' => 'Category'),
             'Cc'                      => array('type' => 'string'),
             'CompleteTime'            => array('type' => 'datetime'),
             'ContentClass'            => array('type' => 'string'),
             'DateReceived'            => array('type' => 'datetime'),
-            'DayOfMonth'              => array('type' => 'number'),
-            'DayOfWeek'               => array('type' => 'number'),
+            #'DayOfMonth'              => array('type' => 'number'),
+            #'DayOfWeek'               => array('type' => 'number'),
             'DisallowNewTimeProposal' => array('type' => 'number'),
             'DisplayTo'               => array('type' => 'string'),
             'DTStamp'                 => array('type' => 'datetime'),
@@ -52,16 +51,16 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
             'Importance'              => array('type' => 'number'),
             'InstanceType'            => array('type' => 'number'),
             'InternetCPID'            => array('type' => 'string'),
-            'Interval'                => array('type' => 'number'),
+            #'Interval'                => array('type' => 'number'),
             'Location'                => array('type' => 'string'),
             'MeetingRequest'          => array('type' => 'container'),
             'MessageClass'            => array('type' => 'string'),
-            'MonthOfYear'             => array('type' => 'number'),
-            'Occurrences'             => array('type' => 'number'),
+            #'MonthOfYear'             => array('type' => 'number'),
+            #'Occurrences'             => array('type' => 'number'),
             'Organizer'               => array('type' => 'string'),
             'Read'                    => array('type' => 'number'),
-            'Recurrence'              => array('type' => 'container'),
-            'RecurrenceId'            => array('type' => 'datetime'),
+            #'Recurrence'              => array('type' => 'container'),
+            #'RecurrenceId'            => array('type' => 'datetime'),
             'Recurrences'             => array('type' => 'container'),
             'Reminder'                => array('type' => 'number'),
             'ReplyTo'                 => array('type' => 'string'),
@@ -73,29 +72,17 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
             'ThreadTopic'             => array('type' => 'string'),
             'TimeZone'                => array('type' => 'timezone'),
             'To'                      => array('type' => 'string'),
-            'Type'                    => array('type' => 'number'),
-            'Until'                   => array('type' => 'datetime'),
-            'WeekOfMonth'             => array('type' => 'number'),
-                
-            //'AttName'               => 0x07,
-            //'AttSize'               => 0x08,
-            //'Att0Id'                => 0x09,
-            //'AttMethod'             => 0x0a,
-            //'AttRemoved'            => 0x0b,
-            //'Body'                  => 0x0c,
-            //'BodySize'              => 0x0d,
-            //'BodyTruncated'         => 0x0e,
-            //'MIMEData'                => 0x36,
-            //'MIMETruncated'           => 0x37,
-            //'MIMESize'                => 0x38,
+            #'Type'                    => array('type' => 'number'),
+            #'Until'                   => array('type' => 'datetime'),
+            #'WeekOfMonth'             => array('type' => 'number'),
         ),
         'Email2' => array(
             'AccountId'             => array('type' => 'string'),
-            'CalendarType'          => array('type' => 'number'),
+            #'CalendarType'          => array('type' => 'number'),
             'ConversationId'        => array('type' => 'byteArray'), // @todo handle this
             'ConversationIndex'     => array('type' => 'byteArray'), // @todo handle this
-            'FirstDayOfWeek'        => array('type' => 'number'),
-            'IsLeapMonth'           => array('type' => 'number'),
+            #'FirstDayOfWeek'        => array('type' => 'number'),
+            #'IsLeapMonth'           => array('type' => 'number'),
             'LastVerbExecuted'      => array('type' => 'number'),
             'LastVerbExecutionTime' => array('type' => 'datetime'),
             'MeetingMessageType'    => array('type' => 'number'),
@@ -106,85 +93,6 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
         ),
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-            
-            $nameSpace = 'uri:' . $nameSpace;
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                case 'Attachments':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $attachment) {
-                        $attachmentElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Attachment');
-                        $attachment->appendXML($attachmentElement);
-                        
-                        $element->appendChild($attachmentElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-                    
-                case 'Body':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    $value->appendXML($element);
-                    
-                    $_domParrent->appendChild($element);
-                    break;
-                    
-                case 'Categories':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                
-                    foreach($value as $category) {
-                        $categoryElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Category');
-                        $categoryElement->appendChild($_domParrent->ownerDocument->createTextNode($category));
-                
-                        $element->appendChild($categoryElement);
-                    }
-                
-                    $_domParrent->appendChild($element);
-                
-                    break;
-                    
-                case 'Recurrence':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    $value->appendXML($element);
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-                    
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Y-m-d\TH:i:s.000\Z");
-                    }
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
     protected function _parseAirSyncBaseNamespace(SimpleXMLElement $properties)
     {
         // fetch data from AirSyncBase namespace
diff --git a/lib/ext/Syncroton/Model/EmailAttachment.php b/lib/ext/Syncroton/Model/EmailAttachment.php
index 2bbd69e..e958f7f 100644
--- a/lib/ext/Syncroton/Model/EmailAttachment.php
+++ b/lib/ext/Syncroton/Model/EmailAttachment.php
@@ -19,12 +19,10 @@
  * @property    string  syncKey
  * @property    int     windowSize
  */
-
 class Syncroton_Model_EmailAttachment extends Syncroton_Model_AEntry
 {
     protected $_xmlBaseElement = 'Attachment';
     
-    // @todo handle body
     protected $_properties = array(
         'AirSyncBase' => array(
             'ContentId'               => array('type' => 'string'),
@@ -41,89 +39,6 @@ class Syncroton_Model_EmailAttachment extends Syncroton_Model_AEntry
         ),
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $_domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSyncBase', 'uri:AirSyncBase');
-        $_domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Email2', 'uri:Email2');
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            $elementProperties = (isset($this->_properties['AirSyncBase'][$elementName])) ?
-            $this->_properties['AirSyncBase'][$elementName] :
-            $this->_properties['Email2'][$elementName];
-            
-            $nameSpace = isset($this->_properties['AirSyncBase'][$elementName]) ? 'uri:AirSyncBase' : 'uri:Email2';
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                case 'Categories':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $category) {
-                        $categoryElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Category');
-                        $categoryElement->appendChild($_domParrent->ownerDocument->createTextNode($category));
-                        
-                        $element->appendChild($categoryElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Recurrence':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    $value->appendXML($element);
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-                    
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Y-m-d\TH:i:s.000\Z");
-                    }
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
-    /**
-     * 
-     * @param SimpleXMLElement $xmlCollection
-     * @throws InvalidArgumentException
-     */
-    public function setFromSimpleXMLElement(SimpleXMLElement $properties)
-    {
-        if ($properties->getName() !== $this->_xmlBaseElement) {
-            throw new InvalidArgumentException('Unexpected element name: ' . $properties->getName());
-        }
-        
-        $this->_elements = array();
-        
-        foreach (array_keys($this->_properties) as $namespace) {
-            $functionName = '_parse' . $namespace . 'Namespace';
-            $this->$functionName($properties);
-        }
-        
-        $airSyncBaseData = $properties->children('uri:AirSyncBase');
-        
-        return;
-    }
-    
     protected function _parseAirSyncBaseNamespace(SimpleXMLElement $properties)
     {
         // fetch data from Email namespace
diff --git a/lib/ext/Syncroton/Model/EmailBody.php b/lib/ext/Syncroton/Model/EmailBody.php
index 8f8b318..4f2af2c 100644
--- a/lib/ext/Syncroton/Model/EmailBody.php
+++ b/lib/ext/Syncroton/Model/EmailBody.php
@@ -41,40 +41,6 @@ class Syncroton_Model_EmailBody extends Syncroton_Model_AEntry
         ),
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-            
-            $nameSpace = 'uri:' . $nameSpace;
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Y-m-d\TH:i:s.000\Z");
-                    }
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
     /**
      * 
      * @param SimpleXMLElement $xmlCollection
diff --git a/lib/ext/Syncroton/Model/Event.php b/lib/ext/Syncroton/Model/Event.php
index cc37324..1571b30 100644
--- a/lib/ext/Syncroton/Model/Event.php
+++ b/lib/ext/Syncroton/Model/Event.php
@@ -29,9 +29,10 @@ class Syncroton_Model_Event extends Syncroton_Model_AEntry
     const BUSY_STATUS_TENATTIVE = 1;
     const BUSY_STATUS_BUSY      = 2;
     
+    protected $_dateTimeFormat = "Ymd\THis\Z";
+    
     protected $_xmlBaseElement = 'ApplicationData';
     
-    // @todo handle body
     protected $_properties = array(
         'AirSyncBase' => array(
             'Body'                   => array('type' => 'container')
@@ -39,15 +40,15 @@ class Syncroton_Model_Event extends Syncroton_Model_AEntry
         'Calendar' => array(
             'AllDayEvent'             => array('type' => 'number'),
             'AppointmentReplyTime'    => array('type' => 'datetime'),
-            'Attendees'               => array('type' => 'container'),
+            'Attendees'               => array('type' => 'container', 'childName' => 'Attendee'),
             //'Body'                    => 0x0b,
             //'BodyTruncated'           => 0x0c,
             'BusyStatus'              => array('type' => 'number'),
-            'Categories'              => array('type' => 'container'),
+            'Categories'              => array('type' => 'container', 'childName' => 'Category'),
             'DisallowNewTimeProposal' => array('type' => 'number'),
             'DtStamp'                 => array('type' => 'datetime'),
             'EndTime'                 => array('type' => 'datetime'),
-            'Exceptions'              => array('type' => 'container'),
+            'Exceptions'              => array('type' => 'container', 'childName' => 'Exception'),
             'Location'                => array('type' => 'string'),
             'MeetingStatus'           => array('type' => 'number'),
             'OnlineMeetingConfLink'   => array('type' => 'string'),
@@ -67,98 +68,6 @@ class Syncroton_Model_Event extends Syncroton_Model_AEntry
         )
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-            
-            $nameSpace = 'uri:' . $nameSpace;
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                case 'Attendees':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach ($value as $attendee) {
-                        $attendeeElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Attendee');
-                        $attendee->appendXML($attendeeElement);
-                        $element->appendChild($attendeeElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Body':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                
-                    $value->appendXML($element);
-                
-                    $_domParrent->appendChild($element);
-                
-                    break;
-                    
-                case 'Categories':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $category) {
-                        $categoryElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Category');
-                        $categoryElement->appendChild($_domParrent->ownerDocument->createTextNode($category));
-                        
-                        $element->appendChild($categoryElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Exceptions':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach ($value as $exception) {
-                        $exceptionElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Exception');
-                        $exception->appendXML($exceptionElement);
-                        $element->appendChild($exceptionElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                                        
-                    break;
-
-                case 'Recurrence':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    $value->appendXML($element);
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-                    
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Ymd\THis\Z");
-                    }
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
     protected function _parseCalendarNamespace(SimpleXMLElement $properties)
     {
         // fetch data from Contacts namespace
diff --git a/lib/ext/Syncroton/Model/EventAttendee.php b/lib/ext/Syncroton/Model/EventAttendee.php
index 3e9946d..7827e30 100644
--- a/lib/ext/Syncroton/Model/EventAttendee.php
+++ b/lib/ext/Syncroton/Model/EventAttendee.php
@@ -38,7 +38,6 @@ class Syncroton_Model_EventAttendee extends Syncroton_Model_AEntry
     const ATTENDEE_TYPE_OPTIONAL = 2;
     const ATTENDEE_TYPE_RESOURCE = 3;
     
-    // @todo handle body
     protected $_properties = array(
         'Calendar' => array(
             'AttendeeStatus'          => array('type' => 'number'),
@@ -48,82 +47,6 @@ class Syncroton_Model_EventAttendee extends Syncroton_Model_AEntry
         )
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $_domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Calendar', 'uri:Calendar');
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            $elementProperties = $this->_properties['Calendar'][$elementName]; 
-            
-            $nameSpace = 'uri:Calendar';
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                case 'Categories':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $category) {
-                        $categoryElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Category');
-                        $categoryElement->appendChild($_domParrent->ownerDocument->createTextNode($category));
-                        
-                        $element->appendChild($categoryElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Children':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $child) {
-                        $childElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Child');
-                        $childElement->appendChild($_domParrent->ownerDocument->createTextNode($child));
-                        
-                        $element->appendChild($childElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Picture':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if (is_resource($value)) {
-                        stream_filter_append($value, 'convert.base64-encode');
-                        $element->appendChild($_domParrent->ownerDocument->createTextNode(stream_get_contents($value)));
-                    } else {
-                        $element->appendChild($_domParrent->ownerDocument->createTextNode(base64_encode($value)));
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-                    
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Ymd\THis\Z");
-                    }
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
     /**
      * 
      * @param SimpleXMLElement $xmlCollection
diff --git a/lib/ext/Syncroton/Model/EventException.php b/lib/ext/Syncroton/Model/EventException.php
index e6881c9..7ab97d7 100644
--- a/lib/ext/Syncroton/Model/EventException.php
+++ b/lib/ext/Syncroton/Model/EventException.php
@@ -24,7 +24,8 @@ class Syncroton_Model_EventException extends Syncroton_Model_Event
 {    
     protected $_xmlBaseElement = 'Exception';
     
-    // @todo handle body
+    protected $_dateTimeFormat = "Ymd\THis\Z";
+    
     protected $_properties = array(
         'Calendar' => array(
             'AllDayEvent'             => array('type' => 'number'),
diff --git a/lib/ext/Syncroton/Model/EventRecurrence.php b/lib/ext/Syncroton/Model/EventRecurrence.php
index 83fe039..d8b9f4c 100644
--- a/lib/ext/Syncroton/Model/EventRecurrence.php
+++ b/lib/ext/Syncroton/Model/EventRecurrence.php
@@ -49,8 +49,9 @@ class Syncroton_Model_EventRecurrence extends Syncroton_Model_AEntry
     const RECUR_DOW_THURSDAY    = 16;
     const RECUR_DOW_FRIDAY      = 32;
     const RECUR_DOW_SATURDAY    = 64;
-        
-    // @todo handle body
+    
+    protected $_dateTimeFormat = "Ymd\THis\Z";
+    
     protected $_properties = array(
         'Calendar' => array(
             'CalendarType'            => array('type' => 'number'),
@@ -67,40 +68,6 @@ class Syncroton_Model_EventRecurrence extends Syncroton_Model_AEntry
         )
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-            
-            $nameSpace = 'uri:' . $nameSpace;
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Ymd\THis\Z");
-                    }
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
     protected function _parseCalendarNamespace(SimpleXMLElement $properties)
     {
         // fetch data from Contacts namespace
diff --git a/lib/ext/Syncroton/Model/FileReference.php b/lib/ext/Syncroton/Model/FileReference.php
index b22bcb0..6c2e67d 100644
--- a/lib/ext/Syncroton/Model/FileReference.php
+++ b/lib/ext/Syncroton/Model/FileReference.php
@@ -29,56 +29,6 @@ class Syncroton_Model_FileReference extends Syncroton_Model_AEntry
         )
     );
         
-    /**
-     * append email data to xml element
-     *
-     * @param DOMElement  $_domParrent   the parrent xml node
-     * @param string      $_folderId  the local folder id
-     */
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-            
-            $nameSpace = 'uri:' . $nameSpace;
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Y-m-d\TH:i:s.000\Z");
-                    }
-                    
-                    if (isset($elementProperties['encoding']) && $elementProperties['encoding'] == 'base64') {
-                        if (is_resource($value)) {
-                            stream_filter_append($value, 'convert.base64-encode');
-                            $value = stream_get_contents($value);
-                        } else {
-                            $value = base64_encode($value);
-                        }
-                    }
-                        
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
     /**
      * 
      * @param SimpleXMLElement $xmlCollection
diff --git a/lib/ext/Syncroton/Model/Folder.php b/lib/ext/Syncroton/Model/Folder.php
index 7aaf91a..50cb189 100644
--- a/lib/ext/Syncroton/Model/Folder.php
+++ b/lib/ext/Syncroton/Model/Folder.php
@@ -15,18 +15,59 @@
  * @package     Model
  */
 
-class Syncroton_Model_Folder implements Syncroton_Model_IFolder
+class Syncroton_Model_Folder extends Syncroton_Model_AEntry implements Syncroton_Model_IFolder
 {
-    public function __construct(array $_data = array())
-    {
-        $this->setFromArray($_data);
-    }
+    protected $_xmlBaseElement = array('FolderUpdate', 'FolderCreate');
     
-    public function setFromArray(array $_data)
-    {
-        foreach($_data as $key => $value) {
-            $this->$key = $value;
-        }
+    protected $_properties = array(
+        'FolderHierarchy' => array(
+            'parentId'     => array('type' => 'string'),
+            'serverId'     => array('type' => 'string'),
+            'displayName'  => array('type' => 'string'),
+            'type'         => array('type' => 'number')
+        ),
+        'Internal' => array(
+            'id'             => array('type' => 'string'),
+            'deviceId'       => array('type' => 'string'),
+            'class'          => array('type' => 'string'),
+            'creationTime'   => array('type' => 'datetime'),
+            'lastfiltertype' => array('type' => 'number')
+        ),
+    );
+    
+    protected function _parseFolderHierarchyNamespace(SimpleXMLElement $properties)
+    {
+        // fetch data from Contacts namespace
+        $children = $properties->children('uri:FolderHierarchy');
+    
+        foreach ($children as $elementName => $xmlElement) {
+            $elementName = lcfirst($elementName);
+            
+            if (!isset($this->_properties['FolderHierarchy'][$elementName])) {
+                continue;
+            }
+            
+            switch ($elementName) {
+                default:
+                    list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
+    
+                    switch ($elementProperties['type']) {
+                        case 'datetime':
+                            $this->$elementName = new DateTime((string) $xmlElement, new DateTimeZone('UTC'));
+    
+                            break;
+    
+                        case 'number':
+                            $this->$elementName = (int) $xmlElement;
+    
+                            break;
+                        default:
+                            $this->$elementName = (string) $xmlElement;
+    
+                            break;
+                    }
+            }
+        }
     }
 }
 
diff --git a/lib/ext/Syncroton/Model/IDevice.php b/lib/ext/Syncroton/Model/IDevice.php
index c084f8c..e2c347e 100644
--- a/lib/ext/Syncroton/Model/IDevice.php
+++ b/lib/ext/Syncroton/Model/IDevice.php
@@ -17,8 +17,8 @@
  * @property    string   deviceid
  * @property    string   devicetype
  * @property    string   policykey
- * @property    string   policy_id
- * @property    string   owner_id
+ * @property    string   policyId
+ * @property    string   ownerId
  * @property    string   acsversion
  * @property    string   pingfolder
  * @property    string   pinglifetime
diff --git a/lib/ext/Syncroton/Model/IFolder.php b/lib/ext/Syncroton/Model/IFolder.php
index ca1e8e3..4ec3700 100644
--- a/lib/ext/Syncroton/Model/IFolder.php
+++ b/lib/ext/Syncroton/Model/IFolder.php
@@ -14,12 +14,12 @@
  *
  * @package     Model
  * @property    string   id
- * @property    string   device_id
+ * @property    string   deviceId
  * @property    string   class
- * @property    string   folderid
- * @property    string   parentid
- * @property    string   displayname
- * @property    string   creation_time
+ * @property    string   serverId
+ * @property    string   parentId
+ * @property    string   displayName
+ * @property    string   creationTime
  * @property    string   lastfiltertype
  */
 
diff --git a/lib/ext/Syncroton/Model/IPolicy.php b/lib/ext/Syncroton/Model/IPolicy.php
new file mode 100644
index 0000000..b6929d3
--- /dev/null
+++ b/lib/ext/Syncroton/Model/IPolicy.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Syncroton
+ *
+ * @package     Model
+ * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
+ * @copyright   Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Lars Kneschke <l.kneschke at metaways.de>
+ */
+
+/**
+ * class to handle ActiveSync Sync command
+ *
+ * @package     Model
+ * @property    string   id
+ * @property    string   deviceid
+ * @property    string   devicetype
+ * @property    string   policyKey
+ * @property    string   policyId
+ * @property    string   ownerId
+ * @property    string   acsversion
+ * @property    string   pingfolder
+ * @property    string   pinglifetime
+ * @property    string   remotewipe
+ * @property    string   useragent
+ */
+
+interface Syncroton_Model_IPolicy
+{
+}
+
diff --git a/lib/ext/Syncroton/Model/Policy.php b/lib/ext/Syncroton/Model/Policy.php
new file mode 100644
index 0000000..9b1dcf3
--- /dev/null
+++ b/lib/ext/Syncroton/Model/Policy.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Syncroton
+ *
+ * @package     Model
+ * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
+ * @copyright   Copyright (c) 2012-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Lars Kneschke <l.kneschke at metaways.de>
+ */
+
+/**
+ * class to handle ActiveSync Sync command
+ *
+ * @package     Model
+ */
+
+class Syncroton_Model_Policy extends Syncroton_Model_AEntry implements Syncroton_Model_IPolicy
+{
+    protected $_xmlBaseElement = 'EASProvisionDoc';
+    
+    protected $_properties = array(
+        'Internal' => array(
+            'id'                                   => array('type' => 'string'),
+            'description'                          => array('type' => 'string'),
+            'name'                                 => array('type' => 'string'),
+            'policyKey'                            => array('type' => 'string'),
+        ),
+        'Provision' => array(
+            'allowBluetooth'                       => array('type' => 'number'),
+            'allowSMIMEEncryptionAlgorithmNegotiation' => array('type' => 'number'),
+            'allowBrowser'                         => array('type' => 'number'),
+            'allowCamera'                          => array('type' => 'number'),
+            'allowConsumerEmail'                   => array('type' => 'number'),
+            'allowDesktopSync'                     => array('type' => 'number'),
+            'allowHTMLEmail'                       => array('type' => 'number'),
+            'allowInternetSharing'                 => array('type' => 'number'),
+            'allowIrDA'                            => array('type' => 'number'),
+            'allowPOPIMAPEmail'                    => array('type' => 'number'),
+            'allowRemoteDesktop'                   => array('type' => 'number'),
+            'allowSimpleDevicePassword'            => array('type' => 'number'),
+            'allowSMIMEEncryptionAlgorithmNegotiation' => array('type' => 'number'),
+            'allowSMIMESoftCerts'                  => array('type' => 'number'),
+            'allowStorageCard'                     => array('type' => 'number'),
+            'allowTextMessaging'                   => array('type' => 'number'),
+            'allowUnsignedApplications'            => array('type' => 'number'),
+            'allowUnsignedInstallationPackages'    => array('type' => 'number'),
+            'allowWifi'                            => array('type' => 'number'),
+            'alphanumericDevicePasswordRequired'   => array('type' => 'number'),
+            'approvedApplicationList'              => array('type' => 'container', 'childName' => 'Hash'),
+            'attachmentsEnabled'                   => array('type' => 'number'),
+            'devicePasswordEnabled'                => array('type' => 'number'),
+            'devicePasswordExpiration'             => array('type' => 'number'),
+            'devicePasswordHistory'                => array('type' => 'number'),
+            'maxAttachmentSize'                    => array('type' => 'number'),
+            'maxCalendarAgeFilter'                 => array('type' => 'number'),
+            'maxDevicePasswordFailedAttempts'      => array('type' => 'number'),
+            'maxEmailAgeFilter'                    => array('type' => 'number'),
+            'maxEmailBodyTruncationSize'           => array('type' => 'number'),
+            'maxEmailHTMLBodyTruncationSize'       => array('type' => 'number'),
+            'maxInactivityTimeDeviceLock'          => array('type' => 'number'),
+            'minDevicePasswordComplexCharacters'   => array('type' => 'number'),
+            'minDevicePasswordLength'              => array('type' => 'number'),
+            'passwordRecoveryEnabled'              => array('type' => 'number'),
+            'requireDeviceEncryption'              => array('type' => 'number'),
+            'requireEncryptedSMIMEMessages'        => array('type' => 'number'),
+            'requireEncryptionSMIMEAlgorithm'      => array('type' => 'number'),
+            'requireManualSyncWhenRoaming'         => array('type' => 'number'),
+            'requireSignedSMIMEAlgorithm'          => array('type' => 'number'),
+            'requireSignedSMIMEMessages'           => array('type' => 'number'),
+            'requireStorageCardEncryption'         => array('type' => 'number'),
+            'unapprovedInROMApplicationList'       => array('type' => 'container', 'childName' => 'ApplicationName')
+        )
+    );
+}
+
diff --git a/lib/ext/Syncroton/Model/StoreRequest.php b/lib/ext/Syncroton/Model/StoreRequest.php
index a108e35..e78f41c 100644
--- a/lib/ext/Syncroton/Model/StoreRequest.php
+++ b/lib/ext/Syncroton/Model/StoreRequest.php
@@ -80,11 +80,10 @@ class Syncroton_Model_StoreRequest
             if (isset($xmlStore->Query)) {
                 $this->_store['query'] = (string) $xmlStore->Query;
             }
-        }
-        else if (isset($xmlStore->Query)) {
+        } elseif (isset($xmlStore->Query)) {
             if (isset($xmlStore->Query->And)) {
                 if (isset($xmlStore->Query->And->FreeText)) {
-                    $this->_store['query']['and']['freeText'] = (string) $xmlStore->Query->And->FreeText;
+                    $this->_store['query']['and']['freetext'] = (string) $xmlStore->Query->And->FreeText;
                 }
                 if (isset($xmlStore->Query->And->ConversationId)) {
                     $this->_store['query']['and']['conversationId'] = (string) $xmlStore->Query->And->ConversationId;
@@ -115,8 +114,7 @@ class Syncroton_Model_StoreRequest
                 foreach ($airSync as $name => $value) {
                     if ($name == 'Class') {
                         $this->_store['query']['and']['classes'][] = (string) $value;
-                    }
-                    else if ($name == 'CollectionId') {
+                    } elseif ($name == 'CollectionId') {
                         $this->_store['query']['and']['collections'][] = (string) $value;
                     }
                 }
@@ -164,8 +162,7 @@ class Syncroton_Model_StoreRequest
 
             if (!empty($xmlStore->Options->Range)) {
                 $this->_store['options']['range'] = (string) $xmlStore->Options->Range;
-            }
-            else {
+            } else {
                 switch ($this->_store['name']) {
                 case 'DocumentLibrary':
                 case 'Document Library': //?
diff --git a/lib/ext/Syncroton/Model/StoreResponse.php b/lib/ext/Syncroton/Model/StoreResponse.php
index 51706a1..cd1770f 100644
--- a/lib/ext/Syncroton/Model/StoreResponse.php
+++ b/lib/ext/Syncroton/Model/StoreResponse.php
@@ -33,7 +33,7 @@ class Syncroton_Model_StoreResponse extends Syncroton_Model_AEntry
     const STATUS_ACCESSBLOCKED    = 13;
     const STATUS_CREDENTIALSREQUIRED = 14;
 
-    protected $_xmlBaseElement = 'ApplicationData';
+    protected $_xmlBaseElement = 'Store';
 
     protected $_properties = array(
         'Search' => array(
diff --git a/lib/ext/Syncroton/Model/StoreResponseResult.php b/lib/ext/Syncroton/Model/StoreResponseResult.php
index 2e1dcca..b79f863 100644
--- a/lib/ext/Syncroton/Model/StoreResponseResult.php
+++ b/lib/ext/Syncroton/Model/StoreResponseResult.php
@@ -16,7 +16,7 @@
  */
 class Syncroton_Model_StoreResponseResult extends Syncroton_Model_AEntry
 {
-    protected $_xmlBaseElement = 'ApplicationData';
+    protected $_xmlBaseElement = 'Result';
 
     protected $_properties = array(
         'AirSync' => array(
@@ -28,33 +28,4 @@ class Syncroton_Model_StoreResponseResult extends Syncroton_Model_AEntry
             'Properties' => array('type' => 'container'),
         )
     );
-
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-
-        foreach ($this->_elements as $elementName => $value) {
-            // skip empty values
-            if ($value === null || $value === '') {
-                continue;
-            }
-
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-
-            $nameSpace = 'uri:' . $nameSpace;
-
-            switch ($elementName) {
-                case 'Properties':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    $value->appendXML($element);
-                    $_domParrent->appendChild($element);
-                    break;
-
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    $_domParrent->appendChild($element);
-            }
-        }
-    }
 }
diff --git a/lib/ext/Syncroton/Model/SyncCollection.php b/lib/ext/Syncroton/Model/SyncCollection.php
index 140881d..736c582 100644
--- a/lib/ext/Syncroton/Model/SyncCollection.php
+++ b/lib/ext/Syncroton/Model/SyncCollection.php
@@ -188,7 +188,7 @@ class Syncroton_Model_SyncCollection
             'collectionId'     => (string)$xmlCollection->CollectionId,
             'deletesAsMoves'   => isset($xmlCollection->DeletesAsMoves)   && (string)$xmlCollection->DeletesAsMoves   === '0' ? false : true,
             'conversationMode' => isset($xmlCollection->ConversationMode) && (string)$xmlCollection->ConversationMode === '0' ? false : true,
-            'getChanges'       => isset($xmlCollection->GetChanges) ? true : false,
+            'getChanges'       => isset($xmlCollection->GetChanges) && (string) $xmlCollection->GetChanges === '0' ? false : true,
             'windowSize'       => isset($xmlCollection->WindowSize) ? (int)$xmlCollection->WindowSize : 100,
             'class'            => isset($xmlCollection->Class) ? (string)$xmlCollection->Class : null,
             'options'          => array(
diff --git a/lib/ext/Syncroton/Model/Task.php b/lib/ext/Syncroton/Model/Task.php
index 30ebc70..ec42cff 100644
--- a/lib/ext/Syncroton/Model/Task.php
+++ b/lib/ext/Syncroton/Model/Task.php
@@ -24,16 +24,12 @@ class Syncroton_Model_Task extends Syncroton_Model_AEntry
 {
     protected $_xmlBaseElement = 'ApplicationData';
     
-    // @todo handle body
     protected $_properties = array(
         'AirSyncBase' => array(
             'Body'                   => array('type' => 'container')
         ),
         'Tasks' => array(
-            //'Body'                    => 0x05,
-            //'BodySize'                => 0x06,
-            //'BodyTruncated'           => 0x07,
-            'Categories'              => array('type' => 'container'),
+            'Categories'              => array('type' => 'container', 'childName' => 'Category'),
             'Complete'                => array('type' => 'number'),
             'DateCompleted'           => array('type' => 'datetime'),
             'DueDate'                 => array('type' => 'datetime'),
@@ -49,72 +45,6 @@ class Syncroton_Model_Task extends Syncroton_Model_AEntry
         )
     );
     
-    public function appendXML(DOMElement $_domParrent)
-    {
-        $this->_addXMLNamespaces($_domParrent);
-        
-        foreach($this->_elements as $elementName => $value) {
-            // skip empty values
-            if($value === null || $value === '' || (is_array($value) && empty($value))) {
-                continue;
-            }
-            
-            list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
-            
-            $nameSpace = 'uri:' . $nameSpace;
-            
-            // strip off any non printable control characters
-            if (!ctype_print($value)) {
-                #$value = $this->removeControlChars($value);
-            }
-            
-            switch($elementName) {
-                case 'Body':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    $value->appendXML($element);
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Categories':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    foreach($value as $category) {
-                        $categoryElement = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Category');
-                        $categoryElement->appendChild($_domParrent->ownerDocument->createTextNode($category));
-                        
-                        $element->appendChild($categoryElement);
-                    }
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-
-                case 'Recurrence':
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    $value->appendXML($element);
-                    
-                    $_domParrent->appendChild($element);
-                    
-                    break;
-                    
-                default:
-                    $element = $_domParrent->ownerDocument->createElementNS($nameSpace, $elementName);
-                    
-                    if ($value instanceof DateTime) {
-                        $value = $value->format("Y-m-d\TH:i:s.000\Z");
-                    }
-                    $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
-                    
-                    $_domParrent->appendChild($element);
-            }
-        }
-        
-    }
-    
     protected function _parseTasksNamespace(SimpleXMLElement $properties)
     {
         // fetch data from Contacts namespace
diff --git a/lib/ext/Syncroton/Registry.php b/lib/ext/Syncroton/Registry.php
index 32838a6..c971456 100644
--- a/lib/ext/Syncroton/Registry.php
+++ b/lib/ext/Syncroton/Registry.php
@@ -41,6 +41,7 @@ class Syncroton_Registry extends ArrayObject
     const CONTENTSTATEBACKEND = 'contentstatebackend';
     const DEVICEBACKEND       = 'devicebackend';
     const FOLDERBACKEND       = 'folderbackend';
+    const POLICYBACKEND       = 'policybackend';
     const SYNCSTATEBACKEND    = 'syncstatebackend';
     
     /**
@@ -238,6 +239,23 @@ class Syncroton_Registry extends ArrayObject
     }
 
     /**
+     * returns policy backend
+     * 
+     * creates Syncroton_Backend_Policy on the fly if not set before via
+     * Syncroton_Registry::set(self::POLICYBACKEND, $backend);
+     * 
+     * @return Syncroton_Backend_ISyncState
+     */
+    public static function getPolicyBackend()
+    {
+        if (!self::isRegistered(self::POLICYBACKEND)) {
+            self::set(self::POLICYBACKEND, new Syncroton_Backend_Policy(self::getDatabase()));
+        }
+        
+        return self::get(self::POLICYBACKEND);
+    }
+
+    /**
      * returns syncstate backend
      * 
      * creates Syncroton_Backend_SyncState on the fly if not before via
diff --git a/lib/ext/Syncroton/Server.php b/lib/ext/Syncroton/Server.php
index 94fa4a9..862614c 100644
--- a/lib/ext/Syncroton/Server.php
+++ b/lib/ext/Syncroton/Server.php
@@ -137,9 +137,16 @@ class Syncroton_Server
             if ($this->_logger instanceof Zend_Log) 
                 $this->_logger->info(__METHOD__ . '::' . __LINE__ . " provisioning needed");
             
-            header("HTTP/1.1 449 Retry after sending a PROVISION command");
-               
-            return;
+            if (version_compare($device->acsversion, '14.0', '>=')) {
+                $response = $sepn->domDocument;
+            } else {
+                // pre 14.0 method
+                header("HTTP/1.1 449 Retry after sending a PROVISION command");
+                   
+                return;
+            }
+            
+            
             
         } catch (Exception $e) {
             if ($this->_logger instanceof Zend_Log)
diff --git a/lib/init.php b/lib/init.php
index f137342..3e63921 100644
--- a/lib/init.php
+++ b/lib/init.php
@@ -85,7 +85,6 @@ function kolab_sync_autoload($classname)
     // Roundcube Framework
     $filename = preg_replace(
         array(
-            '/MDB2_(.+)/',
             '/Mail_(.+)/',
             '/Net_(.+)/',
             '/Auth_(.+)/',
@@ -93,7 +92,6 @@ function kolab_sync_autoload($classname)
             '/^utf8$/',
         ),
         array(
-            'MDB2/\\1',
             'Mail/\\1',
             'Net/\\1',
             'Auth/\\1',
diff --git a/lib/kolab_sync.php b/lib/kolab_sync.php
index 647515d..741fb04 100644
--- a/lib/kolab_sync.php
+++ b/lib/kolab_sync.php
@@ -122,6 +122,7 @@ class kolab_sync extends rcube
         Syncroton_Registry::set(Syncroton_Registry::FOLDERBACKEND,       new kolab_sync_backend_folder);
         Syncroton_Registry::set(Syncroton_Registry::SYNCSTATEBACKEND,    new kolab_sync_backend_state);
         Syncroton_Registry::set(Syncroton_Registry::CONTENTSTATEBACKEND, new kolab_sync_backend_content);
+        Syncroton_Registry::set(Syncroton_Registry::POLICYBACKEND, new kolab_sync_backend_policy);
 
         Syncroton_Registry::setContactsDataClass('kolab_sync_data_contacts');
         Syncroton_Registry::setCalendarDataClass('kolab_sync_data_calendar');
diff --git a/lib/kolab_sync_backend.php b/lib/kolab_sync_backend.php
index d9413fa..8a64878 100644
--- a/lib/kolab_sync_backend.php
+++ b/lib/kolab_sync_backend.php
@@ -92,6 +92,7 @@ class kolab_sync_backend
     public function startup()
     {
         $this->storage = rcube::get_instance()->get_storage();
+
         // @TODO: reset cache? if we do this for every request the cache would be useless
         // There's no session here
         //$this->storage->clear_cache('mailboxes.', true);
@@ -574,9 +575,9 @@ class kolab_sync_backend
 
         // Syncroton folder data array
         return array(
-            'folderid'    => $folder_id,
-            'parentid'    => count($items) ? self::folder_id(implode($delim, $items)) : 0,
-            'displayname' => rcube_charset::convert($name, 'UTF7-IMAP', kolab_sync::CHARSET),
+            'serverId'    => $folder_id,
+            'parentId'    => count($items) ? self::folder_id(implode($delim, $items)) : 0,
+            'displayName' => rcube_charset::convert($name, 'UTF7-IMAP', kolab_sync::CHARSET),
             'type'        => self::type_kolab2activesync($type),
         );
     }
diff --git a/lib/kolab_sync_backend_common.php b/lib/kolab_sync_backend_common.php
new file mode 100644
index 0000000..34e9623
--- /dev/null
+++ b/lib/kolab_sync_backend_common.php
@@ -0,0 +1,212 @@
+<?php
+
+/**
+ +--------------------------------------------------------------------------+
+ | Kolab Sync (ActiveSync for Kolab)                                        |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG <contact at kolabsys.com>         |
+ |                                                                          |
+ | This program is free software: you can redistribute it and/or modify     |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 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 Affero General Public License for more details.                      |
+ |                                                                          |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * Parent backend class for kolab backends
+ */
+class kolab_sync_backend_common implements Syncroton_Backend_IBackend
+{
+    /**
+     * Table name
+     *
+     * @var string
+     */
+    protected $table_name;
+
+    /**
+     * Model interface name
+     *
+     * @var string
+     */
+    protected $interface_name;
+
+    /**
+     * Backend interface name
+     *
+     * @var string
+     */
+    protected $class_name;
+
+    /**
+     * SQL Database engine
+     *
+     * @var rcube_db
+     */
+    protected $db;
+
+
+    /**
+     * Constructor
+     */
+    function __construct()
+    {
+        $this->db = rcube::get_instance()->get_dbh();
+
+        if (empty($this->class_name)) {
+            $this->class_name = str_replace('Model_I', 'Model_', $this->interface_name);
+        }
+    }
+
+    /**
+     * Creates new Syncroton data object in database
+     *
+     * @param Syncroton_Model_* $object
+     * @throws InvalidArgumentException
+     * @return Syncroton_Model_*
+     */
+    public function create($object)
+    {
+        if (! $object instanceof $this->interface_name) {
+            throw new InvalidArgumentException('$object must be instanace of ' . $this->interface_name);
+        }
+
+        $data   = $this->object_to_array($object);
+        $insert = array();
+
+        $data['id'] = sha1(mt_rand(). microtime());
+
+        foreach ($data as $key => $value) {
+            $insert[$this->db->quote_identifier($key)] = $this->db->quote($value);
+        }
+
+        $this->db->query('INSERT INTO ' . $this->table_name
+            . ' (' . implode(', ', array_keys($insert)) . ')' . ' VALUES(' . implode(', ', $insert) . ')');
+
+        return $this->get($data['id']);
+    }
+
+    /**
+     * Returns Syncroton data object
+     *
+     * @param string  $id
+     * @throws Syncroton_Exception_NotFound
+     * @return Syncroton_Model_*
+     */
+    public function get($id)
+    {
+        $id = $id instanceof $this->interface_name ? $id->id : $id;
+
+        $select = $this->db->query('SELECT * FROM ' . $this->table_name . ' WHERE id = ?', array($id));
+        $data   = $this->db->fetch_assoc($select);
+
+        if (empty($data)) {
+            throw new Syncroton_Exception_NotFound('Object not found');
+        }
+
+        return $this->get_object($data);
+    }
+
+    /**
+     * Deletes Syncroton data object
+     *
+     * @param string  $id
+     * @return bool
+     */
+    public function delete($id)
+    {
+        $id = $id instanceof $this->interface_name ? $id->id : $id;
+
+        $result = $this->db->query('DELETE FROM ' . $this->table_name .' WHERE id = ?', array($id));
+
+        return (bool) $this->db->affected_rows($result);
+    }
+
+    /**
+     * Updates Syncroton data object
+     *
+     * @param Syncroton_Model_* $object
+     * @throws InvalidArgumentException
+     * @return Syncroton_Model_*
+     */
+    public function update($object)
+    {
+        if (! $object instanceof $this->interface_name) {
+            throw new InvalidArgumentException('$object must be instanace of ' . $this->interface_name);
+        }
+
+        $data = $this->object_to_array($object);
+        $set  = array();
+
+        foreach ($data as $key => $value) {
+            $set[] = $this->db->quote_identifier($key) . ' = ' . $this->db->quote($value);
+        }
+
+        $this->db->query('UPDATE ' . $this->table_name . ' SET ' . implode(', ', $set)
+            . ' WHERE ' . $this->db->quote_identifier('id') . ' = ' . $this->db->quote($object->id));
+
+        return $this->get($object->id);
+    }
+
+    /**
+     *
+     */
+    protected function get_object($data)
+    {
+        foreach ($data as $key => $value) {
+            unset($data[$key]);
+
+            if (!empty($value) && preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $value)) { // 2012-08-12 07:43:26
+                $value = new DateTime($value, new DateTimeZone('utc'));
+            }
+
+            $data[$this->to_camelcase($key, false)] = $value;
+        }
+
+        return new $this->class_name($data);
+    }
+
+    protected function object_to_array($object)
+    {
+        $data = array();
+
+        foreach ($object as $key => $value) {
+            if ($value instanceof DateTime) {
+                $value = $value->format('Y-m-d H:i:s');
+            } elseif (is_object($value) && isset($value->id)) {
+                $value = $value->id;
+            }
+
+            $data[$this->from_camelcase($key)] = $value;
+        }
+
+        return $data;
+    }
+
+    protected function from_camelcase($string)
+    {
+        $string = lcfirst($string);
+
+        return preg_replace_callback('/([A-Z])/', function ($string) { return '_' . strtolower($string[0]); }, $string);
+    }
+
+    protected function to_camelcase($string, $ucFirst = true)
+    {
+        if ($ucFirst) {
+            $string = ucfirst($string);
+        }
+
+        return preg_replace_callback('/_([a-z])/', function ($string) { return strtoupper($string[1]); }, $string);
+    }
+}
diff --git a/lib/kolab_sync_backend_content.php b/lib/kolab_sync_backend_content.php
index 27c2a29..c13a343 100644
--- a/lib/kolab_sync_backend_content.php
+++ b/lib/kolab_sync_backend_content.php
@@ -24,90 +24,29 @@
 */
 
 /**
- *
- * @package     Syncroton
- * @subpackage  Backend
+ * Kolab backend class for content storage
  */
-class kolab_sync_backend_content implements Syncroton_Backend_IContent
+class kolab_sync_backend_content extends kolab_sync_backend_common implements Syncroton_Backend_IContent
 {
-    /**
-     * the database adapter
-     *
-     * @var rcube_mdb2
-     */
-    protected $db;
+    protected $table_name     = 'syncroton_content';
+    protected $interface_name = 'Syncroton_Model_IContent';
 
 
-    public function __construct()
-    {
-        $this->db = rcube::get_instance()->get_dbh();
-    }
-
-    /**
-     * create new content state
-     *
-     * @param Syncroton_Model_IContent $_state
-     * @return Syncroton_Model_IContent
-     */
-    public function create(Syncroton_Model_IContent $_state)
-    {
-        $id = sha1(mt_rand(). microtime());
-
-        $deviceId = $_state->device_id instanceof Syncroton_Model_IDevice ? $_state->device_id->id : $_state->device_id;
-        $folderId = $_state->folder_id instanceof Syncroton_Model_IFolder ? $_state->folder_id->id : $_state->folder_id;
-
-        $insert[$this->db->quote_identifier('id')]               = $this->db->quote($id);
-        $insert[$this->db->quote_identifier('device_id')]        = $this->db->quote($deviceId);
-        $insert[$this->db->quote_identifier('folder_id')]        = $this->db->quote($folderId);
-        $insert[$this->db->quote_identifier('contentid')]        = $this->db->quote($_state->contentid);
-        $insert[$this->db->quote_identifier('creation_time')]    = $this->db->quote($_state->creation_time->format('Y-m-d H:i:s'));
-        $insert[$this->db->quote_identifier('creation_synckey')] = $this->db->quote($_state->creation_synckey);
-        $insert[$this->db->quote_identifier('is_deleted')]       = $this->db->quote(isset($_state->is_deleted) ? (int)!!$_state->is_deleted : 0);
-
-        $this->db->query('INSERT INTO syncroton_content '
-            . ' (' . implode(', ', array_keys($insert)) . ')' . ' VALUES(' . implode(', ', $insert) . ')');
-
-        return $this->get($id);
-    }
-
     /**
      * mark state as deleted. The state gets removed finally,
      * when the synckey gets validated during next sync.
      *
-     * @param Syncroton_Model_IContent|string $_id
+     * @param Syncroton_Model_IContent|string $id
      */
-    public function delete($_id)
+    public function delete($id)
     {
-        $id = $_id instanceof Syncroton_Model_IContent ? $_id->id : $_id;
+        $id = $id instanceof Syncroton_Model_IContent ? $id->id : $id;
 
-        $result = $this->db->query('UPDATE syncroton_content SET is_deleted = 1 WHERE id = ?', array($id));
+        $result = $this->db->query('UPDATE ' . $this->table_name . ' SET is_deleted = 1 WHERE id = ?', array($id));
 
-//        return (bool) $this->db->affected_rows($result);
+        return (bool) $this->db->affected_rows($result);
     }
 
-    /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_IContent
-     */
-    public function get($_id)
-    {
-        $select = $this->db->query('SELECT * FROM syncroton_content WHERE id = ?', array($_id));
-
-        if ($state = $this->db->fetch_assoc($select)) {
-            $state = new Syncroton_Model_Content($state);
-        }
-
-        if (! $state instanceof Syncroton_Model_IContent) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-
-        if (!empty($state->creation_time)) {
-            $state->creation_time = new DateTime($state->creation_time, new DateTimeZone('utc'));
-        }
-
-        return $state;
-    }
 
     /**
      * @param Syncroton_Model_IDevice|string $_deviceId
@@ -125,21 +64,14 @@ class kolab_sync_backend_content implements Syncroton_Backend_IContent
         $where[] = $this->db->quote_identifier('contentid') . ' = ' . $this->db->quote($_contentId);
         $where[] = $this->db->quote_identifier('is_deleted') . ' = 0';
 
-        $select = $this->db->query('SELECT * FROM syncroton_content WHERE ' . implode(' AND ', $where));
-
-        if ($state = $this->db->fetch_assoc($select)) {
-            $state = new Syncroton_Model_Content($state);
-        }
-
-        if (! $state instanceof Syncroton_Model_IContent) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
+        $select = $this->db->query('SELECT * FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
+        $state  = $this->db->fetch_assoc($select);
 
-        if (!empty($state->creation_time)) {
-            $state->creation_time = new DateTime($state->creation_time, new DateTimeZone('utc'));
+        if (empty($state)) {
+            throw new Syncroton_Exception_NotFound('Content not found');
         }
 
-        return $state;
+        return $this->get_object($state);
     }
 
     /**
@@ -158,7 +90,7 @@ class kolab_sync_backend_content implements Syncroton_Backend_IContent
         $where[] = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folderId);
         $where[] = $this->db->quote_identifier('is_deleted') . ' = 0';
 
-        $select = $this->db->query('SELECT contentid FROM syncroton_content WHERE ' . implode(' AND ', $where));
+        $select = $this->db->query('SELECT contentid FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
         $result = array();
 
         while ($state = $this->db->fetch_assoc($select)) {
@@ -182,6 +114,6 @@ class kolab_sync_backend_content implements Syncroton_Backend_IContent
         $where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
         $where[] = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folderId);
 
-        $this->db->query('DELETE FROM syncroton_content WHERE ' . implode(' AND ', $where));
+        $this->db->query('DELETE FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
     }
 }
diff --git a/lib/kolab_sync_backend_device.php b/lib/kolab_sync_backend_device.php
index 2c5e8fe..34a9759 100644
--- a/lib/kolab_sync_backend_device.php
+++ b/lib/kolab_sync_backend_device.php
@@ -24,10 +24,13 @@
 */
 
 /**
- *
+ * Kolab backend class for device storage
  */
-class kolab_sync_backend_device implements Syncroton_Backend_IDevice
+class kolab_sync_backend_device extends kolab_sync_backend_common implements Syncroton_Backend_IDevice
 {
+    protected $table_name     = 'syncroton_device';
+    protected $interface_name = 'Syncroton_Model_IDevice';
+
     /**
      * Kolab Sync backend
      *
@@ -35,77 +38,61 @@ class kolab_sync_backend_device implements Syncroton_Backend_IDevice
      */
     protected $backend;
 
+
     /**
-     * the database adapter
-     *
-     * @var rcube_mdb2
+     * Constructor
      */
-    protected $db;
-
-
     public function __construct()
     {
+        parent::__construct();
         $this->backend = kolab_sync_backend::get_instance();
-        $this->db      = rcube::get_instance()->get_dbh();
     }
 
+
     /**
      * create new device
      *
-     * @param Syncroton_Model_IDevice $_device
+     * @param Syncroton_Model_IDevice $device
+     *
      * @return Syncroton_Model_IDevice
      */
-    public function create(Syncroton_Model_IDevice $device)
+    public function create($device)
     {
-        $id = sha1(mt_rand() . microtime());
+        $device = parent::create($device);
 
         // Create device entry in kolab backend
         $created = $this->backend->device_create(array(
-            'ID'         => $id,
+            'ID'         => $device->id,
             'TYPE'       => $device->devicetype,
         ), $device->deviceid);
 
         if (!$created) {
-            throw new Syncroton_Exception_NotFound('device creation failed');
+            throw new Syncroton_Exception_NotFound('Device creation failed');
         }
 
-        $insert[$this->db->quote_identifier('id')]         = $this->db->quote($id);
-        $insert[$this->db->quote_identifier('deviceid')]   = $this->db->quote($device->deviceid);
-        $insert[$this->db->quote_identifier('devicetype')] = $this->db->quote($device->devicetype);
-        $insert[$this->db->quote_identifier('owner_id')]   = $this->db->quote($device->owner_id);
-        $insert[$this->db->quote_identifier('policy_id')]  = isset($device->policy_id)  ? $this->db->quote($device->policy_id)  : 1;
-        $insert[$this->db->quote_identifier('policykey')]  = isset($device->policykey)  ? $this->db->quote($device->policykey)  : 'NULL';
-        $insert[$this->db->quote_identifier('useragent')]  = isset($device->useragent)  ? $this->db->quote($device->useragent)  : "''";
-        $insert[$this->db->quote_identifier('acsversion')] = isset($device->acsversion) ? $this->db->quote($device->acsversion) : "''";
-        $insert[$this->db->quote_identifier('remotewipe')] = isset($device->remotewipe) ? $this->db->quote($device->remotewipe) : 'NULL';
-
-        // Add entry to database
-        $this->db->query('INSERT INTO syncroton_device'
-            . ' (' . implode(', ', array_keys($insert)) . ')' . ' VALUES(' . implode(', ', $insert) . ')');
-
-        return $this->get($id);
+        return $device;
     }
 
+
     /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_IDevice
+     * Delete a device
+     *
+     * @param Syncroton_Model_IDevice $device
+     *
+     * @return bool True on success, False on failure
      */
-    public function get($id)
+    public function delete($device)
     {
-        $select = $this->db->query('SELECT * FROM syncroton_device WHERE id = ?', array($id));
-
-        if ($device = $this->db->fetch_assoc($select)) {
-            $device = new Syncroton_Model_Device($device);
-        }
+        $result = $this->backend->device_delete($device->deviceid);
 
-        if (! $device instanceof Syncroton_Model_IDevice) {
-            throw new Syncroton_Exception_NotFound('id not found');
+        if ($result) {
+            $result = parent::delete($device);
         }
 
-        return $device;
+        return $result;
     }
 
+
     /**
      * return device for this user
      *
@@ -119,15 +106,14 @@ class kolab_sync_backend_device implements Syncroton_Backend_IDevice
         $where[] = $this->db->quote_identifier('deviceid') . ' = ' . $this->db->quote($deviceId);
         $where[] = $this->db->quote_identifier('owner_id') . ' = ' . $this->db->quote($ownerId);
 
-        $select = $this->db->query('SELECT * FROM syncroton_device WHERE ' . implode(' AND ', $where));
+        $select = $this->db->query('SELECT * FROM ' . $this->table_name . ' WHERE ' . implode(' AND ', $where));
+        $device = $this->db->fetch_assoc($select);
 
-        if ($device = $this->db->fetch_assoc($select)) {
-            $device = new Syncroton_Model_Device($device);
+        if (empty($device)) {
+            throw new Syncroton_Exception_NotFound('Device not found');
         }
 
-        if (! $device instanceof Syncroton_Model_IDevice) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
+        $device = $this->get_object($device);
 
         // Make sure device exists (could be deleted by the user)
         $dev = $this->backend->device_get($deviceId);
@@ -135,37 +121,9 @@ class kolab_sync_backend_device implements Syncroton_Backend_IDevice
             // Remove the device (and related cached data) from database
             $this->delete($device);
 
-            throw new Syncroton_Exception_NotFound('device not found');
+            throw new Syncroton_Exception_NotFound('Device not found');
         }
 
         return $device;
     }
-
-    public function delete($device)
-    {
-        $result = $this->backend->device_delete($device->deviceid);
-
-        if ($result) {
-            $result = $this->db->query('DELETE FROM syncroton_device'
-            . ' WHERE ' . $this->db->quote_identifier('id') . ' = ' . $this->db->quote($device->id));
-            $result = (bool) $this->db->affected_rows($result);
-        }
-
-        return $result;
-    }
-
-    public function update(Syncroton_Model_IDevice $device)
-    {
-        $set[] = $this->db->quote_identifier('policykey')    . ' = ' . (isset($device->policykey)  ? $this->db->quote($device->policykey)  : 'NULL');
-        $set[] = $this->db->quote_identifier('useragent')    . ' = ' . (isset($device->useragent)  ? $this->db->quote($device->useragent)  : "''");
-        $set[] = $this->db->quote_identifier('acsversion')   . ' = ' . (isset($device->acsversion) ? $this->db->quote($device->acsversion) : "''");
-        $set[] = $this->db->quote_identifier('remotewipe')   . ' = ' . (isset($device->remotewipe) ? $this->db->quote($device->remotewipe) : 'NULL');
-        $set[] = $this->db->quote_identifier('pinglifetime') . ' = ' . (isset($device->pinglifetime) ? $this->db->quote($device->pinglifetime) : 'NULL');
-        $set[] = $this->db->quote_identifier('pingfolder')   . ' = ' . (isset($device->pingfolder) ? $this->db->quote($device->pingfolder) : 'NULL');
-
-        $this->db->query('UPDATE syncroton_device SET ' . implode(', ', $set)
-            . ' WHERE ' . $this->db->quote_identifier('id') . ' = ' . $this->db->quote($device->id));
-
-        return $this->get($device->id);
-    }
 }
diff --git a/lib/kolab_sync_backend_folder.php b/lib/kolab_sync_backend_folder.php
index 4fcb295..8b60b18 100644
--- a/lib/kolab_sync_backend_folder.php
+++ b/lib/kolab_sync_backend_folder.php
@@ -24,86 +24,12 @@
 */
 
 /**
- * sql backend class for the folder state
- *
- * @package     Syncroton
- * @subpackage  Backend
+ * Kolab backend class for the folder state storage
  */
-class kolab_sync_backend_folder implements Syncroton_Backend_IFolder
+class kolab_sync_backend_folder extends kolab_sync_backend_common implements Syncroton_Backend_IFolder
 {
-    /**
-     * the database adapter
-     *
-     * @var rcube_mdb2
-     */
-    protected $db;
-
-
-    public function __construct()
-    {
-        $this->db = rcube::get_instance()->get_dbh();
-    }
-
-    /**
-     * create new folder state
-     *
-     * @param Syncroton_Model_IFolder $_folder
-     * @return Syncroton_Model_IFolder
-     */
-    public function create(Syncroton_Model_IFolder $_folder)
-    {
-        $id       = sha1(mt_rand(). microtime());
-        $deviceId = $_folder->device_id instanceof Syncroton_Model_IDevice ? $_folder->device_id->id : $_folder->device_id;
-        $folderId = $_folder->folderid instanceof Syncroton_Model_IFolder ? $_folder->folderid->id : $_folder->folderid;
-
-        $insert[$this->db->quote_identifier('id')]             = $this->db->quote($id);
-        $insert[$this->db->quote_identifier('device_id')]      = $this->db->quote($deviceId);
-        $insert[$this->db->quote_identifier('class')]          = $this->db->quote($_folder->class);
-        $insert[$this->db->quote_identifier('folderid')]       = $this->db->quote($folderId);
-        $insert[$this->db->quote_identifier('parentid')]       = $this->db->quote($_folder->parentid);
-        $insert[$this->db->quote_identifier('displayname')]    = $this->db->quote($_folder->displayname);
-        $insert[$this->db->quote_identifier('type')]           = $this->db->quote($_folder->type);
-        $insert[$this->db->quote_identifier('creation_time')]  = $this->db->quote($_folder->creation_time->format('Y-m-d H:i:s'));
-        $insert[$this->db->quote_identifier('lastfiltertype')] = $this->db->quote($_folder->lastfiltertype);
-
-        $this->db->query('INSERT INTO syncroton_folder'
-            . ' (' . implode(', ', array_keys($insert)) . ')' . ' VALUES(' . implode(', ', $insert) . ')');
-
-        return $this->get($id);
-    }
-
-    public function delete($_id)
-    {
-        $id = $_id instanceof Syncroton_Model_IFolder ? $_id->id : $_id;
-
-        $result = $this->db->query('DELETE FROM syncroton_folder WHERE id = ?', array($id));
-
-        return (bool) $this->db->affected_rows($result);
-    }
-
-    /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_IFolder
-     */
-    public function get($_id)
-    {
-        $select = $this->db->query('SELECT * FROM syncroton_folder WHERE id = ?', array($_id));
-
-        if ($state = $this->db->fetch_assoc($select)) {
-            $state = new Syncroton_Model_Folder($state);
-        }
-
-        if (! $state instanceof Syncroton_Model_IFolder) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-
-        if (!empty($state->creation_time)) {
-            $state->creation_time = new DateTime($state->creation_time, new DateTimeZone('utc'));
-        }
-
-        return $state;
-    }
+    protected $table_name     = 'syncroton_folder';
+    protected $interface_name = 'Syncroton_Model_IFolder';
 
     /**
      * delete all stored folderId's for given device
@@ -117,16 +43,9 @@ class kolab_sync_backend_folder implements Syncroton_Backend_IFolder
 
         $where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
 
-        $this->db->query('DELETE FROM syncroton_folder WHERE ' . implode(' AND ', $where));
+        $this->db->query('DELETE FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
     }
 
-    public function update(Syncroton_Model_IFolder $_folder)
-    {
-        $this->db->query('UPDATE syncroton_folder SET lastfiltertype = ? WHERE id = ?',
-            array($_folder->lastfiltertype, $_folder->id));
-
-        return $this->get($_folder->id);
-    }
 
     /**
      * get array of ids which got send to the client for a given class
@@ -143,11 +62,11 @@ class kolab_sync_backend_folder implements Syncroton_Backend_IFolder
         $where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
         $where[] = $this->db->quote_identifier('class')     . ' = ' . $this->db->quote($_class);
 
-        $select = $this->db->query('SELECT * FROM syncroton_folder WHERE ' . implode(' AND ', $where));
+        $select = $this->db->query('SELECT * FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
         $result = array();
 
-        while ($row = $this->db->fetch_assoc($select)) {
-            $result[$row['folderid']] = new Syncroton_Model_Folder($row);
+        while ($folder = $this->db->fetch_assoc($select)) {
+            $result[$folder['folderid']] = $this->get_object($folder);
         }
 
         return $result;
@@ -167,20 +86,62 @@ class kolab_sync_backend_folder implements Syncroton_Backend_IFolder
         $where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
         $where[] = $this->db->quote_identifier('folderid')  . ' = ' . $this->db->quote($_folderId);
 
-        $select = $this->db->query('SELECT * FROM syncroton_folder WHERE ' . implode(' AND ', $where));
+        $select = $this->db->query('SELECT * FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
+        $folder = $this->db->fetch_assoc($select);
 
-        if ($folder = $this->db->fetch_assoc($select)) {
-            $folder = new Syncroton_Model_Folder($folder);
+        if (empty($folder)) {
+            throw new Syncroton_Exception_NotFound('Folder not found');
         }
 
-        if (! $folder instanceof Syncroton_Model_IFolder) {
-            throw new Syncroton_Exception_NotFound('folder not found');
-        }
+        return $this->get_object($folder);
+    }
+
 
-        if (!empty($folder->creation_time)) {
-            $folder->creation_time = new DateTime($folder->creation_time, new DateTimeZone('utc'));
+    /**
+     * (non-PHPdoc)
+     * @see kolab_sync_backend_common::from_camelcase()
+     */
+    protected function from_camelcase($string)
+    {
+        switch ($string) {
+            case 'displayName':
+            case 'parentId':
+                return strtolower($string);
+                break;
+
+            case 'serverId':
+                return 'folderid';
+                break;
+
+            default:
+                return parent::from_camelcase($string);
+                break;
         }
+    }
 
-        return $folder;
+
+    /**
+     * (non-PHPdoc)
+     * @see kolab_sync_backend_common::to_camelcase()
+     */
+    protected function to_camelcase($string, $ucFirst = true)
+    {
+        switch ($string) {
+            case 'displayname':
+                return 'displayName';
+                break;
+
+            case 'parentid':
+                return 'parentId';
+                break;
+
+            case 'folderid':
+                return 'serverId';
+                break;
+
+            default:
+                return parent::to_camelcase($string, $ucFirst);
+                break;
+        }
     }
 }
diff --git a/lib/kolab_sync_backend_policy.php b/lib/kolab_sync_backend_policy.php
new file mode 100644
index 0000000..d7b8f09
--- /dev/null
+++ b/lib/kolab_sync_backend_policy.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ +--------------------------------------------------------------------------+
+ | Kolab Sync (ActiveSync for Kolab)                                        |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG <contact at kolabsys.com>         |
+ |                                                                          |
+ | This program is free software: you can redistribute it and/or modify     |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 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 Affero General Public License for more details.                      |
+ |                                                                          |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * sql backend class for policy storage
+ */
+class kolab_sync_backend_policy extends kolab_sync_backend_common //implements Syncroton_Backend_IPolicy
+{
+    protected $table_name     = 'syncroton_policy';
+    protected $interface_name = 'Syncroton_Model_IPolicy';
+}
diff --git a/lib/kolab_sync_backend_state.php b/lib/kolab_sync_backend_state.php
index a59ef43..dfd2127 100644
--- a/lib/kolab_sync_backend_state.php
+++ b/lib/kolab_sync_backend_state.php
@@ -24,25 +24,12 @@
 */
 
 /**
- * sql backend class for the folder state
- *
- * @package     Syncroton
- * @subpackage  Backend
+ * Kolab backend class for the folder state storage
  */
-class kolab_sync_backend_state implements Syncroton_Backend_ISyncState
+class kolab_sync_backend_state extends kolab_sync_backend_common implements Syncroton_Backend_ISyncState
 {
-    /**
-     * the database adapter
-     *
-     * @var rcube_mdb2
-     */
-    protected $db;
-
-
-    public function __construct()
-    {
-        $this->db = rcube::get_instance()->get_dbh();
-    }
+    protected $table_name     = 'syncroton_synckey';
+    protected $interface_name = 'Syncroton_Model_ISyncState';
 
     /**
      * create new sync state
@@ -50,31 +37,16 @@ class kolab_sync_backend_state implements Syncroton_Backend_ISyncState
      * @param Syncroton_Model_ISyncState $_syncState
      * @return Syncroton_Model_SyncState
      */
-    public function create(Syncroton_Model_ISyncState $_syncState, $_keepPreviousSyncState = true)
+    public function create($object, $_keepPreviousSyncState = true)
     {
-        $id       = sha1(mt_rand(). microtime());
-        $deviceId = $_syncState->device_id instanceof Syncroton_Model_IDevice ? $_syncState->device_id->id : $_syncState->device_id;
-        $type     = $_syncState->type instanceof Syncroton_Model_IFolder ? $_syncState->type->id : $_syncState->type;
-        $data     = is_array($_syncState->pendingdata) ? json_encode($_syncState->pendingdata) : null;
-
-        $insert[$this->db->quote_identifier('id')]          = $this->db->quote($id);
-        $insert[$this->db->quote_identifier('device_id')]   = $this->db->quote($deviceId);
-        $insert[$this->db->quote_identifier('type')]        = $this->db->quote($type);
-        $insert[$this->db->quote_identifier('counter')]     = $this->db->quote($_syncState->counter);
-        $insert[$this->db->quote_identifier('lastsync')]    = $this->db->quote($_syncState->lastsync->format('Y-m-d H:i:s'));
-        $insert[$this->db->quote_identifier('pendingdata')] = $data ? $this->db->quote($data) : 'NULL';
-
-        $this->db->query('INSERT INTO syncroton_synckey'
-            . ' (' . implode(', ', array_keys($insert)) . ')' . ' VALUES(' . implode(', ', $insert) . ')');
-
-        $state = $this->get($id);
+        $object = parent::create($object);
 
         if ($_keepPreviousSyncState !== true) {
             // remove all other synckeys
-            $this->_deleteOtherStates($state);
+            $this->_deleteOtherStates($object);
         }
 
-        return $state;
+        return $object;
     }
 
     protected function _deleteOtherStates(Syncroton_Model_ISyncState $_state)
@@ -84,43 +56,42 @@ class kolab_sync_backend_state implements Syncroton_Backend_ISyncState
         $where[] = $this->db->quote_identifier('type')      . ' = '  . $this->db->quote($_state->type);
         $where[] = $this->db->quote_identifier('counter')   . ' <> ' . $this->db->quote($_state->counter);
 
-        $this->db->query('DELETE FROM syncroton_synckey WHERE ' . implode(' AND ', $where));
+        $this->db->query('DELETE FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
 
         return true;
     }
 
+
     /**
-     * @param string  $_id
-     * @throws Syncroton_Exception_NotFound
-     * @return Syncroton_Model_SyncState
+     * @see kolab_sync_backend_common::object_to_array()
      */
-    public function get($_id)
+    protected function object_to_array($object)
     {
-        $select = $this->db->query('SELECT * FROM syncroton_synckey WHERE id = ?', array($_id));
+        $data = parent::object_to_array($object);
 
-        if ($state = $this->db->fetch_assoc($select)) {
-            $state = new Syncroton_Model_SyncState($state);
+        if (is_array($object->pendingdata)) {
+            $data['pendingdata'] = json_encode($object->pendingdata);
         }
 
-        if (! $state instanceof Syncroton_Model_ISyncState) {
-            throw new Syncroton_Exception_NotFound('id not found');
-        }
-
-        $this->_convertFields($state);
-
-        return $state;
+        return $data;
     }
 
-    protected function _convertFields(Syncroton_Model_SyncState $state)
+
+    /**
+     * @see kolab_sync_backend_common::get_object()
+     */
+    protected function get_object($data)
     {
-        if (!empty($state->lastsync)) {
-            $state->lastsync = new DateTime($state->lastsync, new DateTimeZone('utc'));
-        }
-        if ($state->pendingdata) {
-            $state->pendingdata = json_decode($state->pendingdata);
+        $object = parent::get_object($data);
+
+        if ($object->pendingdata) {
+            $object->pendingdata = json_decode($object->pendingdata);
         }
+
+        return $object;
     }
 
+
     /**
      * always returns the latest syncstate
      *
@@ -136,20 +107,16 @@ class kolab_sync_backend_state implements Syncroton_Backend_ISyncState
         $where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
         $where[] = $this->db->quote_identifier('type')      . ' = ' . $this->db->quote($folderId);
 
-        $select = $this->db->limitquery('SELECT * FROM syncroton_synckey WHERE ' . implode(' AND ', $where)
+        $select = $this->db->limitquery('SELECT * FROM ' . $this->table_name . ' WHERE ' . implode(' AND ', $where)
             .' ORDER BY counter DESC', 0, 1);
 
-        if ($state = $this->db->fetch_assoc($select)) {
-            $state = new Syncroton_Model_SyncState($state);
-        }
+        $state = $this->db->fetch_assoc($select);
 
-        if (! $state instanceof Syncroton_Model_ISyncState) {
-            throw new Syncroton_Exception_NotFound('id not found');
+        if (empty($state)) {
+            throw new Syncroton_Exception_NotFound('SyncState not found');
         }
 
-        $this->_convertFields($state);
-
-        return $state;
+        return $this->get_object($state);
     }
 
     /**
@@ -166,18 +133,9 @@ class kolab_sync_backend_state implements Syncroton_Backend_ISyncState
         $where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
         $where[] = $this->db->quote_identifier('type')      . ' = ' . $this->db->quote($folderId);
 
-        $this->db->query('DELETE FROM syncroton_synckey WHERE ' . implode(' AND ', $where));
+        $this->db->query('DELETE FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
     }
 
-    public function update(Syncroton_Model_ISyncState $_syncState)
-    {
-        $data = is_array($_syncState->pendingdata) ? json_encode($_syncState->pendingdata) : 'null';
-
-        $this->db->query('UPDATE syncroton_synckey SET counter = ?, lastsync = ?, pendingdata = ? WHERE id = ?',
-            array($_syncState->counter, $_syncState->lastsync->format('Y-m-d H:i:s'), $data, $_syncState->id));
-
-        return $this->get($_syncState->id);
-    }
 
     /**
      * get array of ids which got send to the client for a given class
@@ -197,16 +155,13 @@ class kolab_sync_backend_state implements Syncroton_Backend_ISyncState
         $where['counter']   = $this->db->quote_identifier('counter')   . ' = ' . $this->db->quote($_syncKey);
 
         $select = $this->db->query('SELECT * FROM syncroton_synckey WHERE ' . implode(' AND ', $where));
+        $state  = $this->db->fetch_assoc($select);
 
-        if ($state = $this->db->fetch_assoc($select)) {
-            $state = new Syncroton_Model_SyncState($state);
-        }
-
-        if (! $state instanceof Syncroton_Model_ISyncState) {
+        if (empty($state)) {
             return false;
         }
 
-        $this->_convertFields($state);
+        $state = $this->get_object($state);
 
         // check if this was the latest syncKey
         $where['counter'] = $this->db->quote_identifier('counter')   . ' = ' . $this->db->quote($_syncKey + 1);
@@ -214,7 +169,7 @@ class kolab_sync_backend_state implements Syncroton_Backend_ISyncState
         $select = $this->db->query('SELECT * FROM syncroton_synckey WHERE ' . implode(' AND ', $where));
 
         if ($moreRecentState = $this->db->fetch_assoc($select)) {
-            $moreRecentState = new Syncroton_Model_SyncState($moreRecentState);
+            $moreRecentState = $this->get_object($moreRecentState);
         }
 
         $where = array();
diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php
index b64568d..3820c24 100644
--- a/lib/kolab_sync_data.php
+++ b/lib/kolab_sync_data.php
@@ -196,7 +196,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         }
 
         if ($default = $this->getDefaultFolder()) {
-            $list = array($default['folderid'] => $default);
+            $list = array($default['serverId'] => $default);
         }
 
         foreach ($list as $idx => $folder) {
@@ -231,9 +231,9 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         }
 
         // Remember real folder ID and set ID/name to root folder
-        $default['realid']      = $default['folderid'];
-        $default['folderid']    = $this->defaultRootFolder;
-        $default['displayname'] = $this->defaultFolder;
+        $default['realid']      = $default['serverId'];
+        $default['serverId']    = $this->defaultRootFolder;
+        $default['displayName'] = $this->defaultFolder;
 
         return $default;
     }
@@ -243,9 +243,9 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
      */
     public function createFolder(Syncroton_Model_IFolder $folder)
     {
-        $parentid     = $folder->parentid;
+        $parentid     = $folder->parentId;
         $type         = $folder->type;
-        $display_name = $folder->displayname;
+        $display_name = $folder->displayName;
 
         if ($parentid) {
             $parent = $this->backend->folder_id2name($parentid, $this->device->deviceid);
@@ -264,7 +264,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         $result = $this->backend->folder_create($name, $type, $this->device->deviceid);
 
         if ($result) {
-            $folder->folderid = $this->backend->folder_id($name);
+            $folder->serverId = $this->backend->folder_id($name);
             return $folder;
         }
 
@@ -276,10 +276,10 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
      */
     public function updateFolder(Syncroton_Model_IFolder $folder)
     {
-        $parentid     = $folder->parentid;
+        $parentid     = $folder->parentId;
         $type         = $folder->type;
-        $display_name = $folder->displayname;
-        $old_name     = $this->backend->folder_id2name($folder->folderid, $this->device->deviceid);
+        $display_name = $folder->displayName;
+        $old_name     = $this->backend->folder_id2name($folder->serverId, $this->device->deviceid);
 
         if ($parentid) {
             $parent = $this->backend->folder_id2name($parentid, $this->device->deviceid);
@@ -304,7 +304,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         }
 
         if ($result) {
-            $folder->folderid = $this->backend->folder_id($name);
+            $folder->serverId = $this->backend->folder_id($name);
             return $folder;
         }
 
@@ -317,7 +317,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
     public function deleteFolder($folder)
     {
         if ($folder instanceof Syncroton_Model_IFolder) {
-            $folder = $folder->folderid;
+            $folder = $folder->serverId;
         }
 
         $name = $this->backend->folder_id2name($folder, $this->device->deviceid);
@@ -594,7 +594,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         // @TODO: Consider looping over all folders here, not in getServerEntries() and
         // getChangesEntriesCount(). This way we could break the loop and not check all folders (see @TODO below)
         // or at least skip redundant cache sync of the same folder
-        $allServerEntries = $this->getServerEntries($folder->folderid, $folder->lastfiltertype);
+        $allServerEntries = $this->getServerEntries($folder->serverId, $folder->lastfiltertype);
 
         $addedEntries   = array_diff($allServerEntries, $allClientEntries);
         $deletedEntries = array_diff($allClientEntries, $allServerEntries);
@@ -604,7 +604,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         // so in case when count($addedEntries) + count($deletedEntries) != 0 we don't need
         // to count changed entries here. We could also revert the order in such case
         // and execute getChangedEntriesCount() before
-        $changedEntries = $this->getChangedEntriesCount($folder->folderid, $syncState->lastsync);
+        $changedEntries = $this->getChangedEntriesCount($folder->serverId, $syncState->lastsync);
 
         return count($addedEntries) + count($deletedEntries) + $changedEntries;
     }
@@ -616,7 +616,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
     protected function getObject($folderid, $entryid, &$folder = null)
     {
         if ($folderid instanceof Syncroton_Model_IFolder) {
-            $folderid = $folderid->folderid;
+            $folderid = $folderid->serverId;
         }
 
         if ($folderid == $this->defaultRootFolder) {
@@ -651,7 +651,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
     {
         if ($folderid == $this->defaultRootFolder) {
             $default  = $this->getDefaultFolder();
-            $folderid = isset($default['realid']) ? $default['realid'] : $default['folderid'];
+            $folderid = isset($default['realid']) ? $default['realid'] : $default['serverId'];
         }
 
         $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index 6cdc476..46ec0d6 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -552,7 +552,7 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         }
     }
 
-    public function forwardEmail($collectionId, $itemId, $body, $saveInSent)
+    public function forwardEmail($itemId, $body, $saveInSent, $replaceMime)
     {
         /*
         @TODO:
@@ -566,14 +566,6 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         as an attachment to the outgoing message. When the SmartForward command is used for a normal message
         or a meeting, the behavior of the SmartForward command is the same as that of the SmartReply command (section 2.2.2.18).
         */
-        /*
-        @TODO:
-        The LongId element is an optional child element of the Source element in SmartForward command requests and
-        SmartReply command requests that specifies the long ID for the source message, which is returned in the Search
-        command response message (section 2.2.2.14.2). If the LongId element is present, the FolderId (section 2.2.3.69),
-        ItemId (section 2.2.3.84), and InstanceId (section 2.2.3.83.2) elements are not present.
-        The LongId element value can be up to 256 characters in length.
-        */
 
         $msg     = $this->parseMessageId($itemId);
         $message = $this->getObject($itemId);
@@ -610,7 +602,7 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         }
     }
 
-    public function replyEmail($collectionId, $itemId, $body, $saveInSent)
+    public function replyEmail($itemId, $body, $saveInSent, $replaceMime)
     {
         $msg     = $this->parseMessageId($itemId);
         $message = $this->getObject($itemId);
@@ -916,6 +908,11 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
      */
     protected function parseMessageId($entryid)
     {
+        // replyEmail/forwardEmail
+        if (is_array($entryid)) {
+            $entryid = $entryid['itemId'];
+        }
+
         list($folderid, $uid) = explode('::', $entryid);
         $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
 
diff --git a/lib/kolab_sync_db.php b/lib/kolab_sync_db.php
index 80ddf72..b56ce52 100644
--- a/lib/kolab_sync_db.php
+++ b/lib/kolab_sync_db.php
@@ -31,7 +31,7 @@ class kolab_sync_db
     /**
      * the database adapter
      *
-     * @var rcube_mdb2
+     * @var rcube_db
      */
     protected $db;
 





More information about the commits mailing list