3 commits - lib/ext lib/kolab_sync_backend.php lib/kolab_sync_body_converter.php lib/kolab_sync_data_calendar.php lib/kolab_sync_data_contacts.php lib/kolab_sync_data_email.php lib/kolab_sync_data.php

Aleksander Machniak machniak at kolabsys.com
Fri Aug 31 12:13:06 CEST 2012


 lib/ext/Syncroton/Command/Interface.php          |   34 ------
 lib/ext/Syncroton/Command/MoveItems.php          |   81 +++++++-------
 lib/ext/Syncroton/Command/Sync.php               |    4 
 lib/ext/Syncroton/Exception/Status/MoveItems.php |   40 +++++++
 lib/kolab_sync_backend.php                       |    4 
 lib/kolab_sync_body_converter.php                |  128 +++++++++++++++++++++++
 lib/kolab_sync_data.php                          |   51 ++++++---
 lib/kolab_sync_data_calendar.php                 |    4 
 lib/kolab_sync_data_contacts.php                 |    4 
 lib/kolab_sync_data_email.php                    |  101 +++++++++++-------
 10 files changed, 318 insertions(+), 133 deletions(-)

New commits:
commit e5d80ca009bb4ccec86ab76be426409b2cec7510
Author: Aleksander Machniak <alec at alec.pl>
Date:   Fri Aug 31 12:06:06 2012 +0200

    Implemented Body conversion between plain and html text formats

diff --git a/lib/kolab_sync_body_converter.php b/lib/kolab_sync_body_converter.php
new file mode 100644
index 0000000..c3f9856
--- /dev/null
+++ b/lib/kolab_sync_body_converter.php
@@ -0,0 +1,128 @@
+<?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>                      |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * Utility class for data convertion between ActiveSync Body formats
+ */
+class kolab_sync_body_converter
+{
+    protected $text;
+    protected $type;
+
+
+    /**
+     * Constructor
+     *
+     * @param string $data Data string
+     * @param int    $type Data type. One of Syncroton_Model_EmailBody constants.
+     */
+    public function __construct($data, $type)
+    {
+        $this->text = $data;
+        $this->type = $type;
+    }
+
+    /**
+     * Converter
+     *
+     * @param int $type Result data type (to which the string will be converted).
+     *                  One of Syncroton_Model_EmailBody constants.
+     *
+     * @return string Body value
+     */
+    public function convert($type)
+    {
+        if (empty($this->text) || empty($type) || $type == $this->type) {
+            return $this->text;
+        }
+
+        // ActiveSync types: TYPE_PLAINTEXT, TYPE_HTML, TYPE_RTF, TYPE_MIME
+        switch ($this->type) {
+        case Syncroton_Model_EmailBody::TYPE_PLAINTEXT:
+            return $this->convert_text_plain($type);
+        case Syncroton_Model_EmailBody::TYPE_HTML:
+            return $this->convert_text_html($type);
+        case Syncroton_Model_EmailBody::TYPE_RTF:
+            return $this->convert_rtf($type);
+        default:
+            return $this->text;
+        }
+    }
+
+    /**
+     * Text/plain converter
+     *
+     * @param int $type Result data type (to which the string will be converted).
+     *                  One of Syncroton_Model_EmailBody constants.
+     *
+     * @return string Body value
+     */
+    protected function convert_text_plain($type)
+    {
+        $data = $this->text;
+
+        switch ($type) {
+        case Syncroton_Model_EmailBody::TYPE_HTML:
+            return '<pre>' . htmlspecialchars($data, ENT_COMPAT, kolab_sync::CHARSET) . '</pre>';
+        }
+
+        return $data;
+    }
+
+    /**
+     * HTML converter
+     *
+     * @param int $type Result data type (to which the string will be converted).
+     *                  One of Syncroton_Model_EmailBody constants.
+     *
+     * @return string Body value
+     */
+    protected function convert_text_html($type)
+    {
+        $data = $this->text;
+
+        switch ($type) {
+        case Syncroton_Model_EmailBody::TYPE_PLAINTEXT:
+            $txt = new html2text($data, false, true);
+            return $txt->get_text();
+        }
+
+        return $data;
+    }
+
+    /**
+     * RTF converter
+     *
+     * @param int $type Result data type (to which the string will be converted).
+     *                  One of Syncroton_Model_EmailBody constants.
+     *
+     * @return string Body value
+     */
+    protected function convert_rtf($type)
+    {
+        // @TODO: not implemented
+        return $this->text;
+    }
+}
diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php
index 733d7e3..06a95d9 100644
--- a/lib/kolab_sync_data.php
+++ b/lib/kolab_sync_data.php
@@ -909,7 +909,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         }
 
         if (!isset($params['Type'])) {
-            $params['type'] = 1;
+            $params['type'] = Syncroton_Model_EmailBody::TYPE_PLAINTEXT;
         }
 
         return new Syncroton_Model_EmailBody($params);
