lib/ext lib/kolab lib/kolab_sync_data_email.php lib/kolab_sync_data.php

Aleksander Machniak machniak at kolabsys.com
Mon Aug 20 20:16:41 CEST 2012


 lib/ext/Syncroton/Model/Email.php     |    7 +-
 lib/ext/Syncroton/Model/EmailFlag.php |  106 ++++++++++++++++++++++++++++++++++
 lib/kolab/kolab_storage_folder.php    |    5 +
 lib/kolab_sync_data.php               |    2 
 lib/kolab_sync_data_email.php         |   50 ++++++----------
 5 files changed, 136 insertions(+), 34 deletions(-)

New commits:
commit bfda2ae15b2cb494ba8ef49ab79e0ea2253c9c77
Author: Aleksander Machniak <alec at alec.pl>
Date:   Mon Aug 20 20:16:20 2012 +0200

    Implemented email message flag (followup) handling
    Fixed bug in imap search result usage with big performance impact and errors
      when checking for changes in more than one data backend (Ping request).

diff --git a/lib/ext/Syncroton/Model/Email.php b/lib/ext/Syncroton/Model/Email.php
index e3aa3ce..ba78525 100644
--- a/lib/ext/Syncroton/Model/Email.php
+++ b/lib/ext/Syncroton/Model/Email.php
@@ -45,7 +45,6 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
             'DTStamp'                 => array('type' => 'datetime'),
             'EndTime'                 => array('type' => 'datetime'),
             'Flag'                    => array('type' => 'container'),
-            'FlagType'                => array('type' => 'string'),
             'From'                    => array('type' => 'string'),
             'GlobalObjId'             => array('type' => 'string'),
             'Importance'              => array('type' => 'number'),
@@ -140,7 +139,11 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
                     $this->$elementName = new Syncroton_Model_EmailBody($xmlElement);
     
                     break;
-    
+
+                case 'Flag':
+                    $this->$elementName = new Syncroton_Model_EmailFlag($xmlElement);
+                    break;
+
                 default:
                     list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName);
     
diff --git a/lib/ext/Syncroton/Model/EmailFlag.php b/lib/ext/Syncroton/Model/EmailFlag.php
new file mode 100644
index 0000000..18fe815
--- /dev/null
+++ b/lib/ext/Syncroton/Model/EmailFlag.php
@@ -0,0 +1,106 @@
+<?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)
+ * @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 Flag element
+ *
+ * @package     Model
+ * @property    int      Status
+ * @property    string   FlagType
+ * @property    datetime CompleteTime
+ */
+class Syncroton_Model_EmailFlag extends Syncroton_Model_AEntry
+{
+    const STATUS_CLEARED  = 0;
+    const STATUS_COMPLETE = 1;
+    const STATUS_ACTIVE   = 2;
+
+    protected $_xmlBaseElement = 'Flag';
+
+    protected $_properties = array(
+        'Email' => array(
+            'CompleteTime'       => array('type' => 'datetime'),
+            'FlagType'           => array('type' => 'string'),
+            'Status'             => array('type' => 'number'),
+        ),
+        'Tasks' => array(
+            'DateCompleted'      => array('type' => 'datetime'),
+            'DueDate'            => array('type' => 'datetime'),
+            'OrdinalDate'        => array('type' => 'datetime'),
+            'ReminderSet'        => array('type' => 'number'),
+            'ReminderTime'       => array('type' => 'datetime'),
+            'StartDate'          => array('type' => 'datetime'),
+            'Subject'            => array('type' => 'string'),
+            'SubOrdinalDate'     => array('type' => 'string'),
+            'UtcStartDate'       => array('type' => 'datetime'),
+            'UtcDueDate'         => array('type' => 'datetime'),
+        ),
+    );
+
+    protected function _parseEmailNamespace(SimpleXMLElement $properties)
+    {
+        // fetch data from AirSyncBase namespace
+        $children = $properties->children('uri:Email');
+
+        foreach ($children as $elementName => $xmlElement) {
+            switch ($elementName) {
+                case 'FlagStatus':
+                    // Android bug http://code.google.com/p/android/issues/detail?id=36113
+                    $elementName = 'Status';
+
+                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;
+                    }
+            }
+        }
+    }
+
+    protected function _parseTasksNamespace(SimpleXMLElement $properties)
+    {
+        // fetch data from AirSyncBase namespace
+        $children = $properties->children('uri:Tasks');
+
+        foreach ($children as $elementName => $xmlElement) {
+            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/kolab/kolab_storage_folder.php b/lib/kolab/kolab_storage_folder.php
index e0f0deb..6dc0e05 100644
--- a/lib/kolab/kolab_storage_folder.php
+++ b/lib/kolab/kolab_storage_folder.php
@@ -429,6 +429,11 @@ class kolab_storage_folder
         $this->imap->set_folder($folder);
 
         $headers = $this->imap->get_message_headers($msguid);
+
+        if (empty($headers)) {
+            return false;
+        }
+
         $object_type = kolab_format::mime2object_type($headers->others['x-kolab-type']);
         $content_type  = kolab_format::KTYPE_PREFIX . $object_type;
 
diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php
index 3820c24..b589714 100644
--- a/lib/kolab_sync_data.php
+++ b/lib/kolab_sync_data.php
@@ -592,7 +592,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         $allClientEntries = $contentBackend->getFolderState($this->device, $folder);
 
         // @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)
+        // getChangedEntriesCount(). 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->serverId, $folder->lastfiltertype);
 
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index fa4d82f..8804cd6 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -174,13 +174,10 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
         // Flagged message
         if (!empty($headers->flags['FLAGGED'])) {
             // Use FollowUp flag which is used in Android when message is marked with a star
-/*
- at TODO:
-            $result['Flag'] = array(
+            $result['Flag'] = new Syncroton_Model_EmailFlag(array(
                 'FlagType' => 'FollowUp',
-                'Status' => 1,
-            );
-*/
+                'Status' => Syncroton_Model_EmailFlag::STATUS_ACTIVE,
+            ));
         }
 
         // Importance/Priority
