lib/plugins

Aleksander Machniak machniak at kolabsys.com
Mon Jun 17 10:23:39 CEST 2013


 lib/plugins/libkolab/lib/kolab_format.php                  |   12 +
 lib/plugins/libkolab/lib/kolab_format_configuration.php    |   12 -
 lib/plugins/libkolab/lib/kolab_format_contact.php          |   53 ++++++-
 lib/plugins/libkolab/lib/kolab_format_distributionlist.php |    2 
 lib/plugins/libkolab/lib/kolab_format_event.php            |   35 +----
 lib/plugins/libkolab/lib/kolab_format_file.php             |   40 +----
 lib/plugins/libkolab/lib/kolab_format_journal.php          |    2 
 lib/plugins/libkolab/lib/kolab_format_note.php             |    2 
 lib/plugins/libkolab/lib/kolab_format_task.php             |    2 
 lib/plugins/libkolab/lib/kolab_format_xcal.php             |   37 +++--
 lib/plugins/libkolab/lib/kolab_storage.php                 |   63 +++++----
 lib/plugins/libkolab/lib/kolab_storage_cache.php           |   89 ++++++++-----
 lib/plugins/libkolab/lib/kolab_storage_folder.php          |   29 +++-
 13 files changed, 231 insertions(+), 147 deletions(-)

New commits:
commit e22783f06f01ee85823bf2d7e7dba3b9a81989a6
Author: Aleksander Machniak <alec at alec.pl>
Date:   Mon Jun 17 10:23:20 2013 +0200

    Update libkolab plugin

diff --git a/lib/plugins/libkolab/lib/kolab_format.php b/lib/plugins/libkolab/lib/kolab_format.php
index 809fb29..66ba380 100644
--- a/lib/plugins/libkolab/lib/kolab_format.php
+++ b/lib/plugins/libkolab/lib/kolab_format.php
@@ -438,6 +438,18 @@ abstract class kolab_format
             $object['x-custom'][] = array($cp->identifier, $cp->value);
         }
 
+        // merge with additional data, e.g. attachments from the message
+        if ($data) {
+            foreach ($data as $idx => $value) {
+                if (is_array($value)) {
+                    $object[$idx] = array_merge((array)$object[$idx], $value);
+                }
+                else {
+                    $object[$idx] = $value;
+                }
+            }
+        }
+
         return $object;
     }
 
diff --git a/lib/plugins/libkolab/lib/kolab_format_configuration.php b/lib/plugins/libkolab/lib/kolab_format_configuration.php
index 5e64e30..104d90f 100644
--- a/lib/plugins/libkolab/lib/kolab_format_configuration.php
+++ b/lib/plugins/libkolab/lib/kolab_format_configuration.php
@@ -98,16 +98,12 @@ class kolab_format_configuration extends kolab_format
         if (!empty($this->data))
             return $this->data;
 
-        $this->init();
+        // read common object props into local data object
+        $object = parent::to_array($data);
+
         $type_map = array_flip($this->type_map);
 
-        // read object properties
-        $object = array(
-            'uid'     => $this->obj->uid(),
-            'created' => self::php_datetime($this->obj->created()),
-            'changed' => self::php_datetime($this->obj->lastModified()),
-            'type'    => $type_map[$this->obj->type()],
-        );
+        $object['type'] = $type_map[$this->obj->type()];
 
         // read type-specific properties
         switch ($object['type']) {
diff --git a/lib/plugins/libkolab/lib/kolab_format_contact.php b/lib/plugins/libkolab/lib/kolab_format_contact.php
index cde0288..d8b5162 100644
--- a/lib/plugins/libkolab/lib/kolab_format_contact.php
+++ b/lib/plugins/libkolab/lib/kolab_format_contact.php
@@ -31,7 +31,7 @@ class kolab_format_contact extends kolab_format
     protected $read_func = 'readContact';
     protected $write_func = 'writeContact';
 
-    public static $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'email');
+    public static $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'email:address');
 
     public $phonetypes = array(
         'home'    => Telephone::Home,
@@ -47,6 +47,12 @@ class kolab_format_contact extends kolab_format
         'other'   => Telephone::Textphone,
     );
 
+    public $emailtypes = array(
+        'home' => Email::Home,
+        'work' => Email::Work,
+        'other' => Email::NoType,
+    );
+
     public $addresstypes = array(
         'home' => Address::Home,
         'work' => Address::Work,
@@ -125,10 +131,21 @@ class kolab_format_contact extends kolab_format
         }
         $org->setRelateds($rels);
 
-        // email, im, url
-        $this->obj->setEmailAddresses(self::array2vector($object['email']));
+        // im, email, url
         $this->obj->setIMaddresses(self::array2vector($object['im']));
 
