plugins/kolab_notes plugins/kolab_tags plugins/libkolab

Aleksander Machniak machniak at kolabsys.com
Wed Aug 6 16:40:14 CEST 2014


 plugins/kolab_notes/kolab_notes.php           |   25 ++-
 plugins/kolab_tags/lib/kolab_tags_engine.php  |  113 -----------------
 plugins/libkolab/lib/kolab_storage_config.php |  166 +++++++++++++++++++++++++-
 3 files changed, 180 insertions(+), 124 deletions(-)

New commits:
commit 08581c0a94f816ba94e0ba9c3a70a36b70b32c8c
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Wed Aug 6 10:39:47 2014 -0400

    Improved relation members handling code

diff --git a/plugins/kolab_notes/kolab_notes.php b/plugins/kolab_notes/kolab_notes.php
index 6dbfa17..cf88772 100644
--- a/plugins/kolab_notes/kolab_notes.php
+++ b/plugins/kolab_notes/kolab_notes.php
@@ -983,6 +983,9 @@ class kolab_notes extends rcube_plugin
                 $this->relations = null; // clear in-memory cache
             }
             else {
+                // make relation members up-to-date
+                kolab_storage_config::resolve_members($relation);
+
                 // assign all links to one relation, others will be removed
                 $members = array_merge($links, array($search));
                 $diff1   = array_diff($members, $relation['members']);
@@ -1020,6 +1023,9 @@ class kolab_notes extends rcube_plugin
 
         foreach ($this->get_relations($uid) as $relation) {
             if (in_array($search, (array) $relation['members'])) {
+                // make relation members up-to-date
+                kolab_storage_config::resolve_members($relation);
+
                 foreach ($relation['members'] as $member) {
                     if ($member != $search) {
                         $result[] = $member;
@@ -1043,18 +1049,15 @@ class kolab_notes extends rcube_plugin
 
         // get UIDs of assigned notes
         foreach ($this->get_relations() as $relation) {
-            foreach ($relation['members'] as $member) {
-                $member = kolab_storage_config::parse_member_url($member);
-                if ($member['folder'] == $folder && $member['uid'] == $message->uid) {
-                    reset($relation['members']);
-                    // find note UID(s)
-                    foreach ($relation['members'] as $member) {
-                        if (strpos($member, 'urn:uuid:') === 0) {
-                            $uids[] = substr($member, 9);
-                        }
-                    }
+            // get Folder/UIDs of relation members
+            $messages = kolab_storage_config::resolve_members($relation);
 
-                    continue 2;
+            if (!empty($messages[$folder]) && in_array($message->uid, $messages[$folder])) {
+                // find note UID(s)
+                foreach ($relation['members'] as $member) {
+                    if (strpos($member, 'urn:uuid:') === 0) {
+                        $uids[] = substr($member, 9);
+                    }
                 }
             }
         }
diff --git a/plugins/kolab_tags/lib/kolab_tags_engine.php b/plugins/kolab_tags/lib/kolab_tags_engine.php
index 1551726..eb8298e 100644
--- a/plugins/kolab_tags/lib/kolab_tags_engine.php
+++ b/plugins/kolab_tags/lib/kolab_tags_engine.php
@@ -220,12 +220,6 @@ class kolab_tags_engine
 
         // for every tag...
         foreach ($taglist as $tag) {
-            $updated = false;
-
-            // make sure members list is up-to-date (UIDs are up-to-date)
-            // @todo: maybe there's a faster way?
-            $this->get_tag_messages($tag);
-
             $tag['members'] = array_unique(array_merge((array) $tag['members'], $members));
 
             // update tag object
@@ -429,91 +423,9 @@ class kolab_tags_engine
      *
      * @return array Folder/UID list
      */
-    protected function get_tag_messages(&$tag)
+    protected function get_tag_messages(&$tag, $force = true)
     {
-        $result = array();
-
-        foreach ((array) $tag['members'] as $member) {
-            if ($url = $this->parse_member_url($member)) {
-                $folder                      = $url['folder'];
-                $result[$folder]['uid'][]    = $url['uid'];
-                $result[$folder]['params'][] = $url['params'];
-                $result[$folder]['member'][] = $member;
-            }
-        }
-
-        if (empty($result)) {
-            return array();
-        }
-
-        // @TODO: caching?
-
-        $rcube   = rcube::get_instance();
-        $storage = $rcube->get_storage();
-
-        foreach ($result as $folder => $data) {
-            // first, we search messages by UID
-            // @FIXME: maybe better use index() which is cached?
-            // @TODO: consider skip_deleted option
-            $index = $storage->search_once($folder, 'UID ' . rcube_imap_generic::compressMessageSet($data['uid']));
-            $uids  = $index->get();
-
-            // search by search parameters
-            $not_found = array_diff($data['uid'], $uids);
-            if (!empty($not_found)) {
-                $params      = array();
-                $old_members = array();
-                $new_members = array();
-
-                foreach ($not_found as $uid) {
-                    $idx = array_search($uid, $data['uid']);
-
-                    if ($p = $data['params'][$idx]) {
-                        $params[$idx] = $p;
-                    }
-
-                    $old_members[] = $data['member'][$idx];
-                }
-
-                if (!empty($params)) {
-                    // @TODO: do this search in chunks (for e.g. 10 messages)?
-                    $search_str = '';
-
-                    foreach ($params as $p) {
-                        $search = array();
-                        foreach ($p as $key => $val) {
-                            $search[] = 'HEADER ' . strtoupper($key) . ' ' . rcube_imap_generic::escape($val);
-                        }
-
-                        $search_str .= ' (' . implode(' ', $search) . ')';
-                    }
-
-                    $search_str = str_repeat(' OR', count($params)-1) . $search_str;
-
-                    // @TODO: we should search all folders
-                    $index = $storage->search_once($folder, $search_str);
-                    $_uids = $index->get();
-
-                    if (!empty($_uids)) {
-                        $uids = array_merge($uids, $_uids);
-                        $msgs = $storage->fetch_headers($folder, $_uids, false);
-
-                        $new_members = array_merge($new_members, $this->build_members($folder, $msgs));
-                    }
-                }
-
-                // merge members
-                $tag['members'] = array_diff($tag['members'], $old_members);
-                $tag['members'] = array_unique(array_merge($tag['members'], $new_members));
-
-                // update tag object with new members list
-                $this->backend->update($tag);
-            }
-
-            $result[$folder] = array_unique($uids);
-        }
-
-        return $result;
+        return kolab_storage_config::resolve_members($tag, $force);
     }
 
     /**
@@ -521,26 +433,7 @@ class kolab_tags_engine
      */
     protected function build_members($folder, $messages)
     {
-        $members = array();
-
-        foreach ((array) $messages as $msg) {
-            $params = array(
-                'folder' => $folder,
-                'uid'    => $msg->uid,
-            );
-
-            // add search parameters
-            // we don't want to build "invalid" searches e.g. that
-            // will return false positives (more or wrong messages)
-            if (($messageid = $msg->get('message-id', false)) && ($date = $msg->get('date', false))) {
-                $params['message-id'] = $messageid;
-                $params['date']       = $date;
-            }
-
-            $members[] = $this->build_member_url($params);
-        }
-
-        return $members;
+        return kolab_storage_config::build_members($folder, $messages);
     }
 
     /**
diff --git a/plugins/libkolab/lib/kolab_storage_config.php b/plugins/libkolab/lib/kolab_storage_config.php
index f5b891d..b759e1d 100644
--- a/plugins/libkolab/lib/kolab_storage_config.php
+++ b/plugins/libkolab/lib/kolab_storage_config.php
@@ -27,6 +27,7 @@ class kolab_storage_config
 {
     const FOLDER_TYPE = 'configuration';
 
+
     /**
      * Singleton instace of kolab_storage_config
      *
@@ -165,9 +166,11 @@ class kolab_storage_config
 
         $folder = $this->find_folder($object);
 
-        $object['type'] = $type;
+        if ($type) {
+            $object['type'] = $type;
+        }
 
-        return $folder->save($object, self::FOLDER_TYPE . '.' . $type, $object['uid']);
+        return $folder->save($object, self::FOLDER_TYPE . '.' . $object['type'], $object['uid']);
     }
 
     /**
@@ -199,7 +202,7 @@ class kolab_storage_config
     /**
      * Find folder
      */
-    private function find_folder($object = array())
+    public function find_folder($object = array())
     {
         // find folder object
         if ($object['_mailbox']) {
@@ -345,4 +348,161 @@ class kolab_storage_config
             );
         }
     }
+
+    /**
+     * Build array of member URIs from set of messages
+     *
+     * @param string $folder   Folder name
+     * @param array  $messages Array of rcube_message objects
+     *
+     * @return array List of members (IMAP URIs)
+     */
+    public static function build_members($folder, $messages)
+    {
+        $members = array();
+
+        foreach ((array) $messages as $msg) {
+            $params = array(
+                'folder' => $folder,
+                'uid'    => $msg->uid,
+            );
+
+            // add search parameters:
+            // we don't want to build "invalid" searches e.g. that
+            // will return false positives (more or wrong messages)
+            if (($messageid = $msg->get('message-id', false)) && ($date = $msg->get('date', false))) {
+                $params['message-id'] = $messageid;
+                $params['date']       = $date;
+
+                if ($subject = $msg->get('subject', false)) {
+                    $params['subject'] = substr($subject, 0, 256);
+                }
+            }
+
+            $members[] = self::build_member_url($params);
+        }
+
+        return $members;
+    }
+
+    /**
+     * Resolve/validate/update members (which are IMAP URIs) of relation object.
+     *
+     * @param array $tag   Tag object
+     * @param bool  $force Force members list update
+     *
+     * @return array Folder/UIDs list
+     */
+    public static function resolve_members(&$tag, $force = true)
+    {
+        $result = array();
+
+        foreach ((array) $tag['members'] as $member) {
+            // IMAP URI members
+            if ($url = self::parse_member_url($member)) {
+                $folder = $url['folder'];
+
+                if (!$force) {
+                    $result[$folder][] = $url['uid'];
+                }
+                else {
+                    $result[$folder]['uid'][]    = $url['uid'];
+                    $result[$folder]['params'][] = $url['params'];
+                    $result[$folder]['member'][] = $member;
+                }
+            }
+        }
+
+        if (empty($result) || !$force) {
+            return $result;
+        }
+
+        $rcube   = rcube::get_instance();
+        $storage = $rcube->get_storage();
+        $search  = array();
+        $missing = array();
+
+        // first we search messages by Folder+UID
+        foreach ($result as $folder => $data) {
+            // @FIXME: maybe better use index() which is cached?
+            // @TODO: consider skip_deleted option
+            $index = $storage->search_once($folder, 'UID ' . rcube_imap_generic::compressMessageSet($data['uid']));
+            $uids  = $index->get();
+
+            // messages that were not found need to be searched by search parameters
+            $not_found = array_diff($data['uid'], $uids);
+            if (!empty($not_found)) {
+                foreach ($not_found as $uid) {
+                    $idx = array_search($uid, $data['uid']);
+
+                    if ($p = $data['params'][$idx]) {
+                        $search[] = $p;
+                    }
+
+                    $missing[] = $result[$folder]['member'][$idx];
+
+                    unset($result[$folder]['uid'][$idx]);
+                    unset($result[$folder]['params'][$idx]);
+                    unset($result[$folder]['member'][$idx]);
+                }
+            }
+
+            $result[$folder] = $uids;
+        }
+
+        // search in all subscribed mail folders using search parameters
+        if (!empty($search)) {
+            // remove not found members from the members list
+            $tag['members'] = array_diff($tag['members'], $missing);
+
+            // get subscribed folders
+            $folders = $storage->list_folders_subscribed('', '*', 'mail', null, true);
+
+            // @TODO: do this search in chunks (for e.g. 10 messages)?
+            $search_str = '';
+
+            foreach ($search as $p) {
+                $search_params = array();
+                foreach ($p as $key => $val) {
+                    $key = strtoupper($key);
+                    // don't search by subject, we don't want false-positives
+                    if ($key != 'SUBJECT') {
+                        $search_params[] = 'HEADER ' . $key . ' ' . rcube_imap_generic::escape($val);
+                    }
+                }
+
+                $search_str .= ' (' . implode(' ', $search_params) . ')';
+            }
+
+            $search_str = trim(str_repeat(' OR', count($search)-1) . $search_str);
+
+            // search
+            $search = $storage->search_once($folders, $search_str);
+
+            // handle search result
+            $folders = (array) $search->get_parameters('MAILBOX');
+
+            foreach ($folders as $folder) {
+                $set  = $search->get_set($folder);
+                $uids = $set->get();
+
+                if (!empty($uids)) {
+                    $msgs    = $storage->fetch_headers($folder, $uids, false);
+                    $members = self::build_members($folder, $msgs);
+
+                    // merge new members into the tag members list
+                    $tag['members'] = array_merge($tag['members'], $members);
+
+                    // add UIDs into the result
+                    $result[$folder] = array_unique(array_merge((array)$result[$folder], $uids));
+                }
+            }
+
+            // update tag object with new members list
+            $tag['members'] = array_unique($tag['members']);
+            kolab_storage_config::get_instance()->save($tag, 'relation', false);
+        }
+
+        return $result;
+    }
 }




More information about the commits mailing list