Projects
Kolab:16:Enterprise
chwala
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 22
View file
chwala.spec
Changed
@@ -37,7 +37,7 @@ %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name} Name: chwala -Version: 0.5.4 +Version: 0.5.5 Release: 1%{?dist} Summary: Glorified WebDAV, done right @@ -158,6 +158,9 @@ %attr(0750,%{httpd_user},%{httpd_group}) %{_localstatedir}/log/%{name} %changelog +* Thu Mar 14 2019 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 0.5.5-1 +- Release 0.5.5 + * Fri Oct 26 2018 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 0.5.4-1 - Release 0.5.4
View file
chwala-0.5.4.tar.gz/lib/api/common.php -> chwala-0.5.5.tar.gz/lib/api/common.php
Changed
@@ -178,6 +178,83 @@ } /** + * Collect folder list request parameters + */ + protected function folder_list_params() + { + $params = array('type' => 0); + + if (!empty($this->args'unsubscribed') && rcube_utils::get_boolean((string) $this->args'unsubscribed')) { + $params'type' |= file_storage::FILTER_UNSUBSCRIBED; + } + + if (!empty($this->args'writable') && rcube_utils::get_boolean((string) $this->args'writable')) { + $params'type' |= file_storage::FILTER_WRITABLE; + } + + if (isset($this->args'search') && strlen($this->args'search')) { + $params'search' = $this->args'search'; + } + + if (!empty($this->args'permissions') && rcube_utils::get_boolean((string) $this->args'permissions')) { + $params'extended' = true; + $params'permissions' = true; + } + + if (!empty($this->args'level') && ($level = intval($this->args'level'))) { + if ($level < 0) { + $level *= -1; + $params'auto_level' = true; + } + + $params'level' = $level; + } + + return $params; + } + + /** + * Wrapper for folder_list() method on specified driver + */ + protected function folder_list($driver, $params, $relative_level = false) + { + $caps = $driver->capabilities(); + + if ($params'type' & file_storage::FILTER_UNSUBSCRIBED) { + if (empty($capsfile_storage::CAPS_SUBSCRIPTIONS)) { + return array(); + } + } + + // If the driver has fast way to get the whole folders hierarchy + // we'll return all folders, despite the requested level, when requested + if (!empty($params'auto_level') & !empty($capsfile_storage::CAPS_FAST_FOLDER_LIST)) { + unset($params'level'); + } + + $prefix = $driver->title() . file_storage::SEPARATOR; + + if (strlen($prefix) > 1 && !$relative_level && $params'level' && (!is_string($params'path') || $params'path' === '')) { + $params'level' -= 1; + } + + $folders = $driver->folder_list($params); + + if (!empty($folders) && strlen($prefix) > 1) { + foreach ($folders as $idx => $folder) { + if (is_array($folder)) { + $folders$idx'folder' = $prefix . $folder'folder'; + } + else { + $folders$idx = $prefix . $folder; + } + } + } + + return $folders; + } + + /** * Update document session on file/folder move */ protected function session_uri_update($from, $to, $is_folder = false)
View file
chwala-0.5.4.tar.gz/lib/api/file_list.php -> chwala-0.5.5.tar.gz/lib/api/file_list.php
Changed
@@ -52,11 +52,6 @@ list($driver, $path) = $this->api->get_driver($this->args'folder'); - // mount point contains only folders - if (!strlen($path)) { - return array(); - } - // add mount point prefix to file paths if ($path != $this->args'folder') { $params'prefix' = substr($this->args'folder', 0, -strlen($path));
View file
chwala-0.5.4.tar.gz/lib/api/folder_auth.php -> chwala-0.5.5.tar.gz/lib/api/folder_auth.php
Changed
@@ -70,14 +70,11 @@ $result = array('folder' => $this->args'folder'); - // get list if folders if requested + // get list of folders if requested if (rcube_utils::get_boolean((string) $this->args'list')) { - $prefix = $this->args'folder' . file_storage::SEPARATOR; - $result'list' = array(); - - foreach ($driver->folder_list() as $folder) { - $result'list' = $prefix . $folder; - } + $params = $this->folder_list_params(); + $params'path' = $path; + $result'list' = $this->folder_list($driver, $params, true); } return $result;
View file
chwala-0.5.4.tar.gz/lib/api/folder_create.php -> chwala-0.5.5.tar.gz/lib/api/folder_create.php
Changed
@@ -90,5 +90,9 @@ // save the mount point info in config $backend->driver_create($data); + + return array( + 'capabilities' => $driver->capabilities(), + ); } }
View file
chwala-0.5.4.tar.gz/lib/api/folder_list.php -> chwala-0.5.5.tar.gz/lib/api/folder_list.php
Changed
@@ -31,85 +31,76 @@ { parent::handle(); - // List parameters - $params = array('type' => 0); - if (!empty($this->args'unsubscribed') && rcube_utils::get_boolean((string) $this->args'unsubscribed')) { - $params'type' |= file_storage::FILTER_UNSUBSCRIBED; - } - if (!empty($this->args'writable') && rcube_utils::get_boolean((string) $this->args'writable')) { - $params'type' |= file_storage::FILTER_WRITABLE; - } - if (isset($this->args'search') && strlen($this->args'search')) { - $params'search' = $this->args'search'; - $search = mb_strtoupper($this->args'search'); + $params = $this->folder_list_params(); + $search = isset($params'search') ? mb_strtoupper($params'search') : null; + $drivers = $this->api->get_drivers(true, $admin_drivers); + $errors = array(); + $has_more = false; + + if (isset($this->args'folder') && strlen($this->args'folder')) { + list($driver, $path) = $this->api->get_driver($this->args'folder'); + + $title = $driver->title(); + $params'path' = $path; + + try { + $folders = $this->folder_list($driver, $params, true); + } + catch (Exception $e) { + $folders = array(); + if ($e->getCode() == file_storage::ERROR_NOAUTH) { + if (!in_array($title, $admin_drivers)) { + // inform UI about to ask user for credentials + $errors$title = $this->parse_metadata($driver->driver_metadata()); + } + else { + $errors$title = array('error' => file_storage::ERROR_NOAUTH); + } + } + } + + $drivers = array(); } - if (!empty($this->args'permissions') && rcube_utils::get_boolean((string) $this->args'permissions')) { - $params'extended' = true; - $params'permissions' = true; + else { + // get folders from default driver + $backend = $this->api->get_backend(); + $folders = $this->folder_list($backend, $params); } - // get folders from default driver - $backend = $this->api->get_backend(); - $folders = $this->folder_list($backend, $params); - // old result format if ($this->api->client_version() < 2) { return $folders; } - $drivers = $this->api->get_drivers(true, $admin_drivers); - $has_more = false; - $errors = array(); - // get folders from external sources foreach ($drivers as $driver) { $title = $driver->title(); $prefix = $title . file_storage::SEPARATOR; // folder exists in main source, replace it with external one - if (($idx = array_search($title, $folders)) !== false) { - foreach ($folders as $idx => $folder) { - if (is_array($folder)) { - $folder = $folder'folder'; - } - if ($folder == $title || strpos($folder, $prefix) === 0) { - unset($folders$idx); - } - } - } - - if (!isset($search) || strpos(mb_strtoupper($title), $search) !== false) { - $has_more = count($folders) > 0; - $folder = $params'extended' ? array('folder' => $title) : $title; - - if ($params'permissions' || ($params'type' & file_storage::FILTER_WRITABLE)) { - if ($readonly = !($driver->folder_rights('') & file_storage::ACL_WRITE)) { - if ($params'permissions') { - $folder'readonly' = true; - } - } + foreach ($folders as $idx => $folder) { + if (is_array($folder)) { + $folder = $folder'folder'; } - else { - $readonly = false; + if ($folder == $title || strpos($folder, $prefix) === 0) { + unset($folders$idx); } + } - if (!$readonly || !($params'type' & file_storage::FILTER_WRITABLE)) { + if ($search === null || strpos(mb_strtoupper($title), $search) !== false) { + if ($folder = $this->driver_root_folder($driver, $params)) { + $has_more = $has_more || count($folders) > 0; $folders = $folder; } } - if ($driver != $backend) { + if ($driver != $backend && $params'level' != 1) { try { - foreach ($this->folder_list($driver, $params) as $folder) { - if (is_array($folder)) { - $folder'folder' = $prefix . $folder'folder'; - } - else { - $folder = $prefix . $folder; - } - - $folders = $folder; - $has_more = true; + $_folders = $this->folder_list($driver, $params); + if (!empty($_folders)) { + $folders = array_merge($folders, $_folders); + $has_more = true; + unset($_folders); } } catch (Exception $e) { @@ -132,23 +123,29 @@ } return array( - 'list' => $folders, + 'list' => array_values($folders), 'auth_errors' => $errors, ); } - /** - * Wrapper for folder_list() method on specified driver - */ - protected function folder_list($driver, $params) + protected function driver_root_folder($driver, $params) { - if ($params'type' & file_storage::FILTER_UNSUBSCRIBED) { - $caps = $driver->capabilities(); - if (empty($capsfile_storage::CAPS_SUBSCRIPTIONS)) { - return array(); + $title = $driver->title(); + $folder = $params'extended' ? array('folder' => $title) : $title; + + if ($params'permissions' || ($params'type' & file_storage::FILTER_WRITABLE)) { + if ($readonly = !($driver->folder_rights('') & file_storage::ACL_WRITE)) { + if ($params'permissions') { + $folder'readonly' = true; + } } } + else { + $readonly = false; + } - return $driver->folder_list($params); + if (!$readonly || !($params'type' & file_storage::FILTER_WRITABLE)) { + return $folder; + } } }
View file
chwala-0.5.4.tar.gz/lib/drivers/kolab/kolab_file_storage.php -> chwala-0.5.5.tar.gz/lib/drivers/kolab/kolab_file_storage.php
Changed
@@ -322,6 +322,7 @@ file_storage::CAPS_LOCKS => true, file_storage::CAPS_SUBSCRIPTIONS => true, file_storage::CAPS_ACL => true, + file_storage::CAPS_FAST_FOLDER_LIST => true, ); } @@ -952,7 +953,7 @@ /** * Returns list of folders. * - * @param array $params List parameters ('type', 'search', 'extended', 'permissions') + * @param array $params List parameters ('type', 'search', 'extended', 'permissions', 'level', 'path') * * @return array List of folders * @throws Exception @@ -962,14 +963,16 @@ $unsubscribed = $params'type' & file_storage::FILTER_UNSUBSCRIBED; $rights = ($params'type' & file_storage::FILTER_WRITABLE) ? 'w' : null; $imap = $this->rc->get_storage(); - $folders = $imap->list_folders_subscribed('', '*', 'file', $rights); + $separator = $imap->get_hierarchy_delimiter(); + $root = isset($params'path') && strlen($params'path') ? $params'path' . '/' : ''; + $folders = $imap->list_folders_subscribed($root, '*', 'file', $rights); if (!is_array($folders)) { throw new Exception("Storage error. Unable to get folders list.", file_storage::ERROR); } // create/subscribe 'Files' folder in case there's no folder of type 'file' - if (empty($folders) && !$unsubscribed) { + if (empty($folders) && !$unsubscribed && !strlen($root)) { $default = 'Files'; // the folder may exist but be unsubscribed @@ -987,7 +990,7 @@ else { if ($unsubscribed) { $subscribed = $folders; - $folders = $imap->list_folders('', '*', 'file', $rights); + $folders = $imap->list_folders($root, '*', 'file', $rights); $folders = array_diff($folders, $subscribed); } @@ -1003,6 +1006,18 @@ $folders = array_map($callback, $folders); } + // This could probably be optimized by doing a direct + // IMAP LIST command with prepared second argument, but + // it would make caching not optimal + if ($params'level' > 0) { + $offset = isset($params'path') && strlen($params'path') ? strlen($params'path') + 1 : 0; + foreach ($folders as $idx => $folder) { + if (substr_count($folder, $separator, $offset) >= $params'level') { + unset($folders$idx); + } + } + } + // searching if (isset($params'search')) { $search = mb_strtoupper($params'search'); @@ -1466,7 +1481,7 @@ // for better performance it's good to assume max. number of records $folder->set_order_and_limit(null, $all ? 0 : 1); - return $folder->select($filter); + return $folder->select($filter, true); } /** @@ -1499,7 +1514,7 @@ } $filter = array( - array('type', '=', 'file'), + // array('type', '=', 'file'), array('filename', '=', $file_name) ); @@ -1523,7 +1538,7 @@ */ protected function get_folder_object($folder_name) { - if ($folder_name === null || $folder_name === '') { + if (!is_string($folder_name) || $folder_name === '') { throw new Exception("Missing folder name", file_storage::ERROR); } @@ -1558,6 +1573,10 @@ */ protected function from_file_object($file) { + if (isset($file'filename') && !$file'name') { + $file'name' = $file'filename'; + } + if (empty($file'_attachments')) { return $file; }
View file
chwala-0.5.4.tar.gz/lib/drivers/seafile/seafile_api.php -> chwala-0.5.5.tar.gz/lib/drivers/seafile/seafile_api.php
Changed
@@ -88,6 +88,7 @@ public function __construct($config = array()) { $this->config = $config; + $this->token = $config'token'; // set Web API URI $this->url = rtrim(trim($config'host'), '/') ?: 'localhost'; @@ -452,6 +453,32 @@ } /** + * Get directory information. + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * + * @return bool|array Directory properties on success, False on failure + */ + public function directory_info($repo_id, $dir) + { + // sanity checks + if (!is_string($dir)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($repo_id === '' || !is_string($repo_id)) { + $this->status = self::BAD_REQUEST; + return false; + } + + $params = array('path' => $dir); + + return $this->request('GET', "repos/$repo_id/dir/detail", $params, null, null, '2.1'); + } + + /** * Update a file * * @param string $repo_id Library identifier
View file
chwala-0.5.4.tar.gz/lib/drivers/seafile/seafile_file_storage.php -> chwala-0.5.5.tar.gz/lib/drivers/seafile/seafile_file_storage.php
Changed
@@ -119,6 +119,8 @@ 'cache' => $this->rc->config->get('fileapi_seafile_cache'), 'cache_ttl' => $this->rc->config->get('fileapi_seafile_cache_ttl', '14d'), 'debug' => $this->rc->config->get('fileapi_seafile_debug', false), + 'token' => $_SESSION$this->title . 'seafile_token' ? $this->rc->decrypt($_SESSION$this->title . 'seafile_token') : null, + ); $this->config = array_merge($config, $this->config); @@ -130,11 +132,26 @@ return true; } + if ($this->config'cache') { + $cache = $this->rc->get_cache('seafile_' . $this->title, + $this->config'cache', $this->config'cache_ttl', true); + } + // try session token - if ($_SESSION$this->title . 'seafile_token' - && ($token = $this->rc->decrypt($_SESSION$this->title . 'seafile_token')) - ) { - $valid = $this->api->ping($token); + if ($config'token') { + // With caching we know the last successful token use, so we can + // skip ping call, which is a big win for case of parallel folders listing + if ($cache) { + $valid = ($ping = $cache->get('ping')) && $ping + 15 >= time(); + } + + if (empty($valid)) { + $valid = $this->api->ping($config'token'); + + if ($cache && $valid) { + $cache->write('ping', time()); + } + } } if (!$valid) { @@ -151,6 +168,10 @@ if ($user) { $valid = $this->authenticate($user, $pass); + + if ($cache) { + $cache->remove('ping'); + } } } @@ -158,6 +179,9 @@ if (!$valid && empty($_SESSION$this->title . 'seafile_user')) { throw new Exception("User credentials not provided", file_storage::ERROR_NOAUTH); } + else if (!$valid && !$this->api) { + throw new Exception("SeaFile storage unavailable", file_storage::ERROR); + } else if (!$valid && $this->api->is_error() == seafile_api::TOO_MANY_REQUESTS) { throw new Exception("SeaFile storage temporarily unavailable (too many requests)", file_storage::ERROR); } @@ -564,6 +588,11 @@ */ public function file_list($folder_name, $params = array()) { + // mount point contains only folders + if (!is_string($folder_name) || $folder_name === '') { + return array(); + } + list($folder, $repo_id) = $this->find_library($folder_name); // prepare search filter @@ -851,44 +880,23 @@ /** * Returns list of folders. * - * @param array $params List parameters ('type', 'search') + * @param array $params List parameters ('type', 'search', 'path', 'level') * * @return array List of folders * @throws Exception */ public function folder_list($params = array()) { - $writable = ($params'type' & file_storage::FILTER_WRITABLE) ? true : false; - $libraries = $this->libraries(); - $folders = array(); - - if ($this->config'cache') { - $repos = array(); - $repo_ids = array(); - $cache = $this->rc->get_cache('seafile_' . $this->title, - $this->config'cache', $this->config'cache_ttl', true); - - if ($cache) { - $repos = (array) $cache->get('repos'); - } - - // Mark unmodified repos - foreach ($libraries as $idx => $library) { - if ($mtime = $repos$library'id') { - if ($mtime == $library'mtime') { - $libraries$idx'use-cache' = true; - } - else { - $cache_update = true; - } - } - else { - $cache_update = true; - } + $libraries = $this->libraries(); + $writable = ($params'type' & file_storage::FILTER_WRITABLE) ? true : false; + $prefix = (string) $params'path'; + $prefix_len = strlen($prefix); + $folders = array(); - $repos$library'id' = $library'mtime'; - $repo_ids = $library'id'; - } + if ($prefix_len) { + $path = explode('/', $prefix); + $lib_search = array_shift($path); + $params'path' = implode('/', $path); } foreach ($libraries as $library) { @@ -896,31 +904,31 @@ continue; } - if (strpos($library'permission', 'w') === false) { - $readonly_prefixes = $library'name'; + if ($prefix_len && $lib_search !== $library'name') { + continue; } - $folders$library'name' = array( - 'mtime' => $library'mtime', - 'permission' => $library'permission', - ); + if (!strlen($params'path')) { + $folders$library'name' = array( + 'mtime' => $library'mtime', + 'permission' => $library'permission', + ); + } + + if ($params'level' == 1 && !$prefix_len) { + // Only list of libraries has been requested + continue; + } - foreach ($this->folders_tree($library) as $folder_name => $folder) { + foreach ($this->folders_tree($library, $params) as $folder_name => $folder) { $folders$library'name' . '/' . $folder_name = $folder; } } - if (empty($folders)) { + if (empty($libraries)) { throw new Exception("Storage error. Unable to get folders list.", file_storage::ERROR); } - if ($cache && $cache_update) { - // Cleanup repos data - $repos = array_intersect_key($repos, array_flip($repo_ids)); - - $cache->set('repos', $repos); - } - // remove read-only folders when requested if ($writable) { foreach ($folders as $folder_name => $folder) { @@ -1376,11 +1384,16 @@ */ public function path2uri($path) { - list($file, $repo_id, $library) = $this->find_library($path); - // Remove protocol prefix and path, we work with host only $host = preg_replace('#(^https?://|/.*$)#i', '', $this->config'host'); + if (!is_string($path) || !strlen($path)) { + $user = $_SESSION$this->title . 'seafile_user'; + return 'seafile://' . rawurlencode($user) . '@' . $host . '/'; + } + + list($file, $repo_id, $library) = $this->find_library($path); + return 'seafile://' . rawurlencode($library'owner') . '@' . $host . '/' . file_utils::encode_path($path); } @@ -1403,10 +1416,12 @@ $path = file_utils::decode_path($matches3); $c_host = preg_replace('#(^https?://|/.*$)#i', '', $this->config'host'); - list($file, $repo_id, $library) = $this->find_library($path, true); + if (strlen($path)) { + list($file, $repo_id, $library) = $this->find_library($path, true); - if (empty($library) || $host != $c_host || $user != $library'owner') { - throw new Exception("Internal storage error. Unresolvable URI.", file_storage::ERROR); + if (empty($library) || $host != $c_host || $user != $library'owner') { + throw new Exception("Internal storage error. Unresolvable URI.", file_storage::ERROR); + } } return $path; @@ -1415,38 +1430,96 @@ /** * Get folders tree in the Seafile library */ - protected function folders_tree($library) + protected function folders_tree($library, $params = array()) { - if ($this->config'cache') { + $root = ''; + if (is_string($params'path') && strlen($params'path')) { + $root = trim($params'path', '/'); + } + + if ($this->config'cache' && empty($params'recursive')) { $cache = $this->rc->get_cache('seafile_' . $this->title, $this->config'cache', $this->config'cache_ttl', true); - if ($cache && $library'use-cache') { - $folders = $cache->get('folders.' . $library'id'); + if ($cache) { + $cache_key = 'folders.' . md5(sprintf('%s:%d:%s', $library'id', $params'level', $root)); + $folders = $cache->get($cache_key); + + if (is_string($folders) && preg_match('/^(0-9+):\{\/', $folders, $m)) { + $cache_mtime = $m1; + $folders = json_decode(substr($folders, strlen($cache_mtime)+1), true); + } + else { + $folders = null; + } + + if (strlen($root)) { + $info = $this->api->directory_info($library'id', $root); + if ($info && $info'mtime') { + try { + $dt = new DateTime($info'mtime'); + $mtime = $dt->format('U'); + } + catch (Exception $e) { + // ignore + rcube::raise_error($e, true, false); + } + } + } + else { + $mtime = $library'mtime'; + } + + if (is_array($folders) && $mtime && $cache_mtime && intval($mtime) === intval($cache_mtime)) { + return $folders; + } } } - if (!isset($folders) || !is_array($folders)) { - $folders = array(); + $folders = array(); + $add_folder = function($item, &$result, $parent) { + if ($item'type' == 'dir' && strlen($item'name')) { + $name = (strlen($parent) > 0 ? "$parent/" : '') . $item'name'; - // get folders in the repo (requires Seafile 4.4.1) - if ($content = $this->api->directory_entries($library'id', '', 'dir', true)) { - foreach ($content as $item) { - if ($item'type' == 'dir' && strlen($item'name')) { - $parent = trim($item'parent_dir', '/'); - $name = (strlen($parent) > 0 ? "$parent/" : '') . $item'name'; + $result$name = array( + 'mtime' => $item'mtime', + 'permission' => $item'permission', + ); - $folders$name = array( - 'mtime' => $item'mtime', - 'permission' => $item'permission', - ); + return $name; + } + }; + + // Full folder hierarchy requested, we can get all in one request... + if (empty($params'recursive') && empty($params'level')) { + if ($content = $this->api->directory_entries($library'id', $root, 'dir', true)) { + foreach ($content as $item) { + $add_folder($item, $folders, $root); + } + } + } + // Only part of the folder tree has been requested... + else if ($content = $this->api->directory_entries($library'id', $root, 'dir', false)) { + $params'recursive' = true; + $params'level' -= 1; + + // Recursively add sub-folders tree + foreach ($content as $item) { + $folder = $add_folder($item, $folders, $root); + + // FIXME: id="0000000000000000000000000000000000000000" means the folder is empty? + if ($folder !== null && $params'level' > 1 && $item'id' !== "0000000000000000000000000000000000000000") { + $params'path' = $folder; + $tree = $this->folders_tree($library, $params); + if (!empty($tree)) { + $folders = array_merge($folders, $tree); } } } + } - if ($cache && is_array($content)) { - $cache->set('folders.' . $library'id', $folders); - } + if ($cache_key && is_array($content) && $mtime && ($_folders = json_encode($folders))) { + $cache->set($cache_key, intval($mtime) . ':' . $_folders); } return $folders; @@ -1457,7 +1530,7 @@ */ protected function libraries() { - // get from memory, @TODO: cache in rcube_cache? + // get from memory if ($this->libraries !== null) { return $this->libraries; } @@ -1466,8 +1539,33 @@ throw new Exception("Storage error. Unable to get list of SeaFile libraries.", file_storage::ERROR); } + if ($this->config'cache') { + $cache = $this->rc->get_cache('seafile_' . $this->title, + $this->config'cache', $this->config'cache_ttl', true); + + if ($cache) { + $repos = $cache->get('repos'); + + if (is_string($repos) && preg_match('/^(0-9+):\{\/', $repos, $m)) { + $mtime = $m1; + $repos = json_decode(substr($repos, strlen($mtime)+1), true); + // We use the cached value for up to 15 seconds + // It should be enough to improve parallel folders listing requests + if (is_array($repos) && $mtime + 15 >= time()) { + return $repos; + } + } + } + } + + $mtime = time(); + if ($list = $this->api->library_list()) { $this->libraries = $list; + + if ($cache) { + $cache->write('repos', $mtime . ':' . json_encode($list)); + } } else { $this->libraries = array();
View file
chwala-0.5.4.tar.gz/lib/drivers/webdav/webdav_file_storage.php -> chwala-0.5.5.tar.gz/lib/drivers/webdav/webdav_file_storage.php
Changed
@@ -160,7 +160,7 @@ } $this->client = new Client(array( - 'baseUri' => $this->config'baseuri', + 'baseUri' => rtrim($this->config'baseuri', '/') . '/', 'userName' => $this->config'username', 'password' => $this->config'password', 'authType' => Client::AUTH_BASIC, @@ -341,9 +341,21 @@ $data = $file'content'; } + if (is_resource($data)) { + // Need to tell Curl the attachments size, so it properly + // sets Content-Length header, that is required in PUT + // request by some webdav servers (#2978) + $stat = fstat($data); + $this->client->addCurlSetting(CURLOPT_INFILESIZE, $stat'size'); + } + $file_name = $this->encode_path($file_name); $response = $this->client->request('PUT', $file_name, $data); + if ($file'path') { + fclose($data); + } + if ($response'statusCode' != 201) { throw new Exception("Storage error. " . $response'body', file_storage::ERROR); } @@ -369,9 +381,21 @@ $data = $file'content'; } + if (is_resource($data)) { + // Need to tell Curl the attachment size, so it properly + // sets Content-Length header, that is required in PUT + // request by some webdav servers (#2978) + $stat = fstat($data); + $this->client->addCurlSetting(CURLOPT_INFILESIZE, $stat'size'); + } + $file_name = $this->encode_path($file_name); $response = $this->client->request('PUT', $file_name, $data); + if ($file'path') { + fclose($data); + } + if ($response'statusCode' != 204) { throw new Exception("Storage error. " . $response'body', file_storage::ERROR); } @@ -745,7 +769,7 @@ /** * Returns list of folders. * - * @param array $params List parameters ('type', 'search') + * @param array $params List parameters ('type', 'search', path, level) * * @return array List of folders * @throws Exception @@ -754,35 +778,11 @@ { $this->init(); - try { - $items = $this->client->propfind('', array( - '{DAV:}resourcetype', - ), 'infinity'); - - // TODO: Replace infinity by recursion - // Many servers just do not support 'Depth: infinity' for security reasons - // E.g. SabreDAV has this optional and disabled by default - } - catch (Exception $e) { - throw new Exception("User credentials not provided", file_storage::ERROR_NOAUTH); + if (empty($params'level')) { + $params'level' = 100; } - $result = array(); - - foreach ($items as $file => $props) { - // Skip files - $is_dir = in_array('{DAV:}collection', $props'{DAV:}resourcetype'->resourceType); - if (!$is_dir) { - continue; - } - - $path = $this->get_relative_url($file); - $path = $this->decode_path($path); - - if ($path !== '') { - $result = $path; - } - } + $result = $this->folders_tree($params); // ensure sorted folders usort($result, array('file_utils', 'sort_folder_comparator')); @@ -1050,6 +1050,60 @@ } /** + * Recursive method to fetch folders tree + */ + protected function folders_tree($params) + { + $folders = array(); + $root = ''; + + if (is_string($params'path') && strlen($params'path')) { + $root = trim($params'path', '/'); + } + + try { + $props = array('{DAV:}resourcetype'); + $items = $this->client->propfind($root, $props, '1,noroot'); + } + catch (Exception $e) { + throw new Exception("User credentials not provided", file_storage::ERROR_NOAUTH); + } + + foreach ($items as $file => $props) { + // Skip files + $is_dir = in_array('{DAV:}collection', $props'{DAV:}resourcetype'->resourceType); + if (!$is_dir) { + continue; + } + + $path = $this->get_relative_url($file); + $path = $this->decode_path($path); + + // 'noroot' not always works + if ($path === $root) { + continue; + } + + $folders = $path; + + $params'level' -= 1; + + // Many servers just do not support 'Depth: infinity' for security reasons + // E.g. SabreDAV has this optional and disabled by default + + if ($params'level' > 0) { + $params'path' = $path; + $tree = $this->folders_tree($params); + if (!empty($tree)) { + $folders = array_merge($folders, $tree); + } + } + } + + return $folders; + } + + /** * Initializes file_locks object */ protected function init_lock_db()
View file
chwala-0.5.4.tar.gz/lib/file_api.php -> chwala-0.5.5.tar.gz/lib/file_api.php
Changed
@@ -46,7 +46,7 @@ public function __construct() { $rcube = rcube::get_instance(); - $rcube->add_shutdown_function(array($this, 'shutdown')); + register_shutdown_function(array($this, 'shutdown')); $this->config = $rcube->config; $this->session_init(); @@ -178,28 +178,27 @@ { // write performance stats to logs/console if ($this->config->get('devel_mode') || $this->config->get('performance_stats')) { + // we have to disable per_user_logging to make sure stats end up in the main console log + $this->config->set('per_user_logging', false); + // make sure logged numbers use unified format setlocale(LC_NUMERIC, 'en_US.utf8', 'en_US.UTF-8', 'en_US', 'C'); - if (function_exists('memory_get_peak_usage')) { - $mem = memory_get_peak_usage(); + if (function_exists('memory_get_usage')) { + $mem = round(memory_get_usage() / 1024 /1024, 1); } - else if (function_exists('memory_get_usage')) { - $mem = memory_get_usage(); + if (function_exists('memory_get_peak_usage')) { + $mem .= '/'. round(memory_get_peak_usage() / 1024 / 1024, 1); } - $path = !empty($this->path) ? '/' . implode($this->path, '/') : ''; + $path = !empty($this->path) ? '/' . implode($this->path, '/') : ''; $request = ($this instanceof file_api_wopi ? 'wopi/' : '') . $this->request; if ($path !== '' && substr_compare($this->request, $path, -1 * strlen($path), strlen($path), true) != 0) { $request .= $path; } - $log = trim(sprintf('%s: %s %s', - $this->method ?: $_SERVER'REQUEST_METHOD', - $request, - $mem ? sprintf('%.1f MB', $mem/1024/1024) : '' - )); + $log = sprintf('%s: %s %s', $this->method ?: $_SERVER'REQUEST_METHOD', trim($request) ?: '/', $mem); if (defined('FILE_API_START')) { rcube::print_timer(FILE_API_START, $log); @@ -225,22 +224,29 @@ } // when used with (f)cgi no PHP_AUTH* variables are available without defining a special rewrite rule else if (!isset($_SERVER'PHP_AUTH_USER')) { - // "Basic didhfiefdhfu4fjfjdsa34drsdfterrde..." - if (isset($_SERVER"REMOTE_USER")) { - $basicAuthData = base64_decode(substr($_SERVER"REMOTE_USER", 6)); - } - else if (isset($_SERVER"REDIRECT_REMOTE_USER")) { - $basicAuthData = base64_decode(substr($_SERVER"REDIRECT_REMOTE_USER", 6)); - } - else if (isset($_SERVER"Authorization")) { - $basicAuthData = base64_decode(substr($_SERVER"Authorization", 6)); - } - else if (isset($_SERVER"HTTP_AUTHORIZATION")) { - $basicAuthData = base64_decode(substr($_SERVER"HTTP_AUTHORIZATION", 6)); - } + $tokens = array( + $_SERVER'REMOTE_USER', + $_SERVER'REDIRECT_REMOTE_USER', + $_SERVER'HTTP_AUTHORIZATION', + rcube_utils::request_header('Authorization'), + ); - if (isset($basicAuthData) && !empty($basicAuthData)) { - list($username, $password) = explode(":", $basicAuthData); + foreach ($tokens as $token) { + if (!empty($token)) { + if (stripos($token, 'Basic ') === 0) { + $basicAuthData = base64_decode(substr($token, 6)); + list($username, $password) = explode(':', $basicAuthData, 2); + if ($username) { + break; + } + } + else if (stripos($token, 'Bearer ') === 0) { + $username = base64_decode(substr($token, 7)); + if ($username) { + break; + } + } + } } }
View file
chwala-0.5.4.tar.gz/lib/file_api_core.php -> chwala-0.5.5.tar.gz/lib/file_api_core.php
Changed
@@ -24,7 +24,7 @@ class file_api_core extends file_locale { - const API_VERSION = 4; + const API_VERSION = 5; const ERROR_UNAUTHORIZED = 401; const ERROR_NOT_FOUND = 404; @@ -95,21 +95,30 @@ $all = array(); $iRony = defined('KOLAB_DAV_ROOT'); + // Disable webdav sources/drivers in iRony that point to the + // same host to prevent infinite recursion + $is_valid_source = function($source) { + if ($source'driver' == 'webdav') { + $self_url = parse_url($_SERVER'SCRIPT_URI'); + $item_url = parse_url($source'baseuri' ?: $source'host'); + $hosts = array($self_url'host', $_SERVER'SERVER_NAME', $_SERVER'SERVER_ADDR'); + + if (in_array($item_url'host', $hosts)) { + return false; + } + } + + return true; + }; + if (!empty($enabled)) { $drivers = $backend->driver_list(); - foreach ($drivers as $item) { - // Disable webdav sources/drivers in iRony that point to the - // same host to prevent infinite recursion - if ($iRony && $item'driver' == 'webdav') { - $self_url = parse_url($_SERVER'SCRIPT_URI'); - $item_url = parse_url($item'host'); - - if ($self_url'host' == $item_url'host') { - continue; - } - } + if ($iRony) { + $drivers = array_filter($drivers, $is_valid_source); + } + foreach ($drivers as $item) { $all = $item'title'; if ($item'enabled' && in_array($item'driver', (array) $enabled)) { @@ -120,8 +129,12 @@ $admin_drivers = array(); - if (empty($result) && !empty($preconf)) { - foreach ((array) $preconf as $title => $item) { + if (!empty($preconf)) { + if ($iRony) { + $preconf = array_filter($preconf, $is_valid_source); + } + + foreach ($preconf as $title => $item) { if (!in_array($title, $all)) { $item'title' = $title; $item'admin' = true;
View file
chwala-0.5.4.tar.gz/lib/file_api_lib.php -> chwala-0.5.5.tar.gz/lib/file_api_lib.php
Changed
@@ -84,8 +84,10 @@ return; case 'folder_list': - // no arguments - $args = array(); + $args = array( + 'folder' => $arguments0, + 'level' => $arguments1, + ); break; case 'folder_create':
View file
chwala-0.5.4.tar.gz/lib/file_storage.php -> chwala-0.5.5.tar.gz/lib/file_storage.php
Changed
@@ -32,6 +32,7 @@ const CAPS_QUOTA = 'QUOTA'; const CAPS_LOCKS = 'LOCKS'; const CAPS_SUBSCRIPTIONS = 'SUBSCRIPTIONS'; + const CAPS_FAST_FOLDER_LIST = 'FAST_FOLDER_LIST'; // config const SEPARATOR = '/';
View file
chwala-0.5.4.tar.gz/lib/file_ui.php -> chwala-0.5.5.tar.gz/lib/file_ui.php
Changed
@@ -58,7 +58,7 @@ public function __construct($output = null) { $rcube = rcube::get_instance(); - $rcube->add_shutdown_function(array($this, 'shutdown')); + register_shutdown_function(array($this, 'shutdown')); $this->config_init(); @@ -355,14 +355,21 @@ public function shutdown() { // write performance stats to logs/console - if ($this->devel_mode) { - if (function_exists('memory_get_peak_usage')) - $mem = memory_get_peak_usage(); - else if (function_exists('memory_get_usage')) - $mem = memory_get_usage(); - - $log = 'ui:' . $this->get_task() . ($this->action ? '/' . $this->action : ''); - $log .= ($mem ? sprintf(' %.1f MB', $mem/1024/1024) : ''); + if ($this->config->get('devel_mode') || $this->config->get('performance_stats')) { + // we have to disable per_user_logging to make sure stats end up in the main console log + $this->config->set('per_user_logging', false); + + // make sure logged numbers use unified format + setlocale(LC_NUMERIC, 'en_US.utf8', 'en_US.UTF-8', 'en_US', 'C'); + + if (function_exists('memory_get_usage')) { + $mem = round(memory_get_usage() / 1024 /1024, 1); + } + if (function_exists('memory_get_peak_usage')) { + $mem .= '/'. round(memory_get_peak_usage() / 1024 / 1024, 1); + } + + $log = 'ui:' . $this->get_task() . ($this->action ? '/' . $this->action : '') . " $mem"; if (defined('FILE_API_START')) { rcube::print_timer(FILE_API_START, $log);
View file
chwala-0.5.4.tar.gz/public_html/js/files_api.js -> chwala-0.5.5.tar.gz/public_html/js/files_api.js
Changed
@@ -208,7 +208,7 @@ this.folder_select_element = function(select, params) { var options = , - selected = params && params.selected ? params.selected : this.env.folder; + selected = params && ('selected' in params) ? params.selected : this.env.folder; if (params && params.empty) options.push($('<option>').val('').text('---'));
View file
chwala.dsc
Changed
@@ -2,7 +2,7 @@ Source: chwala Binary: chwala Architecture: all -Version: 0.5.4-0~kolab1 +Version: 0.5.5-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>, Paul Klos <kolab@klos2day.nl> Homepage: http://kolab.org/about/chwala/ @@ -11,5 +11,5 @@ Package-List: roundcubemail deb web extra Files: - 00000000000000000000000000000000 0 chwala-0.5.4.tar.gz + 00000000000000000000000000000000 0 chwala-0.5.5.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +chwala (0.5.5-0~kolab1) unsable; urgency=low + + * Release version 0.5.5 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabys.com> Thu, 14 Mar 2019 12:12:12 +0100 + chwala (0.5.4-0~kolab1) unsable; urgency=low * Release version 0.5.4
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
.