@@ -918,13 +918,25 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
     /**
      * Getter for Body attribute value according to client version
      *
-     * @param mixed $data Data element
+     * @param mixed $body Body element
+     * @param int   $type Result data type (to which the body will be converted, if specified).
+     *                    One of Syncroton_Model_EmailBody constants.
+     *
+     * @return string Body value
      */
-    protected function getBody($data)
+    protected function getBody($body, $type = null)
     {
-        if ($data && $data->data) {
-            return $data->data;
+        if ($body && $body->data) {
+            $data = $body->data;
+        }
+
+        // Convert to specified type
+        if ($data && $type && $body->type != $type) {
+            $converter = new kolab_sync_body_converter($data, $body->type);
+            $data      = $converter->convert($type);
         }
+
+        return $data;
     }
 
     /**
diff --git a/lib/kolab_sync_data_calendar.php b/lib/kolab_sync_data_calendar.php
index 19ab083..1c756d9 100644
--- a/lib/kolab_sync_data_calendar.php
+++ b/lib/kolab_sync_data_calendar.php
@@ -227,7 +227,7 @@ class kolab_sync_data_calendar extends kolab_sync_data
                 break;
 
             case 'description':
-                $value = $this->setBody($value);
+                $value = $this->setBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT);
                 break;
             }
 
@@ -379,7 +379,7 @@ class kolab_sync_data_calendar extends kolab_sync_data
                 break;
 
             case 'description':
-                $value = $this->getBody($value);
+                $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT);
                 // If description isn't specified keep old description
                 if ($value === null) {
                     continue 2;
diff --git a/lib/kolab_sync_data_contacts.php b/lib/kolab_sync_data_contacts.php
index 8d379c7..5a71da4 100644
--- a/lib/kolab_sync_data_contacts.php
+++ b/lib/kolab_sync_data_contacts.php
@@ -156,7 +156,7 @@ class kolab_sync_data_contacts extends kolab_sync_data
                 break;
 
             case 'notes':
-                $value = $this->setBody($value);
+                $value = $this->setBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT);
                 break;
             }
 
@@ -213,7 +213,7 @@ class kolab_sync_data_contacts extends kolab_sync_data
                 break;
 
             case 'notes':
-                $value = $this->getBody($value);
+                $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT);
                 // If note isn't specified keep old note
                 if ($value === null) {
                     continue 2;
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index 0d62a8c..2f0aaaa 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -245,7 +245,7 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
             $truncateAt  = 0;
             $body_length = 0;
         }
-        else if ($airSyncBaseType == 4) {
+        else if ($airSyncBaseType == Syncroton_Command_Sync::BODY_TYPE_MIME) {
             $messageBody = $this->storage->get_raw_body($message->uid);
             // strip out any non utf-8 characters
             $messageBody = rcube_charset::clean($messageBody);


commit 866e8e53f953d415a8fbbba155e90805a6878ed0
Author: Aleksander Machniak <alec at alec.pl>
Date:   Thu Aug 30 14:41:13 2012 +0200

    Improved error handling in moveItems command handler

diff --git a/lib/ext/Syncroton/Command/Interface.php b/lib/ext/Syncroton/Command/Interface.php
deleted file mode 100644
index af1d2a0..0000000
--- a/lib/ext/Syncroton/Command/Interface.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-/**
- * Tine 2.0
- *
- * @package     ActiveSync
- * @subpackage  ActiveSync
- * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
- * @copyright   Copyright (c) 2008-2009 Metaways Infosystems GmbH (http://www.metaways.de)
- * @author      Lars Kneschke <l.kneschke at metaways.de>
- */
-
-/**
- * class documentation
- *
- * @package     ActiveSync
- * @subpackage  ActiveSync
- */
- 
-interface Syncroton_Command_Interface 
-{
-    /**
-     * the constructor
-     *
-     * @param  mixed                    $_requestBody
-     */
-    public function __construct($_requestBody, Syncroton_Model_IDevice $_device, $_policyKey);
-    
-    /**
-     * process the XML file and add, change, delete or fetches data 
-     */
-    public function handle();
-
-    public function getResponse();
-}
diff --git a/lib/ext/Syncroton/Command/MoveItems.php b/lib/ext/Syncroton/Command/MoveItems.php
index 974cddf..5f3ed8a 100644
--- a/lib/ext/Syncroton/Command/MoveItems.php
+++ b/lib/ext/Syncroton/Command/MoveItems.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * Syncroton
  *
@@ -6,88 +7,90 @@
  * @subpackage  Command
  * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
  * @copyright   Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2012-2012 Kolab Systems AG (http://www.kolabsys.com)
  * @author      Lars Kneschke <l.kneschke at metaways.de>
+ * @author      Aleksander Machniak <machniak at kolabsys.com>
  */
 
 /**
- * class to handle ActiveSync MoveItem command
+ * class to handle ActiveSync MoveItems command
  *
  * @package     Syncroton
  * @subpackage  Command
  */
-class Syncroton_Command_MoveItems extends Syncroton_Command_Wbxml 
-{        
-    const STATUS_INVALID_SOURCE         = 1;
-    const STATUS_INVALID_DESTINATION    = 2;
+class Syncroton_Command_MoveItems extends Syncroton_Command_Wbxml
+{
     const STATUS_SUCCESS                = 3;
-    
+
     protected $_defaultNameSpace    = 'uri:Move';
     protected $_documentElement     = 'Moves';
-    
+
     /**
      * list of items to move
-     * 
+     *
      * @var array
      */
     protected $_moves = array();
-    
+
     /**
      * parse MoveItems request
-     *
      */
     public function handle()
     {
         $xml = simplexml_import_dom($this->_requestBody);
-        
+
         foreach ($xml->Move as $move) {
             $this->_moves[] = array(
                 'srcMsgId' => (string)$move->SrcMsgId,
                 'srcFldId' => (string)$move->SrcFldId,
-                'dstFldId' => (string)$move->DstFldId            
+                'dstFldId' => (string)$move->DstFldId
             );
         }
-        
-        if ($this->_logger instanceof Zend_Log) 
-            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " moves: " . print_r($this->_moves, true));        
+
+        if ($this->_logger instanceof Zend_Log)
+            $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " moves: " . print_r($this->_moves, true));
     }
-    
+
     /**
      * generate MoveItems response
      */
     public function getResponse()
     {
         $moves = $this->_outputDom->documentElement;
-        
+
         foreach ($this->_moves as $move) {
             $response = $moves->appendChild($this->_outputDom->createElementNS('uri:Move', 'Response'));
             $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'SrcMsgId', $move['srcMsgId']));
-            
-            try {
-                $sourceFolder      = $this->_folderBackend->getFolder($this->_device, $move['srcFldId']);
-            } catch (Syncroton_Exception_NotFound $senf) {
-                $sourceFolder = null;
-            }
-            
+
             try {
-                $destinationFolder = $this->_folderBackend->getFolder($this->_device, $move['dstFldId']);
-            } catch (Syncroton_Exception_NotFound $senf) {
-                $destinationFolder = null;
-            }
-                
-            if ($sourceFolder === null) {
-                $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Command_MoveItems::STATUS_INVALID_SOURCE));
-            } else if ($destinationFolder === null) {
-                $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Command_MoveItems::STATUS_INVALID_DESTINATION));
-            } else {
-                $dataController    = Syncroton_Data_Factory::factory($sourceFolder->class, $this->_device, $this->_syncTimeStamp);
-                
-                $newId             = $dataController->moveItem($move['srcFldId'], $move['srcMsgId'], $move['dstFldId']);
-                
+                if ($move['srcFldId'] === $move['dstFldId']) {
+                    throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::SAME_FOLDER);
+                }
+
+                try {
+                    $sourceFolder = $this->_folderBackend->getFolder($this->_device, $move['srcFldId']);
+                } catch (Syncroton_Exception_NotFound $e) {
+                    throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE);
+                }
+
+                try {
+                    $destinationFolder = $this->_folderBackend->getFolder($this->_device, $move['dstFldId']);
+                } catch (Syncroton_Exception_NotFound $senf) {
+                    throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION);
+                }
+
+                $dataController = Syncroton_Data_Factory::factory($sourceFolder->class, $this->_device, $this->_syncTimeStamp);
+                $newId          = $dataController->moveItem($move['srcFldId'], $move['srcMsgId'], $move['dstFldId']);
+
                 $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Command_MoveItems::STATUS_SUCCESS));
                 $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'DstMsgId', $newId));