+        if (class_exists('vectoremail')) {
+            $vemails = new vectoremail;
+            foreach ((array)$object['email'] as $email) {
+                $type = $this->emailtypes[$email['type']];
+                $vemails->push(new Email($email['address'], intval($type)));
+            }
+        }
+        else {
+            $vemails = self::array2vector(array_map(function($v){ return $v['address']; }, $object['email']));
+        }
+        $this->obj->setEmailAddresses($vemails);
+
         $vurls = new vectorurl;
         foreach ((array)$object['website'] as $url) {
             $type = $url['type'] == 'blog' ? Url::Blog : Url::NoType;
@@ -266,7 +283,7 @@ class kolab_format_contact extends kolab_format
             return $this->data;
 
         // read common object props into local data object
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         $object['name'] = $this->obj->name();
 
@@ -290,8 +307,19 @@ class kolab_format_contact extends kolab_format
             $this->read_relateds($org->relateds(), $object);
         }
 
-        $object['email']   = self::vector2array($this->obj->emailAddresses());
-        $object['im']      = self::vector2array($this->obj->imAddresses());
+        $object['im'] = self::vector2array($this->obj->imAddresses());
+
+        $emails = $this->obj->emailAddresses();
+        if ($emails instanceof vectoremail) {
+            $emailtypes = array_flip($this->emailtypes);
+            for ($i=0; $i < $emails->size(); $i++) {
+                $email = $emails->get($i);
+                $object['email'][] = array('address' => $email->address(), 'type' => $emailtypes[$email->types()]);
+            }
+        }
+        else {
+            $object['email'] = self::vector2array($emails);
+        }
 
         $urls = $this->obj->urls();
         for ($i=0; $i < $urls->size(); $i++) {
@@ -357,7 +385,18 @@ class kolab_format_contact extends kolab_format
     {
         $data = '';
         foreach (self::$fulltext_cols as $col) {
-            $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
+            list($col, $field) = explode(':', $colname);
+
+            if ($field) {
+                $a = array();
+                foreach ((array)$this->data[$col] as $attr)
+                    $a[] = $attr[$field];
+                $val = join(' ', $a);
+            }
+            else {
+                $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
+            }
+
             if (strlen($val))
                 $data .= $val . ' ';
         }
diff --git a/lib/plugins/libkolab/lib/kolab_format_distributionlist.php b/lib/plugins/libkolab/lib/kolab_format_distributionlist.php
index d25bd47..0110e4e 100644
--- a/lib/plugins/libkolab/lib/kolab_format_distributionlist.php
+++ b/lib/plugins/libkolab/lib/kolab_format_distributionlist.php
@@ -88,7 +88,7 @@ class kolab_format_distributionlist extends kolab_format
             return $this->data;
 
         // read common object props into local data object
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         // add object properties
         $object += array(
diff --git a/lib/plugins/libkolab/lib/kolab_format_event.php b/lib/plugins/libkolab/lib/kolab_format_event.php
index ec97767..e050774 100644
--- a/lib/plugins/libkolab/lib/kolab_format_event.php
+++ b/lib/plugins/libkolab/lib/kolab_format_event.php
@@ -147,7 +147,7 @@ class kolab_format_event extends kolab_format_xcal
             return $this->data;
 
         // read common xcal props
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         // read object properties
         $object += array(
@@ -168,7 +168,7 @@ class kolab_format_event extends kolab_format_xcal
         if ($status == kolabformat::StatusTentative)
           $object['free_busy'] = 'tentative';
         else if ($status == kolabformat::StatusCancelled)
-          $objec['cancelled'] = true;
+          $object['cancelled'] = true;
 
         // handle attachments
         $vattach = $this->obj->attachments();
@@ -177,13 +177,13 @@ class kolab_format_event extends kolab_format_xcal
 
             // skip cid: attachments which are mime message parts handled by kolab_storage_folder
             if (substr($attach->uri(), 0, 4) != 'cid:' && $attach->label()) {
-                $name = $attach->label();
-                $data = $attach->data();
+                $name    = $attach->label();
+                $content = $attach->data();
                 $object['_attachments'][$name] = array(
                     'name'     => $name,
                     'mimetype' => $attach->mimetype(),
-                    'size'     => strlen($data),
-                    'content'  => $data,
+                    'size'     => strlen($content),
+                    'content'  => $content,
                 );
             }
             else if (substr($attach->uri(), 0, 4) == 'http') {
@@ -207,18 +207,6 @@ class kolab_format_event extends kolab_format_xcal
           $object['thisandfuture'] = $this->obj->thisAndFuture();
         }
 
-        // merge with additional data, e.g. attachments from the message
-        if ($data) {
-            foreach ($data as $idx => $value) {
-                if (is_array($value)) {
-                    $object[$idx] = array_merge((array)$object[$idx], $value);
-                }
-                else {
-                    $object[$idx] = $value;
-                }
-            }
-        }
-
         return $this->data = $object;
     }
 
@@ -247,16 +235,15 @@ class kolab_format_event extends kolab_format_xcal
      */
     private function compact_exception($exception, $master)
     {
-      static $forbidden = array('recurrence','organizer','attendees','sequence');
+      $forbidden = array('recurrence','organizer','attendees','sequence');
 
-      $out = $exception;
-      foreach ($exception as $prop => $val) {
-        if (in_array($prop, $forbidden)) {
-          unset($out[$prop]);
+      foreach ($forbidden as $prop) {
+        if (array_key_exists($prop, $exception)) {
+          unset($exception[$prop]);
         }
       }
 
-      return $out;
+      return $exception;
     }
 
     /**
diff --git a/lib/plugins/libkolab/lib/kolab_format_file.php b/lib/plugins/libkolab/lib/kolab_format_file.php
index 191c7fe..a71a794 100644
--- a/lib/plugins/libkolab/lib/kolab_format_file.php
+++ b/lib/plugins/libkolab/lib/kolab_format_file.php
@@ -98,11 +98,12 @@ class kolab_format_file extends kolab_format
     public function to_array($data = array())
     {
         // return cached result
-        if (!empty($this->data))
+        if (!empty($this->data)) {
             return $this->data;
+        }
 
         // read common object props into local data object
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         $sensitivity_map = array_flip($this->sensitivity_map);
 
@@ -113,18 +114,6 @@ class kolab_format_file extends kolab_format
             'notes'       => $this->obj->note(),
         );
 
-        // merge with additional data, e.g. attachments from the message
-        if ($data) {
-            foreach ($data as $idx => $value) {
-                if (is_array($value)) {
-                    $object[$idx] = array_merge((array)$object[$idx], $value);
-                }
-                else {
-                    $object[$idx] = $value;
-                }
-            }
-        }
-
         return $this->data = $object;
     }
 
@@ -141,22 +130,17 @@ class kolab_format_file extends kolab_format
             $tags[] = rcube_utils::normalize_string($cat);
         }
 
-        return $tags;
-    }
+        // Add file mimetype to tags
+        if (!empty($this->data['_attachments'])) {
+            reset($this->data['_attachments']);
+            $key        = key($this->data['_attachments']);
+            $attachment = $this->data['_attachments'][$key];
 
-    /**
-     * Callback for kolab_storage_cache to get words to index for fulltext search
-     *
-     * @return array List of words to save in cache
-     */
-    public function get_words()
-    {
-        // Store filename in 'words' for fast access to file by name
-        if (empty($this->data['_attachments'])) {
-            return array();
+            if ($attachment['mimetype']) {
+                $tags[] = $attachment['mimetype'];
+            }
         }
 
-        $attachment = array_shift($this->data['_attachments']);
-        return array($attachment['name']);
+        return $tags;
     }
 }
diff --git a/lib/plugins/libkolab/lib/kolab_format_journal.php b/lib/plugins/libkolab/lib/kolab_format_journal.php
index 3528d16..b9a1b4f 100644
--- a/lib/plugins/libkolab/lib/kolab_format_journal.php
+++ b/lib/plugins/libkolab/lib/kolab_format_journal.php
@@ -71,7 +71,7 @@ class kolab_format_journal extends kolab_format
             return $this->data;
 
         // read common object props into local data object
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         // TODO: read object properties
 
diff --git a/lib/plugins/libkolab/lib/kolab_format_note.php b/lib/plugins/libkolab/lib/kolab_format_note.php
index cee6345..466c536 100644
--- a/lib/plugins/libkolab/lib/kolab_format_note.php
+++ b/lib/plugins/libkolab/lib/kolab_format_note.php
@@ -71,7 +71,7 @@ class kolab_format_note extends kolab_format
             return $this->data;
 
         // read common object props into local data object
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         // TODO: read object properties
 
diff --git a/lib/plugins/libkolab/lib/kolab_format_task.php b/lib/plugins/libkolab/lib/kolab_format_task.php
index 0fa2806..56f22dc 100644
--- a/lib/plugins/libkolab/lib/kolab_format_task.php
+++ b/lib/plugins/libkolab/lib/kolab_format_task.php
@@ -80,7 +80,7 @@ class kolab_format_task extends kolab_format_xcal
             return $this->data;
 
         // read common xcal props
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         $object['complete'] = intval($this->obj->percentComplete());
 
diff --git a/lib/plugins/libkolab/lib/kolab_format_xcal.php b/lib/plugins/libkolab/lib/kolab_format_xcal.php
index bbe3404..24f8237 100644
--- a/lib/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/lib/plugins/libkolab/lib/kolab_format_xcal.php
@@ -43,6 +43,14 @@ abstract class kolab_format_xcal extends kolab_format
         'CHAIR' => kolabformat::Chair,
     );
 
+    protected $cutype_map = array(
+        'INDIVIDUAL' => kolabformat::CutypeIndividual,
+        'GROUP'      => kolabformat::CutypeGroup,
+        'ROOM'       => kolabformat::CutypeRoom,
+        'RESOURCE'   => kolabformat::CutypeResource,
+        'UNKNOWN'    => kolabformat::CutypeUnknown,
+    );
+
     protected $rrule_type_map = array(
         'MINUTELY' => RecurrenceRule::Minutely,
         'HOURLY' => RecurrenceRule::Hourly,
@@ -95,7 +103,7 @@ abstract class kolab_format_xcal extends kolab_format
     public function to_array($data = array())
     {
         // read common object props
-        $object = parent::to_array();
+        $object = parent::to_array($data);
 
         $status_map = array_flip($this->status_map);
         $sensitivity_map = array_flip($this->sensitivity_map);
@@ -105,7 +113,8 @@ abstract class kolab_format_xcal extends kolab_format
             'title'       => $this->obj->summary(),
             'location'    => $this->obj->location(),
             'description' => $this->obj->description(),
-            'status'      => $this->status_map[$this->obj->status()],
+            'url'         => $this->obj->url(),
+            'status'      => $status_map[$this->obj->status()],
             'sensitivity' => $sensitivity_map[$this->obj->classification()],
             'priority'    => $this->obj->priority(),
             'categories'  => self::vector2array($this->obj->categories()),
@@ -121,18 +130,22 @@ abstract class kolab_format_xcal extends kolab_format
         }
 
         $role_map = array_flip($this->role_map);
+        $cutype_map = array_flip($this->cutype_map);
         $part_status_map = array_flip($this->part_status_map);
         $attvec = $this->obj->attendees();
         for ($i=0; $i < $attvec->size(); $i++) {
             $attendee = $attvec->get($i);
             $cr = $attendee->contact();
-            $object['attendees'][] = array(
-                'role' => $role_map[$attendee->role()],
-                'status' => $part_status_map[$attendee->partStat()],
-                'rsvp' => $attendee->rsvp(),
-                'email' => $cr->email(),
-                'name' => $cr->name(),
-            );
+            if ($cr->email() != $object['organizer']['email']) {
+                $object['attendees'][] = array(
+                    'role' => $role_map[$attendee->role()],
+                    'cutype' => $cutype_map[$attendee->cutype()],
+                    'status' => $part_status_map[$attendee->partStat()],
+                    'rsvp' => $attendee->rsvp(),
+                    'email' => $cr->email(),
+                    'name' => $cr->name(),
+                );
+            }
         }
 
         // read recurrence rule
@@ -233,6 +246,7 @@ abstract class kolab_format_xcal extends kolab_format
         $this->obj->setPriority($object['priority']);
         $this->obj->setClassification($this->sensitivity_map[$object['sensitivity']]);
         $this->obj->setCategories(self::array2vector($object['categories']));
+        $this->obj->setUrl(strval($object['url']));
 
         // process event attendees
         $attendees = new vectorattendee;
@@ -240,14 +254,15 @@ abstract class kolab_format_xcal extends kolab_format
             if ($attendee['role'] == 'ORGANIZER') {
                 $object['organizer'] = $attendee;
             }
-            else {
+            else if ($attendee['email'] != $object['organizer']['email']) {
                 $cr = new ContactReference(ContactReference::EmailReference, $attendee['email']);
                 $cr->setName($attendee['name']);
 
                 $att = new Attendee;
                 $att->setContact($cr);
-                $att->setPartStat($this->status_map[$attendee['status']]);
+                $att->setPartStat($this->part_status_map[$attendee['status']]);
                 $att->setRole($this->role_map[$attendee['role']] ? $this->role_map[$attendee['role']] : kolabformat::Required);
+                $att->setCutype($this->cutype_map[$attendee['cutype']] ? $this->cutype_map[$attendee['cutype']] : kolabformat::CutypeIndividual);
                 $att->setRSVP((bool)$attendee['rsvp']);
 
                 if ($att->isValid()) {
diff --git a/lib/plugins/libkolab/lib/kolab_storage.php b/lib/plugins/libkolab/lib/kolab_storage.php
index a569af7..08e11b2 100644
--- a/lib/plugins/libkolab/lib/kolab_storage.php
+++ b/lib/plugins/libkolab/lib/kolab_storage.php
@@ -27,8 +27,10 @@ class kolab_storage
 {
     const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
     const CTYPE_KEY_PRIVATE = '/private/vendor/kolab/folder-type';
-    const COLOR_KEY_SHARED = '/shared/vendor/kolab/color';
+    const COLOR_KEY_SHARED  = '/shared/vendor/kolab/color';
     const COLOR_KEY_PRIVATE = '/private/vendor/kolab/color';
+    const NAME_KEY_SHARED   = '/shared/vendor/kolab/name';
+    const NAME_KEY_PRIVATE  = '/private/vendor/kolab/name';
 
     public static $version = '3.0';
     public static $last_error;
@@ -37,7 +39,6 @@ class kolab_storage
     private static $subscriptions;
     private static $states;
     private static $config;
-    private static $cache;
     private static $imap;
 
 
@@ -289,7 +290,7 @@ class kolab_storage
         else {
             // these characters are problematic e.g. when used in LIST/LSUB
             foreach (array($delimiter, '%', '*') as $char) {
-                if (strpos($folder, $delimiter) !== false) {
+                if (strpos($folder, $char) !== false) {
                     self::$last_error = 'forbiddencharacter';
                     return false;
                 }
@@ -331,18 +332,25 @@ class kolab_storage
             $result = self::folder_create($folder, $prop['type'], $prop['subscribed'], $prop['active']);
         }
 
-        // save color in METADATA
+        // save displayname and color in METADATA
         // TODO: also save 'showalarams' and other properties here
-
-        if ($result && $prop['color']) {
-            $meta_saved = false;
-            $ns = self::$imap->folder_namespace($folder);
-            if ($ns == 'personal')  // save in shared namespace for personal folders
-                $meta_saved = self::$imap->set_metadata($folder, array(self::COLOR_KEY_SHARED => $prop['color']));
-            if (!$meta_saved)    // try in private namespace
-                $meta_saved = self::$imap->set_metadata($folder, array(self::COLOR_KEY_PRIVATE => $prop['color']));
-            if ($meta_saved)
-                unset($prop['color']);  // unsetting will prevent fallback to local user prefs
+        if ($result) {
+            $ns = null;
+            foreach (array('color'       => array(self::COLOR_KEY_SHARED,self::COLOR_KEY_PRIVATE),
+                           'displayname' => array(self::NAME_KEY_SHARED,self::NAME_KEY_PRIVATE)) as $key => $metakeys) {
+                if (!empty($prop[$key])) {
+                    if (!isset($ns))
+                        $ns = self::$imap->folder_namespace($folder);
+
+                    $meta_saved = false;
+                    if ($ns == 'personal')  // save in shared namespace for personal folders
+                        $meta_saved = self::$imap->set_metadata($folder, array($metakeys[0] => $prop[$key]));
+                    if (!$meta_saved)    // try in private namespace
+                        $meta_saved = self::$imap->set_metadata($folder, array($metakeys[1] => $prop[$key]));
+                    if ($meta_saved)
+                        unset($prop[$key]);  // unsetting will prevent fallback to local user prefs
+                }
+            }
         }
 
         return $result ? $folder : false;
@@ -362,6 +370,12 @@ class kolab_storage
     {
         self::setup();
 
+        // find custom display name in folder METADATA
+        $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED));
+        if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) {
+            return $name;
+        }
+
         $found     = false;
         $namespace = self::$imap->get_namespace();
 
@@ -493,33 +507,30 @@ class kolab_storage
                 }
             }
 
-            $names[$name] = rcube_charset::convert($name, 'UTF7-IMAP');
+            $names[$name] = self::object_name($name);
         }
 
         // Make sure parent folder is listed (might be skipped e.g. if it's namespace root)
         if ($p_len && !isset($names[$parent])) {
-            $names[$parent] = rcube_charset::convert($parent, 'UTF7-IMAP');
+            $names[$parent] = self::object_name($parent);
         }
 
         // Sort folders list
         asort($names, SORT_LOCALE_STRING);
 
-        $folders = array_keys($names);
-        $names   = array();
-
         // Build SELECT field of parent folder
         $attrs['is_escaped'] = true;
         $select = new html_select($attrs);
         $select->add('---', '');
 
-        foreach ($folders as $name) {
-            $imap_name = $name;
-            $name      = $origname = self::object_name($name);
+        $listnames = array();
+        foreach (array_keys($names) as $imap_name) {
+            $name = $origname = $names[$imap_name];
 
             // find folder prefix to truncate
-            for ($i = count($names)-1; $i >= 0; $i--) {
-                if (strpos($name, $names[$i].' » ') === 0) {
-                    $length = strlen($names[$i].' » ');
+            for ($i = count($listnames)-1; $i >= 0; $i--) {
+                if (strpos($name, $listnames[$i].' » ') === 0) {
+                    $length = strlen($listnames[$i].' » ');
                     $prefix = substr($name, 0, $length);
                     $count  = count(explode(' » ', $prefix));
                     $name   = str_repeat('  ', $count-1) . '» ' . substr($name, $length);
@@ -527,7 +538,7 @@ class kolab_storage
                 }
             }
 
-            $names[] = $origname;
+            $listnames[] = $origname;
             $select->add($name, $imap_name);
         }
 
diff --git a/lib/plugins/libkolab/lib/kolab_storage_cache.php b/lib/plugins/libkolab/lib/kolab_storage_cache.php
index ef4dd22..6d8071b 100644
--- a/lib/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/lib/plugins/libkolab/lib/kolab_storage_cache.php
@@ -35,7 +35,8 @@ class kolab_storage_cache
     private $synched = false;
     private $synclock = false;
     private $ready = false;
-    private $max_sql_packet = 1046576;  // 1 MB - 2000 bytes
+    private $max_sql_packet;
+    private $max_sync_lock_time = 600;
     private $binary_cols = array('photo','pgppublickey','pkcs7publickey');
 
 
@@ -52,9 +53,6 @@ class kolab_storage_cache
         if ($this->enabled) {
             // remove sync-lock on script termination
             $rcmail->add_shutdown_function(array($this, '_sync_unlock'));
-
-            // read max_allowed_packet from mysql config
-            $this->max_sql_packet = min($this->db->get_variable('max_allowed_packet', 1048500), 4*1024*1024) - 2000;  // mysql limit or max 4 MB
         }
 
         if ($storage_folder)
@@ -92,7 +90,7 @@ class kolab_storage_cache
             return;
 
         // increase time limit
-        @set_time_limit(500);
+        @set_time_limit($this->max_sync_lock_time);
 
         // lock synchronization for this folder or wait if locked
         $this->_sync_lock();
@@ -157,7 +155,7 @@ class kolab_storage_cache
     {
         // delegate to another cache instance
         if ($foldername && $foldername != $this->folder->name) {
-            return kolab_storage::get_folder($foldername)->cache->get($msguid, $object);
+            return kolab_storage::get_folder($foldername)->cache->get($msguid, $type);
         }
 
         // load object if not in memory
@@ -238,8 +236,8 @@ class kolab_storage_cache
 
             $result = $this->db->query(
                 "INSERT INTO kolab_cache ".
-                " (resource, type, msguid, uid, created, changed, data, xml, dtstart, dtend, tags, words)".
-                " VALUES (?, ?, ?, ?, " . $this->db->now() . ", ?, ?, ?, ?, ?, ?, ?)",
+                " (resource, type, msguid, uid, created, changed, data, xml, dtstart, dtend, tags, words, filename)".
+                " VALUES (?, ?, ?, ?, " . $this->db->now() . ", ?, ?, ?, ?, ?, ?, ?, ?)",
                 $this->resource_uri,
                 $objtype,
                 $msguid,
@@ -250,7 +248,8 @@ class kolab_storage_cache
                 $sql_data['dtstart'],
                 $sql_data['dtend'],
                 $sql_data['tags'],
-                $sql_data['words']
+                $sql_data['words'],
+                $sql_data['filename']
             );
 
             if (!$this->db->affected_rows($result)) {
@@ -274,12 +273,12 @@ class kolab_storage_cache
      * @param string Entry's Object UID
      * @param string Target IMAP folder to move it to
      */
-    public function move($msguid, $objuid, $target_folder)
+    public function move($msguid, $uid, $target_folder)
     {
         $target = kolab_storage::get_folder($target_folder);
 
         // resolve new message UID in target folder
-        if ($new_msguid = $target->cache->uid2msguid($objuid)) {
+        if ($new_msguid = $target->cache->uid2msguid($uid)) {
             $this->db->query(
                 "UPDATE kolab_cache SET resource=?, msguid=? ".
                 "WHERE resource=? AND msguid=? AND type<>?",
@@ -416,7 +415,17 @@ class kolab_storage_cache
     {
         $sql_where = '';
         foreach ($query as $param) {
-            if ($param[1] == '=' && is_array($param[2])) {
+            if (is_array($param[0])) {
+                $subq = array();
+                foreach ($param[0] as $q) {
+                    $subq[] = preg_replace('/^\s*AND\s+/i', '', $this->_sql_where(array($q)));
+                }
+                if (!empty($subq)) {
+                    $sql_where .= ' AND (' . implode($param[1] == 'OR' ? ' OR ' : ' AND ', $subq) . ')';
+                }
+                continue;
+            }
+            else if ($param[1] == '=' && is_array($param[2])) {
                 $qvalue = '(' . join(',', array_map(array($this->db, 'quote'), $param[2])) . ')';
                 $param[1] = 'IN';
             }
@@ -515,9 +524,9 @@ class kolab_storage_cache
      */
     private function _serialize($object)
     {
-        $bincols = array_flip($this->binary_cols);
+        $bincols  = array_flip($this->binary_cols);
         $sql_data = array('changed' => null, 'dtstart' => null, 'dtend' => null, 'xml' => '', 'tags' => '', 'words' => '');
-        $objtype = $object['_type'] ? $object['_type'] : $this->folder->type;
+        $objtype  = $object['_type'] ? $object['_type'] : $this->folder->type;
 
         // set type specific values
         if ($objtype == 'event') {
@@ -537,14 +546,20 @@ class kolab_storage_cache
             if ($object['due'])
                 $sql_data['dtend']   = date('Y-m-d H:i:s', is_object($object['due'])   ? $object['due']->format('U')   : $object['due']);
         }
+        else if ($objtype == 'file') {
+            if (!empty($object['_attachments'])) {
+                reset($object['_attachments']);
+                $sql_data['filename'] = $object['_attachments'][key($object['_attachments'])]['name'];
+            }
+        }
 
         if ($object['changed']) {
             $sql_data['changed'] = date('Y-m-d H:i:s', is_object($object['changed']) ? $object['changed']->format('U') : $object['changed']);
         }
 
         if ($object['_formatobj']) {
-            $sql_data['xml'] = preg_replace('!(</?[a-z0-9:-]+>)[\n\r\t\s]+!ms', '$1', (string)$object['_formatobj']->write(3.0));
-            $sql_data['tags'] = ' ' . join(' ', $object['_formatobj']->get_tags()) . ' ';  // pad with spaces for strict/prefix search
+            $sql_data['xml']   = preg_replace('!(</?[a-z0-9:-]+>)[\n\r\t\s]+!ms', '$1', (string)$object['_formatobj']->write(3.0));
+            $sql_data['tags']  = ' ' . join(' ', $object['_formatobj']->get_tags()) . ' ';  // pad with spaces for strict/prefix search
             $sql_data['words'] = ' ' . join(' ', $object['_formatobj']->get_words()) . ' ';
         }
 
@@ -625,14 +640,15 @@ class kolab_storage_cache
                 $this->db->quote($sql_data['dtend']),
                 $this->db->quote($sql_data['tags']),
                 $this->db->quote($sql_data['words']),
+                $this->db->quote($sql_data['filename']),
             );
             $line = '(' . join(',', $values) . ')';
         }
 
-        if ($buffer && (!$msguid || (strlen($buffer) + strlen($line) > $this->max_sql_packet))) {
+        if ($buffer && (!$msguid || (strlen($buffer) + strlen($line) > $this->max_sql_packet()))) {
             $result = $this->db->query(
                 "INSERT INTO kolab_cache ".
-                " (resource, type, msguid, uid, created, changed, data, xml, dtstart, dtend, tags, words)".
+                " (resource, type, msguid, uid, created, changed, data, xml, dtstart, dtend, tags, words, filename)".
                 " VALUES $buffer"
             );
             if (!$this->db->affected_rows($result)) {
@@ -649,6 +665,20 @@ class kolab_storage_cache
     }
 
     /**
+     * Returns max_allowed_packet from mysql config
+     */
+    private function max_sql_packet()
+    {
+        if (!$this->max_sql_packet) {
+            // mysql limit or max 4 MB
+            $value = $this->db->get_variable('max_allowed_packet', 1048500);
+            $this->max_sql_packet = min($value, 4*1024*1024) - 2000;
+        }
+
+        return $this->max_sql_packet;
+    }
+
+    /**
      * Check lock record for this folder and wait if locked or set lock
      */
     private function _sync_lock()
@@ -656,12 +686,9 @@ class kolab_storage_cache
         if (!$this->ready)
             return;
 
-        $sql_arr = $this->db->fetch_assoc($this->db->query(
-            "SELECT msguid AS locked, ".$this->db->unixtimestamp('created')." AS created FROM kolab_cache ".
-            "WHERE resource=? AND type=?",
-            $this->resource_uri,
-            'lock'
-        ));
+        $sql_query = "SELECT msguid AS locked, ".$this->db->unixtimestamp('created')." AS created FROM kolab_cache ".
+            "WHERE resource=? AND type=?";
+        $sql_arr = $this->db->fetch_assoc($this->db->query($sql_query, $this->resource_uri, 'lock'));
 
         // abort if database is not set-up
         if ($this->db->is_error()) {
@@ -671,6 +698,12 @@ class kolab_storage_cache
 
         $this->synclock = true;
 
+        // wait if locked (expire locks after 10 minutes)
+        while ($sql_arr && intval($sql_arr['locked']) > 0 && $sql_arr['created'] + $this->max_sync_lock_time > time()) {
+            usleep(500000);
+            $sql_arr = $this->db->fetch_assoc($this->db->query($sql_query, $this->resource_uri, 'lock'));
+        }
+
         // create lock record if not exists
         if (!$sql_arr) {
             $this->db->query(
@@ -681,12 +714,6 @@ class kolab_storage_cache
                 date('Y-m-d H:i:s')
             );
         }
-        // wait if locked (expire locks after 10 minutes)
-        else if (intval($sql_arr['locked']) > 0 && (time() - $sql_arr['created']) < 600) {
-            usleep(500000);
-            return $this->_sync_lock();
-        }
-        // set lock
         else {
             $this->db->query(
                 "UPDATE kolab_cache SET msguid=1, created=? ".
@@ -728,7 +755,7 @@ class kolab_storage_cache
         if (!isset($this->uid2msg[$uid])) {
             // use IMAP SEARCH to get the right message
             $index = $this->imap->search_once($this->folder->name, ($deleted ? '' : 'UNDELETED ') .
-				'HEADER SUBJECT ' . rcube_imap_generic::escape($uid));
+                'HEADER SUBJECT ' . rcube_imap_generic::escape($uid));
             $results = $index->get();
             $this->uid2msg[$uid] = $results[0];
         }
diff --git a/lib/plugins/libkolab/lib/kolab_storage_folder.php b/lib/plugins/libkolab/lib/kolab_storage_folder.php
index dd0e8d2..702b621 100644
--- a/lib/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/lib/plugins/libkolab/lib/kolab_storage_folder.php
@@ -49,12 +49,12 @@ class kolab_storage_folder
     public $cache;
 
     private $type_annotation;
+    private $namespace;
     private $imap;
     private $info;
     private $idata;
     private $owner;
     private $resource_uri;
-    private $uid2msg = array();
 
 
     /**
@@ -160,7 +160,6 @@ class kolab_storage_folder
             break;
 
         default:
-            $owner = '';
             list($prefix, $user) = explode($this->imap->get_hierarchy_delimiter(), $info['name']);
             if (strpos($user, '@') === false) {
                 $domain = strstr($rcmail->get_user_name(), '@');
@@ -182,7 +181,9 @@ class kolab_storage_folder
      */
     public function get_namespace()
     {
-        return $this->imap->folder_namespace($this->name);
+        if (!isset($this->namespace))
+            $this->namespace = $this->imap->folder_namespace($this->name);
+        return $this->namespace;
     }
 
 
@@ -203,7 +204,18 @@ class kolab_storage_folder
 
 
     /**
-     * Get the color value stores in metadata
+     * Get the display name value of this folder
+     *
+     * @return string Folder name
+     */
+    public function get_name()
+    {
+        return kolab_storage::object_name($this->name, $this->namespace);
+    }
+
+
+    /**
+     * Get the color value stored in metadata
      *
      * @param string Default color value to return if not set
      * @return mixed Color value from IMAP metadata or $default is not set
@@ -621,7 +633,7 @@ class kolab_storage_folder
         }
 
         // save contact photo to attachment for Kolab2 format
-        if (kolab_storage::$version == '2.0' && $object['photo'] && !$existing_photo) {
+        if (kolab_storage::$version == '2.0' && $object['photo']) {
             $attkey = 'kolab-picture.png';  // this file name is hard-coded in libkolab/kolabformatV2/contact.cpp
             $object['_attachments'][$attkey] = array(
                 'mimetype'=> rc_image_content_type($object['photo']),
@@ -829,7 +841,7 @@ class kolab_storage_folder
     public function move($uid, $target_folder)
     {
         if ($msguid = $this->cache->uid2msguid($uid)) {
-            if ($success = $this->imap->move_message($msguid, $target_folder, $this->name)) {
+            if ($this->imap->move_message($msguid, $target_folder, $this->name)) {
                 $this->cache->move($msguid, $uid, $target_folder);
                 return true;
             }
@@ -933,10 +945,11 @@ class kolab_storage_folder
         // save object attachments as separate parts
         foreach ((array)$object['_attachments'] as $key => $att) {
             if (empty($att['content']) && !empty($att['id'])) {
+                // @TODO: use IMAP CATENATE to skip attachment fetch+push operation
                 $msguid = !empty($object['_msguid']) ? $object['_msguid'] : $object['uid'];
                 if ($is_file) {
                     $att['path'] = tempnam($temp_dir, 'rcmAttmnt');
-                    if (($fp = fopen($att['path'], 'w')) && $this->get_attachment($msguid, $att['id'], $object['_mailbox'], false, $fp)) {
+                    if (($fp = fopen($att['path'], 'w')) && $this->get_attachment($msguid, $att['id'], $object['_mailbox'], false, $fp, true)) {
                         fclose($fp);
                     }
                     else {
@@ -944,7 +957,7 @@ class kolab_storage_folder
                     }
                 }
                 else {
-                    $att['content'] = $this->get_attachment($msguid, $att['id'], $object['_mailbox']);
+                    $att['content'] = $this->get_attachment($msguid, $att['id'], $object['_mailbox'], false, null, true);
                 }
             }
 






More information about the commits mailing list