Projects
Kolab:Winterfell
roundcubemail-plugins-kolab
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 122
View file
roundcubemail-plugins-kolab.spec
Changed
@@ -41,7 +41,7 @@ %global dash_rel_suffix %{?rc_rel_suffix:-%{rc_rel_suffix}} Name: roundcubemail-plugins-kolab -Version: 3.4.6 +Version: 3.5.0 Release: 1%{?dot_rel_suffix}%{?dist} @@ -2792,6 +2792,9 @@ %defattr(-,root,root,-) %changelog +* Mon Jul 1 2019 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 3.5.0-1 +- Release of version 3.5.0 + * Mon Jun 3 2019 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 3.4.6-1 - Release of version 3.4.6
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +roundcubemail-plugins-kolab (1:3.5.0-0~kolab1) unstable; urgency=low + + * Release of version 3.5.0 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Mon, 1 Jul 2019 11:11:11 +0200 + roundcubemail-plugins-kolab (1:3.4.6-0~kolab2) unstable; urgency=low * Release of version 3.4.6
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_mongodb.php
Deleted
@@ -1,561 +0,0 @@ -<?php - -/** - * Kolab storage cache class providing a local caching layer for Kolab groupware objects. - * - * @version @package_version@ - * @author Thomas Bruederli <bruederli@kolabsys.com> - * - * Copyright (C) 2012, Kolab Systems AG <contact@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/>. - */ - -class kolab_storage_cache_mongodb -{ - private $db; - private $imap; - private $folder; - private $uid2msg; - private $objects; - private $index = array(); - private $resource_uri; - private $enabled = true; - private $synched = false; - private $synclock = false; - private $ready = false; - private $max_sql_packet = 1046576; // 1 MB - 2000 bytes - private $binary_cols = array('photo','pgppublickey','pkcs7publickey'); - - - /** - * Default constructor - */ - public function __construct(kolab_storage_folder $storage_folder = null) - { - $rcmail = rcube::get_instance(); - $mongo = new Mongo(); - $this->db = $mongo->kolab_cache; - $this->imap = $rcmail->get_storage(); - $this->enabled = $rcmail->config->get('kolab_cache', false); - - if ($this->enabled) { - // remove sync-lock on script termination - $rcmail->add_shutdown_function(array($this, '_sync_unlock')); - } - - if ($storage_folder) - $this->set_folder($storage_folder); - } - - - /** - * Connect cache with a storage folder - * - * @param kolab_storage_folder The storage folder instance to connect with - */ - public function set_folder(kolab_storage_folder $storage_folder) - { - $this->folder = $storage_folder; - - if (empty($this->folder->name)) { - $this->ready = false; - return; - } - - // compose fully qualified ressource uri for this instance - $this->resource_uri = $this->folder->get_resource_uri(); - $this->ready = $this->enabled; - } - - - /** - * Synchronize local cache data with remote - */ - public function synchronize() - { - // only sync once per request cycle - if ($this->synched) - return; - - // increase time limit - @set_time_limit(500); - - // lock synchronization for this folder or wait if locked - $this->_sync_lock(); - - // synchronize IMAP mailbox cache - $this->imap->folder_sync($this->folder->name); - - // compare IMAP index with object cache index - $imap_index = $this->imap->index($this->folder->name); - $this->index = $imap_index->get(); - - // determine objects to fetch or to invalidate - if ($this->ready) { - // read cache index - $old_index = array(); - $cursor = $this->db->cache->find(array('resource' => $this->resource_uri), array('msguid' => 1, 'uid' => 1)); - foreach ($cursor as $doc) { - $old_index[] = $doc['msguid']; - $this->uid2msg[$doc['uid']] = $doc['msguid']; - } - - // fetch new objects from imap - foreach (array_diff($this->index, $old_index) as $msguid) { - if ($object = $this->folder->read_object($msguid, '*')) { - try { - $this->db->cache->insert($this->_serialize($object, $msguid)); - } - catch (Exception $e) { - rcmail::raise_error(array( - 'code' => 900, 'type' => 'php', - 'message' => "Failed to write to mongodb cache: " . $e->getMessage(), - ), true); - } - } - } - - // delete invalid entries from local DB - $del_index = array_diff($old_index, $this->index); - if (!empty($del_index)) { - $this->db->cache->remove(array('resource' => $this->resource_uri, 'msguid' => array('$in' => $del_index))); - } - } - - // remove lock - $this->_sync_unlock(); - - $this->synched = time(); - } - - - /** - * Read a single entry from cache or from IMAP directly - * - * @param string Related IMAP message UID - * @param string Object type to read - * @param string IMAP folder name the entry relates to - * @param array Hash array with object properties or null if not found - */ - public function get($msguid, $type = null, $foldername = null) - { - // delegate to another cache instance - if ($foldername && $foldername != $this->folder->name) { - return kolab_storage::get_folder($foldername)->cache->get($msguid, $object); - } - - // load object if not in memory - if (!isset($this->objects[$msguid])) { - if ($this->ready && ($doc = $this->db->cache->findOne(array('resource' => $this->resource_uri, 'msguid' => $msguid)))) - $this->objects[$msguid] = $this->_unserialize($doc); - - // fetch from IMAP if not present in cache - if (empty($this->objects[$msguid])) { - $result = $this->_fetch(array($msguid), $type, $foldername); - $this->objects[$msguid] = $result[0]; - } - } - - return $this->objects[$msguid]; - } - - - /** - * Insert/Update a cache entry - * - * @param string Related IMAP message UID - * @param mixed Hash array with object properties to save or false to delete the cache entry - * @param string IMAP folder name the entry relates to - */ - public function set($msguid, $object, $foldername = null) - { - // delegate to another cache instance - if ($foldername && $foldername != $this->folder->name) { - kolab_storage::get_folder($foldername)->cache->set($msguid, $object); - return; - } - - // write to cache - if ($this->ready) { - // remove old entry - $this->db->cache->remove(array('resource' => $this->resource_uri, 'msguid' => $msguid)); - - // write new object data if not false (wich means deleted) - if ($object) { - try { - $this->db->cache->insert($this->_serialize($object, $msguid)); - } - catch (Exception $e) { - rcmail::raise_error(array( - 'code' => 900, 'type' => 'php', - 'message' => "Failed to write to mongodb cache: " . $e->getMessage(), - ), true); - } - } - } - - // keep a copy in memory for fast access - $this->objects[$msguid] = $object; - - if ($object) - $this->uid2msg[$object['uid']] = $msguid; - } - - /** - * Move an existing cache entry to a new resource - * - * @param string Entry's IMAP message UID - * @param string Entry's Object UID - * @param string Target IMAP folder to move it to - */ - public function move($msguid, $objuid, $target_folder) - { - $target = kolab_storage::get_folder($target_folder); - - // resolve new message UID in target folder - if ($new_msguid = $target->cache->uid2msguid($objuid)) { -/* - $this->db->query( - "UPDATE kolab_cache SET resource=?, msguid=? ". - "WHERE resource=? AND msguid=? AND type<>?", - $target->get_resource_uri(), - $new_msguid, - $this->resource_uri, - $msguid, - 'lock' - ); -*/ - } - else { - // just clear cache entry - $this->set($msguid, false); - } - - unset($this->uid2msg[$uid]); - } - - - /** - * Remove all objects from local cache - */ - public function purge($type = null) - { - return $this->db->cache->remove(array(), array('safe' => true)); - } - - - /** - * Select Kolab objects filtered by the given query - * - * @param array Pseudo-SQL query as list of filter parameter triplets - * triplet: array('<colname>', '<comparator>', '<value>') - * @return array List of Kolab data objects (each represented as hash array) - */ - public function select($query = array()) - { - $result = array(); - - // read from local cache DB (assume it to be synchronized) - if ($this->ready) { - $cursor = $this->db->cache->find(array('resource' => $this->resource_uri) + $this->_mongo_filter($query)); - foreach ($cursor as $doc) { - if ($object = $this->_unserialize($doc)) - $result[] = $object; - } - } - else { - // extract object type from query parameter - $filter = $this->_query2assoc($query); - - // use 'list' for folder's default objects - if ($filter['type'] == $this->type) { - $index = $this->index; - } - else { // search by object type - $search = 'UNDELETED HEADER X-Kolab-Type ' . kolab_storage_folder::KTYPE_PREFIX . $filter['type']; - $index = $this->imap->search_once($this->folder->name, $search)->get(); - } - - // fetch all messages in $index from IMAP - $result = $this->_fetch($index, $filter['type']); - - // TODO: post-filter result according to query - } - - return $result; - } - - - /** - * Get number of objects mathing the given query - * - * @param array $query Pseudo-SQL query as list of filter parameter triplets - * @return integer The number of objects of the given type - */ - public function count($query = array()) - { - $count = 0; - - // cache is in sync, we can count records in local DB - if ($this->synched) { - $cursor = $this->db->cache->find(array('resource' => $this->resource_uri) + $this->_mongo_filter($query)); - $count = $cursor->valid() ? $cursor->count() : 0; - } - else { - // search IMAP by object type - $filter = $this->_query2assoc($query); - $ctype = kolab_storage_folder::KTYPE_PREFIX . $filter['type']; - $index = $this->imap->search_once($this->folder->name, 'UNDELETED HEADER X-Kolab-Type ' . $ctype); - $count = $index->count(); - } - - return $count; - } - - /** - * Helper method to convert the pseudo-SQL query into a valid mongodb filter - */ - private function _mongo_filter($query) - { - $filters = array(); - foreach ($query as $param) { - $filter = array(); - if ($param[1] == '=' && is_array($param[2])) { - $filter[$param[0]] = array('$in' => $param[2]); - $filters[] = $filter; - } - else if ($param[1] == '=') { - $filters[] = array($param[0] => $param[2]); - } - else if ($param[1] == 'LIKE' || $param[1] == '~') { - $filter[$param[0]] = array('$regex' => preg_quote($param[2]), '$options' => 'i'); - $filters[] = $filter; - } - else if ($param[1] == '!~' || $param[1] == '!LIKE') { - $filter[$param[0]] = array('$not' => '/' . preg_quote($param[2]) . '/i'); - $filters[] = $filter; - } - else { - $op = ''; - switch ($param[1]) { - case '>': $op = '$gt'; break; - case '>=': $op = '$gte'; break; - case '<': $op = '$lt'; break; - case '<=': $op = '$lte'; break; - case '!=': - case '<>': $op = '$gte'; break; - } - if ($op) { - $filter[$param[0]] = array($op => $param[2]); - $filters[] = $filter; - } - } - } - - return array('$and' => $filters); - } - - /** - * Helper method to convert the given pseudo-query triplets into - * an associative filter array with 'equals' values only - */ - private function _query2assoc($query) - { - // extract object type from query parameter - $filter = array(); - foreach ($query as $param) { - if ($param[1] == '=') - $filter[$param[0]] = $param[2]; - } - return $filter; - } - - /** - * Fetch messages from IMAP - * - * @param array List of message UIDs to fetch - * @return array List of parsed Kolab objects - */ - private function _fetch($index, $type = null, $folder = null) - { - $results = array(); - foreach ((array)$index as $msguid) { - if ($object = $this->folder->read_object($msguid, $type, $folder)) { - $results[] = $object; - $this->set($msguid, $object); - } - } - - return $results; - } - - - /** - * Helper method to convert the given Kolab object into a dataset to be written to cache - */ - private function _serialize($object, $msguid) - { - $bincols = array_flip($this->binary_cols); - $doc = array( - 'resource' => $this->resource_uri, - 'type' => $object['_type'] ? $object['_type'] : $this->folder->type, - 'msguid' => $msguid, - 'uid' => $object['uid'], - 'xml' => '', - 'tags' => array(), - 'words' => array(), - 'objcols' => array(), - ); - - // set type specific values - if ($this->folder->type == 'event') { - // database runs in server's timezone so using date() is what we want - $doc['dtstart'] = date('Y-m-d H:i:s', is_object($object['start']) ? $object['start']->format('U') : $object['start']); - $doc['dtend'] = date('Y-m-d H:i:s', is_object($object['end']) ? $object['end']->format('U') : $object['end']); - - // extend date range for recurring events - if ($object['recurrence']) { - $doc['dtend'] = date('Y-m-d H:i:s', $object['recurrence']['UNTIL'] ?: strtotime('now + 2 years')); - } - } - - if ($object['_formatobj']) { - $doc['xml'] = preg_replace('!(</?[a-z0-9:-]+>)[\n\r\t\s]+!ms', '$1', (string)$object['_formatobj']->write()); - $doc['tags'] = $object['_formatobj']->get_tags(); - $doc['words'] = $object['_formatobj']->get_words(); - } - - // extract object data - $data = array(); - foreach ($object as $key => $val) { - if ($val === "" || $val === null) { - // skip empty properties - continue; - } - if (isset($bincols[$key])) { - $data[$key] = base64_encode($val); - } - else if (is_object($val)) { - if (is_a($val, 'DateTime')) { - $data[$key] = array('_class' => 'DateTime', 'date' => $val->format('Y-m-d H:i:s'), 'timezone' => $val->getTimezone()->getName()); - $doc['objcols'][] = $key; - } - } - else if ($key[0] != '_') { - $data[$key] = $val; - } - else if ($key == '_attachments') { - foreach ($val as $k => $att) { - unset($att['content'], $att['path']); - if ($att['id']) - $data[$key][$k] = $att; - } - } - } - - $doc['data'] = $data; - return $doc; - } - - /** - * Helper method to turn stored cache data into a valid storage object - */ - private function _unserialize($doc) - { - $object = $doc['data']; - - // decode binary properties - foreach ($this->binary_cols as $key) { - if (!empty($object[$key])) - $object[$key] = base64_decode($object[$key]); - } - - // restore serialized objects - foreach ((array)$doc['objcols'] as $key) { - switch ($object[$key]['_class']) { - case 'DateTime': - $val = new DateTime($object[$key]['date'], new DateTimeZone($object[$key]['timezone'])); - $object[$key] = $val; - break; - } - } - - // add meta data - $object['_type'] = $doc['type']; - $object['_msguid'] = $doc['msguid']; - $object['_mailbox'] = $this->folder->name; - $object['_formatobj'] = kolab_format::factory($doc['type'], $doc['xml']); - - return $object; - } - - /** - * Check lock record for this folder and wait if locked or set lock - */ - private function _sync_lock() - { - if (!$this->ready) - return; - - $this->synclock = true; - $lock = $this->db->locks->findOne(array('resource' => $this->resource_uri)); - - // create lock record if not exists - if (!$lock) { - $this->db->locks->insert(array('resource' => $this->resource_uri, 'created' => time())); - } - // wait if locked (expire locks after 10 minutes) - else if ((time() - $lock['created']) < 600) { - usleep(500000); - return $this->_sync_lock(); - } - // set lock - else { - $lock['created'] = time(); - $this->db->locks->update(array('_id' => $lock['_id']), $lock, array('safe' => true)); - } - } - - /** - * Remove lock for this folder - */ - public function _sync_unlock() - { - if (!$this->ready || !$this->synclock) - return; - - $this->db->locks->remove(array('resource' => $this->resource_uri)); - } - - /** - * Resolve an object UID into an IMAP message UID - * - * @param string Kolab object UID - * @param boolean Include deleted objects - * @return int The resolved IMAP message UID - */ - public function uid2msguid($uid, $deleted = false) - { - 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 ' . $uid); - $results = $index->get(); - $this->uid2msg[$uid] = $results[0]; - } - - return $this->uid2msg[$uid]; - } - -}
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/calendar/calendar_ui.js -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/calendar/calendar_ui.js
Changed
@@ -3096,9 +3096,10 @@ $('#event-export-calendar').val(calendar.id); $('#event-export-range').change(function(e){ - var custom = $('option:selected', this).val() == 'custom', - input = $('#event-export-startdate') - input.parent()[(custom?'show':'hide')](); + var custom = $(this).val() == 'custom', input = $('#event-export-startdate'); + + $(this)[custom ? 'removeClass' : 'addClass']('rounded-right'); // Elastic/Bootstrap + input[custom ? 'show' : 'hide'](); if (custom) input.select(); }) @@ -3109,8 +3110,8 @@ 'class': 'mainaction export', click: function() { if (form) { - var start = 0, range = $('#event-export-range option:selected', this).val(), - source = $('#event-export-calendar option:selected').val(), + var start = 0, range = $('#event-export-range', this).val(), + source = $('#event-export-calendar').val(), attachmt = $('#event-export-attachments').get(0).checked; if (range == 'custom')
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/calendar/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/calendar/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Calendar plugin", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.6", + "version": "3.5.0", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/calendar/lib/calendar_ui.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/calendar/lib/calendar_ui.php
Changed
@@ -571,7 +571,7 @@ html::label(array('for' => 'event-export-calendar', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('calendar')) . html::div('col-sm-8', $this->calendar_select(array('name' => 'calendar', 'id' => 'event-export-calendar', 'class' => 'form-control custom-select')))); - $select = new html_select(array('name' => 'range', 'id' => 'event-export-range', 'class' => 'form-control custom-select')); + $select = new html_select(array('name' => 'range', 'id' => 'event-export-range', 'class' => 'form-control custom-select rounded-right')); $select->add(array( $this->cal->gettext('all'), $this->cal->gettext('onemonthback'), @@ -583,11 +583,11 @@ ), array(0,'1','2','3','6','12','custom')); - $startdate = new html_inputfield(array('name' => 'start', 'size' => 11, 'id' => 'event-export-startdate')); + $startdate = new html_inputfield(array('name' => 'start', 'size' => 11, 'id' => 'event-export-startdate', 'style' => 'display:none')); $html .= html::div('form-section form-group row', html::label(array('for' => 'event-export-range', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('exportrange')) - . html::div('col-sm-8', $select->show(0) . html::span(array('style'=>'display:none'), $startdate->show()))); + . html::div('col-sm-8 input-group', $select->show(0) . $startdate->show())); $checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'event-export-attachments', 'value' => 1, 'class' => 'form-check-input pretty-checkbox')); $html .= html::div('form-section form-check row',
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_2fa/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_2fa/composer.json
Changed
@@ -4,12 +4,17 @@ "description": "Kolab 2-Factor Authentication", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.5", + "version": "3.5.0", "authors": [ { "name": "Thomas Bruederli", "email": "bruederli@kolabsys.com", "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Developer" } ], "repositories": [ @@ -22,7 +27,7 @@ "php": ">=5.3.0", "roundcube/plugin-installer": ">=0.1.3", "spomky-labs/otphp": "~5.0.0", - "endroid/qrcode": "~1.5.0", + "endroid/qr-code": "~1.6.5", "enygma/yubikey": "~3.2" } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_activesync/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_activesync/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "ActiveSync configuration utility for Kolab accounts", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.5", + "version": "3.5.0", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_activesync/kolab_activesync.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_activesync/kolab_activesync.php
Changed
@@ -45,7 +45,6 @@ { $this->rc = rcube::get_instance(); - $this->require_plugin('jqueryui'); $this->require_plugin('libkolab'); $this->register_action('plugin.activesync', array($this, 'config_view'));
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_activesync/kolab_activesync_ui.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_activesync/kolab_activesync_ui.php
Changed
@@ -203,7 +203,9 @@ $classes = array('mailbox'); if ($folder_class = $this->rc->folder_classname($folder)) { - $foldername = html::quote($this->rc->gettext($folder_class)); + if ($this->rc->text_exists($folder_class)) { + $foldername = html::quote($this->rc->gettext($folder_class)); + } $classes[] = $folder_class; }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
Changed
@@ -325,7 +325,9 @@ public function list_records($cols = null, $subset = 0, $nocount = false) { $this->result = new rcube_result_set(0, ($this->list_page-1) * $this->page_size); + $fetch_all = false; + $fast_mode = !empty($cols) && is_array($cols); // list member of the selected group if ($this->gid) { @@ -355,7 +357,7 @@ // get members by UID if (!empty($uids)) { - $this->_fetch_contacts($query = array(array('uid', '=', $uids)), $fetch_all ? false : count($uids)); + $this->_fetch_contacts($query = array(array('uid', '=', $uids)), $fetch_all ? false : count($uids), $fast_mode); $this->sortindex = array_merge($this->sortindex, $local_sortindex); } } @@ -363,11 +365,11 @@ $ids = $this->filter['ids']; if (count($ids)) { $uids = array_map(array($this, 'id2uid'), $this->filter['ids']); - $this->_fetch_contacts($query = array(array('uid', '=', $uids)), count($ids)); + $this->_fetch_contacts($query = array(array('uid', '=', $uids)), count($ids), $fast_mode); } } else { - $this->_fetch_contacts($query = 'contact', true); + $this->_fetch_contacts($query = 'contact', true, $fast_mode); } if ($fetch_all) { @@ -1062,7 +1064,7 @@ /** * Query storage layer and store records in private member var */ - private function _fetch_contacts($query = array(), $limit = false) + private function _fetch_contacts($query = array(), $limit = false, $fast_mode = false) { if (!isset($this->dataset) || !empty($query)) { if ($limit) { @@ -1071,7 +1073,7 @@ } $this->sortindex = array(); - $this->dataset = $this->storagefolder->select($query); + $this->dataset = $this->storagefolder->select($query, $fast_mode); foreach ($this->dataset as $idx => $record) { $contact = $this->_to_rcube_contact($record); @@ -1137,7 +1139,7 @@ { if (!isset($this->distlists)) { $this->distlists = $this->groupmembers = array(); - foreach ($this->storagefolder->select('distribution-list') as $record) { + foreach ($this->storagefolder->select('distribution-list', true) as $record) { $record['ID'] = $this->uid2id($record['uid']); foreach ((array)$record['member'] as $i => $member) { $mid = $this->uid2id($member['uid'] ? $member['uid'] : 'mailto:' . $member['email']); @@ -1145,8 +1147,9 @@ $record['member'][$i]['readonly'] = empty($member['uid']); $this->groupmembers[$mid][] = $record['ID']; - if ($with_contacts && empty($member['uid'])) + if ($with_contacts && empty($member['uid'])) { $this->contacts[$mid] = $record['member'][$i]; + } } $this->distlists[$record['ID']] = $record; }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_delegation/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_delegation/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Kolab delegation feature", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.5", + "version": "3.5.0", "authors": [ { "name": "Aleksander Machniak",
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_delegation/kolab_delegation.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_delegation/kolab_delegation.php
Changed
@@ -581,7 +581,9 @@ $classes = array('mailbox'); if ($folder_class = $this->rc->folder_classname($folder)) { - $foldername = html::quote($this->rc->gettext($folder_class)); + if ($this->rc->text_exists($folder_class)) { + $foldername = html::quote($this->rc->gettext($folder_class)); + } $classes[] = $folder_class; }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_files/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_files/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "User interface for Kolab File Manager (Chwala)", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.5", + "version": "3.5.0", "authors": [ { "name": "Aleksander Machniak",
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_files/kolab_files.js -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_files/kolab_files.js
Changed
@@ -245,7 +245,7 @@ $.extend(editor_config, { // notifications/alerts - gettext: function(label) { return rcmail.get_label('kolab_files.' + label); }, + gettext: function(label) { return rcmail.get_label(label, 'kolab_files'); }, set_busy: function(state, message) { return rcmail.set_busy(state, message ? 'kolab_files.' + message : ''); }, hide_message: function(id) { return rcmail.hide_message(id); }, display_message: function(label, type, is_txt, timeout) { @@ -1487,11 +1487,28 @@ // close editing session rcube_webmail.prototype.document_close = function() { + var delete_fn = function() { + document_editor.terminate(function() { + var win = window.opener || window.parent; + + if (win && win.rcmail && win.file_api) + win.file_api.document_delete(rcmail.env.file_data.session.id); + + // For Elastic: hide the parent dialog + if (rcmail.is_framed()) { + parent.$('.ui-dialog:visible button.cancel').click(); + } + + window.close(); + }); + }; + // check document "unsaved changes" state and display a warning - if (this.commands['document-save']) - this.confirm_dialog(this.gettext('kolab_files.unsavedchanges'), 'kolab_files.terminate', function() { - file_api.document_delete(rcmail.env.file_data.session.id); - }, {button_class: 'delete'}); + // skip the warning for WOPI, Collabora will save the document anyway on session close + if (this.commands['document-save'] && (!this.env.file_data.viewer || !this.env.file_data.viewer.wopi)) + this.confirm_dialog(this.gettext('kolab_files.unsavedchanges'), 'kolab_files.terminate', delete_fn, {button_class: 'delete'}); + else + delete_fn(); }; // document editors management dialog @@ -2264,6 +2281,9 @@ list.append(rows).appendTo(elem) .on('click', 'a.subscription', function(e) { return file_api.folder_list_subscription_button_click(this); + }) + .on('mouseover', 'a.name', function() { + rcube_webmail.long_subject_title_ex(this); }); if (rcmail.env.contextmenu) @@ -2926,7 +2946,10 @@ .on('click', function() { file_api.sharing_delete(post.folder, $(this).closest('tr'), post.mode); }); if (form_info.list_column) { - row.append($('<td>').append($('<span class="name">').text(post[form_info.list_column]))); + row.append($('<td>').append($('<span class="name">') + .text(response.result.display || post[form_info.list_column]) + .attr('title', response.result.title)) + ); } else { $.each(form_info.form || [], function(i, v) { @@ -2942,7 +2965,7 @@ content.append(opts).val(post[i]); } else { - content = $('<span class="name">').text(post[i]); + content = $('<span class="name">').text(response.result.display || post[i]).attr('title', response.result.title); hidden.push($('<input>').attr({type: 'hidden', name: i, value: post[i] || ''})); } @@ -4083,43 +4106,25 @@ this.document_delete = function(id) { this.req = this.set_busy(true, 'kolab_files.sessionterminating'); - this.deleted_session = id; this.request('document_delete', {id: id}, 'document_delete_response'); }; // document session delete response handler - this.document_delete_response = function(response) + this.document_delete_response = function(response, params) { if (!this.response(response)) return; - if (rcmail.task == 'files' && rcmail.env.action == 'edit') { - if (document_editor && document_editor.terminate) - document_editor.terminate(); - // use timeout to have a chance to properly propagate termination request - setTimeout(function() { window.close(); }, 500); - } - - // @todo: force sessions info update - - var win = window, list = rcmail.sessionslist; - - if (!list) { - win = window.opener || window.parent; - if (win && win.rcmail && win.file_api) - list = win.rcmail.sessionslist; - } + var list = rcmail.sessionslist; // remove session from the list (if sessions list exist) if (list) - list.remove_row(this.deleted_session); - if (win && win.file_api && win.file_api.env.sessions_list) - delete win.file_api.env.sessions_list[this.deleted_session]; - - // For Elastic: hide the parent dialog - if (rcmail.is_framed()) { - parent.$('.ui-dialog:visible button.cancel').click(); - } + list.remove_row(params.id); + + if (this.env.sessions_list) + delete this.env.sessions_list[params.id]; + + // @todo: force sessions info update, update files list }; // Invite document session participants
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_files/lib/kolab_files_engine.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_files/lib/kolab_files_engine.php
Changed
@@ -106,7 +106,7 @@ $this->get_external_storage_drivers(); // these labels may be needed even if fetching ext sources failed - $this->plugin->add_label('folderauthtitle', 'authenticating', 'foldershare'); + $this->plugin->add_label('folderauthtitle', 'authenticating', 'foldershare', 'saving'); } if ($list_widget) { @@ -149,7 +149,7 @@ 'more', 'accept', 'decline', 'join', 'status', 'when', 'file', 'comment', 'statusaccepted', 'statusinvited', 'statusdeclined', 'statusrequested', 'invitationaccepting', 'invitationdeclining', 'invitationrequesting', - 'close', 'invitationtitle', 'sessions'); + 'close', 'invitationtitle', 'sessions', 'saving'); } if (!empty($templates)) { @@ -450,7 +450,7 @@ foreach ((array) $info['rights'] as $entry) { if ($entry['mode'] == $mode) { if (!empty($tab['list_column'])) { - $table->add(null, html::span('name', rcube::Q($entry[$tab['list_column']]))); + $table->add(null, html::span(array('title' => $entry['title'], 'class' => 'name'), rcube::Q($entry[$tab['list_column']]))); } else { foreach ($tab['form'] as $index => $field) { @@ -458,7 +458,7 @@ $table->add(null, $fields[$index]->show($entry[$index])); } else if ($fields[$index] instanceof html_inputfield) { - $table->add(null, html::span('name', rcube::Q($entry[$index]))); + $table->add(null, html::span(array('title' => $entry['title'], 'class' => 'name'), rcube::Q($entry[$index]))); } } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_files/localization/en_US.inc -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_files/localization/en_US.inc
Changed
@@ -61,6 +61,7 @@ $labels['submit'] = 'Submit'; $labels['confirmpassword'] = 'Confirm password'; $labels['passwordconflict'] = 'Passwords do not match'; +$labels['saving'] = 'Saving...'; $labels['collection_audio'] = 'Audio'; $labels['collection_video'] = 'Video';
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_files/skins/elastic/ui.js -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_files/skins/elastic/ui.js
Changed
@@ -124,12 +124,20 @@ } else { rcmail.addEventListener('files-folder-select', function(p) { - var is_sess = p.folder == 'folder-collection-sessions'; + var fname, is_sess = p.folder == 'folder-collection-sessions'; + $('#fileslistmenu-link, #layout-content > .pagenav, #layout-content .searchbar')[is_sess ? 'hide' : 'show'](); $('#sessionslistmenu-link')[is_sess ? 'removeClass' : 'addClass']('hidden'); - // set list header title for mobile - // $('#layout-content > .header > .header-title').text($('#files-folder-list li.selected a.name:first').text()); + if (is_sess) + fname = rcmail.gettext('kolab_files.sessions'); + else if (p.folder.match(/^folder-collection-([a-z]+)$/)) + fname = rcmail.gettext('kolab_files.collection_' + RegExp.$1); + else + fname = p.folder.split(file_api.env.directory_separator).pop(); + + // jump to files list and set list header title for mobile + rcmail.triggerEvent('show-content', {title: fname}); }); }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_folders/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_folders/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Type-aware folder management/listing for Kolab", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.0", + "version": "3.5.0", "authors": [ { "name": "Aleksander Machniak",
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_folders/kolab_folders.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_folders/kolab_folders.php
Changed
@@ -72,6 +72,11 @@ // ACL plugin hooks $this->add_hook('acl_rights_simple', array($this, 'acl_rights_simple')); $this->add_hook('acl_rights_supported', array($this, 'acl_rights_supported')); + + // Resolving other user folder names + $this->add_hook('render_mailboxlist', array($this, 'render_folderlist')); + $this->add_hook('render_folder_selector', array($this, 'render_folderlist')); + $this->add_hook('folders_list', array($this, 'render_folderlist')); } /** @@ -709,6 +714,7 @@ * Static getter for default folder of the given type * * @param string $type Folder type + * * @return string Folder name */ public static function default_folder($type) @@ -781,4 +787,65 @@ ); } } + + /** + * Handler for various folders list widgets (hooks) + * + * @param array $args Hash array with hook parameters + * + * @return array Hash array with modified hook parameters + */ + public function render_folderlist($args) + { + $storage = $this->rc->get_storage(); + $ns_other = $storage->get_namespace('other'); + $is_fl = $this->rc->plugins->is_processing('folders_list'); + + foreach ((array) $ns_other as $root) { + $delim = $root[1]; + $prefix = rtrim($root[0], $delim); + $length = strlen($prefix); + + if (!$length) { + continue; + } + + // folders_list hook mode + if ($is_fl) { + foreach ((array) $args['list'] as $folder_name => $folder) { + if (strpos($folder_name, $root[0]) === 0 && !substr_count($folder_name, $root[1], $length+1)) { + if ($name = kolab_storage::folder_id2user(substr($folder_name, $length+1), true)) { + $old = $args['list'][$folder_name]['display']; + $content = $args['list'][$folder_name]['content']; + + $name = rcube::Q($name); + $content = str_replace(">$old<", ">$name<", $content); + + $args['list'][$folder_name]['display'] = $name; + $args['list'][$folder_name]['content'] = $content; + } + } + } + + // TODO: Re-sort the list + } + // render_* hooks mode + else if (!empty($args['list'][$prefix]) && !empty($args['list'][$prefix]['folders'])) { + $map = array(); + foreach ($args['list'][$prefix]['folders'] as $folder_name => $folder) { + if ($name = kolab_storage::folder_id2user($folder_name, true)) { + $args['list'][$prefix]['folders'][$folder_name]['name'] = $name; + } + + $map[$folder_name] = $name ?: $args['list'][$prefix]['folders'][$folder_name]['name']; + } + + // Re-sort the list + uasort($map, 'strcoll'); + $args['list'][$prefix]['folders'] = array_replace($map, $args['list'][$prefix]['folders']); + } + } + + return $args; + } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_notes/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_notes/composer.json
Changed
@@ -4,12 +4,17 @@ "description": "Notes module for Roundcube connecting to a Kolab server for storage", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.5", + "version": "3.5.0", "authors": [ { "name": "Thomas Bruederli", "email": "bruederli@kolabsys.com", "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Developer" } ], "repositories": [ @@ -21,7 +26,6 @@ "require": { "php": ">=5.3.0", "roundcube/plugin-installer": ">=0.1.3", - "kolab/libkolab": ">=3.4.0", - "roundcube/jqueryui": ">=1.10.4" + "kolab/libkolab": ">=3.4.0" } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/kolab_notes/kolab_notes.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/kolab_notes/kolab_notes.php
Changed
@@ -480,7 +480,7 @@ $this->_read_lists(); if ($folder = $this->get_folder($list_id)) { - foreach ($folder->select($query) as $record) { + foreach ($folder->select($query, empty($query)) as $record) { // post-filter search results if (strlen($search)) { $matches = 0;
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libcalendaring/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libcalendaring/composer.json
Changed
@@ -4,12 +4,17 @@ "description": "Library providing common functions for calendaring plugins", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.6", + "version": "3.5.0", "authors": [ { "name": "Thomas Bruederli", "email": "bruederli@kolabsys.com", "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Developer" } ], "repositories": [
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/SQL/mysql.initial.sql -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/SQL/mysql.initial.sql
Changed
@@ -33,7 +33,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, `type` VARCHAR(32) CHARACTER SET ascii NOT NULL, @@ -57,7 +56,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -77,7 +75,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -97,7 +94,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -117,7 +113,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, CONSTRAINT `fk_kolab_cache_note_folder` FOREIGN KEY (`folder_id`) @@ -135,7 +130,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, `filename` varchar(255) DEFAULT NULL, @@ -155,7 +149,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, `type` VARCHAR(32) CHARACTER SET ascii NOT NULL, @@ -175,7 +168,6 @@ `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` LONGTEXT NOT NULL, - `xml` LONGBLOB NOT NULL, `tags` TEXT NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -188,4 +180,4 @@ /*!40014 SET FOREIGN_KEY_CHECKS=1 */; -REPLACE INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2018021300'); +REPLACE INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2018122700');
View file
roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/SQL/mysql/2018122700.sql
Added
@@ -0,0 +1,10 @@ +-- remove xml column, and change data format (clear cache needed) +DELETE FROM `kolab_folders`; +ALTER TABLE `kolab_cache_contact` DROP COLUMN `xml`; +ALTER TABLE `kolab_cache_event` DROP COLUMN `xml`; +ALTER TABLE `kolab_cache_task` DROP COLUMN `xml`; +ALTER TABLE `kolab_cache_journal` DROP COLUMN `xml`; +ALTER TABLE `kolab_cache_note` DROP COLUMN `xml`; +ALTER TABLE `kolab_cache_file` DROP COLUMN `xml`; +ALTER TABLE `kolab_cache_configuration` DROP COLUMN `xml`; +ALTER TABLE `kolab_cache_freebusy` DROP COLUMN `xml`;
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/SQL/oracle.initial.sql -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/SQL/oracle.initial.sql
Changed
@@ -37,7 +37,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, "type" varchar(32) NOT NULL, @@ -60,7 +59,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, "dtstart" timestamp DEFAULT NULL, @@ -79,7 +77,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, "dtstart" timestamp DEFAULT NULL, @@ -98,7 +95,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, "dtstart" timestamp DEFAULT NULL, @@ -117,7 +113,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, PRIMARY KEY ("folder_id", "msguid") @@ -134,7 +129,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, "filename" varchar(255) DEFAULT NULL, @@ -153,7 +147,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, "type" varchar(32) NOT NULL, @@ -172,7 +165,6 @@ "created" timestamp DEFAULT NULL, "changed" timestamp DEFAULT NULL, "data" clob NOT NULL, - "xml" clob NOT NULL, "tags" clob DEFAULT NULL, "words" clob DEFAULT NULL, "dtstart" timestamp DEFAULT NULL, @@ -183,4 +175,4 @@ CREATE INDEX "kolab_cache_fb_uid2msguid" ON "kolab_cache_freebusy" ("folder_id", "uid", "msguid"); -INSERT INTO "system" ("name", "value") VALUES ('libkolab-version', '2018021300'); +INSERT INTO "system" ("name", "value") VALUES ('libkolab-version', '2018122700');
View file
roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/SQL/oracle/2018122700.sql
Added
@@ -0,0 +1,10 @@ +-- remove xml column, and change data format (clear cache needed) +DELETE FROM "kolab_folders"; +ALTER TABLE "kolab_cache_contact" DROP COLUMN "xml"; +ALTER TABLE "kolab_cache_event" DROP COLUMN "xml"; +ALTER TABLE "kolab_cache_task" DROP COLUMN "xml"; +ALTER TABLE "kolab_cache_journal" DROP COLUMN "xml"; +ALTER TABLE "kolab_cache_note" DROP COLUMN "xml"; +ALTER TABLE "kolab_cache_file" DROP COLUMN "xml"; +ALTER TABLE "kolab_cache_configuration" DROP COLUMN "xml"; +ALTER TABLE "kolab_cache_freebusy" DROP COLUMN "xml";
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/SQL/sqlite.initial.sql -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/SQL/sqlite.initial.sql
Changed
@@ -25,7 +25,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, type VARCHAR(32) NOT NULL, @@ -46,7 +45,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, dtstart DATETIME, @@ -63,7 +61,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, dtstart DATETIME, @@ -80,7 +77,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, dtstart DATETIME, @@ -97,7 +93,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, PRIMARY KEY(folder_id,msguid) @@ -112,7 +107,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, filename varchar(255) DEFAULT NULL, @@ -129,7 +123,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, type VARCHAR(32) NOT NULL, @@ -146,7 +139,6 @@ created DATETIME DEFAULT NULL, changed DATETIME DEFAULT NULL, data TEXT NOT NULL, - xml TEXT NOT NULL, tags TEXT NOT NULL, words TEXT NOT NULL, dtstart DATETIME, @@ -156,4 +148,4 @@ CREATE INDEX ix_freebusy_uid2msguid ON kolab_cache_freebusy(folder_id,uid,msguid); -INSERT INTO system (name, value) VALUES ('libkolab-version', '2018021300'); +INSERT INTO system (name, value) VALUES ('libkolab-version', '2018122700');
View file
roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/SQL/sqlite/2018122700.sql
Added
@@ -0,0 +1,137 @@ +DROP TABLE kolab_cache_contact; +CREATE TABLE kolab_cache_contact ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + type VARCHAR(32) NOT NULL, + name VARCHAR(255) NOT NULL, + firstname VARCHAR(255) NOT NULL, + surname VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_contact_type ON kolab_cache_contact(folder_id,type); +CREATE INDEX ix_contact_uid2msguid ON kolab_cache_contact(folder_id,uid,msguid); + +DROP TABLE kolab_cache_event; +CREATE TABLE kolab_cache_event ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + dtstart DATETIME, + dtend DATETIME, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_event_uid2msguid ON kolab_cache_event(folder_id,uid,msguid); + +DROP TABLE kolab_cache_task; +CREATE TABLE kolab_cache_task ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + dtstart DATETIME, + dtend DATETIME, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_task_uid2msguid ON kolab_cache_task(folder_id,uid,msguid); + +DROP TABLE kolab_cache_journal; +CREATE TABLE kolab_cache_journal ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + dtstart DATETIME, + dtend DATETIME, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_journal_uid2msguid ON kolab_cache_journal(folder_id,uid,msguid); + +DROP TABLE kolab_cache_note; +CREATE TABLE kolab_cache_note ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_note_uid2msguid ON kolab_cache_note(folder_id,uid,msguid); + +DROP TABLE kolab_cache_file; +CREATE TABLE kolab_cache_file ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + filename varchar(255) DEFAULT NULL, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_folder_filename ON kolab_cache_file(folder_id,filename); +CREATE INDEX ix_file_uid2msguid ON kolab_cache_file(folder_id,uid,msguid); + +DROP TABLE kolab_cache_configuration; +CREATE TABLE kolab_cache_configuration ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + type VARCHAR(32) NOT NULL, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_configuration_type ON kolab_cache_configuration(folder_id,type); +CREATE INDEX ix_configuration_uid2msguid ON kolab_cache_configuration(folder_id,uid,msguid); + +DROP TABLE kolab_cache_freebusy; +CREATE TABLE kolab_cache_freebusy ( + folder_id INTEGER NOT NULL, + msguid INTEGER NOT NULL, + uid VARCHAR(512) NOT NULL, + created DATETIME DEFAULT NULL, + changed DATETIME DEFAULT NULL, + data TEXT NOT NULL, + tags TEXT NOT NULL, + words TEXT NOT NULL, + dtstart DATETIME, + dtend DATETIME, + PRIMARY KEY(folder_id,msguid) +); + +CREATE INDEX ix_freebusy_uid2msguid ON kolab_cache_freebusy(folder_id,uid,msguid);
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Plugin to setup a basic environment for the interaction with a Kolab server.", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.6", + "version": "3.5.0", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/config.inc.php.dist -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/config.inc.php.dist
Changed
@@ -35,7 +35,8 @@ // When kolab_cache is enabled Roundcube's messages cache will be redundant // when working on kolab folders. Here we can: -// 2 - bypass messages/indexes cache completely +// 3 - bypass only indexes, but use messages cache +// 2 - bypass both messages and indexes cache // 1 - bypass only messages, but use index cache $config['kolab_messages_cache_bypass'] = 0; @@ -64,6 +65,18 @@ // Use these attributes when searching users in LDAP $config['kolab_users_search_attrib'] = array('cn','mail','alias'); +// Which property of the LDAP user record to use as a display name. +// Defaults to the 'kolab_auth_name' configuration option. +$config['kolab_users_name_field'] = null; + +// Type of cache for uid-to-user map. Supported: 'db', 'apc', 'memcache' and 'memcached'. +// Note: This stores only other user folder identifier to user attributes map. +$config['kolab_users_cache'] = null; + +// lifetime of shared folder mapping cache +// possible units: s, m, h, d, w +$config['kolab_users_cache_ttl'] = '10d'; + // JSON-RPC endpoint configuration of the Bonnie web service providing historic data for groupware objects $config['kolab_bonnie_api'] = array( 'uri' => 'https://<kolab-hostname>:8080/api/rpc',
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage.php
Changed
@@ -46,12 +46,14 @@ private static $ready = false; private static $with_tempsubs = true; private static $subscriptions; + private static $ldapcache = array(); private static $typedata = array(); private static $states; private static $config; private static $imap; private static $ldap; + // Default folder names private static $default_folders = array( 'event' => 'Calendar', @@ -354,7 +356,6 @@ return ''; } - /** * Deletes IMAP folder * @@ -421,7 +422,6 @@ return false; } - /** * Renames IMAP folder * @@ -457,7 +457,6 @@ return $success; } - /** * Rename or Create a new IMAP folder. * @@ -552,7 +551,6 @@ return $result ? $folder : false; } - /** * Getter for human-readable name of Kolab object (folder) * with kolab_custom_display_names support. @@ -637,20 +635,18 @@ if (!$found && !empty($namespace['other'])) { foreach ($namespace['other'] as $ns) { if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) { - // remove namespace prefix + // remove namespace prefix and extract username $folder = substr($folder, strlen($ns[0])); $delim = $ns[1]; - // get username - $pos = strpos($folder, $delim); - if ($pos) { - $prefix = '('.substr($folder, 0, $pos).')'; - $folder = substr($folder, $pos+1); - } - else { - $prefix = '('.$folder.')'; - $folder = ''; - } + // get username part and map it to user name + $pos = strpos($folder, $delim); + $fid = $pos ? substr($folder, 0, $pos) : $folder; + $fid = self::folder_id2user($fid, true); + $fid = str_replace($delim, '', $fid); + + $prefix = "($fid)"; + $folder = $pos ? substr($folder, $pos + 1) : ''; $found = true; $folder_ns = 'other'; break; @@ -729,7 +725,6 @@ return $name; } - /** * Creates a SELECT field with folders list * @@ -812,7 +807,6 @@ return $select; } - /** * Returns a list of folder names * @@ -976,7 +970,6 @@ return $folders; } - /** * Sort the given list of kolab folders by namespace/name * @@ -1006,7 +999,6 @@ return $out; } - /** * Check the folder tree and add the missing parents as virtual folders * @@ -1082,7 +1074,6 @@ return $_folders; } - /** * Returns folder types indexed by folder name * @@ -1149,7 +1140,6 @@ return self::$typedata[$prefix]; } - /** * Callback for array_map to select the correct annotation value */ @@ -1165,7 +1155,6 @@ return null; } - /** * Returns type of IMAP folder * @@ -1197,7 +1186,6 @@ return 'mail'; } - /** * Sets folder content-type. * @@ -1220,7 +1208,6 @@ return $success; } - /** * Check subscription status of this folder * @@ -1242,7 +1229,6 @@ ($temp && in_array($folder, (array)$_SESSION['kolab_subscribed_folders'])); } - /** * Change subscription status of this folder * @@ -1273,7 +1259,6 @@ return false; } - /** * Change subscription status of this folder * @@ -1301,7 +1286,6 @@ return false; } - /** * Check activation status of this folder * @@ -1316,7 +1300,6 @@ return in_array($folder, $active_folders); } - /** * Change activation status of this folder * @@ -1331,7 +1314,6 @@ return self::set_state($folder, true); } - /** * Change activation status of this folder * @@ -1347,7 +1329,6 @@ return self::set_state($folder, false); } - /** * Return list of active folders */ @@ -1379,7 +1360,6 @@ return self::$states; } - /** * Update list of active folders */ @@ -1504,7 +1484,6 @@ } } - /** * * @param mixed $query Search value (or array of field => value pairs) @@ -1544,7 +1523,6 @@ return $results; } - /** * Returns a list of IMAP folders shared by the given user * @@ -1584,7 +1562,6 @@ return $folders; } - /** * Get a list of (virtual) top-level folders from the other users namespace * @@ -1635,7 +1612,6 @@ return $folders; } - /** * Handler for user_delete plugin hooks * @@ -1673,4 +1649,142 @@ return $metadata[$folder]; } } + + /** + * Get user attributes for specified other user (imap) folder identifier. + * Note: This uses LDAP config/code from kolab_auth. + * + * @param string $folder_id Folder name w/o path (imap user identifier) + * @param bool $as_string Return configured display name attribute value + * + * @return array User attributes + * @see self::ldap() + */ + public static function folder_id2user($folder_id, $as_string = false) + { + static $domain, $cache, $name_attr; + + $rcube = rcube::get_instance(); + + if ($domain === null) { + list(, $domain) = explode('@', $rcube->get_user_name()); + } + + if ($name_attr === null) { + $name_attr = (array) ($rcube->config->get('kolab_users_name_field', $rcube->config->get('kolab_auth_name')) ?: 'name'); + } + + $token = $folder_id; + if ($domain && strpos($find, '@') === false) { + $token .= '@' . $domain; + } + + if ($cache === null) { + $cache = $rcube->get_cache_shared('kolab_users') ?: false; + } + + // use value cached in memory for repeated lookups + if (!$cache && array_key_exists($token, self::$ldapcache)) { + $user = self::$ldapcache[$token]; + } + + if (empty($user) && $cache) { + $user = $cache->get($token); + } + + if (empty($user) && ($ldap = kolab_storage::ldap())) { + $user = $ldap->get_user_record($token, $_SESSION['imap_host']); + + if (!empty($user)) { + $keys = array('displayname', 'name', 'mail'); // supported keys + $user = array_intersect_key($user, array_flip($keys)); + + if (!empty($user)) { + if ($cache) { + $cache->set($token, $user); + } + else { + self::$ldapcache[$token] = $user; + } + } + } + } + + if (!empty($user)) { + if ($as_string) { + foreach ($name_attr as $attr) { + if ($display = $user[$attr]) { + break; + } + } + + if (!$display) { + $display = $user['displayname'] ?: $user['name']; + } + + if ($display && $display != $folder_id) { + $display = "$display ($folder_id)"; + } + + return $display; + } + + return $user; + } + } + + /** + * Chwala's 'folder_mod' hook handler for mapping other users folder names + */ + public static function folder_mod($args) + { + static $roots; + + if ($roots === null) { + self::setup(); + $roots = self::$imap->get_namespace('other'); + } + + // Note: We're working with UTF7-IMAP encoding here + + if ($args['dir'] == 'in') { + foreach ((array) $roots as $root) { + if (strpos($args['folder'], $root[0]) === 0) { + // remove root and explode folder + $delim = $root[1]; + $folder = explode($delim, substr($args['folder'], strlen($root[0]))); + // compare first (user) part with a regexp, it's supposed + // to look like this: "Doe, Jane (uid)", so we can extract the uid + // and replace the folder with it + if (preg_match('~^[^/]+ \(([^)]+)\)$~', $folder[0], $m)) { + $folder[0] = $m[1]; + $args['folder'] = $root[0] . implode($delim, $folder); + } + + break; + } + } + } + else { // dir == 'out' + foreach ((array) $roots as $root) { + if (strpos($args['folder'], $root[0]) === 0) { + // remove root and explode folder + $delim = $root[1]; + $folder = explode($delim, substr($args['folder'], strlen($root[0]))); + + // Replace uid with "Doe, Jane (uid)" + if ($user = self::folder_id2user($folder[0], true)) { + $user = str_replace($delim, '', $user); + $folder[0] = rcube_charset::convert($user, RCUBE_CHARSET, 'UTF7-IMAP'); + + $args['folder'] = $root[0] . implode($delim, $folder); + } + + break; + } + } + } + + return $args; + } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache.php
Changed
@@ -46,8 +46,8 @@ protected $folders_table; protected $max_sql_packet; protected $max_sync_lock_time = 600; - protected $binary_items = array(); protected $extra_cols = array(); + protected $data_props = array(); protected $order_by = null; protected $limit = null; protected $error = 0; @@ -201,7 +201,7 @@ $this->metadata['changed'] < date(self::DB_DATE_FORMAT, time() - $this->cache_refresh) || $this->metadata['ctag'] != $this->folder->get_ctag() || intval($this->metadata['objectcount']) !== $this->count() - ) { + ) { // lock synchronization for this folder or wait if locked $this->_sync_lock(); @@ -242,7 +242,9 @@ // fetch new objects from imap $i = 0; foreach (array_diff($imap_index, $old_index) as $msguid) { - if ($object = $this->folder->read_object($msguid, '*')) { + // Note: We'll store only objects matching the folder type + // anything else will be silently ignored + if ($object = $this->folder->read_object($msguid)) { // Deduplication: remove older objects with the same UID // Here we do not resolve conflicts, we just make sure // the most recent version of the object will be used @@ -447,7 +449,7 @@ $sql_data['uid'] = $object['uid']; $args = array(); - $cols = array('folder_id', 'msguid', 'uid', 'changed', 'data', 'xml', 'tags', 'words'); + $cols = array('folder_id', 'msguid', 'uid', 'changed', 'data', 'tags', 'words'); $cols = array_merge($cols, $this->extra_cols); foreach ($cols as $idx => $col) { @@ -585,9 +587,12 @@ * @param array Pseudo-SQL query as list of filter parameter triplets * triplet: array('<colname>', '<comparator>', '<value>') * @param boolean Set true to only return UIDs instead of complete objects + * @param boolean Use fast mode to fetch only minimal set of information + * (no xml fetching and parsing, etc.) + * * @return array List of Kolab data objects (each represented as hash array) or UIDs */ - public function select($query = array(), $uids = false) + public function select($query = array(), $uids = false, $fast = false) { $result = $uids ? array() : new kolab_storage_dataset($this); @@ -621,6 +626,9 @@ } while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + if ($fast) { + $sql_arr['fast-mode'] = true; + } if ($uids) { $this->uid2msg[$sql_arr['uid']] = $sql_arr['_msguid']; $result[] = $sql_arr['uid']; @@ -679,7 +687,6 @@ return $result; } - /** * Get number of objects mathing the given query * @@ -851,43 +858,36 @@ */ protected function _serialize($object) { - $sql_data = array('changed' => null, 'xml' => '', 'tags' => '', 'words' => ''); + $data = array(); + $sql_data = array('changed' => null, 'tags' => '', 'words' => ''); if ($object['changed']) { $sql_data['changed'] = date(self::DB_DATE_FORMAT, 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)); + $xml = (string) $object['_formatobj']->write(3.0); + + $data['_size'] = strlen($xml); $sql_data['tags'] = ' ' . join(' ', $object['_formatobj']->get_tags()) . ' '; // pad with spaces for strict/prefix search $sql_data['words'] = ' ' . join(' ', $object['_formatobj']->get_words()) . ' '; } - // extract object data - $data = array(); - foreach ($object as $key => $val) { - // skip empty properties - if ($val === "" || $val === null) { - continue; - } - // mark binary data to be extracted from xml on unserialize() - if (isset($this->binary_items[$key])) { - $data[$key] = true; - } - else if ($key[0] != '_') { - $data[$key] = $val; - } - else if ($key == '_attachments') { - foreach ($val as $k => $att) { - unset($att['content'], $att['path']); - if ($att['id']) - $data[$key][$k] = $att; + // Store only minimal set of object properties + foreach ($this->data_props as $prop) { + if (isset($object[$prop])) { + $data[$prop] = $object[$prop]; + if ($data[$prop] instanceof DateTime) { + $data[$prop] = array( + 'cl' => 'DateTime', + 'dt' => $data[$prop]->format('Y-m-d H:i:s'), + 'tz' => $data[$prop]->getTimezone()->getName(), + ); } } } - // use base64 encoding (Bug #1912, #2662) - $sql_data['data'] = base64_encode(serialize($data)); + $sql_data['data'] = json_encode(rcube_charset::clean($data)); return $sql_data; } @@ -897,44 +897,38 @@ */ protected function _unserialize($sql_arr) { - // check if data is a base64-encoded string, for backward compat. - if (strpos(substr($sql_arr['data'], 0, 64), ':') === false) { - $sql_arr['data'] = base64_decode($sql_arr['data']); - } - - $object = unserialize($sql_arr['data']); - - // de-serialization failed - if ($object === false) { - rcube::raise_error(array( - 'code' => 900, 'type' => 'php', - 'message' => "Malformed data for {$this->resource_uri}/{$sql_arr['msguid']} object." - ), true); - - return null; - } + if ($sql_arr['fast-mode'] && !empty($sql_arr['data']) && ($object = json_decode($sql_arr['data'], true))) { + $object['uid'] = $sql_arr['uid']; - // decode binary properties - foreach ($this->binary_items as $key => $regexp) { - if (!empty($object[$key]) && preg_match($regexp, $sql_arr['xml'], $m)) { - $object[$key] = base64_decode($m[1]); + foreach ($this->data_props as $prop) { + if (isset($object[$prop]) && is_array($object[$prop]) && $object[$prop]['cl'] == 'DateTime') { + $object[$prop] = new DateTime($object[$prop]['dt'], new DateTimeZone($object[$prop]['tz'])); + } + else if (!isset($object[$prop]) && isset($sql_arr[$prop])) { + $object[$prop] = $sql_arr[$prop]; + } } - } - $object_type = $sql_arr['type'] ?: $this->folder->type; - $format_type = $this->folder->type == 'configuration' ? 'configuration' : $object_type; + if ($sql_arr['created'] && empty($object['created'])) { + $object['created'] = new DateTime($sql_arr['created']); + } - // add meta data - $object['_type'] = $object_type; - $object['_msguid'] = $sql_arr['msguid']; - $object['_mailbox'] = $this->folder->name; - $object['_size'] = strlen($sql_arr['xml']); - $object['_formatobj'] = kolab_format::factory($format_type, 3.0, $sql_arr['xml']); + if ($sql_arr['changed'] && empty($object['changed'])) { + $object['changed'] = new DateTime($sql_arr['changed']); + } - // Fix old broken objects with missing creation date - if (empty($object['created']) && method_exists($object['_formatobj'], 'to_array')) { - $new_object = $object['_formatobj']->to_array(); - $object['created'] = $new_object['created']; + $object['_type'] = $sql_arr['type'] ?: $this->folder->type; + $object['_msguid'] = $sql_arr['msguid']; + $object['_mailbox'] = $this->folder->name; + } + // Fetch object xml + else { + // FIXME: Because old cache solution allowed storing objects that + // do not match folder type we may end up with invalid objects. + // 2nd argument of read_object() here makes sure they are still + // usable. However, not allowing them here might be also an intended + // solution in future. + $object = $this->folder->read_object($sql_arr['msguid'], '*'); } return $object; @@ -951,36 +945,38 @@ static $buffer = ''; $line = ''; + $cols = array('folder_id', 'msguid', 'uid', 'created', 'changed', 'data', 'tags', 'words'); + if ($this->extra_cols) { + $cols = array_merge($cols, $this->extra_cols); + } + if ($object) { $sql_data = $this->_serialize($object); - // Skip multifolder insert for Oracle, we can't put long data inline - if ($this->db->db_provider == 'oracle') { - $extra_cols = ''; - if ($this->extra_cols) { - $extra_cols = array_map(function($n) { return "`{$n}`"; }, $this->extra_cols); - $extra_cols = ', ' . join(', ', $extra_cols); - $extra_args = str_repeat(', ?', count($this->extra_cols)); - } - + // Skip multi-folder insert for all databases but MySQL + // In Oracle we can't put long data inline, others we don't support yet + if (strpos($this->db->db_provider, 'mysql') !== 0) { + $extra_args = array(); $params = array($this->folder_id, $msguid, $object['uid'], $sql_data['changed'], - $sql_data['data'], $sql_data['xml'], $sql_data['tags'], $sql_data['words']); + $sql_data['data'], $sql_data['tags'], $sql_data['words']); foreach ($this->extra_cols as $col) { $params[] = $sql_data[$col]; + $extra_args[] = '?'; } + $cols = implode(', ', array_map(function($n) { return "`{$n}`"; }, $cols)); + $extra_args = count($extra_args) ? ', ' . implode(', ', $extra_args) : ''; + $result = $this->db->query( - "INSERT INTO `{$this->cache_table}` " - . " (`folder_id`, `msguid`, `uid`, `created`, `changed`, `data`, `xml`, `tags`, `words` $extra_cols)" - . " VALUES (?, ?, ?, " . $this->db->now() . ", ?, ?, ?, ?, ? $extra_args)", + "INSERT INTO `{$this->cache_table}` ($cols)" + . " VALUES (?, ?, ?, " . $this->db->now() . ", ?, ?, ?, ?$extra_args)", $params ); if (!$this->db->affected_rows($result)) { rcube::raise_error(array( - 'code' => 900, 'type' => 'php', - 'message' => "Failed to write to kolab cache" + 'code' => 900, 'message' => "Failed to write to kolab cache" ), true); } @@ -994,7 +990,6 @@ $this->db->now(), $this->db->quote($sql_data['changed']), $this->db->quote($sql_data['data']), - $this->db->quote($sql_data['xml']), $this->db->quote($sql_data['tags']), $this->db->quote($sql_data['words']), ); @@ -1005,22 +1000,17 @@ } if ($buffer && (!$msguid || (strlen($buffer) + strlen($line) > $this->max_sql_packet()))) { - $extra_cols = ''; - if ($this->extra_cols) { - $extra_cols = array_map(function($n) { return "`{$n}`"; }, $this->extra_cols); - $extra_cols = ', ' . join(', ', $extra_cols); - } + $columns = implode(', ', array_map(function($n) { return "`{$n}`"; }, $cols)); + $update = implode(', ', array_map(function($i) { return "`{$i}` = VALUES(`{$i}`)"; }, array_slice($cols, 2))); $result = $this->db->query( - "INSERT INTO `{$this->cache_table}` ". - " (`folder_id`, `msguid`, `uid`, `created`, `changed`, `data`, `xml`, `tags`, `words` $extra_cols)". - " VALUES $buffer" + "INSERT INTO `{$this->cache_table}` ($columns) VALUES $buffer" + . " ON DUPLICATE KEY UPDATE $update" ); if (!$this->db->affected_rows($result)) { rcube::raise_error(array( - 'code' => 900, 'type' => 'php', - 'message' => "Failed to write to kolab cache" + 'code' => 900, 'message' => "Failed to write to kolab cache" ), true); } @@ -1190,7 +1180,7 @@ } /** - * Set Roundcube storage options and bypass messages cache. + * Set Roundcube storage options and bypass messages/indexes cache. * * We use skip_deleted and threading settings specific to Kolab, * we have to change these global settings only temporarily. @@ -1245,17 +1235,18 @@ switch ($cache_bypass) { case 2: - // Disable messages cache completely + // Disable messages and index cache completely $this->imap->set_messages_caching(!$force); break; + case 3: case 1: - // We'll disable messages cache, but keep index cache. + // We'll disable messages cache, but keep index cache (1) or vice-versa (3) // Default mode is both (MODE_INDEX | MODE_MESSAGE) - $mode = rcube_imap_cache::MODE_INDEX; + $mode = $cache_bypass == 3 ? rcube_imap_cache::MODE_MESSAGE : rcube_imap_cache::MODE_INDEX; if (!$force) { - $mode |= rcube_imap_cache::MODE_MESSAGE; + $mode |= $cache_bypass == 3 ? rcube_imap_cache::MODE_INDEX : rcube_imap_cache::MODE_MESSAGE; } $this->imap->set_messages_caching(true, $mode);
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_configuration.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache_configuration.php
Changed
@@ -32,6 +32,8 @@ */ protected function _serialize($object) { + $this->set_data_props($object['type']); + $sql_data = parent::_serialize($object); $sql_data['type'] = $object['type']; @@ -39,13 +41,28 @@ } /** + * Helper method to convert database record to the given Kolab object + * + * @override + */ + protected function _unserialize($sql_arr) + { + $this->set_data_props($sql_arr['type']); + + return parent::_unserialize($sql_arr); + } + + /** * Select Kolab objects filtered by the given query * - * @param array Pseudo-SQL query as list of filter parameter triplets + * @param array Pseudo-SQL query as list of filter parameter triplets * @param boolean Set true to only return UIDs instead of complete objects + * @param boolean Use fast mode to fetch only minimal set of information + * (no xml fetching and parsing, etc.) + * * @return array List of Kolab data objects (each represented as hash array) or UIDs */ - public function select($query = array(), $uids = false) + public function select($query = array(), $uids = false, $fast = false) { // modify query for IMAP search: query param 'type' is actually a subtype if (!$this->ready) { @@ -57,7 +74,7 @@ } } - return parent::select($query, $uids); + return parent::select($query, $uids, $fast); } /** @@ -85,4 +102,35 @@ return parent::_sql_where($query); } + + /** + * Set $data_props property depending on object type + */ + protected function set_data_props($type) + { + switch ($type) { + case 'dictionary': + $this->data_props = array('language', 'e'); + break; + + case 'file_driver': + $this->data_props = array('driver', 'title', 'enabled', 'host', 'port', 'username', 'password'); + break; + + case 'relation': + // Note: Because relations are heavily used, for performance reasons + // we store all properties for them + $this->data_props = array('name', 'category', 'color', 'parent', 'iconName', 'priority', 'members'); + break; + + case 'snippet': + $this->data_props = array('name'); + break; + + case 'category': + default: + // TODO: implement this + $this->data_props = array(); + } + } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_contact.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache_contact.php
Changed
@@ -24,12 +24,8 @@ class kolab_storage_cache_contact extends kolab_storage_cache { protected $extra_cols_max = 255; - protected $extra_cols = array('type','name','firstname','surname','email'); - protected $binary_items = array( - 'photo' => '|<photo><uri>[^;]+;base64,([^<]+)</uri></photo>|i', - 'pgppublickey' => '|<key><uri>data:application/pgp-keys;base64,([^<]+)</uri></key>|i', - 'pkcs7publickey' => '|<key><uri>data:application/pkcs7-mime;base64,([^<]+)</uri></key>|i', - ); + protected $extra_cols = array('type', 'name', 'firstname', 'surname', 'email'); + protected $data_props = array('type', 'name', 'firstname', 'middlename', 'prefix', 'suffix', 'surname', 'email', 'organization', 'member'); /** * Helper method to convert the given Kolab object into a dataset to be written to cache @@ -69,4 +65,4 @@ return $sql_data; } -} \ No newline at end of file +}
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_event.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache_event.php
Changed
@@ -24,6 +24,7 @@ class kolab_storage_cache_event extends kolab_storage_cache { protected $extra_cols = array('dtstart','dtend'); + protected $data_props = array('categories', 'status', 'attendees'); // start, end /** * Helper method to convert the given Kolab object into a dataset to be written to cache
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_file.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache_file.php
Changed
@@ -24,6 +24,7 @@ class kolab_storage_cache_file extends kolab_storage_cache { protected $extra_cols = array('filename'); + protected $data_props = array('type', 'size', 'filename', 'fileid'); /** * Helper method to convert the given Kolab object into a dataset to be written to cache @@ -32,13 +33,45 @@ */ protected function _serialize($object) { - $sql_data = parent::_serialize($object); - if (!empty($object['_attachments'])) { reset($object['_attachments']); - $sql_data['filename'] = $object['_attachments'][key($object['_attachments'])]['name']; + + $file = $object['_attachments'][key($object['_attachments'])]; + + $object['type'] = $file['mimetype']; + $object['size'] = $file['size']; + $object['fileid'] = $file['id']; + } + + $sql_data = parent::_serialize($object); + + if (!empty($file)) { + $sql_data['filename'] = $file['name']; } return $sql_data; } -} \ No newline at end of file + + /** + * Helper method to turn stored cache data into a valid storage object + * + * @override + */ + protected function _unserialize($sql_arr) + { + $object = parent::_unserialize($sql_arr); + + if ($object && $sql_arr['fast-mode']) { + if (!empty($object['_attachments'])) { + $file = $object['_attachments'][key($object['_attachments'])]; + + $object['type'] = $file['mimetype']; + $object['size'] = $file['size']; + $object['fileid'] = $file['id']; + $object['filename'] = $file['name']; + } + } + + return $object; + } +}
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_journal.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache_journal.php
Changed
@@ -24,6 +24,7 @@ class kolab_storage_cache_journal extends kolab_storage_cache { protected $extra_cols = array('dtstart','dtend'); + protected $data_props = array('categories'); /** * Helper method to convert the given Kolab object into a dataset to be written to cache
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_note.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache_note.php
Changed
@@ -23,5 +23,5 @@ class kolab_storage_cache_note extends kolab_storage_cache { - -} \ No newline at end of file + protected $data_props = array('title'); +}
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_cache_task.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_cache_task.php
Changed
@@ -23,7 +23,8 @@ class kolab_storage_cache_task extends kolab_storage_cache { - protected $extra_cols = array('dtstart','dtend'); + protected $extra_cols = array('dtstart', 'dtend'); + protected $data_props = array('categories', 'status', 'complete', 'start', 'due'); /** * Helper method to convert the given Kolab object into a dataset to be written to cache
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_config.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_config.php
Changed
@@ -131,7 +131,7 @@ $folder->set_order_and_limit(null, $limit); } - foreach ($folder->select($filter) as $object) { + foreach ($folder->select($filter, true) as $object) { unset($object['_formatobj']); $list[] = $object; }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_folder.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_folder.php
Changed
@@ -281,12 +281,14 @@ /** * Select Kolab objects matching the given query * - * @param mixed Pseudo-SQL query as list of filter parameter triplets - * or string with object type (e.g. contact, event, todo, journal, note, configuration) + * @param mixed Pseudo-SQL query as list of filter parameter triplets + * or string with object type (e.g. contact, event, todo, journal, note, configuration) + * @param boolean Use fast mode to fetch only minimal set of information + * (no xml fetching and parsing, etc.) * * @return array List of Kolab data objects (each represented as hash array) */ - public function select($query = array()) + public function select($query = array(), $fast = false) { if (!$this->valid) { return array(); @@ -296,7 +298,7 @@ $this->cache->synchronize(); // fetch objects from cache - return $this->cache->select($this->_prepare_query($query)); + return $this->cache->select($this->_prepare_query($query), false, $fast); } /** @@ -419,6 +421,8 @@ } else { // return message part from IMAP directly + // TODO: We could improve performance if we cache part's encoding + // without 3rd argument get_message_part() will request BODYSTRUCTURE from IMAP return $this->imap->get_message_part($msguid, $part, null, $print, $fp, $skip_charset_conv); } } @@ -486,8 +490,9 @@ $content_type = kolab_format::KTYPE_PREFIX . $object_type; // check object type header and abort on mismatch - if ($type != '*' && $object_type != $type) + if ($type != '*' && strpos($object_type, $type) !== 0 && !($object_type == 'distribution-list' && $type == 'contact')) { return false; + } $attachments = array(); @@ -557,6 +562,7 @@ $object['_msguid'] = $msguid; $object['_mailbox'] = $this->name; $object['_formatobj'] = $format; + $object['_size'] = strlen($xml); return $object; }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/lib/kolab_storage_folder_user.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/lib/kolab_storage_folder_user.php
Changed
@@ -23,8 +23,6 @@ */ class kolab_storage_folder_user extends kolab_storage_folder_virtual { - protected static $ldapcache = array(); - public $ldaprec; public $type; @@ -36,21 +34,13 @@ parent::__construct($name, kolab_storage::object_prettyname($name), 'other', $parent); if (!empty($ldaprec)) { - self::$ldapcache[$name] = $this->ldaprec = $ldaprec; - } - // use value cached in memory for repeated lookups - else if (array_key_exists($name, self::$ldapcache)) { - $this->ldaprec = self::$ldapcache[$name]; + $this->ldaprec = $ldaprec; } - // lookup user in LDAP and set $this->ldaprec - else if ($ldap = kolab_storage::ldap()) { - // get domain from current user - list(,$domain) = explode('@', rcube::get_instance()->get_user_name()); - $this->ldaprec = $ldap->get_user_record(parent::get_foldername($this->name) . '@' . $domain, $_SESSION['imap_host']); + else { + $this->ldaprec = kolab_storage::folder_id2user(parent::get_foldername($this->name)); if (!empty($this->ldaprec)) { $this->ldaprec['kolabtargetfolder'] = $name; } - self::$ldapcache[$name] = $this->ldaprec; } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/libkolab.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/libkolab.php
Changed
@@ -28,7 +28,7 @@ class libkolab extends rcube_plugin { static $http_requests = array(); - static $bonnie_api = false; + static $bonnie_api = false; /** * Required startup method of a Roundcube plugin @@ -46,6 +46,9 @@ $this->add_hook('storage_connect', array($this, 'storage_connect')); $this->add_hook('user_delete', array('kolab_storage', 'delete_user_folders')); + // For Chwala + $this->add_hook('folder_mod', array('kolab_storage', 'folder_mod')); + $rcmail = rcube::get_instance(); try { kolab_format::$timezone = new DateTimeZone($rcmail->config->get('timezone', 'GMT'));
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/skins/elastic/include/calendar.less -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/skins/elastic/include/calendar.less
Changed
@@ -73,11 +73,11 @@ } a.calname { - padding-right: 4em; + padding-right: 2.5em; } .count { - right: 5.5em; + right: 4.2em; font-style: normal; } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/skins/elastic/include/kolab_files.less -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/skins/elastic/include/kolab_files.less
Changed
@@ -109,6 +109,11 @@ position: relative; } +#filesuploadform { + // force upload form position, otherwise it breaks layout + position: absolute !important; +} + #filelistbox { height: 100%;
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/skins/elastic/include/tasklist.less -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/skins/elastic/include/tasklist.less
Changed
@@ -71,6 +71,16 @@ &.droptarget { background-color: @color-list-droptarget-background; } + + &.complete { + span.title { + color: @color-list-deleted; + } + + .progressbar { + display: none; + } + } } & > div, @@ -139,16 +149,6 @@ &.collapsed:before { content: @fa-var-angle-right; } - - &.complete { - span.title { - text-decoration: line-through; - } - - .progressbar { - display: none; - } - } } span.title { @@ -282,7 +282,7 @@ } &.status-completed h2 { - text-decoration: line-through; + color: @color-list-deleted; } &.status-flagged h2:before {
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/libkolab/skins/elastic/libkolab.less -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/libkolab/skins/elastic/libkolab.less
Changed
@@ -51,15 +51,6 @@ position: relative; flex-grow: 1; - &:after { - color: #ccc; - position: absolute; - top: 0; - right: 0; - height: @listing-line-height !important; - font-size: 1.1em !important; - } - & + input { position: initial; } @@ -96,6 +87,13 @@ display: none; } } + + html.touch & { + margin-left: .2rem; + a { + margin-right: .5rem; + } + } } a.quickview { @@ -152,11 +150,25 @@ & > div.readonly a:first-child, &.readonly:not(.virtual) > div a:first-child { - padding-right: 1.6em; - &:after { &:extend(.font-icon-class); content: @fa-var-lock; + position: absolute; + left: 2.25rem; + top: @listing-line-height / 2; + font-size: .9em !important; + width: .9em; + line-height: 1; + height: 1em !important; + background-color: #fff; + border-radius: 50% 50% 0 0; + color: @color-font; + opacity: .9; + + html.touch & { + top: @listing-touch-line-height / 2; + left: 2.7rem; + } } } @@ -222,21 +234,51 @@ } } -html.touch .listing { - li { - & > div { - a:after { - height: @listing-touch-line-height !important; +@treelist-readonly-icon-margin: 1.7em; +.treelist { + ul { + li { + a:first-child:after { + margin-left: 1 * @treelist-readonly-icon-margin !important; } - } - .actions { - margin-left: .2rem; - a { - margin-right: .5rem; + li { + a:first-child:after { + margin-left: 2 * @treelist-readonly-icon-margin !important; + } + + li { + a:first-child:after { + margin-left: 3 * @treelist-readonly-icon-margin !important; + } + + li { + a:first-child:after { + margin-left: 4 * @treelist-readonly-icon-margin !important; + } + + li { + a:first-child:after { + margin-left: 5 * @treelist-readonly-icon-margin !important; + } + + li { + a:first-child:after { + margin-left: 6 * @treelist-readonly-icon-margin !important; + } + } + } + } + } } } } + + &.notree { + li a:first-child:after { + left: 1.3rem !important; + } + } } .searchresults { @@ -282,17 +324,6 @@ .menu { li.search { padding: .25rem .5rem; - .input-group { - - i.icon { - font-size: 80%; - padding: .5rem; - } - - input { - font-size: 100%; - } - } } a.history:before { @@ -459,6 +490,15 @@ position: relative; // for absolute positioning of searchbar overflow: hidden; white-space: nowrap; + + a.button { + color: @color-toolbar-button; + margin: 0 .3rem; + + &:before { + margin: 0; + } + } } .header-title { @@ -502,15 +542,16 @@ padding: 0 !important; } - .selection-list { - border: 0; - } - .ui-dialog-titlebar { display: none; margin: 0; } + .selection-list { + border: 0; + } + + .selection-list, .selection-content { .header-title { margin-left: 0;
View file
roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/loginfail/LICENSE
Added
@@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<http://www.gnu.org/licenses/>.
View file
roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/loginfail/composer.json
Added
@@ -0,0 +1,25 @@ +{ + "name": "kolab/loginfail", + "type": "roundcube-plugin", + "description": "DIsplay additional info on failed login", + "homepage": "https://git.kolab.org/diffusion/RPK/", + "license": "AGPLv3", + "version": "3.5.0", + "authors": [ + { + "name": "Jeroen van Meeuwen", + "email": "vanmeeuwen@kolabsys.com", + "role": "Lead" + } + ], + "repositories": [ + { + "type": "composer", + "url": "https://plugins.roundcube.net" + } + ], + "require": { + "php": ">=5.3.0", + "roundcube/plugin-installer": ">=0.1.3" + } +}
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/loginfail/loginfail.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/loginfail/loginfail.php
Changed
@@ -1,20 +1,23 @@ <?php - class loginfail extends rcube_plugin { - public $task = 'login'; - function init() { - $this->add_hook('login_failed', array($this, 'login_failed')); - } +class loginfail extends rcube_plugin +{ + public $task = 'login'; + + function init() + { + $this->add_hook('login_failed', array($this, 'login_failed')); + } - public function login_failed($args) { - $rcmail = rcmail::get_instance(); + public function login_failed($args) + { + $rcmail = rcmail::get_instance(); - $filename = $this->home . '/loginfail.html'; + $filename = $this->home . '/loginfail.html'; - if (file_exists($filename)) { - $html = file_get_contents($filename); - $rcmail->output->add_footer($html); - } + if (file_exists($filename)) { + $html = file_get_contents($filename); + $rcmail->output->add_footer($html); } } -?> +}
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/tasklist/composer.json -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/tasklist/composer.json
Changed
@@ -4,12 +4,17 @@ "description": "Task management plugin", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.4.6", + "version": "3.5.0", "authors": [ { "name": "Thomas Bruederli", "email": "bruederli@kolabsys.com", "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Developer" } ], "repositories": [ @@ -22,7 +27,6 @@ "php": ">=5.3.0", "roundcube/plugin-installer": ">=0.1.3", "kolab/libcalendaring": ">=3.4.0", - "kolab/libkolab": ">=3.4.0", - "roundcube/jqueryui": ">=1.10.4" + "kolab/libkolab": ">=3.4.0" } }
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
Changed
@@ -587,7 +587,7 @@ continue; } - foreach ($folder->select(array(array('tags','!~','x-complete'))) as $record) { + foreach ($folder->select(array(array('tags','!~','x-complete')), true) as $record) { $rec = $this->_to_rcube_task($record, $list_id, false); if ($this->is_complete($rec)) // don't count complete tasks
View file
roundcubemail-plugins-kolab-3.4.6.tar.gz/plugins/tasklist/tasklist.php -> roundcubemail-plugins-kolab-3.5.0.tar.gz/plugins/tasklist/tasklist.php
Changed
@@ -75,7 +75,6 @@ { $this->require_plugin('libcalendaring'); $this->require_plugin('libkolab'); - $this->require_plugin('jqueryui'); $this->rc = rcube::get_instance(); $this->lib = libcalendaring::get_instance();
View file
roundcubemail-plugins-kolab.dsc
Changed
@@ -2,7 +2,7 @@ Source: roundcubemail-plugins-kolab Binary: roundcubemail-plugins-kolab Architecture: all -Version: 1:3.4.6-0~kolab2 +Version: 1:3.5.0-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Standards-Version: 3.9.3 @@ -37,5 +37,5 @@ roundcubemail-plugin-tinymce-config deb web extra roundcubemail-plugin-wap-client deb web extra Files: - 00000000000000000000000000000000 0 roundcubemail-plugins-kolab-3.4.6.tar.gz + 00000000000000000000000000000000 0 roundcubemail-plugins-kolab-3.5.0.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.