+            } catch (Syncroton_Exception_Status $e) {
+                $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', $e->getCode()));
+            } catch (Exception $e) {
+                $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Exception_Status::SERVER_ERROR));
             }
         }
-        
+
         return $this->_outputDom;
     }
 }
diff --git a/lib/ext/Syncroton/Command/Sync.php b/lib/ext/Syncroton/Command/Sync.php
index a55b92f..74ad41d 100644
--- a/lib/ext/Syncroton/Command/Sync.php
+++ b/lib/ext/Syncroton/Command/Sync.php
@@ -371,6 +371,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
         foreach($this->_collections as $collectionData) {
             $collectionChanges = 0;
             
+            // invalid collectionid provided
             if (! ($collectionData->folder instanceof Syncroton_Model_IFolder)) {
                 $collection = $collections->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collection'));
                 $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', 0));
diff --git a/lib/ext/Syncroton/Exception/Status/MoveItems.php b/lib/ext/Syncroton/Exception/Status/MoveItems.php
new file mode 100644
index 0000000..c03efea
--- /dev/null
+++ b/lib/ext/Syncroton/Exception/Status/MoveItems.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Syncroton
+ *
+ * @package     Syncroton
+ * @subpackage  Exception
+ * @license     http://www.tine20.org/licenses/lgpl.html LGPL Version 3
+ * @copyright   Copyright (c) 2012-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2012-2012 Kolab Systems AG (http://www.kolabsys.com)
+ * @author      Lars Kneschke <l.kneschke at metaways.de>
+ * @author      Aleksander Machniak <machniak at kolabsys.com>
+ */
+
+/**
+ * exception for Status element in MoveItems response
+ *
+ * @package     Syncroton
+ * @subpackage  Exception
+ */
+class Syncroton_Exception_Status_MoveItems extends Syncroton_Exception_Status
+{
+    const INVALID_SOURCE          = 1;
+    const INVALID_DESTINATION     = 2;
+    const SAME_FOLDER             = 4;
+    const ITEM_EXISTS_OR_LOCKED   = 5;
+    const FOLDER_LOCKED           = 7;
+
+    /**
+     * Error messages assigned to error codes
+     *
+     * @var array
+     */
+    protected $_errorMessages = array(
+        self::INVALID_SOURCE          => "Invalid source collection ID or item ID",
+        self::INVALID_DESTINATION     => "Invalid destination collection ID",
+        self::SAME_FOLDER             => "Source and destination collection IDs are the same",
+        self::ITEM_EXISTS_OR_LOCKED   => "The item cannot be moved to more than one item at a time, or the source or destination item was locked",
+        self::FOLDER_LOCKED           => "Source or destination item was locked",
+    );
+}
diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php
index 14f1417..733d7e3 100644
--- a/lib/kolab_sync_data.php
+++ b/lib/kolab_sync_data.php
@@ -329,22 +329,25 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
      * @param string $serverId    Object identifier
      * @param string $dstFolderId Destination folder identifier
      *
+     * @throws Syncroton_Exception_Status
      * @return string New object identifier
      */
     public function moveItem($srcFolderId, $serverId, $dstFolderId)
     {
         $item = $this->getObject($srcFolderId, $serverId, $folder);
 
-        if ($item && $folder) {
-            $dstname = $this->backend->folder_id2name($dstFolderId, $this->device->deviceid);
+        if (!$item || !$folder) {
+            throw Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE);
+        }
 
-            if ($dstname === null) {
-                return;
-            }
+        $dstname = $this->backend->folder_id2name($dstFolderId, $this->device->deviceid);
 
-            if (!$folder->move($serverId, $dstname)) {
-                return;
-            }
+        if ($dstname === null) {
+            throw Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION);
+        }
+
+        if (!$folder->move($serverId, $dstname)) {
+            throw Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE);
         }
 
         return $item['uid'];
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index eb63e9d..0d62a8c 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -412,6 +412,7 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
      * @param string $serverId    Object identifier
      * @param string $dstFolderId Destination folder identifier
      *
+     * @throws Syncroton_Exception_Status
      * @return string New object identifier
      */
     public function moveItem($srcFolderId, $serverId, $dstFolderId)
@@ -419,12 +420,16 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         $msg     = $this->parseMessageId($serverId);
         $dstname = $this->backend->folder_id2name($dstFolderId, $this->device->deviceid);
 
+        if (empty($msg)) {
+            throw Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE);
+        }
+
         if ($dstname === null) {
-            return;
+            throw Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION);
         }
 
         if (!$this->storage->move_message($msg['uid'], $dstname, $msg['foldername'])) {
-            return;
+            throw Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE);
         }
 
         // Use COPYUID feature (RFC2359) to get the new UID of the copied message