@@ -491,29 +488,27 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
      */
     public function updateEntry($folderId, $serverId, Syncroton_Model_IEntry $entry)
     {
-        $msg     = $this->parseMessageId($serverId);
-        $message = $this->getObject($serverId);
+        $msg        = $this->parseMessageId($serverId);
+        $message    = $this->getObject($serverId);
+        $is_flagged = !empty($message->headers->flags['FLAGGED']);
 
+        // Read status change
         if (isset($entry->Read)) {
             // here we update only Read flag
             $flag = (((int)$entry->Read != 1) ? 'UN' : '') . 'SEEN';
             $this->storage->set_flag($msg['uid'], $flag, $msg['foldername']);
         }
 
-        $is_flagged = !empty($message->headers->flags['FLAGGED']);
-
-        // @TODO: Flag change
+        // Flag change
         if (empty($entry->Flag)) {
             if ($is_flagged) {
                 $this->storage->set_flag($msg['uid'], 'UNFLAGGED', $msg['foldername']);
             }
         }
-        else if (!$is_flagged) {
-/*
+        else if (!$is_flagged && !empty($entry->Flag)) {
             if ($entry->Flag->FlagType && preg_match('/^follow\s*up/i', $entry->Flag->FlagType)) {
                 $this->storage->set_flag($msg['uid'], 'FLAGGED', $msg['foldername']);
             }
-*/
         }
     }
 
@@ -705,10 +700,7 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
 //           $this->storage->set_folder($foldername);
             $this->storage->folder_sync($foldername);
 
-            $this->storage->search($foldername, $filter_str, RCMAIL_CHARSET, $sort_by);
-
-            $search = $this->storage->get_search_set();
-            $search = $search[1];
+            $search = $this->storage->search_once($foldername, $filter_str);
 
             if (!($search instanceof rcube_result_index)) {
                 continue;
@@ -772,25 +764,21 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
 //           $this->storage->set_folder($foldername);
             $this->storage->folder_sync($foldername);
 
-            $this->storage->search($foldername, $search_str, RCMAIL_CHARSET, $sort_by);
-
-            $search = $this->storage->get_search_set();
-            $search = $search[1];
+            $search = $this->storage->search_once($foldername, $search_str);
 
             if (!($search instanceof rcube_result_index)) {
                 continue;
             }
 
-            if ($uids = $search->get()) {
-                foreach ($uids as $idx => $uid) {
-                    $uids[$idx] = new Syncroton_Model_StoreResponseResult(array(
-                        'LongId'       => $this->createMessageId($folderid, $uid),
-                        'CollectionId' => $folderid,
-                        'Class'        => 'Email',
-                    ));
-                }
-                $result = array_merge($result, $uids);
+            $uids = $search->get();
+            foreach ($uids as $idx => $uid) {
+                $uids[$idx] = new Syncroton_Model_StoreResponseResult(array(
+                    'LongId'       => $this->createMessageId($folderid, $uid),
+                    'CollectionId' => $folderid,
+                    'Class'        => 'Email',
+                ));
             }
+            $result = array_merge($result, $uids);
 
             // We don't want to search all folders if we've got already a lot messages
             if (count($result) >= self::MAX_SEARCH_RESULT) {





More information about the commits mailing list