commit 71cc2c50f97fa886a0423e8cd036813ee837f232
Author: Aleksander Machniak <alec at alec.pl>
Date:   Thu Aug 30 11:01:48 2012 +0200

    Throw exception when email sending fails

diff --git a/lib/ext/Syncroton/Command/Sync.php b/lib/ext/Syncroton/Command/Sync.php
index 9173e30..a55b92f 100644
--- a/lib/ext/Syncroton/Command/Sync.php
+++ b/lib/ext/Syncroton/Command/Sync.php
@@ -369,10 +369,8 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
         $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'));
                 $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', 0));
@@ -670,7 +668,6 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                     
                     $countOfPendingChanges = (count($serverModifications['added']) + count($serverModifications['changed']) + count($serverModifications['deleted'])); 
                     if ($countOfPendingChanges > 0) {
-                        $moreAvailable = true;
                         $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'MoreAvailable'));
                     }
                 
@@ -690,7 +687,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
                 $this->_syncTimeStamp->modify('+1 sec');
                 
                 // store pending data in sync state when needed
-                if(isset($moreAvailable) && $moreAvailable === true) {
+                if(isset($countOfPendingChanges) && $countOfPendingChanges > 0) {
                     $collectionData->syncState->pendingdata = array(
                         'added'   => (array)$serverModifications['added'],
                         'changed' => (array)$serverModifications['changed'],
diff --git a/lib/kolab_sync_backend.php b/lib/kolab_sync_backend.php
index 1d2923d..3cbd548 100644
--- a/lib/kolab_sync_backend.php
+++ b/lib/kolab_sync_backend.php
@@ -282,6 +282,10 @@ class kolab_sync_backend
      */
     public function folder_set($name, $deviceid, $flag)
     {
+        if (empty($deviceid)) {
+            return false;
+        }
+
         // get folders activesync config
         $metadata = $this->folder_meta();
         $metadata = $metadata[$name];
diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php
index 9fa190d..14f1417 100644
--- a/lib/kolab_sync_data.php
+++ b/lib/kolab_sync_data.php
@@ -322,7 +322,15 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         return $this->backend->folder_delete($name, $this->device->deviceid);
     }
 
-
+    /**
+     * Moves object into another location (folder)
+     *
+     * @param string $srcFolderId Source folder identifier
+     * @param string $serverId    Object identifier
+     * @param string $dstFolderId Destination folder identifier
+     *
+     * @return string New object identifier
+     */
     public function moveItem($srcFolderId, $serverId, $dstFolderId)
     {
         $item = $this->getObject($srcFolderId, $serverId, $folder);
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index 6b6778d..eb63e9d 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -387,7 +387,6 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         return $filter;
     }
 
-
     /**
       * Returns default folder for current class type.
       */
@@ -406,7 +405,15 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         );
     }
 
-
+    /**
+     * Moves object into another location (folder)
+     *
+     * @param string $srcFolderId Source folder identifier
+     * @param string $serverId    Object identifier
+     * @param string $dstFolderId Destination folder identifier
+     *
+     * @return string New object identifier
+     */
     public function moveItem($srcFolderId, $serverId, $dstFolderId)
     {
         $msg     = $this->parseMessageId($serverId);
@@ -500,15 +507,43 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         }
     }
 
+    /**
+     * Send an email
+     *
+     * @param resource|string $body       MIME message
+     * @param boolean         $saveInSent Enables saving the sent message in Sent folder
+     *
+     * @param throws Syncroton_Exception_Status
+     */
     public function sendEmail($body, $saveInSent)
     {
         $sent = $this->backend->send_message($body, $smtp_error);
 
-        if ($sent && $saveInSent) {
-            $this->saveInSent($body);
+        if (!$sent) {
+            throw Syncroton_Exception_Status(Syncroton_Exception_Status::MAIL_SUBMISSION_FAILED);
+        }
+
+        // Save sent message in Sent folder
+        if ($saveInSent) {
+            $sent_folder = kolab_sync::get_instance()->config->get('sent_mbox');
+
+            if (strlen($sent_folder) && $this->storage->folder_exists($sent_folder)) {
+                return $this->storage->save_message($sent_folder, $body);
+            }
         }
     }
 
+    /**
+     * Forward an email
+     *
+     * @param array|string    $itemId      A string LongId or an array with following properties:
+     *                                     collectionId, itemId and instanceId
+     * @param resource|string $body        MIME message
+     * @param boolean         $saveInSent  Enables saving the sent message in Sent folder
+     * @param boolean         $replaceMime If enabled, original message would be appended
+     *
+     * @param throws Syncroton_Exception_Status
+     */
     public function forwardEmail($itemId, $body, $saveInSent, $replaceMime)
     {
         /*
@@ -548,19 +583,25 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         $body = $this->backend->build_mime($headers, $body);
 
         // Send message
-        $sent = $this->backend->send_message($body, $smtp_error);
+        $sent = $this->sendEmail($body, $saveInSent);
 
         // Set FORWARDED flag on the replied message
-        if ($sent && empty($message->headers->flags['FORWARDED'])) {
+        if (empty($message->headers->flags['FORWARDED'])) {
             $this->storage->set_flag($msg['uid'], 'FORWARDED', $msg['foldername']);
         }
-
-        // Save sent message in Sent folder
-        if ($sent && $saveInSent) {
-            $this->saveInSent($body);
-        }
     }
 
+    /**
+     * Reply to an email
+     *
+     * @param array|string    $itemId      A string LongId or an array with following properties:
+     *                                     collectionId, itemId and instanceId
+     * @param resource|string $body        MIME message
+     * @param boolean         $saveInSent  Enables saving the sent message in Sent folder
+     * @param boolean         $replaceMime If enabled, original message would be appended
+     *
+     * @param throws Syncroton_Exception_Status
+     */
     public function replyEmail($itemId, $body, $saveInSent, $replaceMime)
     {
         $msg     = $this->parseMessageId($itemId);
@@ -587,35 +628,12 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         $body = $this->backend->build_mime($headers, $body);
 
         // Send message
-        $sent = $this->backend->send_message($body, $smtp_error);
+        $sent = $this->sendEmail($body, $saveInSent);
 
         // Set ANSWERED flag on the replied message
-        if ($sent && empty($message->headers->flags['ANSWERED'])) {
+        if (empty($message->headers->flags['ANSWERED'])) {
             $this->storage->set_flag($msg['uid'], 'ANSWERED', $msg['foldername']);
         }
-
-        // Save sent message in Sent folder
-        if ($sent && $saveInSent) {
-            $this->saveInSent($body);
-        }
-    }
-
-    /**
-     * Append the message into Sent folder
-     *
-     * @param string $message Complete message source
-     *
-     * @return int|bool Appended message UID or True on success, False on error
-     */
-    protected function saveInSent($message)
-    {
-        $sent_folder = kolab_sync::get_instance()->config->get('sent_mbox');
-
-        if (strlen($sent_folder) && $this->storage->folder_exists($sent_folder)) {
-            return $this->storage->save_message($sent_folder, $message);
-        }
-
-        return false;
     }
 
     /**





More information about the commits mailing list